Commit ffbbabf2 authored by Romain Loth's avatar Romain Loth

fix db saving for picture mediumblob

parent 85b51feb
...@@ -9,7 +9,8 @@ registered.db is a sqlite3 db, with 2 tables: ...@@ -9,7 +9,8 @@ registered.db is a sqlite3 db, with 2 tables:
-- ######################### -- #########################
create table test_table ( create table test_table (
email varchar(255) unique, email varchar(255) unique,
initials varchar(7) initials varchar(7),
pic_file blob
) ; ) ;
...@@ -34,6 +35,6 @@ create table comex_registrations ( ...@@ -34,6 +35,6 @@ create table comex_registrations (
interests_text varchar(1200), interests_text varchar(1200),
community_hashtags varchar(350), community_hashtags varchar(350),
gender char(1), gender char(1),
pic_file blob pic_file mediumblob
) ; ) ;
``` ```
...@@ -93,20 +93,33 @@ def one_big_form(): ...@@ -93,20 +93,33 @@ def one_big_form():
# print("OK accepted") # print("OK accepted")
form_accepted = True form_accepted = True
clean_records = read_records(request.form) clean_records = {}
pic_blob = None
# 1) handles all the text/options inputs
(duuid, rdate, clean_records) = read_records(request.form)
# 2) handles the pic_file if present
if hasattr(request, "files") and 'pic_file' in request.files:
# it's a werkzeug.datastructures.FileStorage
pic = request.files['pic_file']
print("INFO: Storing a picture (%s)" % pic.filename)
pic_blob = pic.stream.read()
try: # 3) pass it on
# try:
# save to DB # save to DB
save_to_db([clean_records.get(k[0], None) for k in COLS]) save_to_db([duuid, rdate] + [clean_records.get(k[0], None) for k in COLS[2:-1]] + [pic_blob])
except Exception as perr:
return render_template("thank_you.html", # except Exception as perr:
records = clean_records, # return render_template("thank_you.html",
form_accepted = False, # records = clean_records,
backend_error = True, # form_accepted = False,
message = ("ERROR ("+str(perr.__class__)+"):<br/>" # backend_error = True,
+ ("<br/>".join(format_tb(perr.__traceback__))) # message = ("ERROR ("+str(perr.__class__)+"):<br/>"
) # + ("<br/>".join(format_tb(perr.__traceback__)))
) # )
# )
# TODO use MY_DEBUG_FLAG here # TODO use MY_DEBUG_FLAG here
return render_template("thank_you.html", return render_template("thank_you.html",
...@@ -149,7 +162,7 @@ def re_hash(userinput, salt="verylonverylongverylonverylongverylonverylong"): ...@@ -149,7 +162,7 @@ def re_hash(userinput, salt="verylonverylongverylonverylongverylonverylong"):
def sanitize(value): def sanitize(value):
""" """
simple and radical: leaves only alphanum and '.' '-' ':' ',' '(', ')', ' ' simple and radical: leaves only alphanum and '.' '-' ':' ',' '(', ')', '#', ' '
TODO better TODO better
""" """
...@@ -157,7 +170,7 @@ def sanitize(value): ...@@ -157,7 +170,7 @@ def sanitize(value):
str_val = str(value) str_val = str(value)
clean_val = sub(r'^\s+', '', str_val) clean_val = sub(r'^\s+', '', str_val)
clean_val = sub(r'\s+$', '', clean_val) clean_val = sub(r'\s+$', '', clean_val)
san_val = sub(r'[^\w@\.-:,() ]', '_', clean_val) san_val = sub(r'[^\w@\.-:,()# ]', '_', clean_val)
if vtype not in [int, str]: if vtype not in [int, str]:
raise ValueError("Value has an incorrect type %s" % str(vtype)) raise ValueError("Value has an incorrect type %s" % str(vtype))
...@@ -176,29 +189,51 @@ def save_to_db(safe_recs_arr): ...@@ -176,29 +189,51 @@ def save_to_db(safe_recs_arr):
# yes =>propose login via doors + overwrite ?) # yes =>propose login via doors + overwrite ?)
# no => proceed # no => proceed
db_fields = [] db_tgtcols = []
db_vals = [] # db_pyvals = []
# we filter ourselves db_qstrvals = []
actual_len_dbg = 0
# REMARK:
# => In theory should be possible to execute(statment, values) to insert all
# (or reg_db.literal(db_pyvals) to convert all)
# => But currently bug in MySQLdb for binary values)
# (see also MySQLdb.converters)
# => So for now we buid the values string ourselves in db_qstrvals instead
# ------------- -----------
# and then we execute(full_statmt) :-)
# + we also filter ourselves
# ---------------------------
for i in range(len(COLS)): for i in range(len(COLS)):
col = COLS[i] col = COLS[i]
colname = col[0]
# NB: each val already contains no quotes because of sanitize()
val = safe_recs_arr[i] val = safe_recs_arr[i]
if val != None:
db_fields.append(col[0])
db_vals.append(val)
# expected colnames "(doors_uid, last_modified_date, email, ...)"
db_mask_str = ','.join(db_fields) if val != None:
actual_len_dbg += 1
# TODO check if str(tuple(vals)) is ok for quotes quotedstrval = ""
# and injection (although we've sanitized them b4) if colname != 'pic_file':
db_vals_str = str(tuple(db_vals)) quotedstrval = "'"+str(val)+"'"
else:
# str(val) for a bin is already quoted but has the 'b' prefix
quotedstrval = '_binary'+str(val)[1:]
# print("DEBUG: added pic blob: " + quotedstrval[:15] + '...' + quotedstrval[-5:])
# anyways
db_tgtcols.append(colname)
db_qstrvals.append(quotedstrval)
# db_pyvals.append(val)
# expected colnames "(doors_uid, last_modified_date, email, ...)"
db_tgtcols_str = ','.join(db_tgtcols)
print("dbmask = ", db_mask_str) # fields converted to sql syntax
print("actual len = ", len(db_vals)) db_vals_str = ','.join(db_qstrvals)
print("actual values str", db_vals_str)
# DB is actually in a docker and forwarded to localhost:3306 # DB is actually in a docker and forwarded to localhost:3306
reg_db = connect( host=MY_SQLDOCKERIP, reg_db = connect( host=MY_SQLDOCKERIP,
...@@ -209,13 +244,13 @@ def save_to_db(safe_recs_arr): ...@@ -209,13 +244,13 @@ def save_to_db(safe_recs_arr):
reg_db_c = reg_db.cursor() reg_db_c = reg_db.cursor()
# print("INSERTING values", safe_recs_arr) # full_statement with formated values
reg_db_c.execute( full_statmt = 'INSERT INTO comex_registrations (%s) VALUES (%s)' % (
'INSERT INTO comex_registrations (%s) VALUES %s' % ( db_tgtcols_str,
db_mask_str,
db_vals_str db_vals_str
) )
)
reg_db_c.execute(full_statmt)
reg_db.commit() reg_db.commit()
reg_db.close() reg_db.close()
...@@ -231,16 +266,15 @@ def read_records(incoming_data): ...@@ -231,16 +266,15 @@ def read_records(incoming_data):
# ========================= # =========================
# NB password values have already been sent by ajax to Doors # NB password values have already been sent by ajax to Doors
duuid = None
rdate = None
# we should have all the mandatory fields (checked in client-side js) # we should have all the mandatory fields (checked in client-side js)
for field_info in COLS: for field_info in COLS:
field = field_info[0] field = field_info[0]
if field in incoming_data: if field in incoming_data:
if field not in ["doors_uid", "last_modified_date"]: if field not in ["doors_uid", "last_modified_date"]:
if field == "pic_file":
# TODO check blob copy goes well here
val = incoming_data[field]
else:
val = sanitize(incoming_data[field]) val = sanitize(incoming_data[field])
if val != '': if val != '':
clean_records[field] = val clean_records[field] = val
...@@ -248,14 +282,14 @@ def read_records(incoming_data): ...@@ -248,14 +282,14 @@ def read_records(incoming_data):
# mysql will want None instead of '' # mysql will want None instead of ''
val = None val = None
# these 2 fields already validated # these 2 fields already validated and useful separately
else: elif field == 'doors_uid':
clean_records[field] = incoming_data[field] duuid = incoming_data[field]
elif field == 'last_modified_date':
rdate = incoming_data[field]
# debug cleaned data keys
# print(clean_records)
return clean_records return (duuid, rdate, clean_records)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment