split quests table, added ability to update quest

This commit is contained in:
iou1name 2018-06-20 13:07:11 -04:00
parent c2fb07d8f9
commit 311b4723ea
7 changed files with 132 additions and 33 deletions

View File

@ -1,17 +1,22 @@
CREATE TABLE `users` (
`id` SMALLINT UNSIGNED NOT NULL AUTO_INCREMENT,
`user_id` SMALLINT UNSIGNED NOT NULL AUTO_INCREMENT,
`username` VARCHAR(20) NOT NULL,
`password_hash` CHAR(73) NOT NULL,
PRIMARY KEY (`id`)
PRIMARY KEY (`user_id`)
) ENGINE=InnoDB CHARSET utf8mb4;
CREATE TABLE `quests` (
`id` SMALLINT UNSIGNED NOT NULL AUTO_INCREMENT,
CREATE TABLE `quest_meta` (
`quest_id` SMALLINT UNSIGNED NOT NULL AUTO_INCREMENT,
`canon_title` VARCHAR(300) DEFAULT NULL,
`ident_title` VARCHAR(300) DEFAULT NULL,
`owner_id` SMALLINT UNSIGNED DEFAULT NULL,
`quest_data` MEDIUMTEXT DEFAULT NULL,
PRIMARY KEY (`id`)
PRIMARY KEY (`quest_id`)
) ENGINE=InnoDB CHARSET utf8mb4;
CREATE TABLE `quest_data` (
`quest_id` SMALLINT UNSIGNED NOT NULL,
`post` MEDIUMTEXT NOT NULL,
`timestamp` INT UNSIGNED NOT NULL
) ENGINE=InnoDB CHARSET utf8mb4;
CREATE TABLE `chat_messages` (

View File

@ -111,3 +111,43 @@ def get_chat_messages(room_id):
"SELECT * FROM `chat_messages` WHERE `room_id` = %s " \
+ "ORDER BY `date` ASC", (room_id,)).fetchall()
return res
def insert_quest(canon_title, ident_title, owner_id):
"""
Creates a new quest entry.
"""
_DB.execute(
"INSERT INTO `quest_meta` (`canon_title`, `ident_title`, `owner_id`) "\
+ "VALUES (%s, %s, %s)", (canon_title, ident_title, owner_id))
quest_id = _DB.execute(
"SELECT `quest_id` FROM `quest_meta` WHERE `ident_title` = %s",
(ident_title,)).fetchone()[0]
return quest_id
def insert_quest_post(quest_id, post, timestamp):
"""
Insers a new quest post.
"""
_DB.execute(
"INSERT INTO `quest_data` (`quest_id`, `post`, `timestamp`) " \
"VALUES (%s, %s, %s)", (quest_id, post, timestamp))
def get_quest_meta(ident_title):
"""
Retrieves all meta info about a quest.
"""
data = _DB.execute("SELECT * FROM `quest_meta` WHERE `ident_title` = %s",
(ident_title,)).fetchone()
return data
def get_quest_data(quest_id):
"""
Retrieves all quest posts.
"""
data = _DB.execute("SELECT * FROM `quest_data` WHERE `quest_id` = %s",
(quest_id,)).fetchall()
return data

View File

@ -11,7 +11,7 @@ import database as db
socketio = SocketIO()
@socketio.on('joined', namespace="/chat")
@socketio.on('joined')
def joined(data):
"""
Sent by clients when they enter a room.
@ -20,8 +20,8 @@ def joined(data):
join_room(room)
@socketio.on('message', namespace="/chat")
def text(data):
@socketio.on('message')
def message(data):
"""
Sent by a client when the user entered a new message.
"""
@ -46,3 +46,19 @@ def text(data):
db.log_chat_message(data)
emit("message", data, room=room)
@socketio.on("new_post")
def new_post(data):
"""
Called when the QM makes a new post.
"""
room = data["room"]
post = data["post"]
post = bleach.clean(post.strip())
post = post.replace("\n", "<br />")
data["post"] = [post]
db.insert_quest_post(int(room), post, int(time.time()))
emit("new_post", data, room=room)

View File

@ -1,4 +1,5 @@
#header {
.header {
display: initial;
position: fixed;
top: 0;
left: 0;
@ -9,10 +10,15 @@
background-color: #dddddd;
}
#header li {
.header li {
display: inline;
}
#headerHidden {
display: none;
width: auto;
}
#questContainer {
display: flex;
overflow: auto;
@ -23,6 +29,9 @@
padding-right: 32%;
}
#newQPostArea {
}
#chatPane {
height: 100%;
width: 30%;
@ -38,14 +47,14 @@
flex: 1;
}
#messageBox {
#messageTextDiv {
padding-bottom: 10px;
width: 100%;
display: flex;
flex-direction: column;
}
#messageTextarea {
#messageTextArea {
resize: none;
box-sizing: border-box;
}

View File

@ -21,9 +21,7 @@
<ul id="header" class="header" style="display:initial;">
<li><a onclick="toggleHeader();" href="javascript:void(0);">^</a></li>
<li><a href="{{ url_for('views.index') }}">Home</a></li>
{% if session.get("user_id") == owner_id %}
<li><a href="{{ url_for('views.edit_quest') }}">Edit Quest</a></li>
{% endif %}
{% block header %}{% endblock %}
</ul>
<ul id="headerHidden" class="header" style="display:none;">
<li><a onclick="toggleHeader();" href="javascript:void(0);">^</a></li>

View File

@ -8,7 +8,7 @@
if ( document.readyState !== 'complete' ) return;
clearInterval( tid );
socket = io.connect('https://' + document.domain + ':' + location.port + '/chat');
socket = io.connect('https://' + document.domain + ':' + location.port);
socket.on('connect', function() {
socket.emit('joined', {room: '{{ room_id }}' });
});
@ -25,7 +25,11 @@
mbox.innerHTML = mbox.innerHTML + msg_str;
mbox.scrollTop = mbox.scrollHeight;
});
mtarea = document.getElementById('messageTextarea');
socket.on('new_post', function(data) {
qposts = document.getElementById('questPosts');
qposts.innerHTML = qposts.innerHTML + '<div class="questPost">' + data.post + '</div>';
});
mtarea = document.getElementById('messageTextArea');
mtarea.addEventListener('keypress', function(event) {
if (event.key == 'Enter' && !event.shiftKey) {
text = mtarea.value.trim();
@ -42,14 +46,42 @@
return number;
}
</script>
{% if session.get("user_id") == owner_id %}
<script>
function makePost() {
qparea = document.getElementById('postTextArea');
text = qparea.value.trim();
qparea.value = '';
if (text == '') { return; }
socket.emit('new_post', {post: text, room: '{{ room_id }}'});
}
</script>
{% endif %}
{% endblock %}
{% block header %}
{% if session.get("user_id") == owner_id %}
<li><a href="{{ url_for('views.edit_quest') }}">Edit Quest</a></li>
{% endif %}
{% endblock %}
{% block content %}
<div id="questContainer">
<div id="questBody">
<h1>{{ quest_title }}</h1>
{% autoescape false %}
{{ quest_body }}
{% endautoescape %}
<div id="questPosts">
{% for quest_post in quest_posts %}
{% autoescape false %}
<div class="questPost">
{{ quest_post[1] }}
</div>
{% endautoescape %}
{% endfor %}
</div>
{% if session.get("user_id") == owner_id %}
<div id="postTextDiv">
<textarea id="postTextArea"></textarea><br />
<input type="submit" name="newPost" value="Post" onclick="makePost();"/>
</div>
{% endif %}
</div>
<div id="chatPane">
<h1>Chat</h1>
@ -65,7 +97,7 @@
{% endfor %}
{% endautoescape %}
</div>
<div id="messageBox"><textarea id="messageTextarea"></textarea></div>
<div id="messageTextDiv"><textarea id="messageTextArea"></textarea></div>
</div>
</div>
{% endblock %}

View File

@ -2,6 +2,7 @@
"""
Database tools and functions.
"""
import time
import string
import urllib
import functools
@ -55,17 +56,16 @@ def quest(quest_title):
"""
An arbituary quest page.
"""
quest_title, _, extra = quest_title.partition("/")
res = db._DB.execute("SELECT * FROM `quests` WHERE `ident_title` = %s",
(quest_title,))
data = res.fetchone()
ident_title, _, extra = quest_title.partition("/")
data = db.get_quest_meta(ident_title)
if not data:
abort(404)
quest_id, quest_title, _, owner_id, quest_data = data
quest_id, quest_title, _, owner_id = data
quest_posts = db.get_quest_data(quest_id)
messages = db.get_chat_messages(quest_id)
return render_template('quest.html',
quest_title=quest_title,
quest_body=quest_data,
quest_posts=quest_posts,
owner_id=owner_id,
room_id=quest_id,
messages=messages)
@ -87,12 +87,11 @@ def create_quest():
quest_body = quest_body.replace("\n", "<br />")
owner_id = session.get("user_id")
timestamp = int(time.time())
quest_id = db.insert_quest(canon_title, ident_title, owner_id)
db.insert_quest_post(quest_id, quest_body, timestamp)
db._DB.execute(
"INSERT INTO `quests` " \
+ "(`canon_title`, `ident_title`, `owner_id`, `quest_data`) " \
+ "VALUES (%s, %s, %s, %s)",
(canon_title, ident_title, owner_id, quest_body))
return redirect(url_for('views.quest', quest_title=ident_title))