Исправлен формат ошибок API, добавлена обязательная верификация номера телефона при регистрации

This commit is contained in:
vlados31 2022-10-16 13:31:17 +03:00
parent 1a6f2d578e
commit e164e74cde
5 changed files with 69 additions and 35 deletions

View File

@ -186,7 +186,7 @@ class SiteAccountManager(BaseUserManager):
class SiteUser(AbstractBaseUser, PermissionsMixin):
surname = models.CharField(max_length=60, verbose_name="Фамилия")
name = models.CharField(max_length=60, verbose_name="Имя")
email = models.EmailField(unique=True, verbose_name="Email")
email = models.EmailField(unique=True, verbose_name="Email", null=True, blank=True, default=None)
phone = models.CharField(unique=True, max_length=16, verbose_name="Телефон", validators=[
RegexValidator(regex="^\\+7[0-9]{10}$"),
])

View File

@ -7,10 +7,10 @@ from arka.settings import PHONE_VERIFICATION_RESEND_TIME_SECS
API_OK_OBJ = {"status": "success"}
API_ERROR_MULTIPLY_ERRORS = (None, 'multiply errors')
API_ERROR_INTERNAL_ERROR = (100, 'internal error')
API_ERROR_MULTIPLY_ERRORS = (101, 'multiply errors')
API_ERROR_METHOD_NOT_FOUND = (200, 'method not found')
API_ERROR_MISSING_ARGUMENT = (201, 'missing argument')
API_ERROR_UNKNOWN_ARGUMENT = (202, 'unknown argument')
@ -24,24 +24,25 @@ API_ERROR_INVALID_TOKEN = (503, 'invalid token')
# времненное решение, позже нужно будет заменить на конкретные ошибки
API_ERROR_USER_REGISTER = (510, 'user registration error')
API_ERROR_NEED_VERIFY = (511, 'need verification code')
API_ERROR_VALIDATION_INVALID_CODE = (520, 'invalid code')
API_ERROR_VALIDATION_MAX_ATTEMPTS = (521, 'max attempts')
API_ERROR_VALIDATION_CURRENTLY_VERIFIED = (522, 'currently phone is verified')
API_ERROR_VALIDATION_FAILED = (523, 'cannot be verified')
API_ERROR_VALIDATION_NOT_READY = (524, 'verification service not ready. call this method later')
API_ERROR_VALIDATION_NOT_FOUND = (525, 'verification service did not send code. call this method without \'code\'')
API_ERROR_VALIDATION_RESEND_LIMIT = (526, f'resend verification limit '
API_ERROR_VERIFY_INVALID_CODE = (520, 'invalid code')
API_ERROR_VERIFY_MAX_ATTEMPTS = (521, 'max attempts')
API_ERROR_CURRENTLY_VERIFIED = (522, 'currently phone is verified')
API_ERROR_VERIFY_FAILED = (523, 'cannot be verified')
API_ERROR_VERIFY_NOT_READY = (524, 'verification service not ready. call this method later')
API_ERROR_VERIFY_NOT_FOUND = (525, 'verification service did not send code. call this method without \'code\'')
API_ERROR_VERIFY_RESEND_LIMIT = (526, f'resend verification limit '
f'(one verify for {PHONE_VERIFICATION_RESEND_TIME_SECS} secs)')
API_ERROR_VALIDATION_UNKNOWN = (527, 'unknown verification error')
API_ERROR_VERIFY_UNKNOWN = (527, 'unknown verification error')
API_ERROR_VALIDATION = {
PhoneVerificationService.CHECK_PHONE_INVALID_CODE: API_ERROR_VALIDATION_INVALID_CODE,
PhoneVerificationService.CHECK_PHONE_MAX_ATTEMPTS: API_ERROR_VALIDATION_MAX_ATTEMPTS,
PhoneVerificationService.CHECK_PHONE_FAILED: API_ERROR_VALIDATION_FAILED,
PhoneVerificationService.CHECK_PHONE_NOT_READY: API_ERROR_VALIDATION_NOT_READY,
PhoneVerificationService.CHECK_PHONE_NOT_FOUND: API_ERROR_VALIDATION_NOT_FOUND,
PhoneVerificationService.CHECK_PHONE_RESEND_LIMIT: API_ERROR_VALIDATION_RESEND_LIMIT,
API_ERROR_VERIFICATION = {
PhoneVerificationService.CHECK_PHONE_INVALID_CODE: API_ERROR_VERIFY_INVALID_CODE,
PhoneVerificationService.CHECK_PHONE_MAX_ATTEMPTS: API_ERROR_VERIFY_MAX_ATTEMPTS,
PhoneVerificationService.CHECK_PHONE_FAILED: API_ERROR_VERIFY_FAILED,
PhoneVerificationService.CHECK_PHONE_NOT_READY: API_ERROR_VERIFY_NOT_READY,
PhoneVerificationService.CHECK_PHONE_NOT_FOUND: API_ERROR_VERIFY_NOT_FOUND,
PhoneVerificationService.CHECK_PHONE_RESEND_LIMIT: API_ERROR_VERIFY_RESEND_LIMIT,
}
@ -66,9 +67,13 @@ def make_error_object(ex: Exception | list):
"status": "error"
}
if type(ex) == list:
data["error"] = [__make_error(e) for e in ex]
data["error"] = {
"code": API_ERROR_MULTIPLY_ERRORS[0],
"message": API_ERROR_MULTIPLY_ERRORS[1],
}
data["related"] = [__make_error(e) for e in ex]
else:
data["error"] = [__make_error(ex)]
data["error"] = __make_error(ex)
return data
except BaseException as err:
@ -76,9 +81,9 @@ def make_error_object(ex: Exception | list):
return {
"status": "error",
"error": [{
"error": {
"code": API_ERROR_INTERNAL_ERROR[0],
"message": API_ERROR_INTERNAL_ERROR[1],
"related": f"Exception {type(err)}: {str(err)}"
}]
}
}

View File

@ -42,10 +42,12 @@ class ApiAccount:
api_make_param("surname", str, "Фамилия пользователя"),
api_make_param("phone", str, "Телефон в формате <code>[[+]7]1112223333</code> "
"<i>(в квадратных скобках необязательная часть)</i>"),
api_make_param("email", str, "Почта"),
api_make_param("email", str, "Почта", False),
api_make_param("password", str, "Пароль пользователя"),
api_make_param("code", int, "Код верификации (требуется если клиенту будет отправлена "
"одна из ошибок <i>верификации</i>)", False),
], returns="Аналогично методу <code>account.auth</code> в случае успеха")
def register(name, surname, phone, email, password):
def register(name, surname, phone, email, password, code):
user = SiteUser.create_user(
name=name,
@ -57,7 +59,29 @@ class ApiAccount:
try:
user.full_clean()
# теперь проверяем телефон
if code is None:
res, err_code = PhoneVerificationService.send_verify(user.phone)
if not res:
if err_code in API_ERROR_VERIFICATION:
raise Exception(API_ERROR_VERIFICATION[err_code])
else:
raise Exception(API_ERROR_VERIFY_UNKNOWN)
raise Exception(API_ERROR_NEED_VERIFY)
else:
res, err_code = PhoneVerificationService.check_code(user.phone, code)
if res:
user.is_phone_verified = True
user.save()
else:
if err_code in API_ERROR_VERIFICATION:
raise Exception(API_ERROR_VERIFICATION[err_code])
else:
raise Exception(API_ERROR_VERIFY_UNKNOWN)
try:
token = UserToken.create_token(user)
@ -81,6 +105,8 @@ class ApiAccount:
})
errors[field_name] = obj
raise Exception(API_ERROR_USER_REGISTER, errors)
except BaseException as ex:
raise ex
@staticmethod
@api_method("account.verifyPhone",
@ -95,16 +121,16 @@ class ApiAccount:
user = access_token.user
if user.is_phone_verified:
raise Exception(API_ERROR_VALIDATION_CURRENTLY_VERIFIED)
raise Exception(API_ERROR_CURRENTLY_VERIFIED)
if code is None:
res, err_code = PhoneVerificationService.send_verify(user.phone)
if not res:
if err_code in API_ERROR_VALIDATION:
raise Exception(API_ERROR_VALIDATION[err_code])
if err_code in API_ERROR_VERIFICATION:
raise Exception(API_ERROR_VERIFICATION[err_code])
else:
raise Exception(API_ERROR_VALIDATION_UNKNOWN)
raise Exception(API_ERROR_VERIFY_UNKNOWN)
return api_make_response({"action": "phone_call"})
else:
@ -115,10 +141,10 @@ class ApiAccount:
user.save()
return api_make_response({})
else:
if err_code in API_ERROR_VALIDATION:
raise Exception(API_ERROR_VALIDATION[err_code])
if err_code in API_ERROR_VERIFICATION:
raise Exception(API_ERROR_VERIFICATION[err_code])
else:
raise Exception(API_ERROR_VALIDATION_UNKNOWN)
raise Exception(API_ERROR_VERIFY_UNKNOWN)
@staticmethod
@api_method("account.get",

View File

@ -82,6 +82,9 @@ def api_method(func_name, doc="", params: list or None = None, returns=""):
errors.append(ex)
print(f"errors: {errors}, args: {func_args}")
if len(errors) > 0:
if len(errors) == 1:
return make_error_object(errors[0])
else:
return make_error_object(errors)
else:
out = func(**func_args)

View File

@ -61,7 +61,7 @@ class UserToken(models.Model):
def save(self, *args, **kwargs):
if len(self.access_token) == 0:
source = bytearray(self.user.email + self.user.password + str(datetime.now()), 'utf-8')
source = bytearray(str(self.user.email) + self.user.password + str(datetime.now()), 'utf-8')
t = sha512(source).hexdigest()
# чекаем токен в базе