Skip to content

Commit

Permalink
feat: add endpoint for cancellin auctions
Browse files Browse the repository at this point in the history
  • Loading branch information
sandronadiradze committed Nov 4, 2024
1 parent 988d198 commit 6d0f5c1
Show file tree
Hide file tree
Showing 5 changed files with 212 additions and 25 deletions.
65 changes: 65 additions & 0 deletions auction/openapi/auction_cancel_openapi_examples.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
from drf_spectacular.openapi import OpenApiExample


def examples():
return [
OpenApiExample(
"Successful auction cancellation (POST)",
summary="Response for successfully cancelling auction",
description="This example demonstrates a successful response after buyer "
"successfully cancels their auction.",
value={"message": "Auction was successfully canceled."},
response_only=True,
status_codes=[200],
),
OpenApiExample(
"Unauthorized user trying to cancel auction (POST)",
summary="Unauthorized user",
description="This example shows an unauthorized user trying to cancel an "
"auction without authentication.",
value={
"type": "client_error",
"errors": [
{
"code": "not_authenticated",
"message": "Authentication credentials were not provided.",
"field_name": None,
}
],
},
response_only=True,
status_codes=[401],
),
OpenApiExample(
"Error: No permission. (GET)",
summary="No permission to cancel auction.",
description="This example shows an error response when a user tries "
"to cancel an auction that does not belong to them.",
value={
"type": "client_error",
"errors": [
{
"code": "permission_denied",
"message": "You do not have permission to perform this action.",
"field_name": None,
}
],
},
response_only=True,
status_codes=[403],
),
OpenApiExample(
"Response example 5 (GET)",
summary="Auction not found",
description="This example demonstrates the response for a scenario where "
"the requested auction ID does not exist.",
value={
"type": "client_error",
"errors": [
{"code": "not_found", "message": "Not found.", "field_name": None}
],
},
response_only=True,
status_codes=[404],
),
]
1 change: 0 additions & 1 deletion auction/permissions.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,5 +60,4 @@ def has_permission(self, request, view):
return True

def has_object_permission(self, request, view, obj):
print("we are here")
return str(obj.auction.author) == str(request.user.id)
2 changes: 2 additions & 0 deletions auction/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
BulkDeleteAuctionView,
BuyerAuctionListView,
BuyerDashboardListView,
CancelAuctionView,
CreateBookmarkView,
CreateDraftAuctionView,
CreateLiveAuctionView,
Expand Down Expand Up @@ -60,4 +61,5 @@
DeclareWinnerView.as_view(),
name="declare-winner",
),
path("cancel/<uuid:auction_id>/", CancelAuctionView.as_view(), name="cancel-auction"),
]
99 changes: 99 additions & 0 deletions auction/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
from auction.models import Auction, AuctionStatistics, Bookmark
from auction.models.auction import StatusChoices
from auction.openapi import (
auction_cancel_openapi_examples,
auction_create_openapi_examples,
auction_declare_winner_openapi_examples,
auction_delete_openapi_examples,
Expand Down Expand Up @@ -53,6 +54,7 @@
BulkDeleteAuctionSerializer,
SellerLiveAuctionListSerializer,
)
from auction.tasks import revoke_auction_bids
from auction.utils import get_currency_symbol
from bid.models import Bid
from bid.models.bid import StatusChoices as BidStatusChoices
Expand Down Expand Up @@ -1169,3 +1171,100 @@ def post(self, request, auction_id, bid_id, *args, **kwargs):
{"message": f"An error occurred while declaring the winner {str(e)}"},
status=status.HTTP_500_INTERNAL_SERVER_ERROR,
)


@extend_schema(
tags=["Auctions"],
responses={
200: inline_serializer(
name="CancelAuction",
fields={
"message": serializers.CharField(),
},
),
401: inline_serializer(
name="CancelAuctionUnauthorized",
fields={
"message": serializers.CharField(help_text="Authentication error message")
},
),
403: inline_serializer(
name="CancelAuctionForbidden",
fields={
"message": serializers.CharField(help_text="Permission error message")
},
),
404: inline_serializer(
name="CancelAuctionNotFound",
fields={
"message": serializers.CharField(help_text="Not found error message")
},
),
},
examples=auction_cancel_openapi_examples.examples(),
)
class CancelAuctionView(generics.GenericAPIView):
"""
Cancel an active auction.
This view allows authenticated users to cancel an active auction, provided they are
the auction owner and not the seller. The cancellation will invalidate all existing
bids and set their status to `Revoked`.
**Permissions:**
- IsAuthenticated: Requires the user to be authenticated.
- IsNotSellerAndIsOwner: Requires the user to be the auction owner and not to be a seller.
**Response:**
- 200 (OK): Auction has been successfully canceled. The response contains a success message.
- 401 (Unauthorized): Authentication credentials are missing or invalid.
- 403 (Forbidden): User does not have permission to cancel the auction.
- 404 (Not Found): The specified auction does not exist.
**Notes:**
- Only active auctions can be canceled. Auctions in draft, canceled, deleted, or completed
states cannot be canceled.
- An auction cannot be canceled after its end date has passed.
- Upon successful cancellation:
- The auction status is set to CANCELED
- All existing bids are revoked(their status gets set to `Revoked`)
"""

permission_classes = [IsAuthenticated, IsNotSellerAndIsOwner]
lookup_url_kwarg = "auction_id"
queryset = Auction.objects.all()

def validate_auction_status(self, auction):

auction_status_responses = {
"Draft": _("You can not cancel draft auctions."),
"Canceled": _("This auction is already canceled."),
"Deleted": _("You can not cancel deleted auctions."),
"Completed": _(
"You can not cancel auctions that have already been completed."
),
}

if auction.end_date < timezone.now():
raise ValidationError(auction_status_responses["Completed"])

if auction.status in auction_status_responses:
raise ValidationError(auction_status_responses[auction.status])

return True

def post(self, request, auction_id):
with transaction.atomic():
auction = self.get_object()
self.validate_auction_status(auction)
auction.status = StatusChoices.CANCELED
auction.save()
transaction.on_commit(lambda: revoke_auction_bids.delay(auction.id))

return Response(
{"message": _("Auction was successfully canceled.")},
status=status.HTTP_200_OK,
)
70 changes: 46 additions & 24 deletions locale/ka/LC_MESSAGES/django.po
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-11-03 21:56+0000\n"
"POT-Creation-Date: 2024-11-04 01:29+0000\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <[email protected]>\n"
Expand All @@ -28,84 +28,106 @@ msgstr ""
"Buyer პროფილის ტიპის მქონე მომხმარებლებს არ შეუძლიათ ამ ოპერაციის "
"განხორციელება."

#: auction/serializers.py:219
#: auction/serializers.py:221
msgid "This auction is already bookmarked."
msgstr "ეს აუქციონი უკვე დაბუქმარქებულია."

#: auction/serializers.py:276
#: auction/serializers.py:278
msgid "This field is read-only."
msgstr ""
"ამ ველის ჩაწერა არ შეიძლება, რადგან ის მხოლოდ წაკითხვისთვისაა განკუთვნილი."

#: auction/serializers.py:281
#: auction/serializers.py:283
msgid "Max price must be greater than 0."
msgstr "აუქციონში განსაზღვრული მაქსიმალური ფასი უნდა იყოს 0-ზე მეტი."

#: auction/serializers.py:286
#: auction/serializers.py:288
msgid "Invalid category."
msgstr "კატეგორია არავალიდურია."

#: auction/serializers.py:292
#: auction/serializers.py:294
msgid "Tags are required, make sure to include them."
msgstr "თეგების გადმოცემა სავალდებულია."

#: auction/serializers.py:325 auction/serializers.py:424
#: auction/serializers.py:327 auction/serializers.py:426
msgid "Start date cannot be in the past."
msgstr "აუქციონის საწყისი დრო არ შეიძლება იყოს ამჟამინდელ დროზე ნაკლები."

#: auction/serializers.py:345 auction/serializers.py:426
#: auction/serializers.py:437
#: auction/serializers.py:347 auction/serializers.py:428
#: auction/serializers.py:439
msgid "End date must be after the start date."
msgstr "აუქციონის დასასრულის დორ არ შეიძლება იყოს საწყის დროზე ნაკლები."

#: auction/serializers.py:369
#: auction/serializers.py:371
msgid "There was an error during the creation of an auction. Please try again."
msgstr "აუქციონის შექმნისას პრობლემამ იჩინა თავი. გთხოვთ სცადოთ თავიდან."

#: auction/serializers.py:405
#: auction/serializers.py:407
msgid "Cannot modify core auction parameters after the auction has started."
msgstr "აუქციონის დაწყების შემდეგ თქვენ აღარ შეგიძლია მისი მონაცემების შეცვლა."

#: auction/serializers.py:411
#: auction/serializers.py:413
msgid "Cannot update auction that has already ended."
msgstr "თქვენ არ შეგიძლიათ შეცვალოთ უკვე დასრულებული აუქციონი."

#: auction/serializers.py:469
#: auction/serializers.py:471
msgid "There was an error during the update of the auction. Please try again."
msgstr "აუქციონის შექმნისას პრობლემამ იჩინა თავი. გთხოვთ სცადოთ თავიდან."

#: auction/views.py:592
#: auction/views.py:596
msgid "Auction deleted successfully."
msgstr "აუქციონი წარმატებით წაიშალა."

#: auction/views.py:702
#: auction/views.py:706
#, python-brace-format
msgid "Auction with UUID {id} does not exist."
msgstr "აუქციონი მოცემული იდენტიფიკატორით {id} არ არსებობს."

#: auction/views.py:711
#: auction/views.py:715
#, python-brace-format
msgid ""
"{deleted} auctions deleted and {marked_deleted} auctions marked as deleted."
msgstr ""
"წაიშალა {deleted} აუქციონი და {marked_deleted} აუქციონი მონიშნულია, როგორც "
"წაშლილი."

#: auction/views.py:1057
#: auction/views.py:1085
msgid ""
"Deleted, rejected or already approved bids cannot be declared as winners."
msgstr ""
"წაშლილ, უარყოფილ ან უკვე დაეფრუვებულ ბიდს გამარჯვებულად ვერ გამოაცხადებთ."

#: auction/views.py:1068
#: auction/views.py:1101
msgid "You can only declare a winner after the auction has been completed."
msgstr ""
"გამარჯვებულის გამოცხადება მხოლოდ აუქციონის დასრულების შემდეგ შეგიძლიათ."

#: auction/views.py:1112
#: auction/views.py:1143
msgid "Winner of this auction has successfully been declared"
msgstr "აუქციონის გამარჯვებული წარმატებით გამოვლინდა."

#: auction/views.py:1243
msgid "You can not cancel draft auctions."
msgstr ""
"თქვენ არ შეგიძლია დრაფტ სტატუსი მქონე აუქციონის გაუქმება."

#: auction/views.py:1244
msgid "This auction is already canceled."
msgstr "ეს აუქციონი უკვე გაუქმებულია."

#: auction/views.py:1245
msgid "You can not cancel deleted auctions."
msgstr ""
"თქვენ არ შეგიძლიათ წაშლილი აუქციონის გაუქმება."

#: auction/views.py:1246
msgid "You can not cancel auctions that have already been completed."
msgstr "თქვენ არ შეგიძლიათ გააუქომთ აუქციონი, რომელიც უკვე დასრულებულია."

#: auction/views.py:1266
msgid "Auction was successfully canceled."
msgstr "აუქციონის გაუქმება წარმატებით განხორციელდა."

#: bid/permissions.py:50
msgid ""
"As a non-premium user you can not place more than five unique bids on this "
Expand All @@ -115,13 +137,13 @@ msgstr ""
"აუქციონზე დადონ 5-ზე მეტი სხვადასხვა ბიდი, მაგრამ თქვენ შეგიძლიათ, რომუკვე "
"არსებული ბიდის შეთავაზება განაახლოთ იმდენჯერ, რამდენჯერაც მოგესურვებათ."

#: bid/serializers.py:213
#: bid/serializers.py:235
msgid "As a non-premium user you cannot upload more than 5 images per bid."
msgstr ""
"მომხმარებლებს, რომლებსაც არ აქვთ პრემიუმ ტიპის ანგარიში, შეუძლიათ, რომ თითო "
"ბიდისთვის ატვირთონ მხოლოდ ხუთი სურათი."

#: bid/serializers.py:324
#: bid/serializers.py:346
msgid ""
"You can not update bid with an offer that is more or equal than the current "
"one. You can only lower the offer when updating a bid"
Expand All @@ -130,16 +152,16 @@ msgstr ""
"მეტი მნიშვნელობის მითითება. ბიდის განახლებისას შესაძლებელია მხოლოდ ფასის "
"დაკლება."

#: bid/views.py:113
#: bid/views.py:114
msgid "You cannot place bids on auctions with a status of `Draft`."
msgstr "თქვენ არ შეგიძლიათ ბიდის განთავსება 'Draft' სტატუსის მქონე აუქციონზე."

#: bid/views.py:121
#: bid/views.py:122
msgid "Auction has already been completed, you can no longer place bids."
msgstr ""
"აუქციონი უკვე დასრულდა, თქვენ ვეღარ შეძლებთ ამ აუქციონზე ბიდის განთავსებას."

#: bid/views.py:127
#: bid/views.py:128
msgid "Auction has not started yet, you cannot place a bid."
msgstr ""
"აუქციონი ჯერ არ დაწყებულა, თქვენ ვერ შეძლებთ ამ აუქციონზე ბიდის განთავსებას."

0 comments on commit 6d0f5c1

Please sign in to comment.