Add the start of the negotiation page

This commit is contained in:
Kienan Stewart 2020-04-19 19:52:13 -04:00
parent 5ada93a0a4
commit 87b160e950
13 changed files with 386 additions and 7 deletions

6
Pipfile Normal file
View File

@ -0,0 +1,6 @@
[packages]
flask="*"
pony="*"
flask-socketio="*"
redis="*"
eventlet="*"

186
Pipfile.lock generated Normal file
View File

@ -0,0 +1,186 @@
{
"_meta": {
"hash": {
"sha256": "707653c558287744f0facfa4f7b2ab0340dcccd0a0461c7a40399200d71e58db"
},
"pipfile-spec": 6,
"requires": {},
"sources": [
{
"name": "pypi",
"url": "https://pypi.python.org/simple",
"verify_ssl": true
}
]
},
"default": {
"click": {
"hashes": [
"sha256:8a18b4ea89d8820c5d0c7da8a64b2c324b4dabb695804dbfea19b9be9d88c0cc",
"sha256:e345d143d80bf5ee7534056164e5e112ea5e22716bbb1ce727941f4c8b471b9a"
],
"version": "==7.1.1"
},
"dnspython": {
"hashes": [
"sha256:36c5e8e38d4369a08b6780b7f27d790a292b2b08eea01607865bf0936c558e01",
"sha256:f69c21288a962f4da86e56c4905b49d11aba7938d3d740e80d9e366ee4f1632d"
],
"version": "==1.16.0"
},
"eventlet": {
"hashes": [
"sha256:4c8ab42c51bff55204fef43cff32616558bedbc7538d876bb6a96ce820c7f9ed",
"sha256:955f2cf538829bfcb7b3aa885ace40e8ae5965dcd5b876c384d0c5869702db1d"
],
"index": "pypi",
"version": "==0.25.2"
},
"flask": {
"hashes": [
"sha256:4efa1ae2d7c9865af48986de8aeb8504bf32c7f3d6fdc9353d34b21f4b127060",
"sha256:8a4fdd8936eba2512e9c85df320a37e694c93945b33ef33c89946a340a238557"
],
"index": "pypi",
"version": "==1.1.2"
},
"flask-socketio": {
"hashes": [
"sha256:2172dff1e42415ba480cee02c30c2fc833671ff326f1598ee3d69aa02cf768ec",
"sha256:7ff5b2f5edde23e875a8b0abf868584e5706e11741557449bc5147df2cd78268"
],
"index": "pypi",
"version": "==4.2.1"
},
"greenlet": {
"hashes": [
"sha256:000546ad01e6389e98626c1367be58efa613fa82a1be98b0c6fc24b563acc6d0",
"sha256:0d48200bc50cbf498716712129eef819b1729339e34c3ae71656964dac907c28",
"sha256:23d12eacffa9d0f290c0fe0c4e81ba6d5f3a5b7ac3c30a5eaf0126bf4deda5c8",
"sha256:37c9ba82bd82eb6a23c2e5acc03055c0e45697253b2393c9a50cef76a3985304",
"sha256:51155342eb4d6058a0ffcd98a798fe6ba21195517da97e15fca3db12ab201e6e",
"sha256:51503524dd6f152ab4ad1fbd168fc6c30b5795e8c70be4410a64940b3abb55c0",
"sha256:7457d685158522df483196b16ec648b28f8e847861adb01a55d41134e7734122",
"sha256:8041e2de00e745c0e05a502d6e6db310db7faa7c979b3a5877123548a4c0b214",
"sha256:81fcd96a275209ef117e9ec91f75c731fa18dcfd9ffaa1c0adbdaa3616a86043",
"sha256:853da4f9563d982e4121fed8c92eea1a4594a2299037b3034c3c898cb8e933d6",
"sha256:8b4572c334593d449113f9dc8d19b93b7b271bdbe90ba7509eb178923327b625",
"sha256:9416443e219356e3c31f1f918a91badf2e37acf297e2fa13d24d1cc2380f8fbc",
"sha256:9854f612e1b59ec66804931df5add3b2d5ef0067748ea29dc60f0efdcda9a638",
"sha256:99a26afdb82ea83a265137a398f570402aa1f2b5dfb4ac3300c026931817b163",
"sha256:a19bf883b3384957e4a4a13e6bd1ae3d85ae87f4beb5957e35b0be287f12f4e4",
"sha256:a9f145660588187ff835c55a7d2ddf6abfc570c2651c276d3d4be8a2766db490",
"sha256:ac57fcdcfb0b73bb3203b58a14501abb7e5ff9ea5e2edfa06bb03035f0cff248",
"sha256:bcb530089ff24f6458a81ac3fa699e8c00194208a724b644ecc68422e1111939",
"sha256:beeabe25c3b704f7d56b573f7d2ff88fc99f0138e43480cecdfcaa3b87fe4f87",
"sha256:d634a7ea1fc3380ff96f9e44d8d22f38418c1c381d5fac680b272d7d90883720",
"sha256:d97b0661e1aead761f0ded3b769044bb00ed5d33e1ec865e891a8b128bf7c656",
"sha256:e538b8dae561080b542b0f5af64d47ef859f22517f7eca617bb314e0e03fd7ef"
],
"version": "==0.4.15"
},
"itsdangerous": {
"hashes": [
"sha256:321b033d07f2a4136d3ec762eac9f16a10ccd60f53c0c91af90217ace7ba1f19",
"sha256:b12271b2047cb23eeb98c8b5622e2e5c5e9abd9784a153e9d8ef9cb4dd09d749"
],
"version": "==1.1.0"
},
"jinja2": {
"hashes": [
"sha256:89aab215427ef59c34ad58735269eb58b1a5808103067f7bb9d5836c651b3bb0",
"sha256:f0a4641d3cf955324a89c04f3d94663aa4d638abe8f733ecd3582848e1c37035"
],
"version": "==2.11.2"
},
"markupsafe": {
"hashes": [
"sha256:00bc623926325b26bb9605ae9eae8a215691f33cae5df11ca5424f06f2d1f473",
"sha256:09027a7803a62ca78792ad89403b1b7a73a01c8cb65909cd876f7fcebd79b161",
"sha256:09c4b7f37d6c648cb13f9230d847adf22f8171b1ccc4d5682398e77f40309235",
"sha256:1027c282dad077d0bae18be6794e6b6b8c91d58ed8a8d89a89d59693b9131db5",
"sha256:13d3144e1e340870b25e7b10b98d779608c02016d5184cfb9927a9f10c689f42",
"sha256:24982cc2533820871eba85ba648cd53d8623687ff11cbb805be4ff7b4c971aff",
"sha256:29872e92839765e546828bb7754a68c418d927cd064fd4708fab9fe9c8bb116b",
"sha256:43a55c2930bbc139570ac2452adf3d70cdbb3cfe5912c71cdce1c2c6bbd9c5d1",
"sha256:46c99d2de99945ec5cb54f23c8cd5689f6d7177305ebff350a58ce5f8de1669e",
"sha256:500d4957e52ddc3351cabf489e79c91c17f6e0899158447047588650b5e69183",
"sha256:535f6fc4d397c1563d08b88e485c3496cf5784e927af890fb3c3aac7f933ec66",
"sha256:596510de112c685489095da617b5bcbbac7dd6384aeebeda4df6025d0256a81b",
"sha256:62fe6c95e3ec8a7fad637b7f3d372c15ec1caa01ab47926cfdf7a75b40e0eac1",
"sha256:6788b695d50a51edb699cb55e35487e430fa21f1ed838122d722e0ff0ac5ba15",
"sha256:6dd73240d2af64df90aa7c4e7481e23825ea70af4b4922f8ede5b9e35f78a3b1",
"sha256:717ba8fe3ae9cc0006d7c451f0bb265ee07739daf76355d06366154ee68d221e",
"sha256:79855e1c5b8da654cf486b830bd42c06e8780cea587384cf6545b7d9ac013a0b",
"sha256:7c1699dfe0cf8ff607dbdcc1e9b9af1755371f92a68f706051cc8c37d447c905",
"sha256:88e5fcfb52ee7b911e8bb6d6aa2fd21fbecc674eadd44118a9cc3863f938e735",
"sha256:8defac2f2ccd6805ebf65f5eeb132adcf2ab57aa11fdf4c0dd5169a004710e7d",
"sha256:98c7086708b163d425c67c7a91bad6e466bb99d797aa64f965e9d25c12111a5e",
"sha256:9add70b36c5666a2ed02b43b335fe19002ee5235efd4b8a89bfcf9005bebac0d",
"sha256:9bf40443012702a1d2070043cb6291650a0841ece432556f784f004937f0f32c",
"sha256:ade5e387d2ad0d7ebf59146cc00c8044acbd863725f887353a10df825fc8ae21",
"sha256:b00c1de48212e4cc9603895652c5c410df699856a2853135b3967591e4beebc2",
"sha256:b1282f8c00509d99fef04d8ba936b156d419be841854fe901d8ae224c59f0be5",
"sha256:b2051432115498d3562c084a49bba65d97cf251f5a331c64a12ee7e04dacc51b",
"sha256:ba59edeaa2fc6114428f1637ffff42da1e311e29382d81b339c1817d37ec93c6",
"sha256:c8716a48d94b06bb3b2524c2b77e055fb313aeb4ea620c8dd03a105574ba704f",
"sha256:cd5df75523866410809ca100dc9681e301e3c27567cf498077e8551b6d20e42f",
"sha256:cdb132fc825c38e1aeec2c8aa9338310d29d337bebbd7baa06889d09a60a1fa2",
"sha256:e249096428b3ae81b08327a63a485ad0878de3fb939049038579ac0ef61e17e7",
"sha256:e8313f01ba26fbbe36c7be1966a7b7424942f670f38e666995b88d012765b9be"
],
"version": "==1.1.1"
},
"monotonic": {
"hashes": [
"sha256:23953d55076df038541e648a53676fb24980f7a1be290cdda21300b3bc21dfb0",
"sha256:552a91f381532e33cbd07c6a2655a21908088962bb8fa7239ecbcc6ad1140cc7"
],
"version": "==1.5"
},
"pony": {
"hashes": [
"sha256:8a9e7339fe7a5182566c83047dbae8053aa1cf458bff0f21f1ae1b106a210cbb"
],
"index": "pypi",
"version": "==0.7.13"
},
"python-engineio": {
"hashes": [
"sha256:222926adb4bc6e03a8fc8e0ef2a3309f030c1c3f8e0fcc94c9ba214574565f02",
"sha256:2481732d93646998f7372ef0ecf003af7817b82720b881db173c3d50b4887916"
],
"version": "==3.12.1"
},
"python-socketio": {
"hashes": [
"sha256:149b98c33f8c3d09273fb4ebeb83781e4dc9411b56b27d9f058bec1bd1ed74b7",
"sha256:81280cbbb7018d8ecdd006bf6025979733d347c0f2612282c1e21f6ed7d3b55b"
],
"version": "==4.5.1"
},
"redis": {
"hashes": [
"sha256:0dcfb335921b88a850d461dc255ff4708294943322bd55de6cfd68972490ca1f",
"sha256:b205cffd05ebfd0a468db74f0eedbff8df1a7bfc47521516ade4692991bb0833"
],
"index": "pypi",
"version": "==3.4.1"
},
"six": {
"hashes": [
"sha256:236bdbdce46e6e6a3d61a337c0f8b763ca1e8717c03b369e87a7ec7ce1319c0a",
"sha256:8f3cd2e254d8f793e7f3d6d9df77b92252b52637291d0f0da013c76ea2724b6c"
],
"version": "==1.14.0"
},
"werkzeug": {
"hashes": [
"sha256:2de2a5db0baeae7b2d2664949077c2ac63fbd16d98da0ff71837f7d1dea3fd43",
"sha256:6c80b1e5ad3665290ea39320b91e1be1e0d5f60652b964a3070216de83d2e47c"
],
"version": "==1.0.1"
}
},
"develop": {}
}

View File

@ -2,11 +2,15 @@
## Prerequisites
apt install python3-flask python3-pony
apt install pipenv
## Dependency installation
pipenv sync
## Running
FLASK_DEBUG=1 FLASK_APP=negotiation.py ./negotiation.py
FLASK_ENV=development FLASK_APP=negotiation.py pipenv run ./negotiation.py
# License

6
docker-compose.yml Normal file
View File

@ -0,0 +1,6 @@
version: '3'
services:
messagequeue:
image: "redis:buster"
ports:
- "6379:6379"

View File

@ -6,6 +6,7 @@ import urllib
import uuid
import flask
import flask_socketio
import pony
from pony.flask import Pony
@ -13,7 +14,12 @@ word_file = "/usr/share/dict/words"
WORDS = open(word_file).read().splitlines()
app = flask.Flask(__name__)
socketio = flask_socketio.SocketIO(app)
db = None
# @TODO Change this into using redis or something else for storage across
# threads etc.
session_map = {}
@app.route('/')
@pony.orm.db_session
@ -58,7 +64,8 @@ def negotiation_create():
return flask.redirect('/') # @TODO Signal error to user. They don't have a uid cookie
if len(n) > 128:
return flask.redirect('/') # @TODO Signal error to user. Request too Large
if pony.orm.exists(nego for nego in Negotiation if nego.name == n):
nego = get_negotiation(n)
if nego:
# @TODO Signal to the user that the negotiation already exists and they
# are being sent to it instead.
return flask.redirect('/negotiations/{}'.format(n))
@ -73,8 +80,57 @@ def negotiation_redir():
@app.route('/negotiations/<negotiation>')
def negotiation(negotiation):
r = flask.Response()
uid = get_uid(r)
return "{}".format(negotiation)
uid, user = get_uid(r)
nego = get_negotiation(negotiation)
if not nego:
return "Error!"
c = {
'negotiation': nego,
'user': uid,
'room_owner': nego.owner,
'room_owner_display_name': nego.owner.display_name if nego.owner.display_name else nego.owner.uid,
'participant_count': len(get_room_participants(negotiation)),
}
r.data = render_page('negotiation.html', c)
return r
@socketio.on('join negotiation')
def handle_join_negotiation(json):
r = flask.Response()
app.logger.info('Received join request: {}'.format(json))
uid, user = get_uid(r)
flask_socketio.join_room(json['room'])
session_map[flask.request.sid] = uid;
app.logger.info('{} has joined room "{}" (sid: {})'.format(uid, json['room'],
flask.request.sid))
participants = get_room_participants(json['room'])
app.logger.info('{} has {} connections'.format(
json['room'], len(participants)))
flask_socketio.emit('participants changed', {'participants': participants},
room = json['room'])
return True
def get_room_participants(room):
sessions = [s for s in socketio.server.manager.get_participants('/', room)]
participants = [p for s,p in session_map.items() if s in sessions]
app.logger.debug(participants)
return participants
@socketio.on('leave negotiation')
def handle_leave_disconnect(json):
r = flask.Response()
app.logger.info('Received join request: {}'.format(json))
uid, user = get_uid(r)
del session_map[flask.request.sid]
app.logger.info('{} has disconnected from {} (sid: {})'.format(uid, json['room'],flask.request.sid))
participants = get_room_participants(json['room'])
flask_socketio.emit('participants changed', {'participants': participants},
room = json['room'])
return True
@pony.orm.db_session
def get_negotiation(negotiation):
return pony.orm.select(nego for nego in Negotiation if nego.name == negotiation).first()
@pony.orm.db_session
def generate_uid():
@ -136,4 +192,4 @@ if __name__ == '__main__':
db.bind(**app.config['PONY'])
db.generate_mapping(create_tables=True)
Pony(app)
app.run(host = bindaddr, port = port)
socketio.run(app, host = bindaddr, port = port)

View File

@ -285,6 +285,10 @@ th {
content: '\e80a'
}
.ic-settings:after {
content: '\2699'
}
@font-face {
font-family: 'Cardo';
font-style: normal;
@ -1410,11 +1414,13 @@ img {
position: relative;
z-index: 10;
margin: 0 0 0.5em;
font-family: 'NordSudA';
font-size: 2em;
line-height: 1em;
font-weight: 700;
text-indent: -1px;
color: #000
color: #600000;
text-shadow: 3px 5px #1d0202;
}
.has-cover .post-title {
@ -1427,6 +1433,10 @@ img {
font-weight: inherit
}
#negotiation-header .post-title {
padding-top: 1em;
}
.home-surtitle {
font-family: 'NordSudA';
font-size: 3em;

2
static/js/jquery-3.5.0.min.js vendored Normal file

File diff suppressed because one or more lines are too long

1
static/js/jquery.min.js vendored Symbolic link
View File

@ -0,0 +1 @@
jquery-3.5.0.min.js

19
static/js/negotiation.js Normal file
View File

@ -0,0 +1,19 @@
class Negotiation {
constructor(room) {
this.socket = io();
this.socket.on('connect', function() {
console.log("Trying to join room " + room);
this.socket.emit('join negotiation', {"room": room});
});
window.addEventListener('beforeunload', function(e) {
console.log("Trying to leave room " + room);
negotiation.socket.emit('leave negotiation', {"room": room});
negotiation.socket.disconnect();
return true;
});
this.socket.on('participants changed', function(data) {
console.log(data);
});
}
}

9
static/js/socket.io.js Normal file

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,64 @@
{% extends "base.html" %}
{% block header %}
<header id="negotiation-header">
<div class="inner">
<nav id="navigation">
<span id="home-button" class="nav-button">
<a class="home-button"><i class="ic ic-settings"></i>Settings</a>
</span>
<h1 class="post-title">Red Markets Negotiations: {{ negotiation.name }}</h1>
<span id="menu-button" class="nav-button">
<a class="menu-button"><i class="ic ic-menu"></i> Menu</a>
</span>
</nav>
</div>
</header>
{% endblock header %}
{% block content %}
<div id="negotiation" class="negotiation-wrapper">
<div class="negotiation-sidebar">{% include 'partials/negotiation-sidebar.html' %}</div>
<div class="negotiation-panel">{% include 'partials/negotiation-panel.html' %}</div>
</div>
<script src="/static/js/jquery.min.js"></script>
<script src="/static/js/socket.io.js"></script>
<script type="text/javascript" charset="utf-8">
// const negotiation = new Negotiation("{{negotiation.name}}")
var socket = io();
var room = "{{negotiation.name}}";
socket.on('connect', function() {
console.log("Trying to join room " + room);
socket.emit('join negotiation', {"room": room});
});
window.addEventListener('beforeunload', function(e) {
console.log("Trying to leave room " + room);
socket.emit('leave negotiation', {"room": room});
socket.disconnect();
return true;
});
socket.on('participants changed', (data) => {
console.log(data);
$("#negotiation .participants .count").html(data['participants'].length);
$("#negotiation .participant-list li").each(function() {
if (!data['participants'].includes($(this).attr('participant-id'))) {
console.log("Removing element for participant id " + $(this).attr('participant-id'));
console.log($(this));
$(this).remove();
}
});
var num_p;
var listed = $('#negotiation .participant-list li');
for (num_p = 0; num_p < data['participants'].length ; num_p++) {
var p = data['participants'][num_p];
console.log('Checking to see if ' + p + ' is in the participant list');
console.log($('#negotiation .participant-list li[participant-id="' + p + '"]'));
if ($('#negotiation .participant-list li[participant-id="' + p + '"]').length < 1) {
$("#negotiation .participant-list").append(
'<li participant-id="' + p + '">' + p + '</li>'
);
}
}
});
</script>
{% endblock content %}

View File

@ -0,0 +1 @@
@TODO Panel

View File

@ -0,0 +1,15 @@
<div class="negotiation-owner">
<p>Negotiation {{negotiation.name}} is being run by {{room_owner_display_name}}</p>
{% if room_owner_display_name == uid %}
<p>Change your display name</p>
{% endif %}
</div>
<div class="participants">
<h4>Participants</h4>
<p><span class="count">{{ participant_count }}</span>&nbsp;<span> takers in this room</span></p>
<ul class="participant-list">
<li participant-id="{{user}}">{{user}}</li>
</ul>
</div>