diff --git a/apps/users/api.py b/apps/users/api.py index 69818f741..5cedd0c5f 100644 --- a/apps/users/api.py +++ b/apps/users/api.py @@ -26,11 +26,15 @@ logger = get_logger(__name__) class UserViewSet(IDInFilterMixin, BulkModelViewSet): queryset = User.objects.exclude(role="App") - # queryset = User.objects.all().exclude(role="App").order_by("date_joined") serializer_class = UserSerializer - permission_classes = (IsSuperUserOrAppUser, IsAuthenticated) + permission_classes = (IsSuperUser,) filter_fields = ('username', 'email', 'name', 'id') + def get_permissions(self): + if self.action == "retrieve": + self.permission_classes = (IsSuperUserOrAppUser,) + return super().get_permissions() + class ChangeUserPasswordApi(generics.RetrieveUpdateAPIView): permission_classes = (IsSuperUser,) @@ -57,7 +61,6 @@ class UserResetPasswordApi(generics.UpdateAPIView): def perform_update(self, serializer): # Note: we are not updating the user object here. # We just do the reset-password stuff. - import uuid from .utils import send_reset_password_mail user = self.get_object() user.password_raw = str(uuid.uuid4()) @@ -68,6 +71,7 @@ class UserResetPasswordApi(generics.UpdateAPIView): class UserResetPKApi(generics.UpdateAPIView): queryset = User.objects.all() serializer_class = UserSerializer + permission_classes = (IsAuthenticated,) def perform_update(self, serializer): from .utils import send_reset_ssh_key_mail @@ -91,6 +95,7 @@ class UserUpdatePKApi(generics.UpdateAPIView): class UserGroupViewSet(IDInFilterMixin, BulkModelViewSet): queryset = UserGroup.objects.all() serializer_class = UserGroupSerializer + permission_classes = (IsSuperUser,) class UserGroupUpdateUserApi(generics.RetrieveUpdateAPIView): diff --git a/apps/users/models/user.py b/apps/users/models/user.py index 0e2e06f39..347848b7b 100644 --- a/apps/users/models/user.py +++ b/apps/users/models/user.py @@ -30,6 +30,11 @@ class User(AbstractUser): (ROLE_USER, _('User')), (ROLE_APP, _('Application')) ) + OTP_LEVEL_CHOICES = ( + (0, _('Disable')), + (1, _('Enable')), + (2, _("Force enable")), + ) id = models.UUIDField(default=uuid.uuid4, primary_key=True) username = models.CharField(max_length=128, unique=True, verbose_name=_('Username')) name = models.CharField(max_length=128, verbose_name=_('Name')) @@ -39,8 +44,8 @@ class User(AbstractUser): avatar = models.ImageField(upload_to="avatar", null=True, verbose_name=_('Avatar')) wechat = models.CharField(max_length=128, blank=True, verbose_name=_('Wechat')) phone = models.CharField(max_length=20, blank=True, null=True, verbose_name=_('Phone')) - enable_otp = models.BooleanField(default=False, verbose_name=_('Enable OTP')) - secret_key_otp = models.CharField(max_length=16, blank=True) + otp_level = models.SmallIntegerField(default=0, choices=OTP_LEVEL_CHOICES, verbose_name=_('Enable OTP')) + otp_secret_key = models.CharField(max_length=16, blank=True) # Todo: Auto generate key, let user download _private_key = models.CharField(max_length=5000, blank=True, verbose_name=_('Private key')) _public_key = models.CharField(max_length=5000, blank=True, verbose_name=_('Public key')) @@ -202,6 +207,20 @@ class User(AbstractUser): def generate_reset_token(self): return signer.sign_t({'reset': str(self.id), 'email': self.email}, expires_in=3600) + @property + def otp_enabled(self): + return self.otp_level > 0 + + def enabled_otp(self): + self.otp_level = 1 + + def force_enable_otp(self): + self.otp_level = 2 + + @property + def otp_force_enabled(self): + return self.otp_level == 2 + def to_json(self): return OrderedDict({ 'id': self.id, diff --git a/apps/users/signals_handler.py b/apps/users/signals_handler.py index 9e1abf350..4c6afc663 100644 --- a/apps/users/signals_handler.py +++ b/apps/users/signals_handler.py @@ -2,19 +2,29 @@ # from django.dispatch import receiver -from django.db.models.signals import post_save +# from django.db.models.signals import post_save from common.utils import get_logger -from .models import User +from .signals import post_user_create +# from .models import User logger = get_logger(__file__) -@receiver(post_save, sender=User) -def on_user_created(sender, instance=None, created=False, **kwargs): - if created: - logger.debug("Receive user `{}` create signal".format(instance.name)) - from .utils import send_user_created_mail - logger.info(" - Sending welcome mail ...".format(instance.name)) - if instance.email: - send_user_created_mail(instance) \ No newline at end of file +# @receiver(post_save, sender=User) +# def on_user_created(sender, instance=None, created=False, **kwargs): +# if created: +# logger.debug("Receive user `{}` create signal".format(instance.name)) +# from .utils import send_user_created_mail +# logger.info(" - Sending welcome mail ...".format(instance.name)) +# if instance.email: +# send_user_created_mail(instance) + + +@receiver(post_user_create) +def on_user_create(sender, user=None, **kwargs): + logger.debug("Receive user `{}` create signal".format(user.name)) + from .utils import send_user_created_mail + logger.info(" - Sending welcome mail ...".format(user.name)) + if user.email: + send_user_created_mail(user) diff --git a/apps/users/views/user.py b/apps/users/views/user.py index 84c670370..1d68eb81d 100644 --- a/apps/users/views/user.py +++ b/apps/users/views/user.py @@ -79,6 +79,7 @@ class UserCreateView(AdminUserRequiredMixin, SuccessMessageMixin, CreateView): user = form.save(commit=False) user.created_by = self.request.user.username or 'System' user.save() + post_user_create.send(self.__class__, user=user) return super().form_valid(form)