mirror of
https://github.com/RoboSats/robosats.git
synced 2025-01-07 06:50:09 +00:00
Implement referral attributes and logics
This commit is contained in:
parent
dea2b665fb
commit
4ee6778e11
@ -90,5 +90,8 @@ PROPORTIONAL_ROUTING_FEE_LIMIT = 0.0002
|
|||||||
# Base flat limit fee for routing in Sats (used only when proportional is lower than this)
|
# Base flat limit fee for routing in Sats (used only when proportional is lower than this)
|
||||||
MIN_FLAT_ROUTING_FEE_LIMIT = 10
|
MIN_FLAT_ROUTING_FEE_LIMIT = 10
|
||||||
|
|
||||||
|
# Reward tip. Reward for every finished trade in the referral program (Satoshis)
|
||||||
|
REWARD_TIP = 100
|
||||||
|
|
||||||
# Username for HTLCs escrows
|
# Username for HTLCs escrows
|
||||||
ESCROW_USERNAME = 'admin'
|
ESCROW_USERNAME = 'admin'
|
||||||
|
@ -103,6 +103,7 @@ class UserProfileAdmin(AdminChangeLinksMixin, admin.ModelAdmin):
|
|||||||
"avatar_tag",
|
"avatar_tag",
|
||||||
"id",
|
"id",
|
||||||
"user_link",
|
"user_link",
|
||||||
|
"is_referred",
|
||||||
"telegram_enabled",
|
"telegram_enabled",
|
||||||
"total_contracts",
|
"total_contracts",
|
||||||
"platform_rating",
|
"platform_rating",
|
||||||
|
@ -1029,12 +1029,19 @@ class Logics:
|
|||||||
cls.return_bond(order.taker_bond)
|
cls.return_bond(order.taker_bond)
|
||||||
cls.return_bond(order.maker_bond)
|
cls.return_bond(order.maker_bond)
|
||||||
##### !!! KEY LINE - PAYS THE BUYER INVOICE !!!
|
##### !!! KEY LINE - PAYS THE BUYER INVOICE !!!
|
||||||
##### Backgroun process "follow_invoices" will try to pay this invoice until success
|
##### Background process "follow_invoices" will try to pay this invoice until success
|
||||||
order.status = Order.Status.PAY
|
order.status = Order.Status.PAY
|
||||||
order.payout.status = LNPayment.Status.FLIGHT
|
order.payout.status = LNPayment.Status.FLIGHT
|
||||||
order.payout.save()
|
order.payout.save()
|
||||||
order.save()
|
order.save()
|
||||||
send_message.delay(order.id,'trade_successful')
|
send_message.delay(order.id,'trade_successful')
|
||||||
|
|
||||||
|
# Add referral rewards (safe)
|
||||||
|
try:
|
||||||
|
Logics.add_rewards(order)
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
return True, None
|
return True, None
|
||||||
|
|
||||||
else:
|
else:
|
||||||
@ -1082,3 +1089,17 @@ class Logics:
|
|||||||
user.profile.save()
|
user.profile.save()
|
||||||
return True, None
|
return True, None
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def add_rewards(cls, order):
|
||||||
|
'''
|
||||||
|
This order is called after a trade is finished.
|
||||||
|
If order participants were referred, we add the reward to the referees.
|
||||||
|
'''
|
||||||
|
|
||||||
|
if order.maker.profile.is_referred:
|
||||||
|
order.maker.profile.referred_by.pending_rewards += int(config('REWARD_TIP'))
|
||||||
|
if order.taker.profile.is_referred:
|
||||||
|
order.taker.profile.referred_by.pending_rewards += int(config('REWARD_TIP'))
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
|
@ -411,6 +411,14 @@ class Profile(models.Model):
|
|||||||
default=False,
|
default=False,
|
||||||
null=False
|
null=False
|
||||||
)
|
)
|
||||||
|
referred_by = models.ForeignKey(
|
||||||
|
'self',
|
||||||
|
related_name="referee",
|
||||||
|
on_delete=models.SET_NULL,
|
||||||
|
null=True,
|
||||||
|
default=None,
|
||||||
|
blank=True,
|
||||||
|
)
|
||||||
referral_code = models.CharField(
|
referral_code = models.CharField(
|
||||||
max_length=15,
|
max_length=15,
|
||||||
null=True,
|
null=True,
|
||||||
@ -421,7 +429,7 @@ class Profile(models.Model):
|
|||||||
# Claimable rewards
|
# Claimable rewards
|
||||||
earned_rewards = models.PositiveIntegerField(null=False, default=0)
|
earned_rewards = models.PositiveIntegerField(null=False, default=0)
|
||||||
# Total claimed rewards
|
# Total claimed rewards
|
||||||
claimed_rewarded = models.PositiveIntegerField(null=False, default=0)
|
claimed_rewards = models.PositiveIntegerField(null=False, default=0)
|
||||||
|
|
||||||
# Disputes
|
# Disputes
|
||||||
num_disputes = models.PositiveIntegerField(null=False, default=0)
|
num_disputes = models.PositiveIntegerField(null=False, default=0)
|
||||||
|
@ -17,9 +17,11 @@ def users_cleansing():
|
|||||||
queryset = User.objects.filter(~Q(last_login__range=active_time_range))
|
queryset = User.objects.filter(~Q(last_login__range=active_time_range))
|
||||||
queryset = queryset.filter(is_staff=False) # Do not delete staff users
|
queryset = queryset.filter(is_staff=False) # Do not delete staff users
|
||||||
|
|
||||||
# And do not have an active trade or any past contract.
|
# And do not have an active trade, any past contract or any reward.
|
||||||
deleted_users = []
|
deleted_users = []
|
||||||
for user in queryset:
|
for user in queryset:
|
||||||
|
if user.profile.pending_rewards > 0 or user.profile.earned_rewards > 0 or user.profile.claimed_rewards > 0:
|
||||||
|
continue
|
||||||
if not user.profile.total_contracts == 0:
|
if not user.profile.total_contracts == 0:
|
||||||
continue
|
continue
|
||||||
valid, _, _ = Logics.validate_already_maker_or_taker(user)
|
valid, _, _ = Logics.validate_already_maker_or_taker(user)
|
||||||
@ -45,6 +47,7 @@ def follow_send_payment(lnpayment):
|
|||||||
|
|
||||||
from api.lightning.node import LNNode, MACAROON
|
from api.lightning.node import LNNode, MACAROON
|
||||||
from api.models import LNPayment, Order
|
from api.models import LNPayment, Order
|
||||||
|
from api.logics import Logics
|
||||||
|
|
||||||
fee_limit_sat = int(
|
fee_limit_sat = int(
|
||||||
max(
|
max(
|
||||||
|
@ -3,9 +3,7 @@ from .views import MakerView, OrderView, UserView, BookView, InfoView
|
|||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path("make/", MakerView.as_view()),
|
path("make/", MakerView.as_view()),
|
||||||
path(
|
path("order/",OrderView.as_view({
|
||||||
"order/",
|
|
||||||
OrderView.as_view({
|
|
||||||
"get": "get",
|
"get": "get",
|
||||||
"post": "take_update_confirm_dispute_cancel"
|
"post": "take_update_confirm_dispute_cancel"
|
||||||
}),
|
}),
|
||||||
|
28
api/views.py
28
api/views.py
@ -10,7 +10,7 @@ from django.contrib.auth import authenticate, login, logout
|
|||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
|
|
||||||
from api.serializers import ListOrderSerializer, MakeOrderSerializer, UpdateOrderSerializer
|
from api.serializers import ListOrderSerializer, MakeOrderSerializer, UpdateOrderSerializer
|
||||||
from api.models import LNPayment, MarketTick, Order, Currency
|
from api.models import LNPayment, MarketTick, Order, Currency, Profile
|
||||||
from api.logics import Logics
|
from api.logics import Logics
|
||||||
from api.messages import Telegram
|
from api.messages import Telegram
|
||||||
from secrets import token_urlsafe
|
from secrets import token_urlsafe
|
||||||
@ -446,7 +446,6 @@ class OrderView(viewsets.ViewSet):
|
|||||||
|
|
||||||
|
|
||||||
class UserView(APIView):
|
class UserView(APIView):
|
||||||
lookup_url_kwarg = "token"
|
|
||||||
NickGen = NickGenerator(lang="English",
|
NickGen = NickGenerator(lang="English",
|
||||||
use_adv=False,
|
use_adv=False,
|
||||||
use_adj=True,
|
use_adj=True,
|
||||||
@ -476,12 +475,8 @@ class UserView(APIView):
|
|||||||
"bad_request"] = f"You are already logged in as {request.user} and have an active order"
|
"bad_request"] = f"You are already logged in as {request.user} and have an active order"
|
||||||
return Response(context, status.HTTP_400_BAD_REQUEST)
|
return Response(context, status.HTTP_400_BAD_REQUEST)
|
||||||
|
|
||||||
# Does not allow this 'mistake' if the last login was sometime ago (5 minutes)
|
token = request.GET.get("token")
|
||||||
# if request.user.last_login < timezone.now() - timedelta(minutes=5):
|
ref_code = request.GET.get("ref_code")
|
||||||
# context['bad_request'] = f'You are already logged in as {request.user}'
|
|
||||||
# return Response(context, status.HTTP_400_BAD_REQUEST)
|
|
||||||
|
|
||||||
token = request.GET.get(self.lookup_url_kwarg)
|
|
||||||
|
|
||||||
# Compute token entropy
|
# Compute token entropy
|
||||||
value, counts = np.unique(list(token), return_counts=True)
|
value, counts = np.unique(list(token), return_counts=True)
|
||||||
@ -515,15 +510,26 @@ class UserView(APIView):
|
|||||||
with open(image_path, "wb") as f:
|
with open(image_path, "wb") as f:
|
||||||
rh.img.save(f, format="png")
|
rh.img.save(f, format="png")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Create new credentials and login if nickname is new
|
# Create new credentials and login if nickname is new
|
||||||
if len(User.objects.filter(username=nickname)) == 0:
|
if len(User.objects.filter(username=nickname)) == 0:
|
||||||
User.objects.create_user(username=nickname,
|
User.objects.create_user(username=nickname,
|
||||||
password=token,
|
password=token,
|
||||||
is_staff=False)
|
is_staff=False)
|
||||||
user = authenticate(request, username=nickname, password=token)
|
user = authenticate(request, username=nickname, password=token)
|
||||||
user.profile.avatar = "static/assets/avatars/" + nickname + ".png"
|
|
||||||
#user.profile.referral_code = token_urlsafe(8)
|
|
||||||
login(request, user)
|
login(request, user)
|
||||||
|
|
||||||
|
context['referral_code'] = token_urlsafe(8)
|
||||||
|
user.profile.referral_code = context['referral_code']
|
||||||
|
user.profile.avatar = "static/assets/avatars/" + nickname + ".png"
|
||||||
|
|
||||||
|
# If the ref_code is not none this is a new referred robot
|
||||||
|
if ref_code != None and ref_code !='undefined':
|
||||||
|
user.profile.is_referred = True
|
||||||
|
user.profile.referred_by = Profile.objects.get(referral_code=ref_code)
|
||||||
|
|
||||||
|
user.profile.save()
|
||||||
return Response(context, status=status.HTTP_201_CREATED)
|
return Response(context, status=status.HTTP_201_CREATED)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
@ -686,6 +692,8 @@ class InfoView(ListAPIView):
|
|||||||
|
|
||||||
if request.user.is_authenticated:
|
if request.user.is_authenticated:
|
||||||
context["nickname"] = request.user.username
|
context["nickname"] = request.user.username
|
||||||
|
context["referral_link"] = str(config('HOST_NAME'))+'/ref/'+str(request.user.profile.referral_code)
|
||||||
|
context["earned_rewards"] = request.user.profile.earned_rewards
|
||||||
has_no_active_order, _, order = Logics.validate_already_maker_or_taker(
|
has_no_active_order, _, order = Logics.validate_already_maker_or_taker(
|
||||||
request.user)
|
request.user)
|
||||||
if not has_no_active_order:
|
if not has_no_active_order:
|
||||||
|
@ -56,7 +56,6 @@ export default class UserGenPage extends Component {
|
|||||||
// sort of cryptographically strong function to generate Base62 token client-side
|
// sort of cryptographically strong function to generate Base62 token client-side
|
||||||
genBase62Token(length)
|
genBase62Token(length)
|
||||||
{
|
{
|
||||||
console.log(this.refCode)
|
|
||||||
return window.btoa(Array.from(
|
return window.btoa(Array.from(
|
||||||
window.crypto.getRandomValues(
|
window.crypto.getRandomValues(
|
||||||
new Uint8Array(length * 2)))
|
new Uint8Array(length * 2)))
|
||||||
@ -66,7 +65,7 @@ export default class UserGenPage extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getGeneratedUser=(token)=>{
|
getGeneratedUser=(token)=>{
|
||||||
fetch('/api/user' + '?token=' + token)
|
fetch('/api/user' + '?token=' + token + '&ref_code=' + this.refCode)
|
||||||
.then((response) => response.json())
|
.then((response) => response.json())
|
||||||
.then((data) => {
|
.then((data) => {
|
||||||
this.setState({
|
this.setState({
|
||||||
|
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue
Block a user