mirror of
https://github.com/more-tech4-magnum-opus/backend.git
synced 2024-11-25 04:33:44 +03:00
fixed blockchain, added base operations
This commit is contained in:
parent
79587c322d
commit
abbd90551a
|
@ -1,4 +1,5 @@
|
||||||
DJANGO_DEBUG=yes
|
DJANGO_DEBUG=yes
|
||||||
DATABASE_URL=postgres://postgres:debug@127.0.0.1:5432/moretech
|
DATABASE_URL=postgres://postgres:debug@127.0.0.1:5432/moretech
|
||||||
CELERY_BROKER_URL=redis://localhost:6379/0
|
CELERY_BROKER_URL=redis://localhost:6379/0
|
||||||
MAIN_WALLET=46d3684932f300a7fcdc8cc73cfa3057b5f61695c6e0299a5cb551f645e4cb9c
|
MAIN_WALLET=46d3684932f300a7fcdc8cc73cfa3057b5f61695c6e0299a5cb551f645e4cb9
|
||||||
|
PUB_KEY=0x1a63208e5b82588320a8C24b2c595Ba5d5cbfF3
|
0
app/blockchain/api/__init__.py
Normal file
0
app/blockchain/api/__init__.py
Normal file
17
app/blockchain/api/serializers.py
Normal file
17
app/blockchain/api/serializers.py
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
from django.core.validators import MinValueValidator
|
||||||
|
from rest_framework import serializers
|
||||||
|
from rest_framework.generics import get_object_or_404
|
||||||
|
|
||||||
|
from users.models import User
|
||||||
|
|
||||||
|
|
||||||
|
class TransactFromAdminSerializer(serializers.Serializer):
|
||||||
|
username = serializers.CharField(max_length=200)
|
||||||
|
amount = serializers.IntegerField(validators=[MinValueValidator(1)])
|
||||||
|
|
||||||
|
def validate_username(self, val):
|
||||||
|
return get_object_or_404(User, username=val)
|
||||||
|
|
||||||
|
|
||||||
|
class TransactToAdminSerializer(serializers.Serializer):
|
||||||
|
amount = serializers.IntegerField(validators=[MinValueValidator(1)])
|
76
app/blockchain/api/views.py
Normal file
76
app/blockchain/api/views.py
Normal file
|
@ -0,0 +1,76 @@
|
||||||
|
from drf_yasg.utils import swagger_auto_schema
|
||||||
|
from rest_framework.permissions import IsAuthenticated
|
||||||
|
from rest_framework.views import APIView
|
||||||
|
from rest_framework.response import Response
|
||||||
|
|
||||||
|
from blockchain.api.serializers import (
|
||||||
|
TransactFromAdminSerializer,
|
||||||
|
TransactToAdminSerializer,
|
||||||
|
)
|
||||||
|
from blockchain.models import Transaction
|
||||||
|
from blockchain.services import (
|
||||||
|
transact_from_admin,
|
||||||
|
transact_to_admin,
|
||||||
|
list_user_transactions,
|
||||||
|
)
|
||||||
|
from common.permissions import IsAdmin
|
||||||
|
from utils.blockchain import get_balance
|
||||||
|
|
||||||
|
|
||||||
|
class TransactFromAdminView(APIView):
|
||||||
|
permission_classes = [IsAuthenticated, IsAdmin]
|
||||||
|
|
||||||
|
@swagger_auto_schema(request_body=TransactFromAdminSerializer)
|
||||||
|
def post(self, request):
|
||||||
|
serializer = TransactFromAdminSerializer(data=request.data)
|
||||||
|
serializer.is_valid(raise_exception=True)
|
||||||
|
user = serializer.validated_data["username"]
|
||||||
|
amount = serializer.validated_data["amount"]
|
||||||
|
transact_from_admin(user, amount)
|
||||||
|
return Response({"amount": user.money})
|
||||||
|
|
||||||
|
|
||||||
|
class TransactToAdminView(APIView):
|
||||||
|
permission_classes = [IsAuthenticated]
|
||||||
|
|
||||||
|
@swagger_auto_schema(request_body=TransactToAdminSerializer)
|
||||||
|
def post(self, request):
|
||||||
|
serializer = TransactToAdminSerializer(data=request.data)
|
||||||
|
serializer.is_valid(raise_exception=True)
|
||||||
|
amount = serializer.validated_data["amount"]
|
||||||
|
transact_to_admin(request.user, amount)
|
||||||
|
return Response({"amount": request.user.money})
|
||||||
|
|
||||||
|
|
||||||
|
class TransactToUserView(APIView):
|
||||||
|
permission_classes = [IsAuthenticated]
|
||||||
|
|
||||||
|
@swagger_auto_schema(request_body=TransactFromAdminSerializer)
|
||||||
|
def post(self, request):
|
||||||
|
serializer = TransactFromAdminSerializer(data=request.data)
|
||||||
|
serializer.is_valid(raise_exception=True)
|
||||||
|
user = serializer.validated_data["username"]
|
||||||
|
amount = serializer.validated_data["amount"]
|
||||||
|
t = Transaction.objects.create(
|
||||||
|
user_from=request.user, user_to=user, amount=amount
|
||||||
|
)
|
||||||
|
return Response({"your_amount": t.user_from.money, "amount": t.user_to.money})
|
||||||
|
|
||||||
|
|
||||||
|
class GetMoneyApi(APIView):
|
||||||
|
permission_classes = [IsAuthenticated]
|
||||||
|
|
||||||
|
def get(self, request):
|
||||||
|
user_money = int(get_balance(request.user.wallet_public_key).coins)
|
||||||
|
if request.user.money != user_money:
|
||||||
|
request.user.money = user_money
|
||||||
|
request.user.save(update_fields=["money"])
|
||||||
|
|
||||||
|
return Response({"amount": user_money})
|
||||||
|
|
||||||
|
|
||||||
|
class TransactionHistoryApi(APIView):
|
||||||
|
permission_classes = [IsAuthenticated]
|
||||||
|
|
||||||
|
def get(self, request):
|
||||||
|
return Response(list_user_transactions(request.user))
|
|
@ -2,5 +2,8 @@ from django.apps import AppConfig
|
||||||
|
|
||||||
|
|
||||||
class BlockchainConfig(AppConfig):
|
class BlockchainConfig(AppConfig):
|
||||||
default_auto_field = 'django.db.models.BigAutoField'
|
default_auto_field = "django.db.models.BigAutoField"
|
||||||
name = 'blockchain'
|
name = "blockchain"
|
||||||
|
|
||||||
|
def ready(self):
|
||||||
|
import blockchain.signals
|
||||||
|
|
|
@ -19,6 +19,18 @@ class Transaction(models.Model):
|
||||||
|
|
||||||
hash = models.CharField(max_length=256, unique=True)
|
hash = models.CharField(max_length=256, unique=True)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def t_type(self):
|
||||||
|
return False
|
||||||
|
|
||||||
|
@property
|
||||||
|
def user_from_username(self):
|
||||||
|
return self.user_from.username
|
||||||
|
|
||||||
|
@property
|
||||||
|
def user_to_username(self):
|
||||||
|
return self.user_to.username
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return f"transaction from {self.user_from} to {self.user_to}"
|
return f"transaction from {self.user_from} to {self.user_to}"
|
||||||
|
|
||||||
|
@ -39,11 +51,15 @@ class AdminTransaction(models.Model):
|
||||||
hash = models.CharField(max_length=256, unique=True)
|
hash = models.CharField(max_length=256, unique=True)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def user_from(self):
|
def user_from_username(self):
|
||||||
return "system" if self.type == self.TransactionType.TO else self.user.username
|
return "system" if self.type == self.TransactionType.TO else self.user.username
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def user_to(self):
|
def t_type(self):
|
||||||
|
return self.type.lower()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def user_to_username(self):
|
||||||
return (
|
return (
|
||||||
"system" if self.type == self.TransactionType.FROM else self.user.username
|
"system" if self.type == self.TransactionType.FROM else self.user.username
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,25 +1,33 @@
|
||||||
|
from itertools import chain
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
from rest_framework.exceptions import ValidationError
|
||||||
|
|
||||||
from blockchain.models import Transaction, AdminTransaction
|
from blockchain.models import Transaction, AdminTransaction
|
||||||
from users.models import User
|
from users.models import User
|
||||||
from utils.blockchain import transfer_rubbles
|
from utils.blockchain import transfer_rubbles, get_balance
|
||||||
|
|
||||||
|
|
||||||
def list_user_transactions(user: User) -> list:
|
def list_user_transactions(user: User) -> list:
|
||||||
transaction = []
|
transaction = []
|
||||||
qs = (
|
l = (
|
||||||
user.transactions_to.all()
|
[x for x in user.transactions_to.all()]
|
||||||
| user.transactions_from.all()
|
+ [x for x in user.transactions_from.all()]
|
||||||
| user.admin_transactions.all()
|
+ [x for x in user.admin_transactions.all()]
|
||||||
|
)
|
||||||
|
l.sort(
|
||||||
|
key=lambda instance: instance.created, reverse=True
|
||||||
)
|
)
|
||||||
qs.order_by("created")
|
|
||||||
username = user.username
|
username = user.username
|
||||||
for el in qs: # type: Transaction
|
for el in l: # type: Transaction
|
||||||
|
if not (t := el.t_type):
|
||||||
|
t = "to" if el.user_from.username == username else "from"
|
||||||
|
|
||||||
transaction.append(
|
transaction.append(
|
||||||
{
|
{
|
||||||
"type": "addition" if el.user_from.username == username else "transfer",
|
"type": t,
|
||||||
"user_from": el.user_from.username,
|
"user_from": el.user_from_username,
|
||||||
"user_to": el.user_to.username,
|
"user_to": el.user_to_username,
|
||||||
"amount": el.amount,
|
"amount": el.amount,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
@ -36,3 +44,21 @@ def transact_from_admin(user: User, amount: int):
|
||||||
user.money += amount
|
user.money += amount
|
||||||
user.save(update_fields=["money"])
|
user.save(update_fields=["money"])
|
||||||
|
|
||||||
|
|
||||||
|
def transact_to_admin(user: User, amount: int):
|
||||||
|
user_from_money = int(get_balance(user.wallet_public_key).coins)
|
||||||
|
if user.money != user_from_money:
|
||||||
|
user.money = user_from_money
|
||||||
|
user.save(update_fields=["money"])
|
||||||
|
|
||||||
|
if user_from_money - amount < 0:
|
||||||
|
raise ValidationError("Not enough money")
|
||||||
|
|
||||||
|
t = transfer_rubbles(user.wallet_private_key, settings.PUB_KEY, amount)
|
||||||
|
print(t.transaction_hash)
|
||||||
|
user.money -= amount
|
||||||
|
user.save(update_fields=["money"])
|
||||||
|
|
||||||
|
AdminTransaction.objects.create(
|
||||||
|
type="PAYMENT", amount=amount, user=user, hash=t.transaction_hash
|
||||||
|
)
|
||||||
|
|
|
@ -21,16 +21,18 @@ def validate_create_transaction(sender, instance: Transaction, **kwargs):
|
||||||
instance.user_from.money = user_from_money
|
instance.user_from.money = user_from_money
|
||||||
instance.user_from.save(update_fields=["money"])
|
instance.user_from.save(update_fields=["money"])
|
||||||
|
|
||||||
if user_from_money - instance.amount <= 0:
|
if user_from_money - instance.amount < 0:
|
||||||
raise ValidationError(
|
raise ValidationError(
|
||||||
f"{instance.user_from.username} doesn't have enough money"
|
f"{instance.user_from.username} doesn't have enough money"
|
||||||
)
|
)
|
||||||
|
try:
|
||||||
transaction = transfer_rubbles(
|
transaction = transfer_rubbles(
|
||||||
instance.user_from.wallet_private_key,
|
instance.user_from.wallet_private_key,
|
||||||
instance.user_to.wallet_public_key,
|
instance.user_to.wallet_public_key,
|
||||||
amount=instance.amount,
|
amount=instance.amount,
|
||||||
)
|
)
|
||||||
|
except AttributeError:
|
||||||
|
raise ValidationError("Transaction unsuccessful")
|
||||||
instance.user_from.money -= instance.amount
|
instance.user_from.money -= instance.amount
|
||||||
instance.user_from.save(update_fields=["money"])
|
instance.user_from.save(update_fields=["money"])
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,12 @@
|
||||||
from django.urls import path, include
|
from django.urls import path, include
|
||||||
from rest_framework_simplejwt.views import TokenObtainPairView, TokenRefreshView
|
from rest_framework_simplejwt.views import TokenObtainPairView, TokenRefreshView
|
||||||
|
|
||||||
|
from blockchain.api.views import (
|
||||||
|
TransactFromAdminView,
|
||||||
|
TransactToUserView,
|
||||||
|
TransactToAdminView,
|
||||||
|
GetMoneyApi, TransactionHistoryApi,
|
||||||
|
)
|
||||||
from events.api.views import (
|
from events.api.views import (
|
||||||
ListCreateEventApi,
|
ListCreateEventApi,
|
||||||
RetrieveUpdateDeleteEventApi,
|
RetrieveUpdateDeleteEventApi,
|
||||||
|
@ -33,6 +39,38 @@ urlpatterns = [
|
||||||
]
|
]
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
path(
|
||||||
|
"blockchain/",
|
||||||
|
include(
|
||||||
|
[
|
||||||
|
path(
|
||||||
|
"salary/",
|
||||||
|
TransactFromAdminView.as_view(),
|
||||||
|
name="admin_to_user_transaction_api",
|
||||||
|
),
|
||||||
|
path(
|
||||||
|
"payment/",
|
||||||
|
TransactToAdminView.as_view(),
|
||||||
|
name="user_to_admin_transaction_api",
|
||||||
|
),
|
||||||
|
path(
|
||||||
|
"transact/",
|
||||||
|
TransactToUserView.as_view(),
|
||||||
|
name="user_to_user_transaction_api",
|
||||||
|
),
|
||||||
|
path(
|
||||||
|
"amount/",
|
||||||
|
GetMoneyApi.as_view(),
|
||||||
|
name="get_user_money_api",
|
||||||
|
),
|
||||||
|
path(
|
||||||
|
"history/",
|
||||||
|
TransactionHistoryApi.as_view(),
|
||||||
|
name="list_transactions_api",
|
||||||
|
),
|
||||||
|
]
|
||||||
|
),
|
||||||
|
),
|
||||||
path(
|
path(
|
||||||
"events/",
|
"events/",
|
||||||
include(
|
include(
|
||||||
|
|
|
@ -219,4 +219,5 @@ CORS_ALLOW_ALL_ORIGINS = True
|
||||||
|
|
||||||
|
|
||||||
MAIN_WALLET = env("MAIN_WALLET")
|
MAIN_WALLET = env("MAIN_WALLET")
|
||||||
|
PUB_KEY = env("PUB_KEY")
|
||||||
TELEGRAM_API = "https://tender-badgers-eat-178-71-165-37.loca.lt"
|
TELEGRAM_API = "https://tender-badgers-eat-178-71-165-37.loca.lt"
|
||||||
|
|
|
@ -23,7 +23,11 @@ class User(AbstractUser):
|
||||||
max_length=6, choices=WorkerType.choices, default=WorkerType.WORKER
|
max_length=6, choices=WorkerType.choices, default=WorkerType.WORKER
|
||||||
)
|
)
|
||||||
clan = models.ForeignKey(
|
clan = models.ForeignKey(
|
||||||
"users.Clan", related_name="users", on_delete=models.SET_NULL, null=True
|
"users.Clan",
|
||||||
|
related_name="users",
|
||||||
|
on_delete=models.SET_NULL,
|
||||||
|
null=True,
|
||||||
|
blank=True,
|
||||||
)
|
)
|
||||||
command = models.ForeignKey(
|
command = models.ForeignKey(
|
||||||
"users.Command", related_name="workers", on_delete=models.CASCADE
|
"users.Command", related_name="workers", on_delete=models.CASCADE
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
from django.db.models.signals import pre_save, post_save
|
from django.db.models.signals import pre_save, post_save
|
||||||
from django.dispatch import receiver
|
from django.dispatch import receiver
|
||||||
|
|
||||||
|
from conf import settings
|
||||||
from users.models import User
|
from users.models import User
|
||||||
from utils.blockchain import create_wallet
|
from utils.blockchain import create_wallet, send_matic
|
||||||
|
|
||||||
|
|
||||||
@receiver(post_save, sender=User)
|
@receiver(post_save, sender=User)
|
||||||
|
@ -11,6 +12,7 @@ def process_user(sender, instance, created, **kwargs):
|
||||||
instance.set_password(instance.password)
|
instance.set_password(instance.password)
|
||||||
|
|
||||||
wallet = create_wallet()
|
wallet = create_wallet()
|
||||||
|
send_matic(settings.MAIN_WALLET, wallet.publicKey, 0.1)
|
||||||
|
|
||||||
instance.wallet_public_key = wallet.publicKey
|
instance.wallet_public_key = wallet.publicKey
|
||||||
instance.wallet_private_key = wallet.privateKey
|
instance.wallet_private_key = wallet.privateKey
|
||||||
|
|
|
@ -132,3 +132,20 @@ def get_balance(my_public_wallet_key: str) -> WalletBalance:
|
||||||
return WalletBalance(
|
return WalletBalance(
|
||||||
matic=res.json()["maticAmount"], coins=res.json()["coinsAmount"]
|
matic=res.json()["maticAmount"], coins=res.json()["coinsAmount"]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def send_matic(
|
||||||
|
my_private_wallet_key: str, transfer_publick_key: str, amount: float
|
||||||
|
) -> TransHash:
|
||||||
|
res = r.post(
|
||||||
|
URL + "/v1/transfers/matic",
|
||||||
|
data=json.dumps(
|
||||||
|
{
|
||||||
|
"fromPrivateKey": my_private_wallet_key,
|
||||||
|
"toPublicKey": transfer_publick_key,
|
||||||
|
"amount": amount,
|
||||||
|
}
|
||||||
|
),
|
||||||
|
headers=base_headers,
|
||||||
|
)
|
||||||
|
return TransHash(transaction_hash=res.json()["transaction"])
|
||||||
|
|
Loading…
Reference in New Issue
Block a user