forked from CGM_Public/pretix_original
Added logging for all basic operations
This commit is contained in:
@@ -50,7 +50,7 @@ class SettingsForm(forms.Form):
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.obj = kwargs.pop('obj')
|
||||
kwargs['initial'] = self.obj.settings
|
||||
kwargs['initial'] = self.obj.settings.freeze()
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
def save(self):
|
||||
|
||||
@@ -3,7 +3,8 @@ import json
|
||||
|
||||
from django import forms
|
||||
from django.conf import settings
|
||||
from django.db.models import SubfieldBase, TextField
|
||||
from django.core.serializers.json import DjangoJSONEncoder
|
||||
from django.db.models import Model, QuerySet, SubfieldBase, TextField
|
||||
from django.utils import translation
|
||||
from django.utils.safestring import mark_safe
|
||||
from typing import Dict, List
|
||||
@@ -233,3 +234,15 @@ class I18nTextField(I18nFieldMixin, TextField, metaclass=SubfieldBase):
|
||||
Like I18nCharField, but for TextFields.
|
||||
"""
|
||||
widget = I18nTextarea
|
||||
|
||||
|
||||
class I18nJSONEncoder(DjangoJSONEncoder):
|
||||
def default(self, obj):
|
||||
if isinstance(obj, LazyI18nString):
|
||||
return obj.data
|
||||
elif isinstance(obj, QuerySet):
|
||||
return list(obj)
|
||||
elif isinstance(obj, Model):
|
||||
return {'type': obj.__class__.__name__, 'id': obj.id}
|
||||
else:
|
||||
return super().default(obj)
|
||||
|
||||
@@ -5,6 +5,8 @@ from django.contrib.auth.models import (
|
||||
from django.db import models
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from .base import LoggingMixin
|
||||
|
||||
|
||||
class UserManager(BaseUserManager):
|
||||
"""
|
||||
@@ -30,7 +32,7 @@ class UserManager(BaseUserManager):
|
||||
return user
|
||||
|
||||
|
||||
class User(AbstractBaseUser, PermissionsMixin):
|
||||
class User(AbstractBaseUser, PermissionsMixin, LoggingMixin):
|
||||
"""
|
||||
This is the user model used by pretix for authentication.
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import json
|
||||
import uuid
|
||||
|
||||
from django.contrib.contenttypes.fields import GenericRelation
|
||||
@@ -5,6 +6,8 @@ from django.db import models
|
||||
from django.db.models.signals import post_delete
|
||||
from django.dispatch import receiver
|
||||
|
||||
from pretix.base.i18n import I18nJSONEncoder
|
||||
|
||||
|
||||
def cachedfile_name(instance, filename: str) -> str:
|
||||
return 'cachedfiles/%012d.%s' % (instance.id, filename.split('.')[-1])
|
||||
@@ -29,10 +32,18 @@ def cached_file_delete(sender, instance, **kwargs):
|
||||
instance.file.delete(False)
|
||||
|
||||
|
||||
class LoggedModel(models.Model):
|
||||
class LoggingMixin:
|
||||
logentries = GenericRelation('LogEntry')
|
||||
|
||||
def log_action(self, user, action, data):
|
||||
def log_action(self, action, data=None, user=None):
|
||||
"""
|
||||
Create a LogEntry object that is related to this object.
|
||||
See the LogEntry documentation for details.
|
||||
|
||||
:param action: The namespaced action code
|
||||
:param data: Any JSON-serializable object
|
||||
:param user: The user performing the action (optional)
|
||||
"""
|
||||
from .log import LogEntry
|
||||
from .event import Event
|
||||
|
||||
@@ -41,7 +52,13 @@ class LoggedModel(models.Model):
|
||||
event = self
|
||||
elif hasattr(self, 'event'):
|
||||
event = self.event
|
||||
LogEntry.objects.create(content_object=self, user=user, action=action, data=data, event=event)
|
||||
l = LogEntry(content_object=self, user=user, action_type=action, event=event)
|
||||
if data:
|
||||
l.data = json.dumps(data, cls=I18nJSONEncoder)
|
||||
l.save()
|
||||
|
||||
|
||||
class LoggedModel(models.Model, LoggingMixin):
|
||||
|
||||
class Meta:
|
||||
abstract = True
|
||||
|
||||
@@ -2,7 +2,7 @@ import random
|
||||
import string
|
||||
from datetime import datetime
|
||||
|
||||
from django.db import models
|
||||
from django.db import models, transaction
|
||||
from django.utils.timezone import now
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from typing import List, Union
|
||||
@@ -177,14 +177,6 @@ class Order(LoggedModel):
|
||||
return True
|
||||
return False # nothing there to modify
|
||||
|
||||
def mark_refunded(self):
|
||||
"""
|
||||
Mark this order as refunded. This sets the payment status and returns the order object.
|
||||
"""
|
||||
self.status = Order.STATUS_REFUNDED
|
||||
self.save()
|
||||
return self
|
||||
|
||||
def _can_be_paid(self) -> Union[bool, str]:
|
||||
error_messages = {
|
||||
'late': _("The payment is too late to be accepted."),
|
||||
|
||||
@@ -359,6 +359,7 @@ class BasePaymentProvider:
|
||||
|
||||
:param order: The order object
|
||||
"""
|
||||
self.order.log_action('pretix.base.order.refunded')
|
||||
return '<div class="alert alert-warning">%s</div>' % _('The money can not be automatically refunded, '
|
||||
'please transfer the money back manually.')
|
||||
|
||||
@@ -379,7 +380,9 @@ class BasePaymentProvider:
|
||||
:param request: The HTTP request
|
||||
:param order: The order object
|
||||
"""
|
||||
order.mark_refunded()
|
||||
from pretix.base.services.orders import mark_order_refunded
|
||||
|
||||
mark_order_refunded(order, user=request.user)
|
||||
messages.success(request, _('The order has been marked as refunded. Please transfer the money '
|
||||
'back to the buyer manually.'))
|
||||
|
||||
@@ -440,7 +443,9 @@ class FreeOrderProvider(BasePaymentProvider):
|
||||
:param request: The HTTP request
|
||||
:param order: The order object
|
||||
"""
|
||||
order.mark_refunded()
|
||||
from pretix.base.services.orders import mark_order_refunded
|
||||
|
||||
mark_order_refunded(order, user=request.user)
|
||||
messages.success(request, _('The order has been marked as refunded.'))
|
||||
|
||||
def is_allowed(self, request: HttpRequest) -> bool:
|
||||
|
||||
@@ -7,7 +7,7 @@ from django.utils.translation import ugettext_lazy as _
|
||||
from typing import List
|
||||
|
||||
from pretix.base.models import (
|
||||
CartPosition, Event, EventLock, Order, OrderPosition, Quota,
|
||||
CartPosition, Event, EventLock, Order, OrderPosition, Quota, User,
|
||||
)
|
||||
from pretix.base.payment import BasePaymentProvider
|
||||
from pretix.base.services.mail import mail
|
||||
@@ -31,7 +31,7 @@ error_messages = {
|
||||
|
||||
|
||||
def mark_order_paid(order: Order, provider: str=None, info: str=None, date: datetime=None, manual: bool=None,
|
||||
force: bool=False) -> Order:
|
||||
force: bool=False, user: User=None) -> Order:
|
||||
"""
|
||||
Marks an order as paid. This sets the payment provider, info and date and returns
|
||||
the order object.
|
||||
@@ -46,6 +46,7 @@ def mark_order_paid(order: Order, provider: str=None, info: str=None, date: date
|
||||
:param force: Whether this payment should be marked as paid even if no remaining
|
||||
quota is available (default: ``False``).
|
||||
:type force: boolean
|
||||
:param user: The user that performed the change
|
||||
:raises Quota.QuotaExceededException: if the quota is exceeded and ``force`` is ``False``
|
||||
"""
|
||||
with order.event.lock():
|
||||
@@ -59,6 +60,13 @@ def mark_order_paid(order: Order, provider: str=None, info: str=None, date: date
|
||||
order.payment_manual = manual
|
||||
order.status = Order.STATUS_PAID
|
||||
order.save()
|
||||
order.log_action('pretix.event.order.paid', {
|
||||
'provider': provider,
|
||||
'info': info,
|
||||
'date': date,
|
||||
'manual': manual,
|
||||
'force': force
|
||||
}, user=user)
|
||||
order_paid.send(order.event, order=order)
|
||||
|
||||
mail(
|
||||
@@ -78,6 +86,32 @@ def mark_order_paid(order: Order, provider: str=None, info: str=None, date: date
|
||||
return order
|
||||
|
||||
|
||||
@transaction.atomic
|
||||
def mark_order_refunded(order: Order, user: User=None):
|
||||
"""
|
||||
Mark this order as refunded. This sets the payment status and returns the order object.
|
||||
:param order: The order to change
|
||||
:param user: The user that performed the change
|
||||
"""
|
||||
order.status = Order.STATUS_REFUNDED
|
||||
order.save()
|
||||
order.log_action('pretix.event.order.refunded', user=user)
|
||||
return order
|
||||
|
||||
|
||||
@transaction.atomic
|
||||
def cancel_order(order: Order, user: User=None):
|
||||
"""
|
||||
Mark this order as canceled
|
||||
:param order: The order to change
|
||||
:param user: The user that performed the change
|
||||
"""
|
||||
order.status = Order.STATUS_CANCELLED
|
||||
order.save()
|
||||
order.log_action('pretix.event.order.cancelled', user=user)
|
||||
return order
|
||||
|
||||
|
||||
class OrderError(Exception):
|
||||
pass
|
||||
|
||||
@@ -154,6 +188,7 @@ def _create_order(event: Event, email: str, positions: List[CartPosition], dt: d
|
||||
payment_provider=payment_provider.identifier
|
||||
)
|
||||
OrderPosition.transform_cart_positions(positions, order)
|
||||
order.log_action('pretix.event.order.placed')
|
||||
order_placed.send(event, order=order)
|
||||
return order
|
||||
|
||||
|
||||
@@ -121,7 +121,20 @@ class SettingsProxy:
|
||||
def _flush(self) -> None:
|
||||
self._cached_obj = None
|
||||
|
||||
def freeze(self):
|
||||
settings = {}
|
||||
for key, v in DEFAULTS.items():
|
||||
settings[key] = self._unserialize(v['default'], v['type'])
|
||||
if self._parent:
|
||||
settings.update(self._parent.settings.freeze())
|
||||
for key, value in self._cache().items():
|
||||
settings[key] = self.get(key)
|
||||
return settings
|
||||
|
||||
def _unserialize(self, value: str, as_type: type) -> Any:
|
||||
if as_type is None and value is not None and value.startswith('file://'):
|
||||
as_type = File
|
||||
|
||||
if as_type is not None and isinstance(value, as_type):
|
||||
return value
|
||||
elif value is None:
|
||||
@@ -186,15 +199,14 @@ class SettingsProxy:
|
||||
if value is None and default is not None:
|
||||
value = default
|
||||
|
||||
if as_type is None and value is not None and value.startswith('file://'):
|
||||
as_type = File
|
||||
|
||||
return self._unserialize(value, as_type)
|
||||
|
||||
def __getitem__(self, key: str) -> Any:
|
||||
return self.get(key)
|
||||
|
||||
def __getattr__(self, key: str) -> Any:
|
||||
if key.startswith('_'):
|
||||
return super().__getattr__(key)
|
||||
return self.get(key)
|
||||
|
||||
def __setattr__(self, key: str, value: Any) -> None:
|
||||
|
||||
Reference in New Issue
Block a user