1
0
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:
Adolfo Gómez García 2022-10-05 23:06:23 +02:00
commit 26d26315ac
No known key found for this signature in database
GPG Key ID: DD1ABF20724CDA23
8 changed files with 144 additions and 6 deletions

View File

@ -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,

View File

@ -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

View File

@ -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:

View File

@ -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()

View File

@ -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,

View File

@ -32,3 +32,4 @@
# Make reports visible to autoloader
from . import users
from . import audit

View 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()

View File

@ -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)