diff --git a/api/logics.py b/api/logics.py
index ab4063c3..c8da042a 100644
--- a/api/logics.py
+++ b/api/logics.py
@@ -375,7 +375,8 @@ class Logics():
# If there was no taker_bond object yet, generates one
order.last_satoshis = cls.satoshis_now(order)
bond_satoshis = int(order.last_satoshis * BOND_SIZE)
- description = f"RoboSats - Taking '{str(order)}' - This is a taker bond, it will freeze in your wallet temporarily and automatically return. It will be charged if you cheat or cancel."
+ pos_text = 'Buying' if cls.is_buyer(order, user) else 'Selling'
+ description = f"RoboSats - Taking 'Order {order.id}' {pos_text} BTC for {order.amount} - This is a taker bond, it will freeze in your wallet temporarily and automatically return. It will be charged if you cheat or cancel."
# Gen hold Invoice
hold_payment = LNNode.gen_hold_invoice(bond_satoshis, description, BOND_EXPIRY*3600)
diff --git a/api/models.py b/api/models.py
index ace4cdf4..bc7edd9f 100644
--- a/api/models.py
+++ b/api/models.py
@@ -4,6 +4,7 @@ from django.core.validators import MaxValueValidator, MinValueValidator, validat
from django.db.models.signals import post_save, pre_delete
from django.dispatch import receiver
from django.utils.html import mark_safe
+import uuid
from decouple import config
from pathlib import Path
@@ -40,6 +41,7 @@ class LNPayment(models.Model):
# payment use details
+ id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
type = models.PositiveSmallIntegerField(choices=Types.choices, null=False, default=Types.HOLD)
concept = models.PositiveSmallIntegerField(choices=Concepts.choices, null=False, default=Concepts.MAKEBOND)
status = models.PositiveSmallIntegerField(choices=Status.choices, null=False, default=Status.INVGEN)
@@ -59,7 +61,7 @@ class LNPayment(models.Model):
receiver = models.ForeignKey(User, related_name='receiver', on_delete=models.CASCADE, null=True, default=None)
def __str__(self):
- return (f'HTLC {self.id}: {self.Concepts(self.concept).label} - {self.Status(self.status).label}')
+ return (f'LN-{str(self.id)[:8]}: {self.Concepts(self.concept).label} - {self.Status(self.status).label}')
class Order(models.Model):
@@ -203,7 +205,7 @@ class MarketTick(models.Model):
maker and taker are commited with bonds (contract
is finished and cancellation has a cost)
'''
-
+ id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
price = models.DecimalField(max_digits=10, decimal_places=2, default=None, null=True, validators=[MinValueValidator(0)])
volume = models.DecimalField(max_digits=8, decimal_places=8, default=None, null=True, validators=[MinValueValidator(0)])
premium = models.DecimalField(max_digits=5, decimal_places=2, default=None, null=True, validators=[MinValueValidator(-100), MaxValueValidator(999)], blank=True)
@@ -235,6 +237,6 @@ class MarketTick(models.Model):
tick.save()
def __str__(self):
- return f'Tick: {self.id}'
+ return f'Tick: {str(self.id)[:8]}'
diff --git a/api/views.py b/api/views.py
index 0b9d9721..46dbd2d3 100644
--- a/api/views.py
+++ b/api/views.py
@@ -116,6 +116,7 @@ class OrderView(viewsets.ViewSet):
data['is_maker'] = order.maker == request.user
data['is_taker'] = order.taker == request.user
data['is_participant'] = data['is_maker'] or data['is_taker']
+ data['ur_nick'] = request.user.username
# 3) If not a participant and order is not public, forbid.
if not data['is_participant'] and order.status != Order.Status.PUB:
diff --git a/chat/consumers.py b/chat/consumers.py
index 34724987..2013b34a 100644
--- a/chat/consumers.py
+++ b/chat/consumers.py
@@ -1,12 +1,29 @@
from channels.generic.websocket import AsyncWebsocketConsumer
+from api.logics import Logics
+from api.models import Order
+
import json
class ChatRoomConsumer(AsyncWebsocketConsumer):
+
async def connect(self):
self.order_id = self.scope['url_route']['kwargs']['order_id']
self.room_group_name = f'chat_order_{self.order_id}'
+ self.user = self.scope["user"]
+ self.user_nick = str(self.user)
+ # Forbit if user is not part of the order
+ # Does not work Async
+ # order = Order.objects.get(id=self.order_id)
+
+ # # Check if user is participant on the order.
+ # if not (Logics.is_buyer(order[0], self.user) or Logics.is_seller(order[0], self.user)):
+ # print ("Outta this chat")
+ # return False
+
+ print(self.user_nick)
+ print(self.order_id)
await self.channel_layer.group_add(
self.room_group_name,
@@ -24,27 +41,24 @@ class ChatRoomConsumer(AsyncWebsocketConsumer):
async def receive(self, text_data):
text_data_json = json.loads(text_data)
message = text_data_json['message']
- username = text_data_json['username']
+ nick = text_data_json['nick']
await self.channel_layer.group_send(
self.room_group_name,
{
'type': 'chatroom_message',
'message': message,
- 'username': username,
+ 'nick': nick,
}
)
async def chatroom_message(self, event):
message = event['message']
- username = event['username']
- try:
- message = int(message)*42
- except:
- pass
+ nick = event['nick']
+
await self.send(text_data=json.dumps({
'message': message,
- 'username': username,
+ 'user_nick': nick,
}))
pass
\ No newline at end of file
diff --git a/frontend/package-lock.json b/frontend/package-lock.json
index 1b34eb74..69c66f59 100644
--- a/frontend/package-lock.json
+++ b/frontend/package-lock.json
@@ -2889,6 +2889,14 @@
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
"integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ=="
},
+ "bufferutil": {
+ "version": "4.0.6",
+ "resolved": "https://registry.npmjs.org/bufferutil/-/bufferutil-4.0.6.tgz",
+ "integrity": "sha512-jduaYOYtnio4aIAyc6UbvPCVcgq7nYpVnucyxr6eCYg/Woad9Hf/oxxBRDnGGjPfjUm6j5O/uBWhIu4iLebFaw==",
+ "requires": {
+ "node-gyp-build": "^4.3.0"
+ }
+ },
"bytes": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz",
@@ -3319,6 +3327,15 @@
"resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.19.tgz",
"integrity": "sha512-ZVxXaNy28/k3kJg0Fou5MiYpp88j7H9hLZp8PDC3jV0WFjfH5E9xHb56L0W59cPbKbcHXeP4qyT8PrHp8t6LcQ=="
},
+ "d": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz",
+ "integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==",
+ "requires": {
+ "es5-ext": "^0.10.50",
+ "type": "^1.0.1"
+ }
+ },
"dayjs": {
"version": "1.10.7",
"resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.10.7.tgz",
@@ -3564,6 +3581,35 @@
"integrity": "sha512-1HQ2M2sPtxwnvOvT1ZClHyQDiggdNjURWpY2we6aMKCQiUVxTmVs2UYPLIrD84sS+kMdUwfBSylbJPwNnBrnHQ==",
"dev": true
},
+ "es5-ext": {
+ "version": "0.10.53",
+ "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.53.tgz",
+ "integrity": "sha512-Xs2Stw6NiNHWypzRTY1MtaG/uJlwCk8kH81920ma8mvN8Xq1gsfhZvpkImLQArw8AHnv8MT2I45J3c0R8slE+Q==",
+ "requires": {
+ "es6-iterator": "~2.0.3",
+ "es6-symbol": "~3.1.3",
+ "next-tick": "~1.0.0"
+ }
+ },
+ "es6-iterator": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz",
+ "integrity": "sha1-p96IkUGgWpSwhUQDstCg+/qY87c=",
+ "requires": {
+ "d": "1",
+ "es5-ext": "^0.10.35",
+ "es6-symbol": "^3.1.1"
+ }
+ },
+ "es6-symbol": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.3.tgz",
+ "integrity": "sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==",
+ "requires": {
+ "d": "^1.0.1",
+ "ext": "^1.1.2"
+ }
+ },
"escalade": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz",
@@ -3706,6 +3752,21 @@
}
}
},
+ "ext": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/ext/-/ext-1.6.0.tgz",
+ "integrity": "sha512-sdBImtzkq2HpkdRLtlLWDa6w4DX22ijZLKx8BMPUuKe1c5lbN6xwQDQCxSfxBQnHZ13ls/FH0MQZx/q/gr6FQg==",
+ "requires": {
+ "type": "^2.5.0"
+ },
+ "dependencies": {
+ "type": {
+ "version": "2.5.0",
+ "resolved": "https://registry.npmjs.org/type/-/type-2.5.0.tgz",
+ "integrity": "sha512-180WMDQaIMm3+7hGXWf12GtdniDEy7nYcyFMKJn/eZz/6tSLXrUN9V0wKSbMjej0I1WHWbpREDEKHtqPQa9NNw=="
+ }
+ }
+ },
"extend": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
@@ -4329,6 +4390,11 @@
"integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==",
"dev": true
},
+ "is-typedarray": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
+ "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo="
+ },
"is-windows": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz",
@@ -5927,6 +5993,11 @@
"resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz",
"integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw=="
},
+ "next-tick": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz",
+ "integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw="
+ },
"nice-try": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz",
@@ -5953,6 +6024,11 @@
"whatwg-url": "^5.0.0"
}
},
+ "node-gyp-build": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.3.0.tgz",
+ "integrity": "sha512-iWjXZvmboq0ja1pUGULQBexmxq8CV4xBhX7VDOTbL7ZR4FOowwY/VOtRxBN/yKxmdGoIp4j5ysNT4u3S2pDQ3Q=="
+ },
"node-int64": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz",
@@ -7902,11 +7978,24 @@
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz",
"integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw=="
},
+ "type": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/type/-/type-1.2.0.tgz",
+ "integrity": "sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg=="
+ },
"type-fest": {
"version": "0.7.1",
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.7.1.tgz",
"integrity": "sha512-Ne2YiiGN8bmrmJJEuTWTLJR32nh/JdL1+PSicowtNb0WFpn59GK8/lfD61bVtzguz7b3PBt74nxpv/Pw5po5Rg=="
},
+ "typedarray-to-buffer": {
+ "version": "3.1.5",
+ "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz",
+ "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==",
+ "requires": {
+ "is-typedarray": "^1.0.0"
+ }
+ },
"uglify-es": {
"version": "3.3.9",
"resolved": "https://registry.npmjs.org/uglify-es/-/uglify-es-3.3.9.tgz",
@@ -8123,6 +8212,14 @@
"object-assign": "^4.1.1"
}
},
+ "utf-8-validate": {
+ "version": "5.0.8",
+ "resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-5.0.8.tgz",
+ "integrity": "sha512-k4dW/Qja1BYDl2qD4tOMB9PFVha/UJtxTc1cXYOe3WwA/2m0Yn4qB7wLMpJyLJ/7DR0XnTut3HsCSzDT4ZvKgA==",
+ "requires": {
+ "node-gyp-build": "^4.3.0"
+ }
+ },
"util-deprecate": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
@@ -8305,6 +8402,34 @@
"integrity": "sha512-cp5qdmHnu5T8wRg2G3vZZHoJPN14aqQ89SyQ11NpGH5zEMDCclt49rzo+MaRazk7/UeILhAI+/sEtcM+7Fr0nw==",
"dev": true
},
+ "websocket": {
+ "version": "1.0.34",
+ "resolved": "https://registry.npmjs.org/websocket/-/websocket-1.0.34.tgz",
+ "integrity": "sha512-PRDso2sGwF6kM75QykIesBijKSVceR6jL2G8NGYyq2XrItNC2P5/qL5XeR056GhA+Ly7JMFvJb9I312mJfmqnQ==",
+ "requires": {
+ "bufferutil": "^4.0.1",
+ "debug": "^2.2.0",
+ "es5-ext": "^0.10.50",
+ "typedarray-to-buffer": "^3.1.5",
+ "utf-8-validate": "^5.0.2",
+ "yaeti": "^0.0.6"
+ },
+ "dependencies": {
+ "debug": {
+ "version": "2.6.9",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+ "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+ "requires": {
+ "ms": "2.0.0"
+ }
+ },
+ "ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
+ }
+ }
+ },
"whatwg-fetch": {
"version": "3.6.2",
"resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.6.2.tgz",
@@ -8440,6 +8565,11 @@
"resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz",
"integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ=="
},
+ "yaeti": {
+ "version": "0.0.6",
+ "resolved": "https://registry.npmjs.org/yaeti/-/yaeti-0.0.6.tgz",
+ "integrity": "sha1-8m9ITXJoTPQr7ft2lwqhYI+/lXc="
+ },
"yaml": {
"version": "1.10.2",
"resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz",
diff --git a/frontend/package.json b/frontend/package.json
index 33d9d3f8..28aa9147 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -33,6 +33,7 @@
"react-native": "^0.66.4",
"react-native-svg": "^12.1.1",
"react-qr-code": "^2.0.3",
- "react-router-dom": "^5.2.0"
+ "react-router-dom": "^5.2.0",
+ "websocket": "^1.0.34"
}
}
diff --git a/frontend/src/components/Chat.js b/frontend/src/components/Chat.js
new file mode 100644
index 00000000..606f25df
--- /dev/null
+++ b/frontend/src/components/Chat.js
@@ -0,0 +1,98 @@
+import React, { Component } from 'react';
+import { w3cwebsocket as W3CWebSocket } from "websocket";
+import {Button, TextField, Link, Grid, Typography, Container, Card, CardHeader, Paper, Avatar} from "@mui/material";
+import { withStyles } from "@mui/material";
+
+
+
+export default class Chat extends Component {
+ constructor(props) {
+ super(props);
+ }
+
+ state = {
+ messages: [],
+ value:'',
+ orderId: 2,
+ };
+
+ client = new W3CWebSocket('ws://' + window.location.host + '/ws/chat/' + this.props.data.orderId + '/');
+
+ componentDidMount() {
+ this.client.onopen = () => {
+ console.log('WebSocket Client Connected')
+ console.log(this.props.data)
+ }
+ this.client.onmessage = (message) => {
+ const dataFromServer = JSON.parse(message.data);
+ console.log('Got reply!', dataFromServer.type);
+ if (dataFromServer){
+ this.setState((state) =>
+ ({
+ messages: [...state.messages,
+ {
+ msg: dataFromServer.message,
+ userNick: dataFromServer.user_nick,
+ }],
+
+ })
+
+ )
+ }
+
+ }
+ }
+
+ onButtonClicked = (e) => {
+ this.client.send(JSON.stringify({
+ type: "message",
+ message: this.state.value,
+ nick: this.props.data.urNick,
+ }));
+ this.state.value = ''
+ e.preventDefault();
+ }
+
+ render() {
+ return (
+
+
+ {this.state.messages.map(message => <>
+ {/* {message.userNick == this.props.data.urNick ? align='right' : align='left'} */}
+
+
+ }
+ title={message.userNick}
+ subheader={message.msg}
+ />
+
+ >)}
+
+
+
+ )
+ }
+}
diff --git a/frontend/src/components/MakerPage.js b/frontend/src/components/MakerPage.js
index 2abc6e36..7d2da795 100644
--- a/frontend/src/components/MakerPage.js
+++ b/frontend/src/components/MakerPage.js
@@ -167,7 +167,7 @@ export default class MakerPage extends Component {
-
+
{
return(
-
+
)
@@ -335,7 +337,7 @@ handleRatingChange=(e)=>{
// Ask for double confirmation.
return(
-
+
)
}
@@ -368,13 +370,13 @@ handleRatingChange=(e)=>{
}
-
- CHAT PLACEHOLDER
-
+
+
+
- {sendFiatButton ? this.showFiatSentButton() : ""}
- {receivedFiatButton ? this.showFiatReceivedButton() : ""}
- {openDisputeButton ? this.showOpenDisputeButton() : ""}
+ {openDisputeButton ? this.showOpenDisputeButton() : ""}
+ {sendFiatButton ? this.showFiatSentButton() : ""}
+ {receivedFiatButton ? this.showFiatReceivedButton() : ""}
{this.showBondIsLocked()}
diff --git a/setup.md b/setup.md
index 803fa170..f530c3d8 100644
--- a/setup.md
+++ b/setup.md
@@ -113,6 +113,7 @@ npm install react-native-svg
npm install react-qr-code
npm install @mui/material
npm install react-markdown
+npm install websocket
```
Note we are using mostly MaterialUI V5 (@mui/material) but Image loading from V4 (@material-ui/core) extentions (so both V4 and V5 are needed)