Fix avatar persistance and login issues. Add onchain payment cleanup.

This commit is contained in:
Reckless_Satoshi 2022-06-20 10:56:08 -07:00
parent 7eb29fb57e
commit 6f7cfb5147
No known key found for this signature in database
GPG Key ID: 9C4585B561315571
9 changed files with 99 additions and 39 deletions

View File

@ -70,7 +70,7 @@ class OrderAdmin(AdminChangeLinksMixin, admin.ModelAdmin):
"taker_bond",
"trade_escrow",
)
list_filter = ("is_disputed", "is_fiat_sent", "type", "currency", "status")
list_filter = ("is_disputed", "is_fiat_sent", "is_swap","type", "currency", "status")
search_fields = ["id","amount","min_amount","max_amount"]
def amt(self, obj):

View File

@ -293,6 +293,10 @@ class Logics:
Order.Status.MLD,
]
# in any case, if order is_swap and there is an onchain_payment, cancel it.
if not order.status in does_not_expire:
cls.cancel_onchain_payment(order)
if order.status in does_not_expire:
return False
@ -600,7 +604,7 @@ class Logics:
valid = cls.create_onchain_payment(order, user, preliminary_amount=context["invoice_amount"])
if not valid:
context["swap_allowed"] = False
context["swap_failure_reason"] = "Not enough onchain liquidity available to offer a SWAP"
context["swap_failure_reason"] = "Not enough onchain liquidity available to offer a swap"
return True, context
context["swap_allowed"] = True
@ -720,9 +724,7 @@ class Logics:
}
# cancel onchain_payout if existing
if order.payout_tx:
order.payout_tx.status = OnchainPayment.Status.CANCE
order.payout_tx.save()
cls.cancel_onchain_payment(order)
num_satoshis = cls.payout_amount(order, user)[1]["invoice_amount"]
payout = LNNode.validate_ln_invoice(invoice, num_satoshis)
@ -894,9 +896,12 @@ class Logics:
# 4.a) When maker cancel after bond (before escrow)
"""The order into cancelled status if maker cancels."""
elif (order.status in [Order.Status.WF2,Order.Status.WFE] and order.maker == user):
# cancel onchain payment if existing
cls.cancel_onchain_payment(order)
# Settle the maker bond (Maker loses the bond for canceling an ongoing trade)
valid = cls.settle_bond(order.maker_bond)
cls.return_bond(order.taker_bond) # returns taker bond
if valid:
order.status = Order.Status.UCA
order.save()
@ -905,9 +910,11 @@ class Logics:
return True, None
# 4.b) When taker cancel after bond (before escrow)
"""The order into cancelled status if maker cancels."""
"""The order into cancelled status if mtker cancels."""
elif (order.status in [Order.Status.WF2, Order.Status.WFE]
and order.taker == user):
# cancel onchain payment if existing
cls.cancel_onchain_payment(order)
# Settle the maker bond (Maker loses the bond for canceling an ongoing trade)
valid = cls.settle_bond(order.taker_bond)
if valid:
@ -957,6 +964,8 @@ class Logics:
def collaborative_cancel(cls, order):
if not order.status in [Order.Status.WFI, Order.Status.CHA]:
return
# cancel onchain payment if existing
cls.cancel_onchain_payment(order)
cls.return_bond(order.maker_bond)
cls.return_bond(order.taker_bond)
cls.return_escrow(order)
@ -1300,6 +1309,16 @@ class Logics:
else:
raise e
def cancel_onchain_payment(order):
''' Cancel onchain_payment if existing '''
if order.payout_tx:
order.payout_tx.status = OnchainPayment.Status.CANCE
order.payout_tx.save()
return True
else:
return False
def cancel_bond(bond):
"""cancel a bond"""
# Same as return bond, but used when the invoice was never LOCKED

View File

@ -251,12 +251,7 @@ class OnchainPayment(models.Model):
default=None)
def __str__(self):
if self.txid:
txname = str(self.txid)[:8]
else:
txname = str(self.id)
return f"TX-{txname}: {self.Concepts(self.concept).label} - {self.Status(self.status).label}"
return f"TX-{str(self.id)}: {self.Concepts(self.concept).label} - {self.Status(self.status).label}"
class Meta:
verbose_name = "Onchain payment"

View File

@ -167,15 +167,17 @@ def follow_send_payment(hash):
context = {"routing_failed": "The payout invoice has expired"}
return False, context
@shared_task(name="lnpayments_cleansing")
def lnpayments_cleansing():
@shared_task(name="payments_cleansing")
def payments_cleansing():
"""
Deletes cancelled lnpayments (hodl invoices never locked) that
belong to orders expired more than 3 days ago
Deletes cancelled payments (hodl invoices never locked) that
belong to orders expired more than 3 days ago.
Deletes cancelled onchain_payments
"""
from django.db.models import Q
from api.models import LNPayment
from api.models import OnchainPayment
from datetime import timedelta
from django.utils import timezone
@ -191,17 +193,35 @@ def lnpayments_cleansing():
# And do not have an active trade, any past contract or any reward.
deleted_lnpayments = []
for lnpayment in queryset:
# Try an except. In case some chatroom is already missing.
# Try and except. In case some payment is already missing.
try:
name = str(lnpayment)
lnpayment.delete()
deleted_lnpayments.append(name)
except:
pass
# same for onchain payments
queryset = OnchainPayment.objects.filter(Q(status=OnchainPayment.Status.CANCEL),
Q(order_paid_TX__expires_at__lt=finished_time))
# And do not have an active trade, any past contract or any reward.
deleted_onchainpayments = []
for onchainpayment in queryset:
# Try and except. In case some payment is already missing.
try:
name = str(onchainpayment)
onchainpayment.delete()
deleted_onchainpayments.append(name)
except:
pass
results = {
"num_deleted": len(deleted_lnpayments),
"num_lnpayments_deleted": len(deleted_lnpayments),
"deleted_lnpayments": deleted_lnpayments,
"num_onchainpayments_deleted": len(deleted_onchainpayments),
"deleted_onchainpayments": deleted_onchainpayments,
}
return results

View File

@ -572,13 +572,13 @@ class UserView(APIView):
# If an existing user opens the main page by mistake, we do not want it to create a new nickname/profile for him
if request.user.is_authenticated:
context = {"nickname": request.user.username}
not_participant, _, _ = Logics.validate_already_maker_or_taker(
not_participant, _, order = Logics.validate_already_maker_or_taker(
request.user)
# Does not allow this 'mistake' if an active order
if not not_participant:
context[
"bad_request"] = f"You are already logged in as {request.user} and have an active order"
context["active_order_id"] = order.id
context["bad_request"] = f"You are already logged in as {request.user} and have an active order"
return Response(context, status.HTTP_400_BAD_REQUEST)
# Deprecated, kept temporarily for legacy reasons
@ -643,13 +643,13 @@ class UserView(APIView):
# If an existing user opens the main page by mistake, we do not want it to create a new nickname/profile for him
if request.user.is_authenticated:
context = {"nickname": request.user.username}
not_participant, _, _ = Logics.validate_already_maker_or_taker(
not_participant, _, order = Logics.validate_already_maker_or_taker(
request.user)
# Does not allow this 'mistake' if an active order
if not not_participant:
context[
"bad_request"] = f"You are already logged in as {request.user} and have an active order"
context["active_order_id"] = order.id
context["bad_request"] = f"You are already logged in as {request.user} and have an active order"
return Response(context, status.HTTP_400_BAD_REQUEST)
# The new way. The token is never sent. Only its SHA256
@ -748,6 +748,16 @@ class UserView(APIView):
login(request, user)
context["public_key"] = user.profile.public_key
context["encrypted_private_key"] = user.profile.encrypted_private_key
# return active order or last made order if any
has_no_active_order, _, order = Logics.validate_already_maker_or_taker(request.user)
if not has_no_active_order:
context["active_order_id"] = order.id
else:
last_order = Order.objects.filter(Q(maker=request.user) | Q(taker=request.user)).last()
if last_order:
context["last_order_id"] = last_order.id
# Sends the welcome back message, only if created +3 mins ago
if request.user.date_joined < (timezone.now() - timedelta(minutes=3)):
context["found"] = "We found your Robot avatar. Welcome back!"

View File

@ -64,9 +64,10 @@ class BottomBar extends Component {
fetch('/api/info/')
.then((response) => response.json())
.then((data) => this.setState(data)
& this.setState({active_order_id: data.active_order_id ? data.active_order_id : null,
last_order_id: data.last_order_id ? data.last_order_id : null})
& this.props.setAppState({nickname:data.nickname, loading:false}));
& this.props.setAppState({nickname:data.nickname,
loading:false,
activeOrderId: data.active_order_id ? data.active_order_id : null,
lastOrderId: data.last_order_id ? data.last_order_id : null}));
}
handleClickOpenStatsForNerds = () => {
@ -129,7 +130,7 @@ class BottomBar extends Component {
bottomBarDesktop =()=>{
const { t } = this.props;
var hasRewards = this.state.earned_rewards > 0 ? true: false;
var hasOrder = this.state.active_order_id > 0 & !this.state.profileShown & this.props.avatarLoaded ? true : false;
var hasOrder = this.props.activeOrderId > 0 & !this.state.profileShown & this.props.avatarLoaded ? true : false;
return(
<Paper elevation={6} style={{height:40}}>
@ -144,7 +145,7 @@ bottomBarDesktop =()=>{
(hasOrder ? t("You have an active order"):"")}
>
<ListItemAvatar sx={{ width: 30, height: 30 }} >
<Badge badgeContent={(this.state.active_order_id > 0 & !this.state.profileShown) ? "": null} color="primary">
<Badge badgeContent={(this.props.activeOrderId > 0 & !this.props.profileShown) ? "": null} color="primary">
<Avatar className='flippedSmallAvatar' sx={{margin: 0, top: -13}}
alt={this.props.nickname}
imgProps={{
@ -163,7 +164,8 @@ bottomBarDesktop =()=>{
<Grid item xs={1.9}>
<ListItem className="bottomItem">
<ListItemIcon size="small">
<IconButton
<IconButton
disabled={!this.showProfileButton()}
color="primary"
onClick={()=> this.props.setAppState({buyChecked: false, sellChecked: true, type:0}) & this.getInfo()}
to={`/book/`}
@ -183,6 +185,7 @@ bottomBarDesktop =()=>{
<ListItem className="bottomItem">
<ListItemIcon size="small">
<IconButton
disabled={!this.showProfileButton()}
color="primary"
onClick={()=> this.props.setAppState({buyChecked: true, sellChecked: false, type:1}) & this.getInfo()}
to={`/book/`}
@ -201,7 +204,9 @@ bottomBarDesktop =()=>{
<Grid item xs={1.9}>
<ListItem className="bottomItem">
<ListItemIcon size="small">
<IconButton color="primary"
<IconButton
disabled={!this.showProfileButton()}
color="primary"
onClick={()=> this.getInfo()}
to={`/`}
component={LinkRouter} >
@ -350,6 +355,7 @@ bottomBarPhone =()=>{
<Grid item xs={1.6} align="center">
<Tooltip enterTouchDelay={300} title={t("Number of public BUY orders")}>
<IconButton
disabled={!this.showProfileButton()}
color="primary"
onClick={()=> this.props.setAppState({buyChecked: false, sellChecked: true, type:0}) & this.getInfo()}
to={`/book/`}
@ -364,6 +370,7 @@ bottomBarPhone =()=>{
<Grid item xs={1.6} align="center">
<Tooltip enterTouchDelay={300} title={t("Number of public SELL orders")}>
<IconButton
disabled={!this.showProfileButton()}
color="primary"
onClick={()=> this.props.setAppState({buyChecked: true, sellChecked: false, type:1}) & this.getInfo()}
to={`/book/`}
@ -377,7 +384,9 @@ bottomBarPhone =()=>{
<Grid item xs={1.6} align="center">
<Tooltip enterTouchDelay={300} title={t("Today active robots")}>
<IconButton color="primary"
<IconButton
disabled={!this.showProfileButton()}
color="primary"
onClick={()=> this.getInfo()}
to={`/`}
component={LinkRouter} >
@ -453,8 +462,8 @@ bottomBarPhone =()=>{
isOpen={this.state.openProfile}
handleClickCloseProfile={this.handleClickCloseProfile}
nickname={this.props.nickname}
activeOrderId={this.state.active_order_id}
lastOrderId={this.state.last_order_id}
activeOrderId={this.props.activeOrderId}
lastOrderId={this.props.lastOrderId}
referralCode={this.state.referral_code}
handleSubmitInvoiceClicked={this.handleSubmitInvoiceClicked}
host={this.getHost()}

View File

@ -22,6 +22,8 @@ export default class HomePage extends Component {
bookCurrencyCode:'ANY',
bookOrders:new Array(),
bookLoading: true,
activeOrderId: null,
lastOrderId: null,
}
}

View File

@ -91,13 +91,17 @@ class UserGenPage extends Component {
// Add nick and token to App state (token only if not a bad request)
(data.bad_request ? this.props.setAppState({
nickname: data.nickname,
avatarLoaded: false,
avatarLoaded: false,
activeOrderId: data.active_order_id ? data.active_order_id : null,
lastOrderId: data.last_order_id ? data.last_order_id : null,
})
:
(this.props.setAppState({
nickname: data.nickname,
token: token,
avatarLoaded: false,
activeOrderId: data.active_order_id ? data.active_order_id : null,
lastOrderId: data.last_order_id ? data.last_order_id : null,
})) & writeCookie("robot_token",token)
& writeCookie("pub_key",data.public_key.split('\n').join('\\'))
& writeCookie("enc_priv_key",data.encrypted_private_key.split('\n').join('\\')))
@ -175,7 +179,7 @@ class UserGenPage extends Component {
<div>
<Grid item xs={12} align="center">
<Typography component="h5" variant="h5">
<b>{this.state.nickname ?
<b>{this.state.nickname && getCookie("sessionid") ?
<div style={{display:'flex', alignItems:'center', justifyContent:'center', flexWrap:'wrap', height:'45px'}}>
<BoltIcon sx={{ color: "#fcba03", height: '33px',width: '33px'}}/><a>{this.state.nickname}</a><BoltIcon sx={{ color: "#fcba03", height: '33px',width: '33px'}}/>
</div>
@ -185,11 +189,12 @@ class UserGenPage extends Component {
<Grid item xs={12} align="center">
<Tooltip enterTouchDelay={0} title={t("This is your trading avatar")}>
<div style={{ maxWidth: 200, maxHeight: 200 }}>
<Image className='newAvatar'
<Image
className='newAvatar'
disableError={true}
cover={true}
color='null'
src={this.state.avatar_url || ""}
src={getCookie("sessionid") ? this.state.avatar_url || "" : ""}
/>
</div>
</Tooltip><br/>

View File

@ -15,7 +15,7 @@ export const getCookie = (name) => {
};
export const writeCookie = (key,value) => {
document.cookie=`${key}=${value};path=/`;
document.cookie=`${key}=${value};path=/;SameSite=Strict`;
}
export const deleteCookie = (name) => {