added products as NFT

This commit is contained in:
Alexander Karpov 2022-10-09 06:27:35 +03:00
parent abbd90551a
commit 5c3b109f47
9 changed files with 76 additions and 13 deletions

View File

@ -5,7 +5,8 @@ from blockchain.api.views import (
TransactFromAdminView, TransactFromAdminView,
TransactToUserView, TransactToUserView,
TransactToAdminView, TransactToAdminView,
GetMoneyApi, TransactionHistoryApi, GetMoneyApi,
TransactionHistoryApi,
) )
from events.api.views import ( from events.api.views import (
ListCreateEventApi, ListCreateEventApi,
@ -15,7 +16,7 @@ from events.api.views import (
ListAttendedWorkersApi, ListAttendedWorkersApi,
SubmitWorkerAttendedEvent, SubmitWorkerAttendedEvent,
) )
from marketplace.api.views import ListCreateProductApi, RetrieveUpdateDestroyProductApi from marketplace.api.views import ListCreateProductApi, RetrieveUpdateDestroyProductApi, BuyProductApi
from users.api.views import ( from users.api.views import (
ListCreateUserApi, ListCreateUserApi,
RetrieveUpdateDeleteUserApi, RetrieveUpdateDeleteUserApi,
@ -27,6 +28,7 @@ from users.api.views import (
RetrieveUpdateDeleteCommandApi, RetrieveUpdateDeleteCommandApi,
CreateSeasonApi, CreateSeasonApi,
ListClansApiView, ListClansApiView,
GetSelfUserApi,
) )
urlpatterns = [ urlpatterns = [
@ -118,6 +120,11 @@ urlpatterns = [
RetrieveUpdateDestroyProductApi.as_view(), RetrieveUpdateDestroyProductApi.as_view(),
name="get_update_destroy_product", name="get_update_destroy_product",
), ),
path(
"product/<str:slug>/buy",
BuyProductApi.as_view(),
name="bui_product",
),
] ]
), ),
), ),
@ -126,6 +133,7 @@ urlpatterns = [
include( include(
[ [
path("", ListCreateUserApi.as_view(), name="list_create_user"), path("", ListCreateUserApi.as_view(), name="list_create_user"),
path("self/", GetSelfUserApi.as_view(), name="get_self_user_api"),
path( path(
"<str:username>", "<str:username>",
RetrieveUpdateDeleteUserApi.as_view(), RetrieveUpdateDeleteUserApi.as_view(),

View File

@ -12,13 +12,11 @@ class ProductSerializer(serializers.ModelSerializer):
"description", "description",
"image", "image",
"image_cropped", "image_cropped",
"nft",
"price", "price",
"creator", "creator",
] ]
extra_kwargs = { extra_kwargs = {
"image": {"write_only": True}, "image": {"write_only": True},
"nft": {"read_only": True},
"slug": {"read_only": True}, "slug": {"read_only": True},
"image_cropped": {"read_only": True}, "image_cropped": {"read_only": True},
"creator": {"read_only": True}, "creator": {"read_only": True},

View File

@ -2,10 +2,14 @@ from rest_framework import generics
from rest_framework.generics import get_object_or_404 from rest_framework.generics import get_object_or_404
from rest_framework.permissions import IsAuthenticated from rest_framework.permissions import IsAuthenticated
from rest_framework.parsers import FormParser, MultiPartParser 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.api.serializers import ProductSerializer
from marketplace.models import Product from marketplace.models import Product
from common.permissions import IsManager from common.permissions import IsManager
from utils.blockchain import transfer_nft
class ListCreateProductApi(generics.ListCreateAPIView): class ListCreateProductApi(generics.ListCreateAPIView):
@ -27,3 +31,16 @@ class RetrieveUpdateDestroyProductApi(generics.RetrieveUpdateDestroyAPIView):
slug=self.request.parser_context["kwargs"]["slug"], slug=self.request.parser_context["kwargs"]["slug"],
) )
return product 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

View File

@ -11,7 +11,7 @@ class Product(models.Model):
image = models.ImageField(upload_to="uploads/") image = models.ImageField(upload_to="uploads/")
image_cropped = models.ImageField(upload_to="cropped/", blank=True) 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)]) price = models.IntegerField(validators=[MinValueValidator(0)])
creator = models.ForeignKey(User, related_name="products", on_delete=models.CASCADE) creator = models.ForeignKey(User, related_name="products", on_delete=models.CASCADE)

View File

@ -5,6 +5,7 @@ from django.dispatch import receiver
from utils.file import crop_image from utils.file import crop_image
from utils.generators import generate_charset from utils.generators import generate_charset
from .models import Product from .models import Product
from .tasks import await_nft
@receiver(pre_save, sender=Product) @receiver(pre_save, sender=Product)
@ -17,9 +18,12 @@ def create_product(sender, instance, **kwargs):
@receiver(post_save, sender=Product) @receiver(post_save, sender=Product)
def process_product(sender, instance, created, **kwargs): 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( instance.image_cropped = File(
crop_image(instance.image.path, cut_to=(250, 250)), crop_image(instance.image.path, cut_to=(250, 250)),
name=instance.image.path.split(".")[0].split("/")[-1] + ".png", name=instance.image.path.split(".")[0].split("/")[-1] + ".png",
) )
instance.save(update_fields=["image_cropped"]) instance.save(update_fields=["image_cropped"])
if created and kwargs["update_fields"] is None:
await_nft.apply_async(kwargs={"pk": instance.pk})

35
app/marketplace/tasks.py Normal file
View File

@ -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

View File

@ -75,3 +75,11 @@ class ListClansApiView(generics.ListAPIView):
serializer_class = ClanSerializer serializer_class = ClanSerializer
queryset = Clan.objects.all() queryset = Clan.objects.all()
permission_classes = [IsAuthenticated, IsAdmin] permission_classes = [IsAuthenticated, IsAdmin]
class GetSelfUserApi(generics.RetrieveAPIView):
def get_object(self):
return self.request.user
permission_classes = [IsAuthenticated]
serializer_class = UserSerializer

View File

@ -1,6 +0,0 @@
from celery import shared_task
@shared_task
def process_dir(path):
return path

View File

@ -81,7 +81,6 @@ def create_nft(wallet_public_key: str, string_url: str) -> TransHash:
def get_nfts(wallet_public_key: str) -> List[NftInfo]: def get_nfts(wallet_public_key: str) -> List[NftInfo]:
res = r.get(URL + f"/v1/wallets/{wallet_public_key}/nft/balance") res = r.get(URL + f"/v1/wallets/{wallet_public_key}/nft/balance")
print(res.json())
return list( return list(
map( map(
lambda res: NftInfo(uri=res["uri"], tokens=res["tokens"]), lambda res: NftInfo(uri=res["uri"], tokens=res["tokens"]),