This commit is contained in:
phear 2005-09-06 17:52:46 +00:00
commit a5eb556ebb
58 changed files with 911 additions and 0 deletions

18
INSTALL Normal file
View file

@ -0,0 +1,18 @@
----------------- creating the database --------------------
#installing PostgreSQL the Debian way
apt-get install postgresql
su postgres
#in template1
psql template1
#at the prompt write:
CREATE DATABASE webgo ;
#now create user who is allowed to administrate this database
#user and password should be changed;>
CREATE USER name PASSWORD 'password';
#now make a super user out of this user:
#TODO:tighter rights for user, this should be unsecure
ALTER USER name CREATEUSER;
#now change the user and password variables in the script
webgouser
webgopassword

39
README Normal file
View file

@ -0,0 +1,39 @@
-------------------------------------------
WebGo Development:
Steps to do to get a runnable version:
1. create /etc/apache2/conf.d/webgo.conf with content:
Alias /webgo /home/mtsrc/daten/projekte/webgo/stderr.py
<DirectoryMatch /home/mtsrc/daten/projekte/webgo/>
Options ExecCGI
AddHandler cgi-script .py
AllowOverride None
order allow,deny
allow from all
</DirectoryMatch>
You should replace the directory settings for optimal results ;>
2. set ownership of webgo directory to ownership of the web server
this should be all. Errors get written to ./cgi_errors.log.
-------------------------------------------
How to make the goban clickable:
data += '<form method="post">'
data += '<input type=image src="img/bottomrightline.png" name="untenrechts">'
#insert rest of goban here
data += '</form>'
print data
How to extract the data from this POST:
import cgi
#get instance of fieldstorage
form = cgi.FieldStorage()
#if form == empty (which means if page is displayed for the first time):
if form.keys() != []:
#cut out the name of the clicked button
print string.split(form.keys()[0],".x")[0]

55
ROADMAP Normal file
View file

@ -0,0 +1,55 @@
M0: debug messages as html
Create a script that prints the python stderr of thea main script as html,
so debugging the cgi becomes more easy.
M1: user interaction thorugh images
Completed, when a user can click on an image, and the image gets replaced
as a result.
m2: autogenerate images
There are partly transparent images of black and white stones, center,
border and hoshi squares, all available in png format. The Milestone is
considered complete when the program can automatically generate combined
images of all squares with all stones. The stones have to be on top ;>
m3: display working 9x9 goban
Completed, when the cgi script has an internal representation of a goban
that can handle stones, and this goban is displayed on a html page.
m4: handle player turns
The program knows wether it is the turn of black or white, and prints the
current turn color on the html page displaying the goban. If player white
clicks on an empty square, a white stone will be layed onto that square.
Same for Player black.
m5: goban inside database
Manage the goban inside a postgresql database, so all user input changes a
table in the database. Includes a 'size' item that contains the length of
on side of the board, so that gobans of size 9x9, 13x13 and 19x19 can be
displayed.
. <--- YOU ARE HERE.
m6: manage users and game sessions inside database
manage user accounts and the game(s) they currently play inside the data-
base. each game has its own table, which contains players, current turn,
size, the goban inside the database. users are managed in a different
table. For each user the following data is stored: password, current games
(up to 8 or so). So if the user calls the cgi script, she has to send
username and password and is then given the choice of game to play. If
there is only one active game, directly present the goban.
m7: implement Go rules
Do not accept player moves which violate go rules. Remove beaten stones.
Count and display the score for each player.
m8: make it pretty, make it fast.
Create nicer images replacing the old ones which were just for testing
Find bottlenecks and optimize them for speed.
-- python profiler
-- http://peter.mapledesign.co.uk/weblog/archives/python_is_slow.html
create a set of images smaller than 50 pixels (for the 19x19 goban)
m9: make it standards compliant
w3c validation

1
TODO Normal file
View file

@ -0,0 +1 @@
- hoshi Bilder fuer weisse und schwarze Steine erstellen

25
generate_goban_images.py Executable file
View file

@ -0,0 +1,25 @@
#!/usr/bin/python
"""
a simple script using pil to generate the goban from background, grid and stone images.
"""
import Image
gridlist = ["bottomleftline","bottomline","bottomrightline",
"centerline","hoshi","leftline","rightline",
"topleftline", "topline","toprightline"]
whitestone = Image.open("imgsource/whitestone.png").convert("RGBA")
blackstone = Image.open("imgsource/blackstone.png").convert("RGBA")
for item in gridlist:
#creating empty goban
bg = Image.open("imgsource/background.png").convert("RGBA")
img = Image.open("imgsource/"+item+".png").convert("RGBA")
bg.paste(img,None,img)
bg.save("img/"+item+".png")
tmp = bg #for the black stones
#filling with white stones
bg.paste(whitestone,None,whitestone)
bg.save("img/"+item+"_white.png")
#filling with black stones
tmp.paste(blackstone,None,blackstone)
tmp.save("img/"+item+"_black.png")

174
goban.py Executable file
View file

@ -0,0 +1,174 @@
#!/usr/bin/python
"""
the main file for WebGo.
"""
import sys,string
import cgi
import pickle
import psql,helper
picklefile = "goban.pickledump"
###############################################################################
def display_goban(goban):
"""
gets: dictionary containing the layout of the used goban.
returns: string containing the HTML code for a clickable goban.
"""
data = ""
hoshis19x19 = [(4,4),(4,10),(4,16),(10,4),(10,10),(10,16),(16,4),(16,10),(16,16)]
hoshis13x13 = [(4,4),(4,10),(7,7),(10,4),(10,10)]
hoshis9x9 = [(3,3),(3,7),(5,5),(7,3),(7,7)]
data += '<form method="post">'
try:
size = goban["size"]
except:
#TODO: proper error management
raise "[EE] display_goban: got broken goban dictionary."
sys.exit(1)
for x in range(1,size+1):
for y in range(1,size+1):
# check for white or black stone
if goban[(x,y)] == 1:
stone = "_white"
elif goban[(x,y)] == 2:
stone = "_black"
else:
stone = ""
sx = str(x)
sy = str(y)
# check position:
if (x == 1) and (y == 1): # upper left
data += '<input type=image src="img/topleftline'+stone+'.png" name="('+sx+','+sy+')">'
elif (x == 1) and (y == size): # upper right
data += '<input type=image src="img/toprightline'+stone+'.png" name="('+sx+','+sy+')"><br>'
elif (x == size) and (y == size): # lower right
data += '<input type=image src="img/bottomrightline'+stone+'.png" name="('+sx+','+sy+')"><br>'
elif (x == size) and (y == 1): # lower left
data += '<input type=image src="img/bottomleftline'+stone+'.png" name="('+sx+','+sy+')">'
elif (y == 1): #left line
data += '<input type=image src="img/leftline'+stone+'.png" name="('+sx+','+sy+')">'
elif (x == 1): # top line
data += '<input type=image src="img/topline'+stone+'.png" name="('+sx+','+sy+')">'
elif (y == size): # right line
data += '<input type=image src="img/rightline'+stone+'.png" name="('+sx+','+sy+')"><br>'
elif (x == size): #bottom line
data += '<input type=image src="img/bottomline'+stone+'.png" name="('+sx+','+sy+')">'
else: # hoshi or empty inner field
defaultfield = '<input type=image src="img/centerline'+stone+'.png" name="('+sx+','+sy+')">'
#too lazy to make special images for hoshi fields with stones:
if goban[(x,y)] == 1:
hoshifield = '<input type=image src="img/centerline_white.png" name="('+sx+','+sy+')">'
elif goban[(x,y)] == 2:
hoshifield = '<input type=image src="img/centerline_black.png" name="('+sx+','+sy+')">'
else: #empty hoshi
hoshifield = '<input type=image src="img/hoshi.png" name="('+sx+','+sy+')">'
if size == 19: # 9 hoshis
if (x,y) in hoshis19x19:
data += hoshifield
else:
data += defaultfield
elif size == 13:
if (x,y) in hoshis13x13:
data += hoshifield
else:
data += defaultfield
elif size == 9:
if (x,y) in hoshis9x9:
data += hoshifield
else:
data += defaultfield
data += '</form>'
return data
def string_to_tuple(str):
"""
gets a string. If the string contains '(',')' and ',', then return
a tuple processed from the string. If the partial string is empty, then
-1 will be returned for that value.
"""
if (str[0] =='(') and (str[-1] ==')') and (string.find(str,',')):
splitlist = string.split(str[1:-1],",")
returnlist = []
for item in splitlist:
try:
returnlist.append(int(item))
except: #empty string
returnlist.append(-1)
return tuple(returnlist)
def process_form(goban):
"""
gets a goban dictionary.
reads out the returned CGI form.
if the goban has been clicked, return a (x,y) tuple of the position.
"""
#get instance of fieldstorage
form = cgi.FieldStorage()
#if form == empty (which means if page is displayed for the first time):
if form.keys() != []:
#cut out the name of the clicked button
namestring = string.split(form.keys()[0],".x")[0]
position = string_to_tuple(namestring)
ret = set_stone(goban, position)
if (type(ret) == type("")):
return (goban,ret) #return old goban and error string
else:
goban = ret
return (goban,"") # return new goban and empty string
def set_stone(goban, position):
"""gets a goban dictionary and a (x,y)-tuple. Returns a modified goban."""
turn = goban["turn_number"]
if (goban[position] == 0): #empty field
goban[position] = (turn % 2) + 1 #even turn: white tone (1), else black stone(2)
goban["turn_number"] += 1
#now write changed values to database
psql.update_goban_field(goban["name"],position[0],position[1],(turn % 2) + 1)
psql.update_turn_number(goban["name"],goban["turn_number"])
return goban
else:
return "Could not make move: Field not empty."
###############################################################################
def main():
# Print the required header that tells the browser how to render the text.
#(currently done by error logger)
#print "Content-Type: text/plain\n\n"
#do stuff
data = helper.header()
#read goban table from database
tmplist = psql.read_table("test")
#make a dictionary out of the list
goban = psql.fetchall_list_to_goban_dict(tmplist)
#print goban
(goban,str) = process_form(goban)
data += "<p> Turn number: %s, %s Player's Move.</p>" % (goban["turn_number"],("White","Black")[goban["turn_number"] % 2]) #eleet ;>
data += display_goban(goban)
if str != "":
data +="\n<p>"+str+"</p>\n"
data += helper.footer()
print data

38
helper.py Normal file
View file

@ -0,0 +1,38 @@
def header():
"""return html header"""
data = """
<html><HEAD>
</HEAD><body>
"""
return data
def footer():
"""return html footer"""
data = """
</body></html>
"""
return data
# create a unique session id
def generate_session_id():
import md5, time, base64, random, string
m = md5.new()
m.update(str(time.time()))
m.update(str(random.random()))
return string.replace(base64.encodestring(m.digest())[:-3], '/', '$')
def check_for_int(data):
"""
gets a string. if string is an integer: return integer.
else return given string.
"""
#check if value is int
num = [n for n in data if n.isdigit()]
tmp = "".join(num)
if tmp == data:
ret = int(data)
else:
ret = data
return ret

BIN
img/bottomleftline.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

BIN
img/bottomline.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

BIN
img/bottomline_black.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

BIN
img/bottomline_white.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

BIN
img/bottomrightline.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

BIN
img/centerline.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

BIN
img/centerline_black.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

BIN
img/centerline_white.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

BIN
img/centerwhite.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

BIN
img/hoshi.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

BIN
img/hoshi_black.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

BIN
img/hoshi_white.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

BIN
img/leftline.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

BIN
img/leftline_black.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

BIN
img/leftline_white.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

BIN
img/rightline.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

BIN
img/rightline_black.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

BIN
img/rightline_white.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

BIN
img/topleftline.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

BIN
img/topleftline_black.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

BIN
img/topleftline_white.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

BIN
img/topline.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

BIN
img/topline_black.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

BIN
img/topline_white.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

BIN
img/toprightline.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

BIN
img/toprightline_black.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

BIN
img/toprightline_white.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

BIN
imgsource/background.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

BIN
imgsource/blackstone.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 187 B

BIN
imgsource/bottomline.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 188 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 189 B

BIN
imgsource/centerline.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 194 B

BIN
imgsource/hoshi.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 229 B

BIN
imgsource/leftline.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 195 B

BIN
imgsource/rightline.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 194 B

BIN
imgsource/topleftline.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 188 B

BIN
imgsource/topline.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 187 B

BIN
imgsource/toprightline.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 189 B

BIN
imgsource/whitestone.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

23
init_webgo.py Executable file
View file

@ -0,0 +1,23 @@
import psql
def clear():
try:
psql.drop_table("test")
psql.drop_table("users")
except:
pass
def create():
psql.create_goban_table(9)
psql.create_user_table()
psql.add_webgo_user("gast","gast")
psql.add_webgo_user("gast2","gast2")
def main():
clear()
create()

130
login.py Executable file
View file

@ -0,0 +1,130 @@
import psql,init_webgo,helper
import time
from mod_python import *
def process_form(req,form):
"""
reads username and passsword from form
"""
#if form == empty (which means if page is displayed for the first time):
req.write(str(form.keys()))
#req.write("<br>"+"name="+form['name']+", password="+form['password']+"<hr>")
if form.keys() != []:
if ("name" in form.keys()) and ("password" in form.keys()):
#extract name and password
name = form["name"]
password = form["password"]
sessionid = form["sessionid"]
origpassword = psql.get_user_info(name,"password")
#check if user exists (else we would get an error string)
if origpassword != "no such user": #no error message, now check password
req.write("hier bin ich in der Schleife.<br>")
req.write(str(origpassword)+"<br>")
if password == origpassword:
#login accepted
psql.set_user_sessionid(name,sessionid)
psql.set_user_timeout(name)
#now display list of games.
game_overview_form(req,name,sessionid)
else:
req.write("Login incorrect. Please try again.<br>")
req.write(login_form())
else: #no such user
req.write("Login incorrect. Please try again.<br>")
req.write(login_form())
else: #one of (name,password) is missing:
req.write("Please enter your name and password.")
req.write(login_form())
def game_overview_form(req,user,sessionid):
"""
gets the name of a user and the queue of games.
prints a form with the option to select,create and delete games.
"""
data = helper.header()+ """
<h2> Current Games: </h2>
<form method="post">
"""
gamelist = psql.get_user_game_list(user)
req.write(str(gamelist)+"<hr>\n")
#display list of current games
counter = 10
tmp = ""
for item in gamelist:
if (item != None) and (item != "None"):
tmp += '<input type="radio"> name="game" value="%s"> %s\n' % (item,item)
tmp += '<input type="hidden" name="sessionid" value="%s">\n' % sessionid
tmp += '<input type="hidden" name="username" value="%s">\n' % user
#later write partners name and whether its our turn or not
#data += "Your partner: %s."
tmp +="<br>"
counter -= 1
if tmp == "": #no current games
data += "You don't have any running games.\n"
else:
data += tmp
data += '<input type=submit name="play" value="Play selected game">\n<input type=submit name="delete" value="Delete selected game">\n</form>'
#now comes the option for creating new games.
data += "<h2>Start a new Game</h2>\n"
if counter > 0:
data+= "You have %s free game slots.<br>" % counter
data += """
<form>
<input type=submit name="create" value="Start a new game">
<input type="hidden" name="sessionid" value="%s">
<input type="hidden" name="username" value="%s">
</form>
""" % (sessionid, user)
else:
data+= "Sorry, all your game slots are in use."
#display "You have ... free game slots" + Button "create game"
#bei "create game neue funktion zum Erstellen + Mitspieler aus Liste auswählen.
data+=helper.footer()
#check for timeout:
if (psql.get_user_info(user,'timeout') >= int(time.time())) and (sessionid == psql.get_user_info(user,'sessionid')):
req.write(data)
else:
req.write(helper.header()+ 'your session timed out'+helper.footer())
def login_form():
"""
print welcome message and html form.
"""
data = helper.header() + """
<form method="post">
<p>Name:<br>
<input name="name" size="40"></p>
<p>Pasword:<br>
<input name="password" size="40"></p>
<input type="hidden" name="sessionid" value="%s">
<p><input type="submit" value="login"></p>
</form>
""" % helper.generate_session_id()
data += helper.footer()
return data
def create_new_game(req,user):
"""
create a new game for user.
gets: request object, username.
"""
def main(req):
#get instance of fieldstorage
form = util.FieldStorage(req)
if "sessionid" not in form.keys():
req.write(login_form())
elif ("create" in form.keys()) and ("username" in form.keys()):
#user wants to create a new game
create_new_game(req,form["username"])
else:
process_form(req,form)

73
main.py Executable file
View file

@ -0,0 +1,73 @@
#!/usr/bin/python
"""
simple cgi wrapper for a cgi script, prints the error of the script as html
taken from http://gnosis.cx/publish/programming/feature_5min_python.html
modified a little
"""
from mod_python import apache
import sys, traceback
import init_webgo
DEBUG = 1
def handler(req):
# "Content-type: text/html\n\n"
req.content_type = "text/html"
try: # use explicit exception handling
#reinitialize database
init_webgo.main()
login = apache.import_module("login")
login.main(req)
return apache.OK
except:
import time
errtime = '----- '+ time.ctime(time.time()) +' -----\n'
errlog = open('/tmp/cgi_errors.log', 'a')
errlog.write(errtime)
errlog.write(ErrorMsg())
data = """<html><head><title>CGI Error Encountered!</title></head>
<body><p>Sorry, a problem was encountered running WebGo.</p>
<p>Please check the error log on the server for details.</p>
<hr><pre>"""
data += ErrorMsg()
data+="</pre>\n</body></html>"
req.write(data)
return apache.OK
def ErrorMsg(escape=0):
"""
returns: string
simualtes the traceback output and if argemument
<escape> set to 1 (true) the string will be
converted to fit into html documents without problems.
from Dirk Holtwick
"""
import traceback, sys, string
type=None
value=None
tb=None
limit=None
type, value, tb = sys.exc_info()
body = "Traceback (innermost last):\n"
list = traceback.format_tb(tb, limit) + traceback.format_exception_only(type, value)
body = body + "%-20s %s" % (
string.join(list[:-1], ""),
list[-1],
)
if escape:
import cgi
body = cgi.escape(body)
return body
#start(req)

7
mptest.py Executable file
View file

@ -0,0 +1,7 @@
from mod_python import apache
def handler(req):
req.write("Hello World!")
return apache.OK

51
old_functions.py Executable file
View file

@ -0,0 +1,51 @@
def init_goban(size=9):
"""
Returns an empty goban in the form of a dictionary where the keys are
x,y-tuples: (1,1) is the upper left corner, (9,9) the lower right one
for a 9x9 goban.
The additional key named size contains the length of a side of the goban.
Content of a field:
0 == empty field
1 == white stone on field
2 == black stone on field
Field turn_number: Current turn to be played. Even: white, uneven: black.
Optional argument size: define length of a side of the goban (one of
9, 12 or 19). Defaults to 9.
Returns dictionary.
"""
goban = {}
for x in range(1,size+1):
for y in range(1,size+1):
goban[(x,y)] = 0
if (size == 9) or (size == 13) or (size == 19):
goban["size"] = size
else:
goban["size"] = 9
goban["turn_number"] = 1
#some stones for testing purposes
goban[(1,2)] = 1; goban[(2,1)] = 1; goban[(2,3)] = 1; goban[(3,3)] = 1; goban[(6,7)] = 1; goban[(6,9)] = 1
goban[(2,2)] = 2; goban[(1,3)] = 2; goban[(4,7)] = 2; goban[(4,9)] = 2; goban[(5,8)] = 2; goban[(7,9)] = 2
return goban
def save_goban(goban):
"""gets a goban dictionary and pickles it to a file.
"""
try:
f = open(picklefile,"w")
pickle.dump(goban,f)
f.close()
except:
print "error: could not write to file "+picklefile+"!"
def load_goban():
"""trys to load and return a pickled goban. If this does not work return
a newly initialized goban."""
try:
f = open(picklefile,"r")
return pickle.load(f)
f.close() #datei ist jetzt genullt
except:
return init_goban()

274
psql.py Executable file
View file

@ -0,0 +1,274 @@
import helper
import pgdb,sys
dbusername="webgouser"
dbpassword="webgopassword"
dbname="webgo"
#pgdb.connect(connect_string) -> connection
#connect_string = 'host:database:user:password:opt:tty'
connect_string='localhost:'+dbname+':'+dbusername+':'+dbpassword
db=pgdb.connect(connect_string)
def create_table(name,layout=""):
"""
create_table(name:string, layout:string)
returns name if successfull, None if not.
simple function to create a table. the function itself would just
create an empty table with the command 'CREATE TABLE ();'.
The real layout is given to the function as an argument of type
string. This string contains all column declarations in SQL syntax:
"var1 real, var2 int"
name is the name of the table
"""
executestring = "CREATE TABLE %s ( %s );" % (name,layout)
sql_one_liner(executestring)
def insert_into_table(table, content):
"""
gets the name of a table and a content string.
executes INSERT INTO name VALUES content;
"""
executestring = "INSERT INTO %s VALUES %s" % (table,content)
sql_one_liner(executestring)
def drop_table(name):
"""
gets: name of table.
executes DROP TABLE <name>
"""
executestring = "DROP TABLE %s;" % (name)
sql_one_liner(executestring)
def sql_one_liner(data):
"""
gets:SQL statement
creates a cursor, executes <statement>, closes cursor.
"""
cursor=db.cursor()
cursor.execute(data)
# Commit the changes
db.commit()
cursor.close()
def create_goban_table(size):
"""
gets:size of goban.
creates postgresql table containing goban data.
returns: name of created table.
"""
tablename="test"
data="line varchar(15)"
for i in range(1,size+1):
if data != "":
data += ", "
data += "x"+str(i) + ' varchar(15)'
create_table(tablename,data)
#table created, now fill the table
for i in range(1,size+1):
tmplist=[]
tmplist.append("y"+str(i))
for k in range(1,size+1):
tmplist.append(0)
insert_into_table(tablename,str(tuple(tmplist)))
#ok, goban itself has been created and filled,
#now insert additional variables
tmplist=[]
tmplist.append("turn_number")
tmplist.append("1")
insert_into_table(tablename,str(tuple(tmplist)))
#size of goban
tmplist=[]
tmplist.append("size")
tmplist.append(size)
insert_into_table(tablename,str(tuple(tmplist)))
#name of goban (=name of table in database)
tmplist=[]
tmplist.append("name")
tmplist.append(tablename)
insert_into_table(tablename,str(tuple(tmplist)))
return tablename
def create_user_table():
"""
creates a table named users with following columns:
name - name of user
password - passsword of user
game1 - the 10 game slots of this user contain names
... of goban tables
game10
sessionid - id of current session
timeout - when does session time out?
"""
data = "username varchar(15)"
data += ", password varchar(15)"
for i in range(1,11):
data += ", game"+str(i)+" varchar(15)"
data += ", sessionid text"
data += ", timeout int"
create_table("users",data)
def read_table(table):
"""
gets the name of a table, does a
SELECT * FROM table;
returns output.
"""
cursor=db.cursor()
data="SELECT * FROM %s;" % (table)
cursor.execute(data)
# Commit the changes
db.commit()
ret = cursor.fetchall()
cursor.close()
return ret
def get_user_game_list(name):
"""
gets a username, returns the list of games for user.
"""
cursor=db.cursor()
ret = []
for x in range(1,11):
data="SELECT game%s FROM users WHERE username = '%s'" % (x,name)
try:
cursor.execute(data)
# Commit the changes
db.commit()
ret.append(cursor.fetchone()[0]) #[0], because return is a list
except:
ret = "could not get info of all games -- table corrupt?"
return ret
cursor.close()
return ret
def get_user_info(name,infotype):
"""
gets the name of a user and the type of requested info.
returns info from database.
"""
cursor=db.cursor()
if infotype in ("password","sessionid","timeout"):
data="SELECT %s FROM users WHERE username = '%s'" % (infotype,name)
try:
cursor.execute(data)
# Commit the changes
db.commit()
ret = cursor.fetchone()[0] #[0], because return is a list
except:
ret = "no such user"
cursor.close()
else:
ret = "Are your sure about the infotype?"
return ret
def set_user_sessionid(username,sessionid):
"""
gets username and sessionid, writes sessid into database
"""
executestring ="UPDATE users SET sessionid = '%s' WHERE username = '%s'" %(sessionid, username)
sql_one_liner(executestring)
def set_user_timeout(username):
"""
gets username, sets timeout to time.time + 30min
"""
import time
timeout = int(time.time()) + 1800 #current time in seconds + seconds for session
executestring ="UPDATE users SET timeout = '%s' WHERE username = '%s'" %(timeout, username)
sql_one_liner(executestring)
def update_database_field(table,column,line,data):
"""
gets: table name, column name, line name, new content for field.
executes an SQL UPDATE statement for line.
"""
#TODO:schreiben
executestring ="UPDATE %s SET %s = '%s' WHERE line = '%s'" %(table,column,data,line)
sql_one_liner(executestring)
def update_goban_field(table,x,y,content):
"""
gets: goban dictionary, x,y coordinates, new content for field.
modifies goban in database.
"""
update_database_field(table,"x"+str(x),"y"+str(y),content)
def update_turn_number(table,new_number):
"""
gets: name of table,new turn number
modifies 'turn_number' in table
"""
update_database_field(table,"x1","turn_number",new_number)
def add_webgo_user(name,password):
"""
adds a database entry for a user.
gets: username and password
"""
#size of goban
tmplist=[]
tmplist.append(name)
tmplist.append(password)
insert_into_table("users",str(tuple(tmplist)))
def fetchall_list_to_goban_dict(list):
"""
gets the output from read_table (a list),
returns a goban dictionary.
"""
#create dictionary
ret = {}
#get size of goban
for item in list:
if item[0] == "size":
size=int(item[1])
ret["size"] = size
#populate dictionary with goban field
for item in list:
if item[0][0] == "y": #goban fields
#get current y coordinate
y = int(item[0][1:])
#fill dictionary for current y coordinate
for x in range(1,size+1):
ret[(x,y)]=helper.check_for_int(item[x])
else: #other variables
ret[item[0]]=helper.check_for_int(item[1])
return ret
def test():
#create_table("test")
drop_table("test")
create_goban_table(9)
update_database_field("test","x1","turn_number",4)
list = read_table("test")
print list
dict = fetchall_list_to_goban_dict(list)
print dict
print dict["turn_number"]
print dict["name"]
print type(dict["turn_number"])
#test()

3
test.py Normal file
View file

@ -0,0 +1,3 @@
def hello(req):
x = "Hello, world!"
return x