-
Notifications
You must be signed in to change notification settings - Fork 0
/
markovChains.py
executable file
·276 lines (251 loc) · 8.65 KB
/
markovChains.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
#!/usr/bin/env python3.3
import bcrypt
import cgi
import configparser
import http.cookies
import os
import pymysql # https://github.com/PyMySQL/PyMySQL/
import random
import string
import sys
"""
markovChains.py
This file contains helper functions that are common to all pages of the webapp.
It should contain functions to do all database calls, and return only valid
python objects and data structures.
"""
# Global variables:
conn = None
# -----------------------------------------------------------------------------
# Begin HTML functions
# -----------------------------------------------------------------------------
def check_browser_cookie(require_login=True):
cookie = []
if "HTTP_COOKIE" in os.environ:
cookie = http.cookies.SimpleCookie(os.environ["HTTP_COOKIE"])
if "session" in cookie:
user = check_cookie(cookie["session"].value)
if user:
return user
if not require_login:
return False
redirect("index.py?error=nologin")
sys.exit(0)
def printHeader():
print("""Content-Type: text/html
<!doctype html>
<html>
<head>
<title>Markov Chains</title>
<link rel="stylesheet" type="text/css" href="cssreset.css" />
<link rel="stylesheet" type="text/css" href="stylesheet.css" />
</head>
<body>
<div id="main">
<center><h1>Markov Chains</h1><a href="user.py">User page</a></center>
<hr>
<br />
""")
def printFooter():
print("""</div>
</body>""", end="")
def redirect(loc, headers=""):
print("""Content-Type: text/html""")
print(headers)
print("""
<!doctype html>
<html>
<head>
<meta http-equiv="refresh" content="0; url=""" + loc + """">
</head>
<body>
<a href='""" + loc + """'> Please click here if you are not redirected.<a/>
</body>
</html>""")
# -----------------------------------------------------------------------------
# End HTML functions
# -----------------------------------------------------------------------------
# Begin database functions
# -----------------------------------------------------------------------------
# Increment this number whenever the schema is changed, and databases will
# automatically remake themselves. (Warning: existing data will be deleted.)
db_version = 19
def initdb():
global conn
config = configparser.ConfigParser()
# Storing the cfg file in the web folder is not secure,
# don't do this on a real install.
config.read("markovChains.cfg")
host = config['db']['host']
database = config['db']['database']
username = config['db']['username']
password = config['db']['password']
conn = pymysql.connect(host=host,
user=username,
passwd=password,
db=database)
c = conn.cursor()
try:
c.execute("SELECT value FROM info WHERE `key` = 'db_version'")
r = int(c.fetchall()[0][0])
if r < db_version:
#print("DB is old, remaking")
create_db()
elif r > db_version:
#print("DB is newer than code, aborting")
sys.exit(1)
except pymysql.err.ProgrammingError:
create_db()
def create_db():
c = conn.cursor()
c.execute("DROP TABLE IF EXISTS info")
c.execute("CREATE TABLE info (`key` VARCHAR(255) PRIMARY KEY, value TEXT)")
c.execute("INSERT INTO info VALUES ('db_version', %s)", (db_version, ))
c.execute("DROP TABLE IF EXISTS users")
c.execute("""CREATE TABLE users
(username VARCHAR(255) PRIMARY KEY,
password TEXT,
cookie TEXT,
cookie_expire DATETIME)""")
# blank password
c.execute("INSERT INTO users VALUES ('test', '$2a$12$6J4OyHUwI4Z8xAqslIpxLeFnQmuGkf700V7Rm9kMGpmMeW2VXHJkK', '', NOW() + INTERVAL 1 DAY)")
c.execute("DROP TABLE IF EXISTS blocks")
c.execute("""CREATE TABLE blocks
(id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(255),
user VARCHAR(255),
original_text LONGTEXT,
source_url TEXT,
FOREIGN KEY (user) REFERENCES users(username) ON DELETE CASCADE ON UPDATE CASCADE)""")
c.execute("DROP TABLE IF EXISTS chunks")
c.execute("""CREATE TABLE chunks
(block_id INT,
context_length INT,
context VARCHAR(25),
next VARCHAR(25),
INDEX (context),
FOREIGN KEY (block_id) REFERENCES block(id) ON DELETE CASCADE ON UPDATE CASCADE)""")
c.execute("DROP TABLE IF EXISTS generated_text")
c.execute("""CREATE TABLE generated_text
(block_id INT,
date DATETIME,
text LONGTEXT,
FOREIGN KEY (block_id) REFERENCES block(id) ON DELETE CASCADE ON UPDATE CASCADE)""")
conn.commit()
c.close()
def check_credentials(user, password):
c = conn.cursor()
c.execute("SELECT password FROM users WHERE username = %s", (user, ))
r = c.fetchone()
c.close()
if r == None:
# user does not exist
return False
hashed = r[0]
if bcrypt.hashpw(password, hashed) == hashed:
# user exists, password is good
session_id = randomCookie()
cookie = http.cookies.SimpleCookie()
cookie['session'] = session_id
c = conn.cursor()
c.execute("UPDATE users SET cookie = %s, cookie_expire = NOW() + INTERVAL 1 WEEK WHERE username = %s", (session_id, user))
return cookie.output()
else:
# user exists, password is bad
return False
def check_cookie(cookie):
c = conn.cursor()
c.execute("SELECT username FROM users WHERE cookie = %s AND cookie_expire > NOW()", (cookie, ))
r = c.fetchone()
c.close()
if r == None:
return False
else:
return r[0]
def create_user(user, password):
c = conn.cursor()
hashed = bcrypt.hashpw(password, bcrypt.gensalt(12))
# c.execute("DELETE FROM users WHERE username = %s", (user, ))
try:
c.execute("INSERT INTO users VALUES (%s, %s, '', NOW())", (user, hashed))
except pymysql.err.IntegrityError:
# It's likely the user already exists
return False
finally:
conn.commit()
c.close()
return True
def create_block(name, user, text, url=None):
c = conn.cursor()
c.execute("INSERT INTO blocks VALUES (null, %s, %s, %s, %s)", (name, user, text, url))
c.execute("SELECT max(id) FROM blocks")
id = c.fetchone()[0]
if False:
# This doesn't work for some reason :(
for context_length in range(1, 11):
for i in range(context_length, len(text)):
try:
context = text[i-context_length:i]
string = str(text[i])
c.execute("INSERT INTO chunks VALUES (%s, %s, %s, %s)", (id, context_length, context, string))
except:
pass
words = text.split()
for i in range(1, len(words)):
try:
context = words[i-1]
string = words[i]
c.execute("INSERT INTO chunks VALUES (%s, %s, %s, %s)", (id, 0, context, string))
except:
pass
conn.commit()
c.close()
def get_blocks(user, id=None):
c = conn.cursor(pymysql.cursors.DictCursor)
if id:
c.execute("SELECT * FROM blocks WHERE user = %s AND id = %s", (user, id))
else:
c.execute("SELECT * FROM blocks WHERE user = %s", (user, ))
blocks = c.fetchall()
conn.commit()
c.close()
return blocks
def create_chain(id, context_length, length):
context_length = int(context_length)
c = conn.cursor(pymysql.cursors.DictCursor)
text = ""
if context_length == 0:
text = "test"
c.execute("SELECT * FROM chunks WHERE block_id = %s ORDER BY RAND() LIMIT 1", (id, ))
context = c.fetchone()['next']
text = context
for i in range(length):
c.execute("SELECT * FROM chunks WHERE block_id = %s AND context = %s", (id, context))
words = c.fetchall()
if len(words) < 1:
c.execute("SELECT * FROM chunks WHERE block_id = %s ORDER BY RAND() LIMIT 1", (id, ))
context = c.fetchone()['next']
else:
context = random.choice(words)['next']
text += context + " "
else:
# TODO: implement
for i in range(length):
pass
# TODO: add text to generated_text table
conn.commit()
c.close()
return text.encode('ascii', 'ignore')[2:-1]
# -----------------------------------------------------------------------------
# End database functions
# -----------------------------------------------------------------------------
def randomCookie(length=40):
return "".join(random.choice(string.ascii_uppercase +\
string.ascii_lowercase + string.digits) for x in range(length))
def init():
initdb()
if __name__ == "__main__":
print("Error: This file should not be run on its own, only included")
sys.exit(1)
else:
init()