From 5c3b109f4758e81ca97eff2205105f34d6d5e460 Mon Sep 17 00:00:00 2001 From: Alexander-D-Karpov Date: Sun, 9 Oct 2022 06:27:35 +0300 Subject: [PATCH] added products as NFT --- app/conf/api.py | 12 ++++++++-- app/marketplace/api/serializers.py | 2 -- app/marketplace/api/views.py | 17 +++++++++++++++ app/marketplace/models.py | 2 +- app/marketplace/signals.py | 6 ++++- app/marketplace/tasks.py | 35 ++++++++++++++++++++++++++++++ app/users/api/views.py | 8 +++++++ app/users/tasks.py | 6 ----- app/utils/blockchain.py | 1 - 9 files changed, 76 insertions(+), 13 deletions(-) create mode 100644 app/marketplace/tasks.py diff --git a/app/conf/api.py b/app/conf/api.py index 909eb86..eb7fd9c 100644 --- a/app/conf/api.py +++ b/app/conf/api.py @@ -5,7 +5,8 @@ from blockchain.api.views import ( TransactFromAdminView, TransactToUserView, TransactToAdminView, - GetMoneyApi, TransactionHistoryApi, + GetMoneyApi, + TransactionHistoryApi, ) from events.api.views import ( ListCreateEventApi, @@ -15,7 +16,7 @@ from events.api.views import ( ListAttendedWorkersApi, SubmitWorkerAttendedEvent, ) -from marketplace.api.views import ListCreateProductApi, RetrieveUpdateDestroyProductApi +from marketplace.api.views import ListCreateProductApi, RetrieveUpdateDestroyProductApi, BuyProductApi from users.api.views import ( ListCreateUserApi, RetrieveUpdateDeleteUserApi, @@ -27,6 +28,7 @@ from users.api.views import ( RetrieveUpdateDeleteCommandApi, CreateSeasonApi, ListClansApiView, + GetSelfUserApi, ) urlpatterns = [ @@ -118,6 +120,11 @@ urlpatterns = [ RetrieveUpdateDestroyProductApi.as_view(), name="get_update_destroy_product", ), + path( + "product//buy", + BuyProductApi.as_view(), + name="bui_product", + ), ] ), ), @@ -126,6 +133,7 @@ urlpatterns = [ include( [ path("", ListCreateUserApi.as_view(), name="list_create_user"), + path("self/", GetSelfUserApi.as_view(), name="get_self_user_api"), path( "", RetrieveUpdateDeleteUserApi.as_view(), diff --git a/app/marketplace/api/serializers.py b/app/marketplace/api/serializers.py index b299e67..b47fe20 100644 --- a/app/marketplace/api/serializers.py +++ b/app/marketplace/api/serializers.py @@ -12,13 +12,11 @@ class ProductSerializer(serializers.ModelSerializer): "description", "image", "image_cropped", - "nft", "price", "creator", ] extra_kwargs = { "image": {"write_only": True}, - "nft": {"read_only": True}, "slug": {"read_only": True}, "image_cropped": {"read_only": True}, "creator": {"read_only": True}, diff --git a/app/marketplace/api/views.py b/app/marketplace/api/views.py index 1f4006f..39172f1 100644 --- a/app/marketplace/api/views.py +++ b/app/marketplace/api/views.py @@ -2,10 +2,14 @@ from rest_framework import generics from rest_framework.generics import get_object_or_404 from rest_framework.permissions import IsAuthenticated from rest_framework.parsers import FormParser, MultiPartParser +from rest_framework.views import APIView +from blockchain.services import transact_to_admin +from conf import settings from marketplace.api.serializers import ProductSerializer from marketplace.models import Product from common.permissions import IsManager +from utils.blockchain import transfer_nft class ListCreateProductApi(generics.ListCreateAPIView): @@ -27,3 +31,16 @@ class RetrieveUpdateDestroyProductApi(generics.RetrieveUpdateDestroyAPIView): slug=self.request.parser_context["kwargs"]["slug"], ) return product + + +class BuyProductApi(generics.DestroyAPIView): + permission_classes = [IsAuthenticated] + + def get_object(self): + product = get_object_or_404( + Product, + slug=self.request.parser_context["kwargs"]["slug"], + ) + transact_to_admin(self.request.user, product.price) + transfer_nft(settings.MAIN_WALLET, self.request.user.wallet_public_key, product.token) + return product diff --git a/app/marketplace/models.py b/app/marketplace/models.py index 14bb8ce..85a2c25 100644 --- a/app/marketplace/models.py +++ b/app/marketplace/models.py @@ -11,7 +11,7 @@ class Product(models.Model): image = models.ImageField(upload_to="uploads/") image_cropped = models.ImageField(upload_to="cropped/", blank=True) - nft = models.CharField(max_length=500, blank=True) + token = models.IntegerField(default=0) price = models.IntegerField(validators=[MinValueValidator(0)]) creator = models.ForeignKey(User, related_name="products", on_delete=models.CASCADE) diff --git a/app/marketplace/signals.py b/app/marketplace/signals.py index 156ff55..09ba5de 100644 --- a/app/marketplace/signals.py +++ b/app/marketplace/signals.py @@ -5,6 +5,7 @@ from django.dispatch import receiver from utils.file import crop_image from utils.generators import generate_charset from .models import Product +from .tasks import await_nft @receiver(pre_save, sender=Product) @@ -17,9 +18,12 @@ def create_product(sender, instance, **kwargs): @receiver(post_save, sender=Product) def process_product(sender, instance, created, **kwargs): - if instance.image and kwargs["update_fields"] != frozenset({"image_cropped"}): + if instance.image and kwargs["update_fields"] is None: instance.image_cropped = File( crop_image(instance.image.path, cut_to=(250, 250)), name=instance.image.path.split(".")[0].split("/")[-1] + ".png", ) instance.save(update_fields=["image_cropped"]) + + if created and kwargs["update_fields"] is None: + await_nft.apply_async(kwargs={"pk": instance.pk}) diff --git a/app/marketplace/tasks.py b/app/marketplace/tasks.py new file mode 100644 index 0000000..401df5f --- /dev/null +++ b/app/marketplace/tasks.py @@ -0,0 +1,35 @@ +from time import sleep + +from celery import shared_task + +from conf import settings +from marketplace.models import Product +from utils.blockchain import check_transaction, get_nfts, create_nft + + +@shared_task +def await_nft(pk: int): + product = Product.objects.get(pk=pk) + url = product.image.url + t = create_nft(settings.PUB_KEY, url) + + status = "" + try: + status = check_transaction(t.transaction_hash) + except KeyError as e: + pass + + while status != "Success": + sleep(3) + try: + status = check_transaction(t.transaction_hash) + except KeyError as e: + pass + + print(status) + nfts = get_nfts(settings.PUB_KEY) + for nft in nfts: + if nft.uri == product.image.url: + product.token = nft.tokens[0] + product.save(update_fields=["token"]) + return pk diff --git a/app/users/api/views.py b/app/users/api/views.py index b41819d..6d072be 100644 --- a/app/users/api/views.py +++ b/app/users/api/views.py @@ -75,3 +75,11 @@ class ListClansApiView(generics.ListAPIView): serializer_class = ClanSerializer queryset = Clan.objects.all() permission_classes = [IsAuthenticated, IsAdmin] + + +class GetSelfUserApi(generics.RetrieveAPIView): + def get_object(self): + return self.request.user + + permission_classes = [IsAuthenticated] + serializer_class = UserSerializer diff --git a/app/users/tasks.py b/app/users/tasks.py index d7c3152..e69de29 100644 --- a/app/users/tasks.py +++ b/app/users/tasks.py @@ -1,6 +0,0 @@ -from celery import shared_task - - -@shared_task -def process_dir(path): - return path diff --git a/app/utils/blockchain.py b/app/utils/blockchain.py index d31c789..c25f5a4 100644 --- a/app/utils/blockchain.py +++ b/app/utils/blockchain.py @@ -81,7 +81,6 @@ def create_nft(wallet_public_key: str, string_url: str) -> TransHash: def get_nfts(wallet_public_key: str) -> List[NftInfo]: res = r.get(URL + f"/v1/wallets/{wallet_public_key}/nft/balance") - print(res.json()) return list( map( lambda res: NftInfo(uri=res["uri"], tokens=res["tokens"]),