Browse Source

Add logging to admin actions

devel
Dmitry Novikov 8 years ago
parent
commit
535389b9c4
  1. 129
      abonapp/locale/ru/LC_MESSAGES/django.po
  2. 11
      abonapp/views.py
  3. 3
      accounts_app/admin.py
  4. 142
      accounts_app/locale/ru/LC_MESSAGES/django.po
  5. 45
      accounts_app/migrations/0003_new_user_profile_log.py
  6. 56
      accounts_app/models.py
  7. 29
      accounts_app/templates/accounts/action_log.html
  8. 11
      accounts_app/templates/accounts/ext.htm
  9. 4
      accounts_app/urls.py
  10. 32
      accounts_app/views.py
  11. 1
      devapp/forms.py
  12. 12
      devapp/views.py
  13. 2
      msg_app/templates/msg_app/chat.html
  14. 10
      nas_app/views.py
  15. 15
      tariff_app/views.py

129
abonapp/locale/ru/LC_MESSAGES/django.po

@ -7,7 +7,7 @@
msgid ""
msgstr ""
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2018-08-25 14:55+0300\n"
"POT-Creation-Date: 2018-08-26 19:21+0300\n"
"Last-Translator: Dmitry Novikov nerosketch@gmail.com\n"
"Language: ru\n"
"MIME-Version: 1.0\n"
@ -211,11 +211,12 @@ msgid "Buy service default log"
msgstr "Покупка тарифного плана через админку"
#: models.py:228
#, python-format
msgid "Account \"%(username)s\" not have any active leases"
msgstr "Учётная запись %(username)s не имеет ни одной активной сессии"
msgstr "Учётная запись \"%(username)s\" не имеет ни одной активной сессии"
#: models.py:238 models.py:255 models.py:272 views.py:676 views.py:1124
#: views.py:1167
#: models.py:238 models.py:255 models.py:272 views.py:684 views.py:1132
#: views.py:1175
msgid "NAS required"
msgstr "Необходимо выбрать NAS"
@ -352,7 +353,9 @@ msgstr "Статус оплаты"
#: templates/abonapp/addInvoice.html:57
msgid "This credit will be visible in user page, be careful with your text."
msgstr "Этот долг будет виден на странице абонента, будьте осторожны с высказываниями."
msgstr ""
"Этот долг будет виден на странице абонента, будьте осторожны с "
"высказываниями."
#: templates/abonapp/buy_tariff.html:10 templates/abonapp/buy_tariff.html:15
#: templates/abonapp/buy_tariff.html:31 templates/abonapp/service.html:74
@ -908,134 +911,134 @@ msgstr "Это не правильный IPv6 адрес"
msgid "Address"
msgstr "Адрес"
#: views.py:132
#: views.py:136
msgid "create abon success msg"
msgstr "Абонент успешно создан"
#: views.py:143 views.py:317 views.py:436 views.py:532 views.py:857
#: views.py:941 views.py:1014 views.py:1110
#: views.py:147 views.py:325 views.py:444 views.py:540 views.py:865
#: views.py:949 views.py:1022 views.py:1118
msgid "fix form errors"
msgstr "Некоторые поля заполнены не правильно, проверте ещё раз"
#: views.py:167
#: views.py:175
msgid "delete abon success msg"
msgstr "Абонент успешно удалён"
#: views.py:172
#: views.py:180
#, python-format
msgid "NAS says: '%s'"
msgstr "NAS сказал: '%s'"
#: views.py:193
#: views.py:201
msgid "fill account through admin side"
msgstr "Пополнение счёта через админку"
#: views.py:196
#: views.py:204
#, python-format
msgid "Account filled successfully on %.2f"
msgstr "Счёт пополнен на %.2f"
#: views.py:199
#: views.py:207
msgid "I not know the account id"
msgstr "Счёт успешно пополнен на %.2f"
#: views.py:260
#: views.py:268
msgid "User group id is not matches with group in url"
msgstr "Группа абонента не совпадает с группой указанной в url"
#: views.py:313
#: views.py:321
msgid "edit abon success msg"
msgstr "Абонент успешно изменён"
#: views.py:324
#: views.py:332
msgid "User device was not found"
msgstr "Пользовательское устройство не найдено"
#: views.py:337
#: views.py:345
msgid "User has not have password, and cannot login"
msgstr "Для абонента не задан пароль, он не сможет войти в учётку"
#: views.py:384
#: views.py:392
msgid "Receipt has been created"
msgstr "Квитанция на оплату была создана"
#: views.py:411
#: views.py:419
#, python-format
msgid "Service '%(service_name)s' has connected via admin"
msgstr "Услуга '%(service_name)s' подключена администратором"
#: views.py:421
#: views.py:429
msgid "Tariff has been picked"
msgstr "Тариф успешно выбран"
#: views.py:431
#: views.py:439
msgid "Tariff your picked does not exist"
msgstr "Тариф, который вы выбрали, не существует"
#: views.py:453
#: views.py:461
msgid "User has been detached from service"
msgstr "Абонент отвязан от услуги"
#: views.py:523
#: views.py:531
msgid "Passport information has been saved"
msgstr "Информация о паспорте сохранена"
#: views.py:554
#: views.py:562
msgid "Successfully saved"
msgstr "Успешно сохранено"
#: views.py:575
#: views.py:583
msgid "Device has successfully attached"
msgstr "Устройство успешно прикреплено"
#: views.py:580
#: views.py:588
msgid "Device your selected already does not exist"
msgstr "Устройство, выбранное вами, уже не существует"
#: views.py:582 views.py:604 views.py:642
#: views.py:590 views.py:612 views.py:650
msgid "Abon does not exist"
msgstr "Абонент не найден"
#: views.py:602
#: views.py:610
msgid "Device has successfully unattached"
msgstr "Устройство успешно откреплено"
#: views.py:645
#: views.py:653
msgid "Group what you want doesn't exist"
msgstr "Указанная вами группа не найдена"
#: views.py:667
#: views.py:675
msgid "no ping"
msgstr "не пингуется"
#: views.py:671
#: views.py:679
msgid "Ip not passed"
msgstr "Ip адрес не передан"
#: views.py:683 views.py:699
#: views.py:691 views.py:707
msgid "ping ok"
msgstr "пингуется"
#: views.py:690
#: views.py:698
#, python-format
msgid "IP Conflict! %(all)d/%(return)d results"
msgstr "IP Конфликт! ping %(all)d из %(return)d"
#: views.py:693
#: views.py:701
#, python-format
msgid "ok ping, %(all)d/%(return)d loses"
msgstr "пингуется, %(all)d/%(return)d"
#: views.py:697
#: views.py:705
#, python-format
msgid "no ping, %(all)d/%(return)d loses"
msgstr "не пингуется, %(all)d/%(return)d"
#: views.py:803
#: views.py:811
msgid "Method is not POST"
msgstr "Метод не POST"
#: views.py:820
#: views.py:828
#, python-format
msgid ""
"<a href='%(user_url)s'>%(user_name)s</a> already pinned to this port on this "
@ -1044,108 +1047,108 @@ msgstr ""
"<a href='%(user_url)s'>%(user_name)s</a> уже привязан к этому порту на этом "
"устройстве"
#: views.py:828
#: views.py:836
msgid "Multiple users on the same device port"
msgstr "Несколько абонентов на одном и том же порту устройства"
#: views.py:837
#: views.py:845
msgid "User port has been saved"
msgstr "Порт абонента успешно выбран"
#: views.py:839
#: views.py:847
msgid "Selected port does not exist"
msgstr "Выбранный порт не существует"
#: views.py:841
#: views.py:849
msgid "User does not exist"
msgstr "Абонент не найден"
#: views.py:854
#: views.py:862
msgid "Street successfully saved"
msgstr "Улица успешно сохранена"
#: views.py:877
#: views.py:885
msgid "Streets has been saved"
msgstr "Улицы сохранены"
#: views.py:885
#: views.py:893
msgid "One of these streets has not been found"
msgstr "Одна из этих улиц не была найдена"
#: views.py:897
#: views.py:905
msgid "The street successfully deleted"
msgstr "Улица успешно удалена"
#: views.py:899
#: views.py:907
msgid "The street has not been found"
msgstr "Улица не найдена"
#: views.py:938
#: views.py:946
msgid "New telephone has been saved"
msgstr "Новый телефон сохранен"
#: views.py:959
#: views.py:967
msgid "Additional telephone successfully deleted"
msgstr "Номер телефона успешно удалён"
#: views.py:961
#: views.py:969
msgid "Telephone not found"
msgstr "Телефон не найден"
#: views.py:1011
#: views.py:1019
#, python-format
msgid "Unexpected format %(export_format)s"
msgstr "Нежиданный формат %(export_format)s"
#: views.py:1061
#: views.py:1069
msgid "Periodic pays has been designated"
msgstr "Периодический платёж назначен"
#: views.py:1063
#: views.py:1071
msgid "Something wrong in form"
msgstr "Что-то не так в форме"
#: views.py:1083
#: views.py:1091
msgid "Periodic pay successfully deleted"
msgstr "Периодический платёж успешно удалён"
#: views.py:1115
#: views.py:1123
msgid "User flags has changed successfully"
msgstr "Флаги абонента изменены успешно"
#: views.py:1133
#: views.py:1141
msgid "Ip lease has been freed"
msgstr "Аренда ip освобождена"
#: views.py:1136
#: views.py:1144
msgid "You cannot disable last session"
msgstr "Вы не можете отключить последний ip"
#: views.py:1141
#: views.py:1149
msgid "Ip lease has been started"
msgstr "Аренда ip включена"
#: views.py:1143
#: views.py:1151
msgid "Unexpected action"
msgstr "Непредвиденное действие"
#: views.py:1174
#: views.py:1182
msgid "Ip lease has been created"
msgstr "Аренда ip создана"
#: views.py:1179
#: views.py:1187
msgid "Check form errors"
msgstr "Некоторые поля заполнены не правильно, проверте ещё раз"
#: views.py:1205
#: views.py:1213
msgid "Network access server for users in this group, has been updated"
msgstr "Сервер доступа в интернет привязан к пользователям в этой группе"
#: views.py:1208
#: views.py:1216
msgid "Users not found"
msgstr "Пользователи не найдены"
#: views.py:1210
#: views.py:1218
msgid "You must select gateway"
msgstr "Вы должны выбрать шлюз"

11
abonapp/views.py

@ -129,6 +129,10 @@ class AbonCreateView(CreateView):
assign_perm("abonapp.can_buy_tariff", me, abon)
assign_perm("abonapp.can_view_passport", me, abon)
assign_perm('abonapp.can_add_ballance', me, abon)
me.log(self.request.META, 'cusr', '%s, "%s", %s' % (
abon.username, abon.fio,
abon.group.title if abon.group else ''
))
messages.success(self.request, _('create abon success msg'))
self.abon = abon
return super(AbonCreateView, self).form_valid(form)
@ -164,6 +168,13 @@ class DelAbonDeleteView(DeleteView):
abon = self.get_object()
gid = abon.group.id
abon.delete()
request.user.log(request.META, 'dusr', ('%(uname)s, "%(fio)s", %(group)s %(street)s %(house)s' % {
'uname': abon.username,
'fio': abon.fio or '-',
'group': abon.group.title if abon.group else '',
'street': abon.street.name if abon.street else '',
'house': abon.house or ''
}).strip())
messages.success(request, _('delete abon success msg'))
return redirect('abonapp:people_list', gid=gid)
except NasNetworkError as e:

3
accounts_app/admin.py

@ -1,5 +1,6 @@
from django.contrib import admin
from .models import UserProfile
from .models import UserProfile, UserProfileLog
admin.site.register(UserProfile)
admin.site.register(UserProfileLog)

142
accounts_app/locale/ru/LC_MESSAGES/django.po

@ -7,7 +7,7 @@
msgid ""
msgstr ""
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2018-08-09 14:54+0300\n"
"POT-Creation-Date: 2018-08-26 19:09+0300\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: Dmitry Novikov nerosketch@gmail.com\n"
"Language: ru\n"
@ -18,49 +18,105 @@ msgstr ""
"%10<=4 && (n%100<12 || n%100>14) ? 1 : n%10==0 || (n%10>=5 && n%10<=9) || (n"
"%100>=11 && n%100<=14)? 2 : 3);\n"
#: models.py:19
#: models.py:21
msgid "Users must have an telephone number"
msgstr "У пользователей должен быть номер телефона"
#: models.py:47 templates/accounts/acc_list.html:21
#: models.py:49 templates/accounts/acc_list.html:21
msgid "profile username"
msgstr "Логин"
#: models.py:52
#: models.py:54
msgid "fio"
msgstr "ФИО"
#: models.py:53
#: models.py:55
msgid "birth day"
msgstr "дата рождения"
#: models.py:54
#: models.py:56
msgid "Is active"
msgstr "Активен"
#: models.py:58 templates/accounts/acc_list.html:23
#: models.py:60 templates/accounts/acc_list.html:23
#: templates/accounts/create_acc.html:62 templates/accounts/index.html:9
#: templates/accounts/settings/ch_info.html:38
msgid "Telephone"
msgstr "Телефон"
#: models.py:94
msgid "Author"
msgstr "Автор"
#: models.py:95 templates/accounts/action_log.html:12
msgid "Meta information"
msgstr "Мета информация"
#: models.py:97
msgid "Create user"
msgstr "Создание абонента"
#: models.py:98
msgid "Delete user"
msgstr "Удаление абонента"
#: models.py:99
msgid "Create device"
msgstr "Создание устройства"
#: models.py:100
msgid "Delete device"
msgstr "Удаление устройства"
#: models.py:101
msgid "Create NAS"
msgstr "Создание NAS"
#: models.py:102
msgid "Delete NAS"
msgstr "Удаление NAS"
#: models.py:103
msgid "Create service"
msgstr "Создание тарифа"
#: models.py:104
msgid "Delete service"
msgstr "Удаление тарифа"
#: models.py:106
msgid "Action type"
msgstr "Тип действия"
#: models.py:107
msgid "Additional info"
msgstr "Дополнительная информация"
#: models.py:108
msgid "Action date"
msgstr "Дата действия"
#: models.py:115
msgid "User profile log"
msgstr "Лог действий учётной записи"
#: models.py:116
msgid "User profile logs"
msgstr "Логи действий учётной записи"
#: models.py:125
msgid "Avatar"
msgstr "Аватар"
#: models.py:99
#: models.py:127
msgid "Responsibility groups"
msgstr "Группы администратора"
#: models.py:114
msgid "Can view staff profile"
msgstr "Может просматривать учётку сотрудника"
#: models.py:116
#: models.py:141
msgid "Staff account profile"
msgstr "Учётная запись работника"
#: models.py:117
#: models.py:142
msgid "Staff account profiles"
msgstr "Учётные записи работников"
@ -104,6 +160,22 @@ msgstr "Пользователи не найдены"
msgid "Add account"
msgstr "Добавить учётную запись"
#: templates/accounts/action_log.html:9
msgid "Date"
msgstr "Дата"
#: templates/accounts/action_log.html:10
msgid "Additional"
msgstr "Дополнительное"
#: templates/accounts/action_log.html:11
msgid "Description"
msgstr "Описание"
#: templates/accounts/action_log.html:24
msgid "That admin has no logs"
msgstr "Эта учётная запись не имеет логов"
#: templates/accounts/create_acc.html:9
msgid "Add"
msgstr "Добавить"
@ -145,7 +217,7 @@ msgstr "Повторите пароль"
msgid "Save"
msgstr "Сохранить"
#: templates/accounts/create_acc.html:92 templates/accounts/login.html:59
#: templates/accounts/create_acc.html:92
#: templates/accounts/manage_responsibility_groups.html:21
#: templates/accounts/perms/perms_edit.html:68
#: templates/accounts/set_abon_groups_permission.html:21
@ -153,8 +225,7 @@ msgstr "Сохранить"
msgid "Reset"
msgstr "Сбросить"
#: templates/accounts/index.html:13 templates/accounts/login.html:39
#: templates/accounts/settings/ch_info.html:9
#: templates/accounts/index.html:13 templates/accounts/settings/ch_info.html:9
#: templates/accounts/settings/ch_info.html:13
msgid "User name"
msgstr "Логин"
@ -179,13 +250,13 @@ msgstr "Административный доступ (все права)"
msgid "Auth"
msgstr "Аутентификация"
#: templates/accounts/login.html:27 templates/accounts/login.html:56
#: templates/accounts/login.html:27 templates/accounts/login.html:43
msgid "Login"
msgstr "Войти"
#: templates/accounts/login.html:47
msgid "Password"
msgstr "Пароль"
#: templates/accounts/login.html:48
msgid "Login by location"
msgstr "Войти по местоположению"
#: templates/accounts/manage_responsibility_groups.html:5
msgid "The responsibility of the administrator of the group of subscribers"
@ -235,50 +306,53 @@ msgstr "Старый пароль"
msgid "New password"
msgstr "Новый пароль"
#: views.py:47
#: views.py:32
msgid "Wrong login or password, please try again"
msgstr "Неправильный логин или пароль, попробуйте ещё раз"
#: views.py:123
#: views.py:120
msgid "New password is empty, fill it"
msgstr "Новый пароль пустой, придумайте себе пароль"
#: views.py:125
#: views.py:122
msgid "Wrong password"
msgstr "Неправильный пароль"
#: views.py:127
#: views.py:124
msgid "Empty password, fill it"
msgstr "Пустой пароль, впишите что-то в пароль"
#: views.py:150
#: views.py:148
msgid "You forget specify a password for the new account"
msgstr "Забыли указать пароль для нового аккаунта"
#: views.py:153
#: views.py:151
msgid "You forget to repeat a password for the new account"
msgstr "Забыли повторить пароль для нового аккаунта"
#: views.py:162
#: views.py:160
msgid "Subscriber with this name already exist"
msgstr "Пользователь с таким именем уже есть"
#: views.py:164
#: views.py:162
msgid "Passwords does not match, try again"
msgstr "Пароли не совпадают, попробуйте ещё раз"
#: views.py:179
#: views.py:177
msgid "Profile has been deleted"
msgstr "Учётная запись удалена"
#: views.py:252
#: views.py:255
msgid "Permissions has successfully updated"
msgstr "Права успешно обновлены"
#: views.py:318
#: views.py:322
msgid "Responsibilities has been updated"
msgstr "Ответственность за группы обновлена"
msgid "Password"
msgstr "Пароль"
msgid "Change self onfo"
msgstr "Изменить инфу о себе"
@ -297,5 +371,5 @@ msgstr "Ответственность за группы"
msgid "Profile"
msgstr "Учётная запись"
msgid "Login by location"
msgstr "Войти по местоположению"
msgid "Action log"
msgstr "Лог действий"

45
accounts_app/migrations/0003_new_user_profile_log.py

@ -0,0 +1,45 @@
# Generated by Django 2.1 on 2018-08-26 19:52
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
import jsonfield.fields
class Migration(migrations.Migration):
dependencies = [
('accounts_app', '0002_auto_20180807_1548'),
]
operations = [
migrations.CreateModel(
name='UserProfileLog',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('meta_info', jsonfield.fields.JSONField(default=dict, verbose_name='Meta information')),
('do_type', models.CharField(choices=[('cusr', 'Create user'), ('dusr', 'Delete user'), ('cdev', 'Create device'), ('ddev', 'Delete device'), ('cnas', 'Create NAS'), ('dnas', 'Delete NAS'), ('csrv', 'Create service'), ('dsrv', 'Delete service')], max_length=4, verbose_name='Action type')),
('additional_text', models.CharField(blank=True, null=True, verbose_name='Additional info', max_length=512)),
('action_date', models.DateTimeField(auto_now_add=True, verbose_name='Action date')),
],
options={
'verbose_name': 'User profile log',
'verbose_name_plural': 'User profile logs',
'ordering': ('-action_date',),
},
),
migrations.AlterModelOptions(
name='userprofile',
options={'ordering': ('fio',), 'verbose_name': 'Staff account profile', 'verbose_name_plural': 'Staff account profiles'},
),
migrations.AlterField(
model_name='userprofile',
name='avatar',
field=models.ImageField(blank=True, default=None, null=True, upload_to='user/avatar', verbose_name='Avatar'),
),
migrations.AddField(
model_name='userprofilelog',
name='account',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, verbose_name='Author'),
),
]

56
accounts_app/models.py

@ -1,6 +1,8 @@
# -*- coding:utf-8 -*-
import os
from PIL import Image
from jsonfield import JSONField
from django.db import models
from django.contrib.auth.models import BaseUserManager, AbstractBaseUser, PermissionsMixin
from django.core.validators import RegexValidator
@ -85,7 +87,33 @@ class BaseAccount(AbstractBaseUser, PermissionsMixin):
class Meta:
db_table = 'base_accounts'
ordering = ('username',)
ordering = 'username',
class UserProfileLog(models.Model):
account = models.ForeignKey('UserProfile', on_delete=models.CASCADE, verbose_name=_('Author'))
meta_info = JSONField(verbose_name=_('Meta information'))
ACTION_TYPES = (
('cusr', _('Create user')),
('dusr', _('Delete user')),
('cdev', _('Create device')),
('ddev', _('Delete device')),
('cnas', _('Create NAS')),
('dnas', _('Delete NAS')),
('csrv', _('Create service')),
('dsrv', _('Delete service'))
)
do_type = models.CharField(_('Action type'), max_length=4, choices=ACTION_TYPES)
additional_text = models.CharField(_('Additional info'), blank=True, null=True, max_length=512)
action_date = models.DateTimeField(_('Action date'), auto_now_add=True)
def __str__(self):
return self.get_do_type_display()
class Meta:
ordering = '-action_date',
verbose_name = _('User profile log')
verbose_name_plural = _('User profile logs')
class UserProfileManager(MyUserManager):
@ -110,12 +138,9 @@ class UserProfile(BaseAccount):
return self.get_big_ava()
class Meta:
permissions = (
('can_view_userprofile', _('Can view staff profile')),
)
verbose_name = _('Staff account profile')
verbose_name_plural = _('Staff account profiles')
ordering = ('fio',)
ordering = 'fio',
def _thumbnail_avatar(self):
if self.avatar and os.path.isfile(self.avatar.path):
@ -127,3 +152,24 @@ class UserProfile(BaseAccount):
r = super().save(*args, **kwargs)
self._thumbnail_avatar()
return r
def log(self, request_meta: dict, do_type: str, additional_text=None) -> None:
"""
Make log about administrator actions.
:param request_meta: META from django request.
:param do_type: Choice from UserProfileLog.ACTION_TYPES
:param additional_text: Additional information for action
:return: None
"""
inf = {
'src_ip': request_meta.get('REMOTE_ADDR'),
'username': request_meta.get('USER'),
'hostname': request_meta.get('HOSTNAME'),
'useragent': request_meta.get('HTTP_USER_AGENT')
}
UserProfileLog.objects.create(
account=self,
meta_info=inf,
do_type=do_type,
additional_text=additional_text
)

29
accounts_app/templates/accounts/action_log.html

@ -0,0 +1,29 @@
{% extends request.is_ajax|yesno:'nullcont.htm,accounts/ext.htm' %}
{% load i18n %}
{% block content %}
<div class="table-responsive">
<table class="table table-striped table-bordered">
<thead>
<tr>
<th>{% trans 'Date' %}</th>
<th>{% trans 'Additional' %}</th>
<th>{% trans 'Description' %}</th>
<th>{% trans 'Meta information' %}</th>
</tr>
</thead>
<tbody>
{% for log in object_list %}
<tr>
<td>{{ log.action_date|date:'D d E Y H:i:s' }}</td>
<td>{{ log.additional_text|default_if_none:'-' }}</td>
<td>{{ log.get_do_type_display }}</td>
<td>{{ log.meta_info }}</td>
</tr>
{% empty %}
<tr><td colspan="4">{% trans 'That admin has no logs' %}</td></tr>
{% endfor %}
</tbody>
</table>
</div>
{% endblock %}

11
accounts_app/templates/accounts/ext.htm

@ -70,6 +70,17 @@
</a>
</li>
{% endif %}
{% if perms.accounts_app.view_userprofilelog %}
{% url 'acc_app:action_log' uid as actlog %}
<li{% if actlog == request.path %} class="active"{% endif %}>
<a href="{{ actlog }}">
<span class="glyphicon glyphicon-book"></span>
{% trans 'Action log' %}
</a>
</li>
{% endif %}
</ul>
<div class="tab-content">
<div class="tab-pane active">

4
accounts_app/urls.py

@ -37,5 +37,7 @@ urlpatterns = [
path('<int:uid>/manage_responsibility_groups/',
views.ManageResponsibilityGroups.as_view(),
name='manage_responsibility_groups')
name='manage_responsibility_groups'),
path('<int:uid>/actions/', views.ActionListView.as_view(), name='action_log')
]

32
accounts_app/views.py

@ -14,7 +14,7 @@ from django.conf import settings
from group_app.models import Group
from .models import UserProfile
from .models import UserProfile, UserProfileLog
from .forms import AvatarChangeForm
from djing import lib
from djing.lib.decorators import only_admins
@ -67,7 +67,7 @@ def profile_show(request, uid=0):
return redirect('acc_app:other_profile', uid=request.user.id)
usr = get_object_or_404(UserProfile, id=uid)
if request.user != usr and not request.user.has_perm('accounts_app.can_view_userprofile', usr):
if request.user != usr and not request.user.has_perm('accounts_app.view_userprofile', usr):
raise PermissionDenied
if request.method == 'POST':
usr.username = request.POST.get('username')
@ -168,7 +168,7 @@ def create_profile(request):
@login_required
@only_admins
def delete_profile(request, uid):
def delete_profile(request, uid: int):
prf = get_object_or_404(UserProfile, id=uid)
if uid != request.user.id:
if not request.user.has_perm('acc_app.delete_userprofile', prf):
@ -187,12 +187,12 @@ class AccountsListView(ListView):
def get_queryset(self):
users = UserProfile.objects.filter(is_admin=True).exclude(pk=self.request.user.pk)
users = get_objects_for_user(self.request.user, 'accounts_app.can_view_userprofile', users)
users = get_objects_for_user(self.request.user, 'accounts_app.view_userprofile', users)
return users
@login_required
def perms(request, uid):
def perms(request, uid: int):
if not request.user.is_superuser:
raise PermissionDenied
userprofile = get_object_or_404(UserProfile, id=uid)
@ -239,7 +239,7 @@ class PermissionClassListView(ListView):
@login_required
@only_admins
def perms_edit(request, uid, klass_name, obj_id):
def perms_edit(request, uid: int, klass_name, obj_id):
if not request.user.is_superuser:
raise PermissionDenied
from django.apps import apps
@ -265,7 +265,7 @@ def perms_edit(request, uid, klass_name, obj_id):
@login_required
@only_admins
def set_abon_groups_permission(request, uid):
def set_abon_groups_permission(request, uid: int):
# Only superuser can change object permissions
if not request.user.is_superuser:
raise PermissionDenied
@ -321,3 +321,21 @@ class ManageResponsibilityGroups(ListView):
profile.responsibility_groups.add(*checked_groups)
messages.success(request, _('Responsibilities has been updated'))
return HttpResponseRedirect(self.get_success_url())
@method_decorator(login_decs, name='dispatch')
@method_decorator(permission_required('accounts_app.view_userprofilelog'), name='dispatch')
class ActionListView(ListView):
paginate_by = getattr(settings, 'PAGINATION_ITEMS_PER_PAGE', 10)
template_name = 'accounts/action_log.html'
model = UserProfileLog
def get_queryset(self):
uid = self.kwargs.get('uid')
return UserProfileLog.objects.filter(account__id=uid)
def get_context_data(self, **kwargs):
context = super(ActionListView, self).get_context_data(**kwargs)
context['uid'] = self.kwargs.get('uid')
context['userprofile'] = UserProfile.objects.get(pk=context['uid'])
return context

1
devapp/forms.py

@ -22,6 +22,7 @@ class DeviceForm(forms.ModelForm):
else:
comment = None
super(DeviceForm, self).__init__(*args, **kwargs)
if comment:
self.fields['comment'].widget.attrs['placeholder'] = comment
mac_addr = forms.CharField(widget=forms.TextInput(attrs={

12
devapp/views.py

@ -79,8 +79,13 @@ class DeviceDeleteView(DeleteView):
def delete(self, request, *args, **kwargs):
res = super().delete(request, *args, **kwargs)
try:
request.user.log(request.META, 'ddev', 'ip %s, mac: %s, "%s"' % (
self.object.ip_address or '-',
self.object.mac_addr or '-',
self.object.comment or '-'
))
self.object.update_dhcp()
except DeviceDBException as e:
except (DeviceDBException, PermissionError) as e:
messages.error(request, e)
messages.success(request, _('Device successfully deleted'))
return res
@ -183,6 +188,11 @@ class DeviceCreateView(CreateView):
r = super().form_valid(form)
# change device info in dhcpd.conf
try:
self.request.user.log(self.request.META, 'cdev', 'ip %s, mac: %s, "%s"' % (
self.object.ip_address,
self.object.mac_addr,
self.object.comment
))
self.object.update_dhcp()
messages.success(self.request, _('Device info has been saved'))
except PermissionError as e:

2
msg_app/templates/msg_app/chat.html

@ -25,7 +25,7 @@
</div>
<div class="list-group scroll-area">
{% with can_view_profile=perms.accounts_app.can_view_userprofile %}
{% with can_view_profile=perms.accounts_app.view_userprofile %}
{% for msg in msg_list %}
{% with author=msg.author %}
<div class="list-group-item">

10
nas_app/views.py

@ -34,6 +34,11 @@ class NasCreateView(CreateView):
r = super(NasCreateView, self).form_valid(form)
assign_perm("nas_app.change_nasmodel", self.request.user, self.object)
assign_perm("nas_app.can_view_nas", self.request.user, self.object)
self.request.user.log(self.request.META, 'cnas', '"%(title)s", %(ip)s, %(type)s' % {
'title': self.object.title,
'ip': self.object.ip_address,
'type': self.object.get_nas_type_display()
})
messages.success(self.request, _('New NAS has been created'))
return r
@ -48,6 +53,11 @@ class NasDeleteView(DeleteView):
def delete(self, request, *args, **kwargs):
try:
r = super(NasDeleteView, self).delete(request, *args, **kwargs)
request.user.log(request.META, 'dnas', '"%(title)s", %(ip)s, %(type)s' % {
'title': self.object.title,
'ip': self.object.ip_address,
'type': self.object.get_nas_type_display()
})
messages.success(request, _('Server successfully removed'))
return r
except MessageFailure as e:

15
tariff_app/views.py

@ -47,9 +47,15 @@ def edit_tarif(request, tarif_id=0):
if request.method == 'POST':
frm = forms.TariffForm(request.POST, instance=tarif)
if frm.is_valid():
new_service = frm.save()
service = frm.save()
if tarif is None:
request.user.log(request.META, 'csrv', '"%(title)s", "%(descr)s", %(amount).2f' % {
'title': service.title or '-',
'descr': service.descr or '-',
'amount': service.amount or 0.0
})
messages.success(request, _('Service has been saved'))
return redirect('tarifs:edit', tarif_id=new_service.pk)
return redirect('tarifs:edit', tarif_id=service.pk)
else:
messages.warning(request, _('Some fields were filled incorrect, please try again'))
else:
@ -70,6 +76,11 @@ class TariffDeleteView(DeleteView):
def delete(self, request, *args, **kwargs):
res = super().delete(request, *args, **kwargs)
request.user.log(request.META, 'dsrv', '"%(title)s", "%(descr)s", %(amount).2f' % {
'title': self.object.title or '-',
'descr': self.object.descr or '-',
'amount': self.object.amount or 0.0
})
messages.success(request, _('Service has been deleted'))
return res

Loading…
Cancel
Save