old_console/users/services/userinfo.py
2024-11-02 14:12:45 +03:00

128 lines
4 KiB
Python

import datetime
import hashlib
import logging
from abc import ABC, abstractmethod
from typing import Optional
import redis
from django.conf import settings
from django.contrib.auth.models import User
from django.utils import timezone
from console import conslog
from core.utils import dtnow
from users.models import UserInfo
_log = logging.getLogger()
def get_active_users_query():
return User.objects.exclude(username__startswith='deleted_')
def create_user(*args, **kwargs):
user_info_fields_names = (ui.name for ui in UserInfo._meta.get_fields())
user_info_kwargs = {name: kwargs.pop(name) for name in user_info_fields_names if name in kwargs}
if isinstance(user_info_kwargs.get('expire_date', None), datetime.date):
kwargs['is_active'] = kwargs.get('is_active', True) and user_info_kwargs['expire_date'] >= dtnow().date()
if 'user' not in user_info_kwargs:
user_info_kwargs['user'] = User.objects.create_user(*args, **kwargs)
user_info_kwargs['user'].save()
UserInfo.objects.create(**user_info_kwargs)
return user_info_kwargs['user']
def delete_user(user_deleting, log_deletion=True):
""" Method for deleting user by changing his is_active status to False and renaming him """
now = datetime.datetime.now()
hash = hashlib.sha256()
hash.update(str(now).encode('utf-8'))
try:
username_before = user_deleting.username
user_deleting.is_active = False
user_deleting.username = f'deleted_{user_deleting.username}_{hash.hexdigest()[:10]}'
user_deleting.save()
username_after = user_deleting.username
if log_deletion:
log_message = f"User [{user_deleting}] deleted [{username_before}]. " \
f"new username: [{username_after}]"
_log.info(log_message)
except Exception as e:
log_message = f"Exception {e} appears during deleting user"
conslog.add_error_log(log_message, _log)
class UserStatusStrategyABC(ABC):
@abstractmethod
def set_date(self, date):
...
@abstractmethod
def get_date(self):
...
class InUserInfoStrategy(UserStatusStrategyABC):
def __init__(self, user):
self.user = user
def set_date(self, date) -> None:
self.user.userinfo.last_seen = date
self.user.userinfo.save()
def get_date(self) -> str:
return self.user.userinfo.last_seen
class InRedisStrategy(UserStatusStrategyABC):
user_status_field = 'USER_STATUS_{}'
def __init__(self, user):
self.user = user
self.redis_instance = redis.StrictRedis(
host=getattr(settings, 'REDIS_HOST', 'redis'),
port=getattr(settings, 'REDIS_PORT', 6379)
)
def set_date(self, date):
field = self.user_status_field.format(self.user.pk)
data = str(date.timestamp())
self.redis_instance.set(field, data)
def get_date(self):
field = self.user_status_field.format(self.user.pk)
timestamp = self.redis_instance.get(field)
if not timestamp:
return
return datetime.datetime.fromtimestamp(float(timestamp.decode()))
class UserStatusService:
"""User status service."""
timeout_minute = 1
def __init__(self, user, *, strategy: Optional[UserStatusStrategyABC] = None) -> None:
self._status = None
if not strategy:
strategy = InUserInfoStrategy
self._strategy = strategy(user)
self.user = user
def get_status(self) -> str:
"""Return user status online or offline"""
last_date = self._strategy.get_date()
if not last_date:
return 'offline'
last_date = last_date.replace(tzinfo=timezone.utc)
now = dtnow()
delta = datetime.timedelta(minutes=self.timeout_minute)
if now - last_date > delta:
return 'offline'
return 'online'
def set_status(self) -> None:
"""Set last date seen in db."""
now = dtnow()
self._strategy.set_date(now)