Rename ValidationError to HttpError.
This commit is contained in:
parent
34c548acda
commit
a75d5479fa
@ -25,7 +25,7 @@ from django_etebase.token_auth.models import AuthToken
|
|||||||
from django_etebase.token_auth.models import get_default_expiry
|
from django_etebase.token_auth.models import get_default_expiry
|
||||||
from django_etebase.utils import create_user, get_user_queryset, CallbackContext
|
from django_etebase.utils import create_user, get_user_queryset, CallbackContext
|
||||||
from django_etebase.views import msgpack_encode, msgpack_decode
|
from django_etebase.views import msgpack_encode, msgpack_decode
|
||||||
from .exceptions import AuthenticationFailed, transform_validation_error, ValidationError
|
from .exceptions import AuthenticationFailed, transform_validation_error, HttpError
|
||||||
from .msgpack import MsgpackRoute
|
from .msgpack import MsgpackRoute
|
||||||
from .utils import BaseModel
|
from .utils import BaseModel
|
||||||
|
|
||||||
@ -207,20 +207,20 @@ def validate_login_request(
|
|||||||
challenge_data = msgpack_decode(box.decrypt(validated_data.challenge))
|
challenge_data = msgpack_decode(box.decrypt(validated_data.challenge))
|
||||||
now = int(datetime.now().timestamp())
|
now = int(datetime.now().timestamp())
|
||||||
if validated_data.action != expected_action:
|
if validated_data.action != expected_action:
|
||||||
raise ValidationError("wrong_action", f'Expected "{challenge_sent_to_user.response}" but got something else')
|
raise HttpError("wrong_action", f'Expected "{challenge_sent_to_user.response}" but got something else')
|
||||||
elif now - challenge_data["timestamp"] > app_settings.CHALLENGE_VALID_SECONDS:
|
elif now - challenge_data["timestamp"] > app_settings.CHALLENGE_VALID_SECONDS:
|
||||||
raise ValidationError("challenge_expired", "Login challenge has expired")
|
raise HttpError("challenge_expired", "Login challenge has expired")
|
||||||
elif challenge_data["userId"] != user.id:
|
elif challenge_data["userId"] != user.id:
|
||||||
raise ValidationError("wrong_user", "This challenge is for the wrong user")
|
raise HttpError("wrong_user", "This challenge is for the wrong user")
|
||||||
elif not settings.DEBUG and validated_data.host.split(":", 1)[0] != host_from_request:
|
elif not settings.DEBUG and validated_data.host.split(":", 1)[0] != host_from_request:
|
||||||
raise ValidationError(
|
raise HttpError(
|
||||||
"wrong_host", f'Found wrong host name. Got: "{validated_data.host}" expected: "{host_from_request}"'
|
"wrong_host", f'Found wrong host name. Got: "{validated_data.host}" expected: "{host_from_request}"'
|
||||||
)
|
)
|
||||||
verify_key = nacl.signing.VerifyKey(bytes(user.userinfo.loginPubkey), encoder=nacl.encoding.RawEncoder)
|
verify_key = nacl.signing.VerifyKey(bytes(user.userinfo.loginPubkey), encoder=nacl.encoding.RawEncoder)
|
||||||
try:
|
try:
|
||||||
verify_key.verify(challenge_sent_to_user.response, challenge_sent_to_user.signature)
|
verify_key.verify(challenge_sent_to_user.response, challenge_sent_to_user.signature)
|
||||||
except nacl.exceptions.BadSignatureError:
|
except nacl.exceptions.BadSignatureError:
|
||||||
raise ValidationError("login_bad_signature", "Wrong password for user.", status.HTTP_401_UNAUTHORIZED)
|
raise HttpError("login_bad_signature", "Wrong password for user.", status.HTTP_401_UNAUTHORIZED)
|
||||||
|
|
||||||
|
|
||||||
@authentication_router.get("/is_etebase/")
|
@authentication_router.get("/is_etebase/")
|
||||||
@ -269,7 +269,7 @@ def dashboard_url(user: User = Depends(get_authenticated_user)):
|
|||||||
# XXX-TOM
|
# XXX-TOM
|
||||||
get_dashboard_url = app_settings.DASHBOARD_URL_FUNC
|
get_dashboard_url = app_settings.DASHBOARD_URL_FUNC
|
||||||
if get_dashboard_url is None:
|
if get_dashboard_url is None:
|
||||||
raise ValidationError("not_supported", "This server doesn't have a user dashboard.")
|
raise HttpError("not_supported", "This server doesn't have a user dashboard.")
|
||||||
|
|
||||||
ret = {
|
ret = {
|
||||||
"url": get_dashboard_url(request, *args, **kwargs),
|
"url": get_dashboard_url(request, *args, **kwargs),
|
||||||
@ -301,7 +301,7 @@ def signup_save(data: SignupIn, request: Request) -> User:
|
|||||||
raise EtebaseValidationError("generic", str(e))
|
raise EtebaseValidationError("generic", str(e))
|
||||||
|
|
||||||
if hasattr(instance, "userinfo"):
|
if hasattr(instance, "userinfo"):
|
||||||
raise ValidationError("user_exists", "User already exists", status_code=status.HTTP_409_CONFLICT)
|
raise HttpError("user_exists", "User already exists", status_code=status.HTTP_409_CONFLICT)
|
||||||
|
|
||||||
models.UserInfo.objects.create(**data.dict(exclude={"user"}), owner=instance)
|
models.UserInfo.objects.create(**data.dict(exclude={"user"}), owner=instance)
|
||||||
return instance
|
return instance
|
||||||
|
@ -11,7 +11,7 @@ from fastapi import APIRouter, Depends, status
|
|||||||
|
|
||||||
from django_etebase import models
|
from django_etebase import models
|
||||||
from .authentication import get_authenticated_user
|
from .authentication import get_authenticated_user
|
||||||
from .exceptions import ValidationError, transform_validation_error, PermissionDenied
|
from .exceptions import HttpError, transform_validation_error, PermissionDenied
|
||||||
from .msgpack import MsgpackRoute
|
from .msgpack import MsgpackRoute
|
||||||
from .stoken_handler import filter_by_stoken_and_limit, filter_by_stoken, get_stoken_obj, get_queryset_stoken
|
from .stoken_handler import filter_by_stoken_and_limit, filter_by_stoken, get_stoken_obj, get_queryset_stoken
|
||||||
from .utils import get_object_or_404, Context, Prefetch, PrefetchQuery, is_collection_admin, BaseModel
|
from .utils import get_object_or_404, Context, Prefetch, PrefetchQuery, is_collection_admin, BaseModel
|
||||||
@ -144,7 +144,7 @@ class ItemDepIn(BaseModel):
|
|||||||
item = models.CollectionItem.objects.get(uid=self.uid)
|
item = models.CollectionItem.objects.get(uid=self.uid)
|
||||||
etag = self.etag
|
etag = self.etag
|
||||||
if item.etag != etag:
|
if item.etag != etag:
|
||||||
raise ValidationError(
|
raise HttpError(
|
||||||
"wrong_etag",
|
"wrong_etag",
|
||||||
"Wrong etag. Expected {} got {}".format(item.etag, etag),
|
"Wrong etag. Expected {} got {}".format(item.etag, etag),
|
||||||
status_code=status.HTTP_409_CONFLICT,
|
status_code=status.HTTP_409_CONFLICT,
|
||||||
@ -274,7 +274,7 @@ def process_revisions_for_item(item: models.CollectionItem, revision_data: Colle
|
|||||||
chunk_obj.chunkFile.save("IGNORED", ContentFile(content))
|
chunk_obj.chunkFile.save("IGNORED", ContentFile(content))
|
||||||
chunk_obj.save()
|
chunk_obj.save()
|
||||||
else:
|
else:
|
||||||
raise ValidationError("chunk_no_content", "Tried to create a new chunk without content")
|
raise HttpError("chunk_no_content", "Tried to create a new chunk without content")
|
||||||
|
|
||||||
chunks_objs.append(chunk_obj)
|
chunks_objs.append(chunk_obj)
|
||||||
|
|
||||||
@ -290,12 +290,12 @@ def process_revisions_for_item(item: models.CollectionItem, revision_data: Colle
|
|||||||
def _create(data: CollectionIn, user: User):
|
def _create(data: CollectionIn, user: User):
|
||||||
with transaction.atomic():
|
with transaction.atomic():
|
||||||
if data.item.etag is not None:
|
if data.item.etag is not None:
|
||||||
raise ValidationError("bad_etag", "etag is not null")
|
raise HttpError("bad_etag", "etag is not null")
|
||||||
instance = models.Collection(uid=data.item.uid, owner=user)
|
instance = models.Collection(uid=data.item.uid, owner=user)
|
||||||
try:
|
try:
|
||||||
instance.validate_unique()
|
instance.validate_unique()
|
||||||
except django_exceptions.ValidationError:
|
except django_exceptions.ValidationError:
|
||||||
raise ValidationError(
|
raise HttpError(
|
||||||
"unique_uid", "Collection with this uid already exists", status_code=status.HTTP_409_CONFLICT
|
"unique_uid", "Collection with this uid already exists", status_code=status.HTTP_409_CONFLICT
|
||||||
)
|
)
|
||||||
instance.save()
|
instance.save()
|
||||||
@ -355,7 +355,7 @@ def item_create(item_model: CollectionItemIn, collection: models.Collection, val
|
|||||||
return instance
|
return instance
|
||||||
|
|
||||||
if validate_etag and cur_etag != etag:
|
if validate_etag and cur_etag != etag:
|
||||||
raise ValidationError(
|
raise HttpError(
|
||||||
"wrong_etag",
|
"wrong_etag",
|
||||||
"Wrong etag. Expected {} got {}".format(cur_etag, etag),
|
"Wrong etag. Expected {} got {}".format(cur_etag, etag),
|
||||||
status_code=status.HTTP_409_CONFLICT,
|
status_code=status.HTTP_409_CONFLICT,
|
||||||
@ -425,7 +425,7 @@ def item_bulk_common(data: ItemBatchIn, user: User, stoken: t.Optional[str], uid
|
|||||||
collection_object = queryset.select_for_update().get(uid=uid)
|
collection_object = queryset.select_for_update().get(uid=uid)
|
||||||
|
|
||||||
if stoken is not None and stoken != collection_object.stoken:
|
if stoken is not None and stoken != collection_object.stoken:
|
||||||
raise ValidationError("stale_stoken", "Stoken is too old", status_code=status.HTTP_409_CONFLICT)
|
raise HttpError("stale_stoken", "Stoken is too old", status_code=status.HTTP_409_CONFLICT)
|
||||||
|
|
||||||
# XXX-TOM: make sure we return compatible errors
|
# XXX-TOM: make sure we return compatible errors
|
||||||
data.validate_db()
|
data.validate_db()
|
||||||
@ -482,7 +482,7 @@ def fetch_updates(
|
|||||||
item_limit = 200
|
item_limit = 200
|
||||||
|
|
||||||
if len(data) > item_limit:
|
if len(data) > item_limit:
|
||||||
raise ValidationError("too_many_items", "Request has too many items.", status_code=status.HTTP_400_BAD_REQUEST)
|
raise HttpError("too_many_items", "Request has too many items.", status_code=status.HTTP_400_BAD_REQUEST)
|
||||||
|
|
||||||
queryset, stoken_rev = filter_by_stoken(stoken, queryset, models.CollectionItem.stoken_annotation)
|
queryset, stoken_rev = filter_by_stoken(stoken, queryset, models.CollectionItem.stoken_annotation)
|
||||||
|
|
||||||
|
@ -3,19 +3,17 @@ import typing as t
|
|||||||
|
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
|
|
||||||
from django_etebase.exceptions import EtebaseValidationError
|
|
||||||
|
|
||||||
|
class HttpErrorField(BaseModel):
|
||||||
class ValidationErrorField(BaseModel):
|
|
||||||
field: str
|
field: str
|
||||||
code: str
|
code: str
|
||||||
detail: str
|
detail: str
|
||||||
|
|
||||||
|
|
||||||
class ValidationErrorOut(BaseModel):
|
class HttpErrorOut(BaseModel):
|
||||||
code: str
|
code: str
|
||||||
detail: str
|
detail: str
|
||||||
errors: t.Optional[t.List[ValidationErrorField]]
|
errors: t.Optional[t.List[HttpErrorField]]
|
||||||
|
|
||||||
|
|
||||||
class CustomHttpException(Exception):
|
class CustomHttpException(Exception):
|
||||||
@ -59,24 +57,23 @@ class PermissionDenied(CustomHttpException):
|
|||||||
super().__init__(code=code, detail=detail, status_code=status_code)
|
super().__init__(code=code, detail=detail, status_code=status_code)
|
||||||
|
|
||||||
|
|
||||||
class ValidationError(CustomHttpException):
|
class HttpError(CustomHttpException):
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
code: str,
|
code: str,
|
||||||
detail: str,
|
detail: str,
|
||||||
status_code: int = status.HTTP_400_BAD_REQUEST,
|
status_code: int = status.HTTP_400_BAD_REQUEST,
|
||||||
field: t.Optional[str] = None,
|
errors: t.Optional[t.List["HttpError"]] = None,
|
||||||
errors: t.Optional[t.List["ValidationError"]] = None,
|
|
||||||
):
|
):
|
||||||
self.errors = errors
|
self.errors = errors
|
||||||
super().__init__(code=code, detail=detail, status_code=status_code)
|
super().__init__(code=code, detail=detail, status_code=status_code)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def as_dict(self) -> dict:
|
def as_dict(self) -> dict:
|
||||||
return ValidationErrorOut(code=self.code, errors=self.errors, detail=self.detail).dict()
|
return HttpErrorOut(code=self.code, errors=self.errors, detail=self.detail).dict()
|
||||||
|
|
||||||
|
|
||||||
def flatten_errors(field_name, errors) -> t.List[ValidationError]:
|
def flatten_errors(field_name, errors) -> t.List[HttpError]:
|
||||||
ret = []
|
ret = []
|
||||||
if isinstance(errors, dict):
|
if isinstance(errors, dict):
|
||||||
for error_key in errors:
|
for error_key in errors:
|
||||||
@ -98,5 +95,5 @@ def transform_validation_error(prefix, err):
|
|||||||
elif not hasattr(err, "message"):
|
elif not hasattr(err, "message"):
|
||||||
errors = flatten_errors(prefix, err.error_list)
|
errors = flatten_errors(prefix, err.error_list)
|
||||||
else:
|
else:
|
||||||
raise EtebaseValidationError(err.code, err.message)
|
raise HttpError(err.code, err.message)
|
||||||
raise ValidationError(code="field_errors", detail="Field validations failed.", errors=errors)
|
raise HttpError(code="field_errors", detail="Field validations failed.", errors=errors)
|
||||||
|
@ -8,7 +8,7 @@ from fastapi import APIRouter, Depends, status, Request
|
|||||||
from django_etebase import models
|
from django_etebase import models
|
||||||
from django_etebase.utils import get_user_queryset, CallbackContext
|
from django_etebase.utils import get_user_queryset, CallbackContext
|
||||||
from .authentication import get_authenticated_user
|
from .authentication import get_authenticated_user
|
||||||
from .exceptions import ValidationError, PermissionDenied
|
from .exceptions import HttpError, PermissionDenied
|
||||||
from .msgpack import MsgpackRoute
|
from .msgpack import MsgpackRoute
|
||||||
from .utils import get_object_or_404, Context, is_collection_admin, BaseModel
|
from .utils import get_object_or_404, Context, is_collection_admin, BaseModel
|
||||||
|
|
||||||
@ -42,7 +42,7 @@ class CollectionInvitationCommon(BaseModel):
|
|||||||
class CollectionInvitationIn(CollectionInvitationCommon):
|
class CollectionInvitationIn(CollectionInvitationCommon):
|
||||||
def validate_db(self, context: Context):
|
def validate_db(self, context: Context):
|
||||||
if context.user.username == self.username.lower():
|
if context.user.username == self.username.lower():
|
||||||
raise ValidationError("no_self_invite", "Inviting yourself is not allowed")
|
raise HttpError("no_self_invite", "Inviting yourself is not allowed")
|
||||||
|
|
||||||
|
|
||||||
class CollectionInvitationOut(CollectionInvitationCommon):
|
class CollectionInvitationOut(CollectionInvitationCommon):
|
||||||
@ -186,7 +186,7 @@ def outgoing_create(
|
|||||||
**data.dict(exclude={"collection", "username"}), user=to_user, fromMember=member
|
**data.dict(exclude={"collection", "username"}), user=to_user, fromMember=member
|
||||||
)
|
)
|
||||||
except IntegrityError:
|
except IntegrityError:
|
||||||
raise ValidationError("invitation_exists", "Invitation already exists")
|
raise HttpError("invitation_exists", "Invitation already exists")
|
||||||
|
|
||||||
|
|
||||||
@invitation_outgoing_router.get("/", response_model=InvitationListResponse)
|
@invitation_outgoing_router.get("/", response_model=InvitationListResponse)
|
||||||
|
@ -10,7 +10,7 @@ from django.contrib.auth import get_user_model
|
|||||||
|
|
||||||
from django_etebase.models import AccessLevels
|
from django_etebase.models import AccessLevels
|
||||||
|
|
||||||
from .exceptions import ValidationError
|
from .exceptions import HttpError
|
||||||
|
|
||||||
User = get_user_model()
|
User = get_user_model()
|
||||||
|
|
||||||
@ -35,7 +35,7 @@ def get_object_or_404(queryset: QuerySet, **kwargs):
|
|||||||
try:
|
try:
|
||||||
return queryset.get(**kwargs)
|
return queryset.get(**kwargs)
|
||||||
except ObjectDoesNotExist as e:
|
except ObjectDoesNotExist as e:
|
||||||
raise ValidationError("does_not_exist", str(e), status_code=status.HTTP_404_NOT_FOUND)
|
raise HttpError("does_not_exist", str(e), status_code=status.HTTP_404_NOT_FOUND)
|
||||||
|
|
||||||
|
|
||||||
def is_collection_admin(collection, user):
|
def is_collection_admin(collection, user):
|
||||||
|
Loading…
Reference in New Issue
Block a user