Skip to content

Commit

Permalink
Basic chat display on the route /msg/user1/user2
Browse files Browse the repository at this point in the history
  • Loading branch information
etrian-dev committed Feb 26, 2022
1 parent d20772e commit 53aae8a
Show file tree
Hide file tree
Showing 8 changed files with 196 additions and 45 deletions.
9 changes: 6 additions & 3 deletions TODO.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
+ GET/POST endpoint for registration
+ Chat page design
+ Left header for navigation
- Chat page design (two-sided columns)
- Left header for navigation
- index page on route '/'
- User detail page
- Encryption/decryption of message data
- logout function and proper authentication (maybe sessions)
25 changes: 10 additions & 15 deletions chatroom/Auth.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,6 @@
from . import User
from . import db

# Create users
#users = dict()
#user_map = dict() # reverse lookup from username to user ID(s)
#for u in ['mario', 'luigi', 'chiara' , 'jacopo', 'andrea', 'beatrice']:
# new_user = User.User(u, 'pwd')
# print('Created new user:', new_user, sep='\n')
# users[new_user] = False # not logged
# if u not in user_map.keys():
# user_map[u] = [new_user.user_id]
# else:
# user_map[u].append(new_user.user_id)

from flask import (
Blueprint, flash, g, redirect, render_template, request, session, url_for
)
Expand All @@ -31,9 +19,12 @@ def register():
# insert the newly created user into the db
conn = db.get_db()
try:
conn.execute('''
cur = conn.execute('''
INSERT INTO Users(username, password, pk_n, pk_e, pk_d)
VALUES (?,?,?,?,?)''', [new_user.username, new_user.password, new_user.pub_key[0], new_user.pub_key[1], new_user.priv_key])
# gets the rowid of the last row, which is the same as the new user_id
# iff user_id is an integer primary key with autoincrement
new_user.user_id = cur.lastrowid
except DatabaseError:
error = 'Insert failed'
conn.rollback()
Expand All @@ -55,15 +46,18 @@ def login():
if (not username) or (not pwd):
error = 'Username or password unspecified'
else:
cur = db.get_db().cursor()
conn = db.get_db()
cur = conn.cursor()
cur.execute('SELECT user_id, username, password FROM Users WHERE username=?;', [username])

user_id = None
row = cur.fetchone()
while row is not None:
if row['password'] == pwd:
user_id = row['user_id']
print(user_id)
# create a new session for this user
cur.execute('INSERT INTO Sessions(userref,login_tm) VALUES (?, CURRENT_TIMESTAMP)', [user_id])
conn.commit()
break;
row = cur.fetchone()
cur.close()
Expand All @@ -77,3 +71,4 @@ def login():
flash(error)
return render_template('login.html', error=error)


87 changes: 77 additions & 10 deletions chatroom/Chat.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@
from time import time
from sqlite3 import Connection, Cursor, DatabaseError

from flask import (
Blueprint, flash, g, redirect, render_template, request, session, url_for
)

class Chat:
"""Defines a chat between two users.
"""
Expand Down Expand Up @@ -35,10 +39,11 @@ def delete_message(target):
def home_user(user_id: int):
cur = db.get_db().cursor()
user_data = dict()
user_data['user_id'] = user_id
try:
# Fetch the username
cur.execute('''SELECT username FROM Users WHERE user_id = ?''', [user_id])
user_data['username'] = cur.fetchone()
user_data['username'] = cur.fetchone()['username']
# fetch this users's chats
# FIXME: maybe use ? IN (participant1, participant2)
cur.execute('''
Expand All @@ -52,7 +57,7 @@ def home_user(user_id: int):
ch.creation_time = row['creation_tm']
ch.last_activity = row['last_mod_tm']
# insert that into the user_data dict
if user_data['chats'] is None:
if 'chats' not in user_data:
user_data['chats'] = [ch]
else:
user_data['chats'].append(ch)
Expand All @@ -61,16 +66,78 @@ def home_user(user_id: int):
return render_template('chats.html')
return render_template('chats.html', user_data=user_data)

@blueprint.route('/<creator>/', methods=['GET'])
# TODO: post
@blueprint.route('/<int:creator>/', methods=['POST'])
def create_chat(creator):
data = request.get_json()
if data is not None:
pass
else:
pass
return "POSTed chat by " + creator
# TODO: check that the current session for this client is logged as <creator>
error = None
matching_users = []
if request.method == 'POST':
# get the username of the user the creator wants to chat with
username = request.form['username']
# get matching users
db_conn = db.get_db()
try:
cursor = db_conn.execute('''
SELECT user_id, username, password
FROM Users
WHERE username=?;''', [username])

# TODO: handle multiple users with the same username
match = cursor.fetchone()
if match is not None:
cursor.execute('''
INSERT INTO Chats(participant1, participant2, creation_tm, last_mod_tm)
VALUES (?,?,?,?)''', [creator, match['user_id'], 'CURRENT_TIMESTAMP', 'CURRENT_TIMESTAMP'])
db_conn.commit()
cursor.close()

return redirect(url_for('chat.display_chat', user=creator, other=match['user_id']))
except DatabaseError:
error = 'DB lookup or insert failed'
return render_template('chat_choice.html', matching_users)

@blueprint.route('/<int:user>/<int:other>', methods=['GET'])
def display_chat(user, other):
chat_info = dict()
chat_info['this_user_id'] = user
chat_info['other_user_id'] = other
db_conn = db.get_db()
# fetch user IDs and usernames
# of the current user and the other participant in the chat
cur = db_conn.execute('''
SELECT username FROM Users WHERE user_id = ?;
''', [user])
chat_info['this_user'] = cur.fetchone()['username']
cur.execute('''
SELECT user_id,username FROM Users WHERE user_id = ?;
''', [other])
chat_info['other_user'] = cur.fetchone()['username']
# fetch the chat
cur.execute('''
SELECT * FROM Chats
WHERE (participant1 = ? AND ? = participant2) OR (participant1 = ? AND participant2 = ?);
''', [user, other, other, user])
chat = cur.fetchone()
# fetch all messages
cur.execute('''
SELECT * FROM Messages WHERE chatref = ?;
''', [chat['chat_id']])
msgs_encoded = cur.fetchall()
messages = []
#decode messages
for msg in msgs_encoded:
sender = None
receiver = None
if msg['sender'] == user:
sender = chat_info['this_user']
receiver = chat_info['other_user']
else:
sender = chat_info['other_user']
receiver = chat_info['this_user']
messages.append({'sender': sender, 'receiver': receiver, 'data': msg['msg_data'].decode(encoding='utf-8')})
chat_info['messages'] = messages

return render_template('messages.html', **chat_info)

@blueprint.route('/<creator>/<recipient>/', methods=['GET'])
# TODO: delete
Expand Down
39 changes: 34 additions & 5 deletions chatroom/Msg.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,12 @@ def __init__(self, data: str, stamp: int):
self.message = data
self.timestamp = stamp

from flask import Blueprint
from . import db
from sqlite3 import Connection, Cursor, DatabaseError

from flask import (
Blueprint, flash, g, redirect, render_template, request, session, url_for
)

blueprint = Blueprint('msg', __name__, url_prefix='/msg')

Expand All @@ -18,14 +23,38 @@ def get_message(sender, receiver, msg_id):
return f"GET msg from {sender} to {receiver}: ID = {msg_id}"


@blueprint.route('/<sender>/<receiver>/', methods=['GET'])
@blueprint.route('/<int:sender>/<int:recipient>/', methods=['POST'])
# TODO: post
def send_message(sender, receiver):
return f"POSTed msg from {sender} to {receiver}"
def send_message(sender, recipient):
db_conn = db.get_db()
try:
# get the chat id
cur = db_conn.execute('''
SELECT chat_id FROM Chats
WHERE :sender != :recipient
AND :sender IN (participant1, participant2)
AND :recipient IN (participant1, participant2);
''', {"sender": sender, "recipient": recipient})
chat_id = cur.fetchone()['chat_id']
# get the private key of this user
cur.execute('''
''')
# retrieve the message data
msg_data = request.form['message']
# insert the message
cur.execute('''
INSERT INTO Messages(chatref,sender,recipient,msg_data)
VALUES (?, ?, ?, ?);
''', [chat_id, sender, recipient, msg_data.encode(encoding='utf-8')])
db_conn.commit()
print(f"{sender} said: {msg_data} to {recipient}")
# return an empty response, with a 201 Created code
return redirect(url_for('chat.display_chat', user=sender, other=recipient))
except DatabaseError:
return f"Error"


@blueprint.route('/<sender>/<receiver>/<int:msg_id>', methods=['GET'])
# TODO: put
def edit_message(sender, receiver, msg_id):
return f"PUTed msg from {sender} to {receiver}: {msg_id}"

Expand Down
2 changes: 0 additions & 2 deletions chatroom/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,6 @@ def create_app(testing=None):
app.register_blueprint(Chat.blueprint)
app.register_blueprint(Msg.blueprint)

print(app.url_map)

# init the db
db.init_app(app)

Expand Down
8 changes: 6 additions & 2 deletions chatroom/db_schema.sql
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,15 @@ CREATE TABLE Chats (
participant2 INTEGER REFERENCES Users(user_id),
creation_tm INTEGER,
last_mod_tm INTEGER,
CHECK (participant1 != participant2)
CHECK (participant1 != participant2),
UNIQUE(participant1, participant2)
);

CREATE TABLE Messages (
msg_id INTEGER PRIMARY KEY AUTOINCREMENT,
chatref INTEGER REFERENCES Chats(chat_id),
msg_data BLOB
sender INTEGER REFERENCES Users(user_id),
recipient INTEGER REFERENCES Users(user_id),
msg_data BLOB,
CHECK (sender != recipient)
);
36 changes: 28 additions & 8 deletions chatroom/templates/chats.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,43 @@
<html>
<head>
<script src="{{ url_for('static', filename='jquery-3.6.0.js') }}"></script>
<script src="{{ url_for('static', filename='myrequests.js') }}"></script>
<link rel="stylesheet" href="{{ url_for('static', filename='spectre.css') }}"></link>
<title>RSA chatroom - {{ user_data['username'] }}</title>
</head>
<body>
<ul class="menu">
<li class="divider" data-content="{{ user_data['username'] }}"></li>
<li class="menu-item">
<a href="#">Log out</a>
</li>
</ul>
<ul class="menu">
{% for user in user_data['chats'] %}
<li class="menu-item">
<a href="/chats/{{ user.chat_id }}">
Chat with:
{% if user.participant1 is eq user_data['username'] %}
{{ user.participant2 }}
{% else %}
{{ user.participant2 }}
{% endif %}
</a>
Chat with:
{% if user.participant1 is eq user_data['user_id'] %}
<a href="/chats/{{ user_data['user_id'] }}/{{ user.participant2 }}">
{{ user.participant2 }}
</a>
{% else %}
<a href="/chats/{{ user_data['user_id'] }}/{{ user.participant1 }}">
{{ user.participant1 }}
</a>
{% endif %}

</li>
{% endfor %}
</ul>
<div>
<form action="{{ url_for('chat.create_chat', creator=user_data['user_id']) }}" id='chat-creation' method='POST'>
<span class='form-label'>Chat with: </span>
<input class='form-input' type='text' name='username' placeholder='username'>
<select class='form-select'>
<option></option>
</select>
<input class='btn btn-primary' type='submit' value='Create'>
</form>
</div>
<body>
</html>
35 changes: 35 additions & 0 deletions chatroom/templates/messages.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<!DOCTYPE html>
<html>
<head>
<script src="{{ url_for('static', filename='jquery-3.6.0.js') }}"></script>
<script src="{{ url_for('static', filename='myrequests.js') }}"></script>
<link rel="stylesheet" href="{{ url_for('static', filename='spectre.css') }}"></link>
<title>RSA chatroom - {{ other_user|title }}</title>
</head>
<body>
{% for msg in messages %}
<div class="card columns">
<div class='card-header'>from:
<span class='chip'>
<a href='#' }}>{{ msg['sender'] }}</a>
</span>
</div>
{% if msg['sender'] is eq this_user %}
<div class='card-body bg-primary float-right col-2'>{{ msg['data'] }}</div>
{% else %}
<div class='card-body bg-secondary float-left col-2'>{{ msg['data'] }}</div>
{% endif %}
<div class='card-footer'>
<span class='chip'>
<a href='#' }}>{{ msg['receiver'] }}</a>
</span>
</div>
</div>
{% endfor %}
<form action="{{ url_for('msg.send_message', sender=this_user_id, recipient=other_user_id) }}"
id='msg-sending' method='POST'>
<input class='form-input' type='textarea' name='message' placeholder='Say something'>
<input class='btn btn-primary' type='submit' value='Send'>
</form>
<body>
</html>

0 comments on commit 53aae8a

Please sign in to comment.