def newacct(): try: emaddr = dbacc.reqarg("email", "AppUser.email", required=True) emaddr = normalize_email(emaddr) verify_new_email_valid(emaddr) pwd = dbacc.reqarg("password", "string", required=True) cretime = dbacc.nowISO() appuser = { "dsType": "AppUser", "created": cretime, "email": "placeholder", "phash": "whatever", "accessed": cretime + ";1", "completed": "[]", "started": "[]", "built": "[]" } update_email_and_password(appuser, emaddr, pwd) update_account_fields(appuser) appuser = dbacc.write_entity(appuser) dbacc.entcache.cache_put(appuser) # will need this again shortly token = token_for_user(appuser) except ValueError as e: return serve_value_error(e) return respJSON([appuser, token], audience="private")
def fetchtl(): """ Return the requested timeline and note the fetch. """ try: tlid = dbacc.reqarg("tlid", "dbid") if tlid: tl = dbacc.cfbk("Timeline", "dsId", str(tlid), required=True) else: slug = dbacc.reqarg("slug", "string") if not slug: slug = "default" slug = slug.lower() # in case someone camelcased the url. tl = dbacc.cfbk("Timeline", "slug", slug, required=True) tls = contained_timelines(tl) # Note the timeline was fetched for daily stats tracking det = { "referer": flask.request.headers.get("Referer", ""), "useragent": flask.request.headers.get("User-Agent", ""), "tlid": tl["dsId"], "tlname": tl["name"], "uid": dbacc.reqarg("uid", "dbid") } dcd = { "dsType": "DayCount", "tstamp": dbacc.timestamp(), "rtype": "tlfetch", "detail": json.dumps(det) } dbacc.write_entity(dcd) except ValueError as e: return util.serve_value_error(e) return util.respJSON(tls)
def authenticate(): emaddr = dbacc.reqarg("an", "AppUser.email") if not emaddr: emaddr = dbacc.reqarg("email", "AppUser.email") if not emaddr: raise ValueError("'an' or 'email' parameter required") emaddr = normalize_email(emaddr) appuser = dbacc.cfbk("AppUser", "email", emaddr) if not appuser: raise ValueError(emaddr + " not found") dbacc.entcache.cache_put(appuser) # will likely reference again soon reqtok = dbacc.reqarg("at", "string") if not reqtok: password = dbacc.reqarg("password", "string") if not password: raise ValueError("Access token or password required") phash = make_password_hash(emaddr, password, appuser["created"]) if phash == appuser["phash"]: # authenticated, rebuild token reqtok = token_for_user(appuser) else: # failing now due to lack of token, log for analysis if needed logging.info(appuser["email"] + " password hash did not match") logging.info(" AppUser[\"phash\"]: " + appuser["phash"]) logging.info(" Server phash: " + phash) srvtok = token_for_user(appuser) if reqtok != srvtok: logging.info(appuser["email"] + " authenticated token did not match") logging.info(" reqtok: " + reqtok) logging.info(" srvtok: " + srvtok) raise ValueError("Wrong password") return appuser, srvtok
def set_fields_from_reqargs(fields, obj): for fld in fields: val = dbacc.reqarg(fld, "string") if not val: val = dbacc.reqarg(fld + "in", "string") if val: if val.lower() == "noval": # remove any existing value val = "" obj[fld] = val return obj
def url_for_mail_message(): returl = dbacc.reqarg("returl", "string") if not returl: returl = site_home() + "/timeline/default" else: returl = urllib.parse.unquote(returl) return returl
def upldpic(): """ Form submit and monitoring for uploading a point pic. """ # flask.request.method always returns "GET", so check for file input. picfile = flask.request.files.get("picfilein") if not picfile: logging.info("upldpic ready for upload") return util.respond("Ready", mimetype="text/plain") try: appuser, _ = util.authenticate() ptid = dbacc.reqarg("ptid", "dbid", required=True) pt = dbacc.cfbk("Point", "dsId", ptid, required=True) logging.info(appuser["email"] + " upldpic Point " + str(ptid)) if not appuser["dsId"] in util.csv_to_list(pt["editors"]): raise ValueError("Not authorized to edit this point") img = Image.open(picfile) img = ImageOps.exif_transpose(img) # correct vertical orientation sizemaxdims = 400, 400 # max allowed width/height for thumbnail resize img.thumbnail(sizemaxdims) # modify, preserving aspect ratio bbuf = io.BytesIO() # file-like object for save img.save(bbuf, format="PNG") pt["pic"] = base64.b64encode(bbuf.getvalue()) pt = dbacc.write_entity(pt, pt["modified"]) except ValueError as e: logging.info("upldpic Point " + str(ptid) + ": " + str(e)) return util.serve_value_error(e) return util.respond("Done: " + pt["modified"], mimetype="text/plain")
def obimg(): """ Return the associated image for the give object, or a blank 4x4. """ # The client might make a call to get a pic for an object which might # not have one. Better to return a blank than an error in that case. imgdat = B64ENCTRANSPARENT4X4PNG try: dsType = dbacc.reqarg("dt", "string", required=True) dsId = dbacc.reqarg("di", "string", required=True) inst = dbacc.cfbk(dsType, "dsId", dsId) if inst: picfldmap = {"Point": "pic"} imgdat = inst[picfldmap[dsType]] imgdat = base64.b64decode(imgdat) except ValueError as e: return util.serve_value_error(e) return util.respond(imgdat, mimetype="image/png")
def fetchobj(): """ General purpose object retrieval, public info only. """ oj = "" try: dsType = dbacc.reqarg("dt", "string", required=True) keyfld = dbacc.reqarg("ak", "string") # alternate key if keyfld: fldval = dbacc.reqarg("kv", "string", required=True) else: keyfld = "dsId" fldval = dbacc.reqarg("di", "string", required=True) inst = dbacc.cfbk(dsType, keyfld, fldval) if not inst: raise ValueError(dsType + " " + keyfld + ": " + fldval + " not found") oj = util.safe_JSON(inst) except ValueError as e: return util.serve_value_error(e) return util.respJSON("[" + oj + "]")
def findcomps(): """ Return completions from other people for the given timeline. """ try: appuser, _ = util.authenticate() tlid = dbacc.reqarg("tlid", "dbid", required=True) where = ("WHERE tlid = " + tlid + " AND userid != " + appuser["dsId"] + " ORDER BY modified DESC LIMIT 50") tlcs = dbacc.query_entity("TLComp", where) except ValueError as e: return util.serve_value_error(e) return util.respJSON(tlcs)
def supphelp(): accurl = "Nope." try: administrator_auth() emaddr = dbacc.reqarg("email", "AppUser.email", required=True) appuser = dbacc.cfbk("AppUser", "email", emaddr) accurl = (site_home() + "/timeline/default?an=" + urllib.parse.quote(appuser["email"]) + "&at=" + token_for_user(appuser)) except ValueError as e: return serve_value_error(e) return accurl
def notefs(): """ Note first save of Timeline progress. """ # normally called to make note of an anonymous user having reached the # first save point in a timeline. Shows someone interacted with the # timeline even if they don't create an account. try: det = { "useragent": flask.request.headers.get("User-Agent", ""), "tlid": dbacc.reqarg("tlid", "dbid"), "tlname": dbacc.reqarg("tlname", "string"), "uid": dbacc.reqarg("uid", "dbid") } dcd = { "dsType": "DayCount", "tstamp": dbacc.timestamp(), "rtype": "guestsave", "detail": json.dumps(det) } dbacc.write_entity(dcd) except ValueError as e: return util.serve_value_error(e) return util.respJSON("[]")
def updacc(): try: appuser, token = authenticate() chg = update_email_and_password( appuser, dbacc.reqarg("updemail", "AppUser.email"), dbacc.reqarg("updpassword", "string")) if chg != "nochange": logging.info("Changing " + chg + " for " + appuser["email"]) update_account_fields(appuser) update_accessed_count(appuser) actcode = dbacc.reqarg("actcode", "string") if actcode: logging.info(appuser["email"] + " actcode: " + actcode) if actcode == appuser["actcode"]: appuser["status"] = "Active" else: logging.info("actcode did not match: " + appuser["actcode"]) appuser = dbacc.write_entity(appuser, appuser["modified"]) dbacc.entcache.cache_put(appuser) # ensure cache has latest token = token_for_user(appuser) # return possibly updated token except ValueError as e: return serve_value_error(e) return respJSON([appuser, token], audience="private")
def mailpwr(): try: subj = "PastKey.org account password reset link" emaddr = dbacc.reqarg("email", "AppUser.email", required=True) returl = url_for_mail_message() body = "You asked to reset your PastKey account password.\n\n" user = dbacc.cfbk("AppUser", "email", emaddr) if user: logging.info("mailpwr sending access link to " + emaddr) body += "Use this link to access the settings for your account: " body += (returl + "?an=" + urllib.parse.quote(user["email"]) + "&at=" + token_for_user(user) + "\n\n") else: logging.info("mailpwr no account found for " + emaddr) body += "You do not have an account for " + emaddr + ". " body += "Either you have not signed up yet, or you used " body += "a different email address. To create an account " body += "visit " + returl + "\n\n" send_mail(emaddr, subj, body) except ValueError as e: return serve_value_error(e) return respJSON("[]")