mirror of
https://github.com/dkmstr/openuds.git
synced 2025-01-11 05:17:55 +03:00
Merge remote-tracking branch 'origin/v3.6'
This commit is contained in:
commit
26d26315ac
@ -34,7 +34,7 @@ import typing
|
||||
from uds.models import Log, getSqlDatetime
|
||||
from uds.core.util.log import (
|
||||
REST,
|
||||
OWNER_TYPE_REST,
|
||||
OWNER_TYPE_AUDIT,
|
||||
DEBUG,
|
||||
INFO,
|
||||
WARNING,
|
||||
@ -60,7 +60,7 @@ def log_operation(handler: typing.Optional['Handler'], response_code: int, level
|
||||
# Global log is used without owner nor type
|
||||
Log.objects.create(
|
||||
owner_id=0,
|
||||
owner_type=OWNER_TYPE_REST,
|
||||
owner_type=OWNER_TYPE_AUDIT,
|
||||
created=getSqlDatetime(),
|
||||
level=level,
|
||||
source=REST,
|
||||
|
@ -591,7 +591,7 @@ class gui:
|
||||
except Exception:
|
||||
return datetime.date.min if min else datetime.date.max
|
||||
|
||||
def datetime(self, min: bool) -> datetime.datetime:
|
||||
def datetime(self, min: bool = True) -> datetime.datetime:
|
||||
"""
|
||||
Returns the date this object represents
|
||||
|
||||
|
@ -87,7 +87,7 @@ __valueLevels = {v: k for k, v in __nameLevels.items()}
|
||||
|
||||
# Global log owner types:
|
||||
OWNER_TYPE_GLOBAL = -1
|
||||
OWNER_TYPE_REST = -2
|
||||
OWNER_TYPE_AUDIT = -2
|
||||
|
||||
|
||||
def logLevelFromStr(level: str) -> int:
|
||||
|
@ -99,5 +99,5 @@ class AuditLogCleanup(Job):
|
||||
- datetime.timedelta(
|
||||
days=config.GlobalConfig.MAX_AUDIT_LOGS_DURATION.getInt()
|
||||
),
|
||||
owner_type=log.OWNER_TYPE_REST,
|
||||
owner_type=log.OWNER_TYPE_AUDIT,
|
||||
).delete()
|
||||
|
@ -33,6 +33,7 @@
|
||||
import logging
|
||||
|
||||
from django.db import models
|
||||
from uds.core.util.log import logStrFromLevel
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@ -49,7 +50,7 @@ class Log(models.Model):
|
||||
|
||||
if owner id is 0, these are valid owner_type values:
|
||||
-1: Global log
|
||||
-2: REST API log
|
||||
-2: AUDIT log
|
||||
See :py:mod:`uds.core.util.log` for more information
|
||||
"""
|
||||
|
||||
@ -72,6 +73,10 @@ class Log(models.Model):
|
||||
db_table = 'uds_log'
|
||||
app_label = 'uds'
|
||||
|
||||
@property
|
||||
def level_str(self) -> str:
|
||||
return logStrFromLevel(self.level)
|
||||
|
||||
def __str__(self) -> str:
|
||||
return "Log of {}({}): {} - {} - {} - {}".format(
|
||||
self.owner_type,
|
||||
|
@ -32,3 +32,4 @@
|
||||
|
||||
# Make reports visible to autoloader
|
||||
from . import users
|
||||
from . import audit
|
131
server/src/uds/reports/lists/audit.py
Normal file
131
server/src/uds/reports/lists/audit.py
Normal file
@ -0,0 +1,131 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
#
|
||||
# Copyright (c) 2022 Virtual Cable S.L.U.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without modification,
|
||||
# are permitted provided that the following conditions are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
# * Neither the name of Virtual Cable S.L.U. nor the names of its contributors
|
||||
# may be used to endorse or promote products derived from this software
|
||||
# without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
"""
|
||||
Author: Adolfo Gómez, dkmaster at dkmon dot com
|
||||
"""
|
||||
import re
|
||||
import io
|
||||
import typing
|
||||
import csv
|
||||
import datetime
|
||||
import logging
|
||||
|
||||
from django.utils.translation import ugettext, ugettext_lazy as _
|
||||
|
||||
from uds.core.ui import gui
|
||||
from uds.core.util import log
|
||||
from uds.models import Log
|
||||
|
||||
from .base import ListReport
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
|
||||
class ListReportAuditCSV(ListReport):
|
||||
name = _('Audit Log list') # Report name
|
||||
description = _('List administration audit logs') # Report description
|
||||
filename = 'audit.csv'
|
||||
mime_type = 'text/csv'
|
||||
encoded = False
|
||||
# PDF Report of audit logs is extremely slow on pdf, so we will use csv only
|
||||
|
||||
startDate = gui.DateField(
|
||||
order=2,
|
||||
label=_('Starting date'),
|
||||
tooltip=_('starting date for report'),
|
||||
defvalue=datetime.date.min,
|
||||
required=True,
|
||||
)
|
||||
|
||||
endDate = gui.DateField(
|
||||
order=3,
|
||||
label=_('Finish date'),
|
||||
tooltip=_('finish date for report'),
|
||||
defvalue=datetime.date.max,
|
||||
required=True,
|
||||
)
|
||||
|
||||
uuid = 'b5f5ebc8-44e9-11ed-97a9-efa619da6a49'
|
||||
|
||||
# Generator of data
|
||||
def genData(self) -> typing.Generator[typing.Tuple, None, None]:
|
||||
# Xtract user method, response_code and request from data
|
||||
# the format is "user: [method/response_code] request"
|
||||
rx = re.compile(r'(?P<user>[^:]*): \[(?P<method>[^/]*)/(?P<response_code>[^\]]*)\] (?P<request>.*)')
|
||||
|
||||
start = self.startDate.datetime().replace(hour=0, minute=0, second=0, microsecond=0)
|
||||
end = self.endDate.datetime().replace(hour=23, minute=59, second=59, microsecond=999999)
|
||||
for i in Log.objects.filter(
|
||||
created__gte=start, created__lte=end, owner_id=0, owner_type=log.OWNER_TYPE_AUDIT,
|
||||
).order_by('-created'):
|
||||
# extract user, method, response_code and request from data field
|
||||
m = rx.match(i.data)
|
||||
|
||||
if m is not None:
|
||||
# Skip fields with 200 and one of this words on the request
|
||||
# overview, tableinfo, gui, types, system
|
||||
if m.group('response_code') == '200' and any(x in m.group('request') for x in ('overview', 'tableinfo', 'gui', 'types', 'system')):
|
||||
continue
|
||||
# Convert response code to an string if 200, else, to an error
|
||||
response_code = {
|
||||
'200': 'OK',
|
||||
'400': 'Bad Request',
|
||||
'401': 'Unauthorized',
|
||||
'403': 'Forbidden',
|
||||
'404': 'Not Found',
|
||||
'405': 'Method Not Allowed',
|
||||
'500': 'Internal Server Error',
|
||||
'501': 'Not Implemented',
|
||||
}.get(m.group('response_code'), 'CODE: ' + m.group('response_code'))
|
||||
yield (
|
||||
i.created,
|
||||
i.level_str,
|
||||
m.group('user'),
|
||||
m.group('method'),
|
||||
response_code,
|
||||
m.group('request'),
|
||||
)
|
||||
|
||||
def generate(self) -> bytes:
|
||||
output = io.StringIO()
|
||||
writer = csv.writer(output)
|
||||
|
||||
writer.writerow(
|
||||
[ugettext('Date'), ugettext('Level'), ugettext('User'), ugettext('Method'), ugettext('Response code'), ugettext('Request')]
|
||||
)
|
||||
|
||||
for l in self.genData():
|
||||
writer.writerow(l)
|
||||
|
||||
# writer.writerow(['ñoño', 'ádios', 'hola'])
|
||||
|
||||
return output.getvalue().encode()
|
@ -83,6 +83,7 @@ class UsageByPool(StatsReport):
|
||||
vals = [gui.choiceItem('0-0-0-0', gettext('ALL POOLS'))] + [
|
||||
gui.choiceItem(v.uuid, v.name)
|
||||
for v in ServicePool.objects.all().order_by('name')
|
||||
if v.uuid
|
||||
]
|
||||
self.pool.setValues(vals)
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user