mirror of
https://github.com/RoboSats/robosats.git
synced 2025-01-18 12:11:35 +00:00
Fix avatar persistance and login issues. Add onchain payment cleanup.
This commit is contained in:
parent
7eb29fb57e
commit
6f7cfb5147
@ -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):
|
||||
|
@ -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
|
||||
|
@ -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"
|
||||
|
32
api/tasks.py
32
api/tasks.py
@ -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
|
||||
|
||||
|
22
api/views.py
22
api/views.py
@ -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!"
|
||||
|
@ -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()}
|
||||
|
@ -22,6 +22,8 @@ export default class HomePage extends Component {
|
||||
bookCurrencyCode:'ANY',
|
||||
bookOrders:new Array(),
|
||||
bookLoading: true,
|
||||
activeOrderId: null,
|
||||
lastOrderId: null,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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/>
|
||||
|
@ -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) => {
|
||||
|
Loading…
Reference in New Issue
Block a user