def test_attach_file_from_form(self): data = { "animalname": "Testio", "estimatedage": "1", "animaltype": "1", "entryreason": "1", "species": "1" } post = utils.PostedData(data, "en") nid, code = animal.insert_animal_from_form(base.get_dbo(), post, "test") f = open(base.PATH + "../src/media/reports/nopic.jpg", "rb") data = f.read() f.close() post = utils.PostedData({ "base64image": "data:" + base64.b64encode(data) }, "en") media.attach_file_from_form(base.get_dbo(), "test", media.ANIMAL, nid, post) animal.delete_animal(base.get_dbo(), "test", nid)
def test_attach_file_from_form(self): data = { "animalname": "Testio", "estimatedage": "1", "animaltype": "1", "entryreason": "1", "species": "1" } post = utils.PostedData(data, "en") nid, code = animal.insert_animal_from_form(base.get_dbo(), post, "test") f = open(base.PATH + "../src/media/reports/nopic.jpg", "rb") data = f.read() f.close() post = utils.PostedData( { "filename": "image.jpg", "filetype": "image/jpeg", "filedata": "data:image/jpeg;base64," + base64.b64encode(data) }, "en") media.attach_file_from_form(base.get_dbo(), "test", media.ANIMAL, nid, post) animal.delete_animal(base.get_dbo(), "test", nid)
def handler(post, path, remoteip, referer, querystring): """ Handles the various service method types. post: The GET/POST parameters path: The current system path/code.PATH remoteip: The IP of the caller referer: The referer HTTP header querystring: The complete querystring return value is a tuple containing MIME type, max-age, content """ # Get service parameters account = post["account"] username = post["username"] password = post["password"] method = post["method"] animalid = post.integer("animalid") formid = post.integer("formid") seq = post.integer("seq") title = post["title"] strip_personal = post.integer("sensitive") == 0 cache_key = querystring.replace(" ", "") # Do we have a cached response for these parameters? cached_response = get_cached_response(cache_key) if cached_response is not None: al.debug("cache hit for %s" % (cache_key), "service.handler") return cached_response # Are we dealing with multiple databases, but no account was specified? if account == "" and MULTIPLE_DATABASES: return ("text/plain", 0, 0, "ERROR: No database/alias specified") dbo = db.get_database(account) if dbo.database in ("FAIL", "DISABLED", "WRONGSERVER"): al.error( "auth failed - invalid smaccount %s from %s (%s)" % (account, remoteip, dbo.database), "service.handler", dbo) return ("text/plain", 0, 0, "ERROR: Invalid database (%s)" % dbo.database) # If the database has disabled the service API, stop now if not configuration.service_enabled(dbo): al.error("Service API is disabled (%s)" % method, "service.handler", dbo) return ("text/plain", 0, 0, "ERROR: Service API is disabled") # Do any database updates need doing in this db? dbo.installpath = path if dbupdate.check_for_updates(dbo): dbupdate.perform_updates(dbo) # Does the method require us to authenticate? If so, do it. user = None securitymap = "" if method in AUTH_METHODS: # If the database has authenticated service methods disabled, stop now if not configuration.service_auth_enabled(dbo): al.error("Service API for auth methods is disabled (%s)" % method, "service.handler", dbo) return ("text/plain", 0, 0, "ERROR: Service API for authenticated methods is disabled") user = users.authenticate(dbo, username, password) if user is None: al.error( "auth failed - %s/%s is not a valid username/password from %s" % (username, password, remoteip), "service.handler", dbo) return ("text/plain", 0, 0, "ERROR: Invalid username and password") securitymap = users.get_security_map(dbo, user["USERNAME"]) # Get the preferred locale and timezone for the site l = configuration.locale(dbo) dbo.locale = l dbo.timezone = configuration.timezone(dbo) al.info("call %s->%s [%s %s]" % (username, method, str(animalid), title), "service.handler", dbo) if method == "animal_image": hotlink_protect("animal_image", referer) if utils.cint(animalid) == 0: al.error( "animal_image failed, %s is not an animalid" % str(animalid), "service.handler", dbo) return ("text/plain", 0, 0, "ERROR: Invalid animalid") else: mediadate, data = media.get_image_file_data( dbo, "animal", utils.cint(animalid), seq) if data == "NOPIC": mediadate, data = media.get_image_file_data(dbo, "nopic", 0) return set_cached_response(cache_key, "image/jpeg", 86400, 3600, data) elif method == "animal_thumbnail": if utils.cint(animalid) == 0: al.error( "animal_thumbnail failed, %s is not an animalid" % str(animalid), "service.handler", dbo) return ("text/plain", 0, 0, "ERROR: Invalid animalid") else: mediadate, data = media.get_image_file_data( dbo, "animalthumb", utils.cint(animalid), seq) if data == "NOPIC": mediadate, data = media.get_image_file_data(dbo, "nopic", 0) return set_cached_response(cache_key, "image/jpeg", 86400, 86400, data) elif method == "animal_view": if utils.cint(animalid) == 0: al.error( "animal_view failed, %s is not an animalid" % str(animalid), "service.handler", dbo) return ("text/plain", 0, 0, "ERROR: Invalid animalid") else: return set_cached_response( cache_key, "text/html", 86400, 120, publishers.html.get_animal_view(dbo, utils.cint(animalid))) elif method == "animal_view_adoptable_js": return set_cached_response( cache_key, "application/javascript", 10800, 600, publishers.html.get_animal_view_adoptable_js(dbo)) elif method == "animal_view_adoptable_html": return set_cached_response( cache_key, "text/html", 86400, 120, publishers.html.get_animal_view_adoptable_html(dbo)) elif method == "dbfs_image": hotlink_protect("dbfs_image", referer) return set_cached_response( cache_key, "image/jpeg", 86400, 86400, utils.iif(title.startswith("/"), dbfs.get_string_filepath(dbo, title), dbfs.get_string(dbo, title))) elif method == "extra_image": hotlink_protect("extra_image", referer) return set_cached_response(cache_key, "image/jpeg", 86400, 86400, dbfs.get_string(dbo, title, "/reports")) elif method == "json_adoptable_animal": if utils.cint(animalid) == 0: al.error( "json_adoptable_animal failed, %s is not an animalid" % str(animalid), "service.handler", dbo) return ("text/plain", 0, 0, "ERROR: Invalid animalid") else: users.check_permission_map(l, user["SUPERUSER"], securitymap, users.VIEW_ANIMAL) rs = publishers.base.get_animal_data( dbo, None, utils.cint(animalid), include_additional_fields=True) return set_cached_response(cache_key, "application/json", 3600, 3600, utils.json(rs)) elif method == "html_adoptable_animals": return set_cached_response(cache_key, "text/html", 10800, 1800, \ publishers.html.get_adoptable_animals(dbo, style=post["template"], \ speciesid=post.integer("speciesid"), animaltypeid=post.integer("animaltypeid"), locationid=post.integer("locationid"))) elif method == "html_adopted_animals": return set_cached_response(cache_key, "text/html", 10800, 1800, \ publishers.html.get_adopted_animals(dbo, daysadopted=post.integer("days"), style=post["template"], \ speciesid=post.integer("speciesid"), animaltypeid=post.integer("animaltypeid"))) elif method == "html_deceased_animals": return set_cached_response(cache_key, "text/html", 10800, 1800, \ publishers.html.get_deceased_animals(dbo, daysdeceased=post.integer("days"), style=post["template"], \ speciesid=post.integer("speciesid"), animaltypeid=post.integer("animaltypeid"))) elif method == "html_held_animals": return set_cached_response(cache_key, "text/html", 10800, 1800, \ publishers.html.get_held_animals(dbo, style=post["template"], \ speciesid=post.integer("speciesid"), animaltypeid=post.integer("animaltypeid"))) elif method == "json_adoptable_animals": users.check_permission_map(l, user["SUPERUSER"], securitymap, users.VIEW_ANIMAL) rs = publishers.base.get_animal_data(dbo, None, include_additional_fields=True) if strip_personal: rs = strip_personal_data(rs) return set_cached_response(cache_key, "application/json", 3600, 3600, utils.json(rs)) elif method == "jsonp_adoptable_animals": users.check_permission_map(l, user["SUPERUSER"], securitymap, users.VIEW_ANIMAL) rs = publishers.base.get_animal_data(dbo, None, include_additional_fields=True) if strip_personal: rs = strip_personal_data(rs) return ("application/javascript", 0, 0, "%s(%s);" % (post["callback"], utils.json(rs))) elif method == "xml_adoptable_animal": if utils.cint(animalid) == 0: al.error( "xml_adoptable_animal failed, %s is not an animalid" % str(animalid), "service.handler", dbo) return ("text/plain", 0, 0, "ERROR: Invalid animalid") else: users.check_permission_map(l, user["SUPERUSER"], securitymap, users.VIEW_ANIMAL) rs = publishers.base.get_animal_data( dbo, None, utils.cint(animalid), include_additional_fields=True) return set_cached_response(cache_key, "application/xml", 3600, 3600, html.xml(rs)) elif method == "xml_adoptable_animals": users.check_permission_map(l, user["SUPERUSER"], securitymap, users.VIEW_ANIMAL) rs = publishers.base.get_animal_data(dbo, None, include_additional_fields=True) if strip_personal: rs = strip_personal_data(rs) return set_cached_response(cache_key, "application/xml", 3600, 3600, html.xml(rs)) elif method == "json_found_animals": users.check_permission_map(l, user["SUPERUSER"], securitymap, users.VIEW_FOUND_ANIMAL) rs = lostfound.get_foundanimal_last_days(dbo) return set_cached_response(cache_key, "application/json", 3600, 3600, utils.json(rs)) elif method == "jsonp_found_animals": users.check_permission_map(l, user["SUPERUSER"], securitymap, users.VIEW_FOUND_ANIMAL) rs = lostfound.get_foundanimal_last_days(dbo) return ("application/javascript", 0, 0, "%s(%s);" % (post["callback"], utils.json(rs))) elif method == "xml_found_animals": users.check_permission_map(l, user["SUPERUSER"], securitymap, users.VIEW_FOUND_ANIMAL) rs = lostfound.get_foundanimal_last_days(dbo) return set_cached_response(cache_key, "application/json", 3600, 3600, html.xml(rs)) elif method == "json_lost_animals": users.check_permission_map(l, user["SUPERUSER"], securitymap, users.VIEW_LOST_ANIMAL) rs = lostfound.get_lostanimal_last_days(dbo) return set_cached_response(cache_key, "application/json", 3600, 3600, utils.json(rs)) elif method == "jsonp_lost_animals": users.check_permission_map(l, user["SUPERUSER"], securitymap, users.VIEW_LOST_ANIMAL) rs = lostfound.get_lostanimal_last_days(dbo) return ("application/javascript", 0, 0, "%s(%s);" % (post["callback"], utils.json(rs))) elif method == "xml_lost_animals": users.check_permission_map(l, user["SUPERUSER"], securitymap, users.VIEW_LOST_ANIMAL) rs = lostfound.get_lostanimal_last_days(dbo) return set_cached_response(cache_key, "application/json", 3600, 3600, html.xml(rs)) elif method == "json_recent_adoptions": users.check_permission_map(l, user["SUPERUSER"], securitymap, users.VIEW_ANIMAL) rs = movement.get_recent_adoptions(dbo) return set_cached_response(cache_key, "application/json", 3600, 3600, utils.json(rs)) elif method == "jsonp_recent_adoptions": users.check_permission_map(l, user["SUPERUSER"], securitymap, users.VIEW_ANIMAL) rs = movement.get_recent_adoptions(dbo) return ("application/javascript", 0, 0, "%s(%s);" % (post["callback"], utils.json(rs))) elif method == "xml_recent_adoptions": users.check_permission_map(l, user["SUPERUSER"], securitymap, users.VIEW_ANIMAL) rs = movement.get_recent_adoptions(dbo) return set_cached_response(cache_key, "application/xml", 3600, 3600, html.xml(rs)) elif method == "html_report": users.check_permission_map(l, user["SUPERUSER"], securitymap, users.VIEW_REPORT) crid = reports.get_id(dbo, title) p = reports.get_criteria_params(dbo, crid, post) rhtml = reports.execute(dbo, crid, username, p) return set_cached_response(cache_key, "text/html", 600, 600, rhtml) elif method == "csv_mail" or method == "csv_report": users.check_permission_map(l, user["SUPERUSER"], securitymap, users.VIEW_REPORT) crid = reports.get_id(dbo, title) p = reports.get_criteria_params(dbo, crid, post) rows, cols = reports.execute_query(dbo, crid, username, p) mcsv = utils.csv(l, rows, cols, True) return set_cached_response(cache_key, "text/csv", 600, 600, mcsv) elif method == "jsonp_recent_changes": users.check_permission_map(l, user["SUPERUSER"], securitymap, users.VIEW_ANIMAL) sa = animal.get_recent_changes(dbo) return ("application/javascript", 0, 0, "%s(%s);" % (post["callback"], utils.json(sa))) elif method == "json_recent_changes": users.check_permission_map(l, user["SUPERUSER"], securitymap, users.VIEW_ANIMAL) sa = animal.get_recent_changes(dbo) return set_cached_response(cache_key, "application/json", 3600, 3600, utils.json(sa)) elif method == "xml_recent_changes": users.check_permission_map(l, user["SUPERUSER"], securitymap, users.VIEW_ANIMAL) sa = animal.get_recent_changes(dbo) return set_cached_response(cache_key, "application/xml", 3600, 3600, html.xml(sa)) elif method == "jsonp_shelter_animals": users.check_permission_map(l, user["SUPERUSER"], securitymap, users.VIEW_ANIMAL) sa = animal.get_shelter_animals(dbo) if strip_personal: sa = strip_personal_data(sa) return ("application/javascript", 0, 0, "%s(%s);" % (post["callback"], utils.json(sa))) elif method == "json_shelter_animals": users.check_permission_map(l, user["SUPERUSER"], securitymap, users.VIEW_ANIMAL) sa = animal.get_shelter_animals(dbo) if strip_personal: sa = strip_personal_data(sa) return set_cached_response(cache_key, "application/json", 3600, 3600, utils.json(sa)) elif method == "xml_shelter_animals": users.check_permission_map(l, user["SUPERUSER"], securitymap, users.VIEW_ANIMAL) sa = animal.get_shelter_animals(dbo) if strip_personal: sa = strip_personal_data(sa) return set_cached_response(cache_key, "application/xml", 3600, 3600, html.xml(sa)) elif method == "rss_timeline": users.check_permission_map(l, user["SUPERUSER"], securitymap, users.VIEW_ANIMAL) return set_cached_response(cache_key, "application/rss+xml", 3600, 3600, html.timeline_rss(dbo)) elif method == "upload_animal_image": users.check_permission_map(l, user["SUPERUSER"], securitymap, users.ADD_MEDIA) media.attach_file_from_form(dbo, username, media.ANIMAL, int(animalid), post) return ("text/plain", 0, 0, "OK") elif method == "online_form_html": if formid == 0: raise utils.ASMError( "method online_form_html requires a valid formid") return set_cached_response(cache_key, "text/html; charset=utf-8", 120, 120, onlineform.get_onlineform_html(dbo, formid)) elif method == "online_form_json": if formid == 0: raise utils.ASMError( "method online_form_json requires a valid formid") return set_cached_response(cache_key, "application/json; charset=utf-8", 30, 30, onlineform.get_onlineform_json(dbo, formid)) elif method == "online_form_post": flood_protect("online_form_post", remoteip, 15) onlineform.insert_onlineformincoming_from_form(dbo, post, remoteip) redirect = post["redirect"] if redirect == "": redirect = BASE_URL + "/static/pages/form_submitted.html" return ("redirect", 0, 0, redirect) elif method == "sign_document": if formid == 0: raise utils.ASMError( "method sign_document requires a valid formid") if post["sig"] == "": return set_cached_response(cache_key, "text/html", 2, 2, sign_document_page(dbo, formid)) else: media.sign_document(dbo, "service", formid, post["sig"], post["signdate"]) media.create_log(dbo, "service", formid, "ES02", _("Document signed", l)) return ("text/plain", 0, 0, "OK") else: al.error("invalid method '%s'" % method, "service.handler", dbo) raise utils.ASMError("Invalid method '%s'" % method)
def handler(dbo, user, post): """ Handles posts from the frontend. Depending on the type we either return more HTML for the javascript to inject, or GO URL to have the controller redirect to URL """ l = dbo.locale homelink = "<a href='mobile' class='ui-btn-right' data-icon='home' data-theme='b'>%s</a>" % _( "Home", l) mode = post["posttype"] pid = post.integer("id") animalid = post.integer("animalid") if mode == "vacc": # We're vaccinating an animal a = animal.get_animal(dbo, animalid) medical.update_vaccination_today(dbo, user, pid) return jqm_page_header("", _("Vaccination Given", l), homelink) + \ jqm_p(_("Vaccination marked as given for {0} - {1}", l).format(a["ANIMALNAME"], a["SHELTERCODE"])) + \ jqm_button("mobile#vacc", _("More Vaccinations", l), "", "false") + \ jqm_page_footer() if mode == "test": # We're performing a test on an animal a = animal.get_animal(dbo, animalid) medical.update_test_today(dbo, user, pid, post.integer("resultid")) return jqm_page_header("", _("Test Performed", l), homelink) + \ jqm_p(_("Test marked as performed for {0} - {1}", l).format(a["ANIMALNAME"], a["SHELTERCODE"])) + \ jqm_button("mobile#test", _("More Tests", l), "", "false") + \ jqm_page_footer() elif mode == "med": # We're treating an animal a = animal.get_animal(dbo, animalid) medical.update_treatment_today(dbo, user, pid) return jqm_page_header("", _("Treatment Given", l), homelink) + \ jqm_p(_("Treatment marked as given for {0} - {1}", l).format(a["ANIMALNAME"], a["SHELTERCODE"])) + \ jqm_button("mobile#med", _("More Medications", l), "", "false") + \ jqm_page_footer() elif mode == "dia": # We're completing a diary task d = diary.get_diary(dbo, pid) if post["on"] == "0": diary.complete_diary_note(dbo, user, pid) return jqm_page_header("", _("Completed", l), homelink) + \ jqm_p(_("Diary note {0} marked completed", l).format(d["SUBJECT"])) + \ jqm_button("mobile#diary", _("More diary notes", l), "", "false") + \ jqm_page_footer() else: diary.rediarise_diary_note(dbo, user, pid, post.date("on")) return jqm_page_header("", _("Rediarised", l), homelink) + \ jqm_p(_("Diary note {0} rediarised for {1}", l).format(d["SUBJECT"], post["on"])) + \ jqm_button("mobile#diary", _("More diary notes", l), "", "false") + \ jqm_page_footer() elif mode == "dianew": # We're adding a diary note diary.insert_diary(dbo, user, 0, 0, post.date("diarydate"), post["diaryfor"], post["subject"], post["note"]) return "GO mobile" elif mode == "message": # We're adding a message lookups.add_message(dbo, user, post.boolean("email"), post["message"], post["forname"], post.integer("priority"), post.date("expires")) return "GO mobile" elif mode == "log": # We're adding a log to an animal a = animal.get_animal(dbo, animalid) log.add_log(dbo, user, log.ANIMAL, animalid, post.integer("logtypeid"), post["logtext"]) return "GO mobile" elif mode == "hc": # We're marking an owner homechecked person.update_pass_homecheck(dbo, user, post.integer("personid"), post["comments"]) return "GO mobile" elif mode == "vsa": # Return a list of the shelter animals h = [] alin = [] h.append(header(l)) h.append(jqm_page_header("", _("Shelter Animals", l), homelink)) an = animal.get_animal_find_simple(dbo, "", "all") for a in an: alin.append( jqm_listitem_link( "mobile_post?posttype=va&id=%d" % a["ID"], "%s - %s (%s %s %s) %s" % (a["CODE"], a["ANIMALNAME"], a["SEXNAME"], a["BREEDNAME"], a["SPECIESNAME"], a["IDENTICHIPNUMBER"]), "animal")) h.append(jqm_list("\n".join(alin), True)) h.append(jqm_page_footer()) h.append("</body></html>") return "\n".join(h) elif mode == "uai": # Upload an animal image media.attach_file_from_form(dbo, user, media.ANIMAL, animalid, post.data) return "GO mobile_post?posttype=va&id=%d&success=true" % animalid elif mode == "va": # Display a page containing the selected animal by id a = animal.get_animal(dbo, pid) af = additional.get_additional_fields(dbo, pid, "animal") return handler_viewanimal(l, a, af, homelink, post)
def handler(dbo, user, post): """ Handles posts from the frontend. Depending on the type we either return more HTML for the javascript to inject, or GO URL to have the controller redirect to URL """ l = dbo.locale homelink = "<a href='mobile' class='ui-btn-right' data-icon='home' data-theme='b'>%s</a>" % _("Home", l) mode = post["posttype"] pid = post.integer("id") animalid = post.integer("animalid") if mode == "vacc": # We're vaccinating an animal a = animal.get_animal(dbo, animalid) medical.update_vaccination_today(dbo, user, pid) return ( jqm_page_header("", _("Vaccination Given", l), homelink) + jqm_p(_("Vaccination marked as given for {0} - {1}", l).format(a["ANIMALNAME"], a["SHELTERCODE"])) + jqm_button("mobile#vacc", _("More Vaccinations", l), "", "false") + jqm_page_footer() ) if mode == "test": # We're performing a test on an animal a = animal.get_animal(dbo, animalid) medical.update_test_today(dbo, user, pid, post.integer("resultid")) return ( jqm_page_header("", _("Test Performed", l), homelink) + jqm_p(_("Test marked as performed for {0} - {1}", l).format(a["ANIMALNAME"], a["SHELTERCODE"])) + jqm_button("mobile#test", _("More Tests", l), "", "false") + jqm_page_footer() ) elif mode == "med": # We're treating an animal a = animal.get_animal(dbo, animalid) medical.update_treatment_today(dbo, user, pid) return ( jqm_page_header("", _("Treatment Given", l), homelink) + jqm_p(_("Treatment marked as given for {0} - {1}", l).format(a["ANIMALNAME"], a["SHELTERCODE"])) + jqm_button("mobile#med", _("More Medications", l), "", "false") + jqm_page_footer() ) elif mode == "dia": # We're completing a diary task d = diary.get_diary(dbo, pid) if post["on"] == "0": diary.complete_diary_note(dbo, user, pid) return ( jqm_page_header("", _("Completed", l), homelink) + jqm_p(_("Diary note {0} marked completed", l).format(d["SUBJECT"])) + jqm_button("mobile#diary", _("More diary notes", l), "", "false") + jqm_page_footer() ) else: diary.rediarise_diary_note(dbo, user, pid, post.date("on")) return ( jqm_page_header("", _("Rediarised", l), homelink) + jqm_p(_("Diary note {0} rediarised for {1}", l).format(d["SUBJECT"], post["on"])) + jqm_button("mobile#diary", _("More diary notes", l), "", "false") + jqm_page_footer() ) elif mode == "dianew": # We're adding a diary note diary.insert_diary(dbo, user, 0, 0, post.date("diarydate"), post["diaryfor"], post["subject"], post["note"]) return "GO mobile" elif mode == "message": # We're adding a message lookups.add_message( dbo, user, post.boolean("email"), post["message"], post["forname"], post.integer("priority"), post.date("expires"), ) return "GO mobile" elif mode == "log": # We're adding a log to an animal a = animal.get_animal(dbo, animalid) log.add_log(dbo, user, log.ANIMAL, animalid, post.integer("logtypeid"), post["logtext"]) return "GO mobile" elif mode == "hc": # We're marking an owner homechecked person.update_pass_homecheck(dbo, user, post.integer("personid"), post["comments"]) return "GO mobile" elif mode == "vsa": # Return a list of the shelter animals h = [] alin = [] h.append(header(l)) h.append(jqm_page_header("", _("Shelter Animals", l), homelink)) an = animal.get_animal_find_simple(dbo, "", "all") for a in an: alin.append( jqm_listitem_link( "mobile_post?posttype=va&id=%d" % a["ID"], "%s - %s (%s %s %s) %s" % ( a["CODE"], a["ANIMALNAME"], a["SEXNAME"], a["BREEDNAME"], a["SPECIESNAME"], a["IDENTICHIPNUMBER"], ), "animal", ) ) h.append(jqm_list("\n".join(alin), True)) h.append(jqm_page_footer()) h.append("</body></html>") return "\n".join(h) elif mode == "uai": # Upload an animal image media.attach_file_from_form(dbo, user, media.ANIMAL, animalid, post.data) return "GO mobile_post?posttype=va&id=%d&success=true" % animalid elif mode == "va": # Display a page containing the selected animal by id a = animal.get_animal(dbo, pid) af = additional.get_additional_fields(dbo, pid, "animal") return handler_viewanimal(l, a, af, homelink, post)
def csvimport(dbo, csvdata, encoding = "utf8", user = "", createmissinglookups = False, cleartables = False, checkduplicates = False): """ Imports the csvdata. createmissinglookups: If a lookup value is given that's not in our data, add it cleartables: Clear down the animal, owner and adoption tables before import """ # Convert line endings to standard unix lf to prevent # the Python CSV importer barfing. csvdata = csvdata.replace("\r\n", "\n") csvdata = csvdata.replace("\r", "\n") if user == "": user = "******" else: user = "******" % user reader = None if encoding == "utf8": reader = utils.UnicodeCSVReader(StringIO(csvdata)) else: reader = utils.UnicodeCSVReader(StringIO(csvdata), encoding=encoding) # Make sure we have a valid header cols = None for row in reader: cols = row break if cols is None: asynctask.set_last_error(dbo, "Your CSV file is empty") return onevalid = False hasanimal = False hasanimalname = False hasmed = False hasvacc = False hasperson = False haspersonlastname = False haspersonname = False haslicence = False haslicencenumber = False hasmovement = False hasmovementdate = False hasdonation = False hasdonationamount = False hasoriginalowner = False hasoriginalownerlastname = False for col in cols: if col in VALID_FIELDS: onevalid = True if col.startswith("ANIMAL"): hasanimal = True if col == "ANIMALNAME": hasanimalname = True if col.startswith("ORIGINALOWNER"): hasoriginalowner = True if col.startswith("VACCINATION"): hasvacc = True if col.startswith("MEDICAL"): hasmed = True if col.startswith("LICENSE"): haslicence = True if col == "LICENSENUMBER": haslicencenumber = True if col == "ORIGINALOWNERLASTNAME": hasoriginalownerlastname = True if col.startswith("PERSON"): hasperson = True if col == "PERSONLASTNAME": haspersonlastname = True if col == "PERSONNAME": haspersonname = True if col.startswith("MOVEMENT"): hasmovement = True if col == "MOVEMENTDATE": hasmovementdate = True if col.startswith("DONATION"): hasdonation = True if col == "DONATIONAMOUNT": hasdonationamount = True # Any valid fields? if not onevalid: asynctask.set_last_error(dbo, "Your CSV file did not contain any fields that ASM recognises") return # If we have any animal fields, make sure at least ANIMALNAME is supplied if hasanimal and not hasanimalname: asynctask.set_last_error(dbo, "Your CSV file has animal fields, but no ANIMALNAME column") return # If we have any person fields, make sure at least PERSONLASTNAME or PERSONNAME is supplied if hasperson and not haspersonlastname and not haspersonname: asynctask.set_last_error(dbo, "Your CSV file has person fields, but no PERSONNAME or PERSONLASTNAME column") return # If we have any original owner fields, make sure at least ORIGINALOWNERLASTNAME is supplied if hasoriginalowner and not hasoriginalownerlastname: asynctask.set_last_error(dbo, "Your CSV file has original owner fields, but no ORIGINALOWNERLASTNAME column") return # If we have any movement fields, make sure MOVEMENTDATE is supplied if hasmovement and not hasmovementdate: asynctask.set_last_error(dbo, "Your CSV file has movement fields, but no MOVEMENTDATE column") return # If we have any donation fields, we need an amount if hasdonation and not hasdonationamount: asynctask.set_last_error(dbo, "Your CSV file has donation fields, but no DONATIONAMOUNT column") return # We also need a valid person if hasdonation and not (haspersonlastname or haspersonname): asynctask.set_last_error(dbo, "Your CSV file has donation fields, but no person to apply the donation to") return # If we have any med fields, we need an animal if hasmed and not hasanimal: asynctask.set_last_error(dbo, "Your CSV file has medical fields, but no animal to apply them to") return # If we have any vacc fields, we need an animal if hasvacc and not hasanimal: asynctask.set_last_error(dbo, "Your CSV file has vaccination fields, but no animal to apply them to") return # If we have licence fields, we need a number if haslicence and not haslicencenumber: asynctask.set_last_error(dbo, "Your CSV file has license fields, but no LICENSENUMBER column") return # We also need a valid person if haslicence and not (haspersonlastname or haspersonname): asynctask.set_last_error(dbo, "Your CSV file has license fields, but no person to apply the license to") # Read the whole CSV file into a list of maps. Note, the # reader has a cursor at the second row already because # we read the header in the first row above data = [] for row in reader: currow = {} for i, col in enumerate(row): if i >= len(cols): continue # skip if we run out of cols currow[cols[i]] = col data.append(currow) al.debug("reading CSV data, found %d rows" % len(data), "csvimport.csvimport", dbo) # If we're clearing down tables first, do it now if cleartables: al.warn("Resetting the database by removing all non-lookup data", "csvimport.csvimport", dbo) dbupdate.reset_db(dbo) # Now that we've read them in, go through all the rows # and start importing. errors = [] rowno = 1 asynctask.set_progress_max(dbo, len(data)) for row in data: al.debug("import csv: row %d of %d" % (rowno, len(data)), "csvimport.csvimport", dbo) asynctask.increment_progress_value(dbo) # Should we stop? if asynctask.get_cancel(dbo): break # Do we have animal data to read? animalid = 0 if hasanimal and gks(row, "ANIMALNAME") != "": a = {} a["animalname"] = gks(row, "ANIMALNAME") a["sheltercode"] = gks(row, "ANIMALCODE") a["shortcode"] = gks(row, "ANIMALCODE") if gks(row, "ANIMALSEX") == "": a["sex"] = "2" # Default unknown if not set else: a["sex"] = gks(row, "ANIMALSEX").lower().startswith("m") and "1" or "0" a["basecolour"] = gkl(dbo, row, "ANIMALCOLOR", "basecolour", "BaseColour", createmissinglookups) if a["basecolour"] == "0": a["basecolour"] = str(configuration.default_colour(dbo)) a["species"] = gkl(dbo, row, "ANIMALSPECIES", "species", "SpeciesName", createmissinglookups) if a["species"] == "0": a["species"] = str(configuration.default_species(dbo)) a["animaltype"] = gkl(dbo, row, "ANIMALTYPE", "animaltype", "AnimalType", createmissinglookups) if a["animaltype"] == "0": a["animaltype"] = str(configuration.default_type(dbo)) a["breed1"] = gkbr(dbo, row, "ANIMALBREED1", a["species"], createmissinglookups) if a["breed1"] == "0": a["breed1"] = str(configuration.default_breed(dbo)) a["breed2"] = gkbr(dbo, row, "ANIMALBREED2", a["species"], createmissinglookups) if a["breed2"] != "0" and a["breed2"] != a["breed1"]: a["crossbreed"] = "on" a["size"] = gkl(dbo, row, "ANIMALSIZE", "lksize", "Size", False) if gks(row, "ANIMALSIZE") == "": a["size"] = str(configuration.default_size(dbo)) a["internallocation"] = gkl(dbo, row, "ANIMALLOCATION", "internallocation", "LocationName", createmissinglookups) if a["internallocation"] == "0": a["internallocation"] = str(configuration.default_location(dbo)) a["unit"] = gks(row, "ANIMALUNIT") a["comments"] = gks(row, "ANIMALCOMMENTS") a["markings"] = gks(row, "ANIMALMARKINGS") a["hiddenanimaldetails"] = gks(row, "ANIMALHIDDENDETAILS") a["healthproblems"] = gks(row, "ANIMALHEALTHPROBLEMS") a["notforadoption"] = gkbi(row, "ANIMALNOTFORADOPTION") a["nonshelter"] = gkbi(row, "ANIMALNONSHELTER") a["housetrained"] = gkynu(row, "ANIMALHOUSETRAINED") a["goodwithcats"] = gkynu(row, "ANIMALGOODWITHCATS") a["goodwithdogs"] = gkynu(row, "ANIMALGOODWITHDOGS") a["goodwithkids"] = gkynu(row, "ANIMALGOODWITHKIDS") a["reasonforentry"] = gks(row, "ANIMALREASONFORENTRY") a["estimatedage"] = gks(row, "ANIMALAGE") a["dateofbirth"] = gkd(dbo, row, "ANIMALDOB", True) if gks(row, "ANIMALDOB") == "" and a["estimatedage"] != "": a["dateofbirth"] = "" # if we had an age and dob was blank, prefer the age a["datebroughtin"] = gkd(dbo, row, "ANIMALENTRYDATE", True) a["deceaseddate"] = gkd(dbo, row, "ANIMALDECEASEDDATE") a["neutered"] = gkbc(row, "ANIMALNEUTERED") a["neutereddate"] = gkd(dbo, row, "ANIMALNEUTEREDDATE") if a["neutereddate"] != "": a["neutered"] = "on" a["microchipnumber"] = gks(row, "ANIMALMICROCHIP") if a["microchipnumber"] != "": a["microchipped"] = "on" a["microchipdate"] = gkd(dbo, row, "ANIMALMICROCHIPDATE") # image data if any was supplied imagedata = gks(row, "ANIMALIMAGE") if imagedata.startswith("http"): # It's a URL, get the image from the remote server r = utils.get_image_url(imagedata, timeout=5000) if r["status"] == 200: al.debug("retrieved image from %s (%s bytes)" % (imagedata, len(r["response"])), "csvimport.csvimport", dbo) imagedata = "data:image/jpeg;base64,%s" % base64.b64encode(r["response"]) else: row_error(errors, "animal", rowno, row, "error reading image from '%s': %s" % (imagedata, r), dbo, sys.exc_info()) continue elif imagedata.startswith("data:image"): # It's a base64 encoded data URI - do nothing as attach_file requires it pass else: # We don't know what it is, don't try and do anything with it imagedata = "" # If an original owner is specified, create a person record # for them and attach it to the animal as original owner if gks(row, "ORIGINALOWNERLASTNAME") != "": p = {} p["title"] = gks(row, "ORIGINALOWNERTITLE") p["initials"] = gks(row, "ORIGINALOWNERINITIALS") p["forenames"] = gks(row, "ORIGINALOWNERFIRSTNAME") p["surname"] = gks(row, "ORIGINALOWNERLASTNAME") p["address"] = gks(row, "ORIGINALOWNERADDRESS") p["town"] = gks(row, "ORIGINALOWNERCITY") p["county"] = gks(row, "ORIGINALOWNERSTATE") p["postcode"] = gks(row, "ORIGINALOWNERZIPCODE") p["jurisdiction"] = gkl(dbo, row, "ORIGINALOWNERJURISDICTION", "jurisdiction", "JurisdictionName", createmissinglookups) p["hometelephone"] = gks(row, "ORIGINALOWNERHOMEPHONE") p["worktelephone"] = gks(row, "ORIGINALOWNERWORKPHONE") p["mobiletelephone"] = gks(row, "ORIGINALOWNERCELLPHONE") p["emailaddress"] = gks(row, "ORIGINALOWNEREMAIL") try: if checkduplicates: dups = person.get_person_similar(dbo, p["emailaddress"], p["surname"], p["forenames"], p["address"]) if len(dups) > 0: a["originalowner"] = str(dups[0]["ID"]) if "originalowner" not in a: ooid = person.insert_person_from_form(dbo, utils.PostedData(p, dbo.locale), user, geocode=False) a["originalowner"] = str(ooid) # Identify an ORIGINALOWNERADDITIONAL additional fields and create them create_additional_fields(dbo, row, errors, rowno, "ORIGINALOWNERADDITIONAL", "person", ooid) except Exception as e: row_error(errors, "originalowner", rowno, row, e, dbo, sys.exc_info()) try: if checkduplicates: dup = animal.get_animal_sheltercode(dbo, a["sheltercode"]) if dup is not None: animalid = dup["ID"] if animalid == 0: animalid, newcode = animal.insert_animal_from_form(dbo, utils.PostedData(a, dbo.locale), user) # Identify any ANIMALADDITIONAL additional fields and create them create_additional_fields(dbo, row, errors, rowno, "ANIMALADDITIONAL", "animal", animalid) # If we have some image data, add it to the animal if len(imagedata) > 0: imagepost = utils.PostedData({ "filename": "image.jpg", "filetype": "image/jpeg", "filedata": imagedata }, dbo.locale) media.attach_file_from_form(dbo, user, media.ANIMAL, animalid, imagepost) except Exception as e: row_error(errors, "animal", rowno, row, e, dbo, sys.exc_info()) # Person data? personid = 0 if hasperson and (gks(row, "PERSONLASTNAME") != "" or gks(row, "PERSONNAME") != ""): p = {} p["ownertype"] = gks(row, "PERSONCLASS") if p["ownertype"] != "1" and p["ownertype"] != "2": p["ownertype"] = "1" p["title"] = gks(row, "PERSONTITLE") p["initials"] = gks(row, "PERSONINITIALS") p["forenames"] = gks(row, "PERSONFIRSTNAME") p["surname"] = gks(row, "PERSONLASTNAME") # If we have a person name, all upto the last space is first names, # everything after the last name if gks(row, "PERSONNAME") != "": pname = gks(row, "PERSONNAME") if pname.find(" ") != -1: p["forenames"] = pname[0:pname.rfind(" ")] p["surname"] = pname[pname.rfind(" ")+1:] else: p["surname"] = pname p["address"] = gks(row, "PERSONADDRESS") p["town"] = gks(row, "PERSONCITY") p["county"] = gks(row, "PERSONSTATE") p["postcode"] = gks(row, "PERSONZIPCODE") p["jurisdiction"] = gkl(dbo, row, "PERSONJURISDICTION", "jurisdiction", "JurisdictionName", createmissinglookups) p["hometelephone"] = gks(row, "PERSONHOMEPHONE") p["worktelephone"] = gks(row, "PERSONWORKPHONE") p["mobiletelephone"] = gks(row, "PERSONCELLPHONE") p["emailaddress"] = gks(row, "PERSONEMAIL") p["gdprcontactoptin"] = gks(row, "PERSONGDPRCONTACTOPTIN") flags = gks(row, "PERSONFLAGS") if gkb(row, "PERSONFOSTERER"): flags += ",fosterer" if gkb(row, "PERSONMEMBER"): flags += ",member" if gkb(row, "PERSONDONOR"): flags += ",donor" p["flags"] = flags p["comments"] = gks(row, "PERSONCOMMENTS") p["membershipnumber"] = gks(row, "PERSONMEMBERSHIPNUMBER") p["membershipexpires"] = gkd(dbo, row, "PERSONMEMBERSHIPEXPIRY") p["matchactive"] = gkbi(row, "PERSONMATCHACTIVE") if p["matchactive"] == "1": if "PERSONMATCHADDED" in cols: p["matchadded"] = gkd(dbo, row, "PERSONMATCHADDED") if "PERSONMATCHEXPIRES" in cols: p["matchexpires"] = gkd(dbo, row, "PERSONMATCHEXPIRES") if "PERSONMATCHSEX" in cols: p["matchsex"] = gks(row, "PERSONMATCHSEX").lower().startswith("m") and "1" or "0" if "PERSONMATCHSIZE" in cols: p["matchsize"] = gkl(dbo, row, "PERSONMATCHSIZE", "lksize", "Size", False) if "PERSONMATCHCOLOR" in cols: p["matchcolour"] = gkl(dbo, row, "PERSONMATCHCOLOR", "basecolour", "BaseColour", createmissinglookups) if "PERSONMATCHAGEFROM" in cols: p["matchagefrom"] = gks(row, "PERSONMATCHAGEFROM") if "PERSONMATCHAGETO" in cols: p["matchageto"] = gks(row, "PERSONMATCHAGETO") if "PERSONMATCHTYPE" in cols: p["matchanimaltype"] = gkl(dbo, row, "PERSONMATCHTYPE", "animaltype", "AnimalType", createmissinglookups) if "PERSONMATCHSPECIES" in cols: p["matchspecies"] = gkl(dbo, row, "PERSONMATCHSPECIES", "species", "SpeciesName", createmissinglookups) if "PERSONMATCHBREED1" in cols: p["matchbreed"] = gkbr(dbo, row, "PERSONMATCHBREED1", p["matchspecies"], createmissinglookups) if "PERSONMATCHBREED2" in cols: p["matchbreed2"] = gkbr(dbo, row, "PERSONMATCHBREED2", p["matchspecies"], createmissinglookups) if "PERSONMATCHGOODWITHCATS" in cols: p["matchgoodwithcats"] = gkynu(row, "PERSONMATCHGOODWITHCATS") if "PERSONMATCHGOODWITHDOGS" in cols: p["matchgoodwithdogs"] = gkynu(row, "PERSONMATCHGOODWITHDOGS") if "PERSONMATCHGOODWITHCHILDREN" in cols: p["matchgoodwithchildren"] = gkynu(row, "PERSONMATCHGOODWITHCHILDREN") if "PERSONMATCHHOUSETRAINED" in cols: p["matchhousetrained"] = gkynu(row, "PERSONMATCHHOUSETRAINED") if "PERSONMATCHCOMMENTSCONTAIN" in cols: p["matchcommentscontain"] = gks(row, "PERSONMATCHCOMMENTSCONTAIN") try: if checkduplicates: dups = person.get_person_similar(dbo, p["emailaddress"], p["surname"], p["forenames"], p["address"]) if len(dups) > 0: personid = dups[0].ID # Merge flags and any extra details person.merge_flags(dbo, user, personid, flags) person.merge_gdpr_flags(dbo, user, personid, p["gdprcontactoptin"]) # If we deduplicated on the email address, and address details are # present, assume that they are newer than the ones we had and update them # (we do this by setting force=True parameter to merge_person_details, # otherwise we do a regular merge which only fills in any blanks) person.merge_person_details(dbo, user, personid, p, force=dups[0].EMAILADDRESS == p["emailaddress"]) if personid == 0: personid = person.insert_person_from_form(dbo, utils.PostedData(p, dbo.locale), user, geocode=False) # Identify any PERSONADDITIONAL additional fields and create them create_additional_fields(dbo, row, errors, rowno, "PERSONADDITIONAL", "person", personid) except Exception as e: row_error(errors, "person", rowno, row, e, dbo, sys.exc_info()) # Movement to tie animal/person together? movementid = 0 if hasmovement and personid != 0 and animalid != 0 and gks(row, "MOVEMENTDATE") != "": m = {} m["person"] = str(personid) m["animal"] = str(animalid) movetype = gks(row, "MOVEMENTTYPE") if movetype == "": movetype = "1" # Default to adoption if not supplied m["type"] = str(movetype) m["movementdate"] = gkd(dbo, row, "MOVEMENTDATE", True) m["returndate"] = gkd(dbo, row, "MOVEMENTRETURNDATE") m["comments"] = gks(row, "MOVEMENTCOMMENTS") m["returncategory"] = str(configuration.default_entry_reason(dbo)) try: movementid = movement.insert_movement_from_form(dbo, user, utils.PostedData(m, dbo.locale)) except Exception as e: row_error(errors, "movement", rowno, row, e, dbo, sys.exc_info()) # Donation? if hasdonation and personid != 0 and gkc(row, "DONATIONAMOUNT") != 0: d = {} d["person"] = str(personid) d["animal"] = str(animalid) d["movement"] = str(movementid) d["amount"] = str(gkc(row, "DONATIONAMOUNT")) d["fee"] = str(gkc(row, "DONATIONFEE")) d["comments"] = gks(row, "DONATIONCOMMENTS") d["received"] = gkd(dbo, row, "DONATIONDATE", True) d["chequenumber"] = gks(row, "DONATIONCHECKNUMBER") d["type"] = gkl(dbo, row, "DONATIONTYPE", "donationtype", "DonationName", createmissinglookups) if d["type"] == "0": d["type"] = str(configuration.default_donation_type(dbo)) d["payment"] = gkl(dbo, row, "DONATIONPAYMENT", "donationpayment", "PaymentName", createmissinglookups) if d["payment"] == "0": d["payment"] = "1" try: financial.insert_donation_from_form(dbo, user, utils.PostedData(d, dbo.locale)) except Exception as e: row_error(errors, "payment", rowno, row, e, dbo, sys.exc_info()) if movementid != 0: movement.update_movement_donation(dbo, movementid) # Vaccination? if hasvacc and animalid != 0 and gks(row, "VACCINATIONDUEDATE") != "": v = {} v["animal"] = str(animalid) v["type"] = gkl(dbo, row, "VACCINATIONTYPE", "vaccinationtype", "VaccinationType", createmissinglookups) if v["type"] == "0": v["type"] = str(configuration.default_vaccination_type(dbo)) v["required"] = gkd(dbo, row, "VACCINATIONDUEDATE", True) v["given"] = gkd(dbo, row, "VACCINATIONGIVENDATE") v["expires"] = gkd(dbo, row, "VACCINATIONEXPIRESDATE") v["batchnumber"] = gks(row, "VACCINATIONBATCHNUMBER") v["manufacturer"] = gks(row, "VACCINATIONMANUFACTURER") v["comments"] = gks(row, "VACCINATIONCOMMENTS") try: medical.insert_vaccination_from_form(dbo, user, utils.PostedData(v, dbo.locale)) except Exception as e: row_error(errors, "vaccination", rowno, row, e, dbo, sys.exc_info()) # Medical? if hasmed and animalid != 0 and gks(row, "MEDICALGIVENDATE") != "" and gks(row, "MEDICALNAME") != "": m = {} m["animal"] = str(animalid) m["treatmentname"] = gks(row, "MEDICALNAME") m["dosage"] = gks(row, "MEDICALDOSAGE") m["startdate"] = gkd(dbo, row, "MEDICALGIVENDATE") m["comments"] = gks(row, "MEDICALCOMMENTS") m["singlemulti"] = "0" # single treatment m["status"] = "2" # completed try: medical.insert_regimen_from_form(dbo, user, utils.PostedData(m, dbo.locale)) except Exception as e: row_error(errors, "medical", rowno, row, e, dbo, sys.exc_info()) # License? if haslicence and personid != 0 and gks(row, "LICENSENUMBER") != "": l = {} l["person"] = str(personid) l["animal"] = str(animalid) l["type"] = gkl(dbo, row, "LICENSETYPE", "licencetype", "LicenceTypeName", createmissinglookups) if l["type"] == "0": l["type"] = 1 l["number"] = gks(row, "LICENSENUMBER") l["fee"] = str(gkc(row, "LICENSEFEE")) l["issuedate"] = gkd(dbo, row, "LICENSEISSUEDATE") l["expirydate"] = gkd(dbo, row, "LICENSEEXPIRESDATE") l["comments"] = gks(row, "LICENSECOMMENTS") try: financial.insert_licence_from_form(dbo, user, utils.PostedData(l, dbo.locale)) except Exception as e: row_error(errors, "license", rowno, row, e, dbo, sys.exc_info()) rowno += 1 h = [ "<p>%d success, %d errors</p><table>" % (len(data) - len(errors), len(errors)) ] for rowno, row, err in errors: h.append("<tr><td>%s</td><td>%s</td><td>%s</td></tr>" % (rowno, row, err)) h.append("</table>") return "".join(h)
def handler(data, remoteip, referer): """ Handles the various service method types. data: The GET/POST parameters return value is a tuple containing MIME type, max-age, content """ # Database info dbo = db.DatabaseInfo() # Get service parameters account = utils.df_ks(data, "account") username = utils.df_ks(data, "username") password = utils.df_ks(data, "password") method = utils.df_ks(data, "method") animalid = utils.df_ki(data, "animalid") formid = utils.df_ki(data, "formid") title = utils.df_ks(data, "title") cache_key = "a" + account + "u" + username + "p" + password + "m" + method + "a" + str( animalid) + "f" + str(formid) + "t" + title # cache keys aren't allowed spaces cache_key = cache_key.replace(" ", "") # Do we have a cached response for these parameters? cached_response = get_cached_response(cache_key) if cached_response is not None: al.debug( "cache hit for %s/%s/%s/%s" % (account, method, animalid, title), "service.handler") return cached_response # Are we dealing with multiple databases, but no account was specified? if account == "" and MULTIPLE_DATABASES: return ("text/plan", 0, "ERROR: No database/alias specified") # Are we dealing with multiple databases and an account was specified? if account != "": if MULTIPLE_DATABASES: if MULTIPLE_DATABASES_TYPE == "smcom": # Is this sheltermanager.com? If so, we need to get the # database connection info (dbo) before we can login. dbo = smcom.get_database_info(account) else: # Look up the database info from our map dbo = db.get_multiple_database_info(account) if dbo.database == "FAIL" or dbo.database == "DISABLED": al.error( "auth failed - invalid smaccount %s from %s" % (account, remoteip), "service.handler", dbo) return ("text/plain", 0, "ERROR: Invalid database") # Does the method require us to authenticate? If so, do it. user = None if method in AUTH_METHODS: user = users.authenticate(dbo, username, password) if user is None: al.error( "auth failed - %s/%s is not a valid username/password from %s" % (username, password, remoteip), "service.handler", dbo) return ("text/plain", 0, "ERROR: Invalid username and password") # Get the preferred locale for the site dbo.locale = configuration.locale(dbo) al.info("call %s->%s [%s %s]" % (username, method, str(animalid), title), "service.handler", dbo) if method == "animal_image": # If we have a hotlinking restriction, enforce it if referer != "" and IMAGE_HOTLINKING_ONLY_FROM_DOMAIN != "" and referer.find( IMAGE_HOTLINKING_ONLY_FROM_DOMAIN) == -1: raise utils.ASMPermissionError("Image hotlinking is forbidden.") if animalid == "" or utils.cint(animalid) == 0: al.error( "animal_image failed, %s is not an animalid" % str(animalid), "service.handler", dbo) return ("text/plain", 0, "ERROR: Invalid animalid") # If the option is on, forbid hotlinking else: seq = utils.df_ki(data, "seq") if seq == 0: seq = 1 mm = media.get_media_by_seq(dbo, media.ANIMAL, utils.cint(animalid), seq) if len(mm) == 0: return ("image/jpeg", 86400, dbfs.get_string(dbo, "nopic.jpg", "/reports")) else: return ("image/jpeg", 86400, dbfs.get_string(dbo, mm[0]["MEDIANAME"])) elif method == "extra_image": return ("image/jpeg", 86400, dbfs.get_string(dbo, title, "/reports")) elif method == "json_adoptable_animals": pc = publish.PublishCriteria(configuration.publisher_presets(dbo)) rs = publish.get_animal_data(dbo, pc, True) return set_cached_response(cache_key, "application/json", 3600, html.json(rs)) elif method == "xml_adoptable_animals": pc = publish.PublishCriteria(configuration.publisher_presets(dbo)) rs = publish.get_animal_data(dbo, pc, True) return set_cached_response(cache_key, "application/xml", 3600, html.xml(rs)) elif method == "json_recent_adoptions": rs = movement.get_recent_adoptions(dbo) return set_cached_response(cache_key, "application/json", 3600, html.json(rs)) elif method == "xml_recent_adoptions": rs = movement.get_recent_adoptions(dbo) return set_cached_response(cache_key, "application/xml", 3600, html.xml(rs)) elif method == "html_report": crid = reports.get_id(dbo, title) p = reports.get_criteria_params(dbo, crid, data) rhtml = reports.execute(dbo, crid, username, p) return set_cached_response(cache_key, "text/html", 3600, rhtml) elif method == "jsonp_shelter_animals": sa = animal.get_animal_find_simple(dbo, "", "shelter") return set_cached_response( cache_key, "application/javascript", 3600, str(utils.df_ks(data, "callback")) + "(" + html.json(sa) + ")") elif method == "json_shelter_animals": sa = animal.get_animal_find_simple(dbo, "", "shelter") return set_cached_response(cache_key, "application/json", 3600, html.json(sa)) elif method == "xml_shelter_animals": sa = animal.get_animal_find_simple(dbo, "", "shelter") return set_cached_response(cache_key, "application/xml", 3600, html.json(sa)) elif method == "upload_animal_image": media.attach_file_from_form(dbo, username, media.ANIMAL, int(animalid), data) return ("text/plain", 0, "OK") elif method == "online_form_html": if formid == 0: raise utils.ASMError( "method online_form_html requires a valid formid") return set_cached_response(cache_key, "text/html", 120, onlineform.get_onlineform_html(dbo, formid)) elif method == "online_form_post": onlineform.insert_onlineformincoming_from_form(dbo, data, remoteip) redirect = utils.df_ks(data, "redirect") if redirect == "": redirect = BASE_URL + "/static/pages/form_submitted.html" return ("redirect", 0, redirect) else: al.error("invalid method '%s'" % method, "service.handler", dbo) raise utils.ASMError("Invalid method '%s'" % method)
def handler(data, remoteip, referer): """ Handles the various service method types. data: The GET/POST parameters return value is a tuple containing MIME type, max-age, content """ # Database info dbo = db.DatabaseInfo() # Get service parameters account = utils.df_ks(data, "account") username = utils.df_ks(data, "username") password = utils.df_ks(data, "password") method = utils.df_ks(data, "method") animalid = utils.df_ki(data, "animalid") formid = utils.df_ki(data, "formid") title = utils.df_ks(data, "title") cache_key = "a" + account + "u" + username + "p" + password + "m" + method + "a" + str(animalid) + "f" + str(formid) + "t" + title # cache keys aren't allowed spaces cache_key = cache_key.replace(" ", "") # Do we have a cached response for these parameters? cached_response = get_cached_response(cache_key) if cached_response is not None: al.debug("cache hit for %s/%s/%s/%s" % (account, method, animalid, title), "service.handler") return cached_response # Are we dealing with multiple databases, but no account was specified? if account == "" and MULTIPLE_DATABASES: return ("text/plan", 0, "ERROR: No database/alias specified") # Are we dealing with multiple databases and an account was specified? if account != "": if MULTIPLE_DATABASES: if MULTIPLE_DATABASES_TYPE == "smcom": # Is this sheltermanager.com? If so, we need to get the # database connection info (dbo) before we can login. dbo = smcom.get_database_info(account) else: # Look up the database info from our map dbo = db.get_multiple_database_info(account) if dbo.database == "FAIL" or dbo.database == "DISABLED": al.error("auth failed - invalid smaccount %s from %s" % (account, remoteip), "service.handler", dbo) return ("text/plain", 0, "ERROR: Invalid database") # Does the method require us to authenticate? If so, do it. user = None if method in AUTH_METHODS: user = users.authenticate(dbo, username, password) if user is None: al.error("auth failed - %s/%s is not a valid username/password from %s" % (username, password, remoteip), "service.handler", dbo) return ("text/plain", 0, "ERROR: Invalid username and password") # Get the preferred locale for the site dbo.locale = configuration.locale(dbo) al.info("call %s->%s [%s %s]" % (username, method, str(animalid), title), "service.handler", dbo) if method =="animal_image": # If we have a hotlinking restriction, enforce it if referer != "" and IMAGE_HOTLINKING_ONLY_FROM_DOMAIN != "" and referer.find(IMAGE_HOTLINKING_ONLY_FROM_DOMAIN) == -1: raise utils.ASMPermissionError("Image hotlinking is forbidden.") if animalid == "" or utils.cint(animalid) == 0: al.error("animal_image failed, %s is not an animalid" % str(animalid), "service.handler", dbo) return ("text/plain", 0, "ERROR: Invalid animalid") # If the option is on, forbid hotlinking else: seq = utils.df_ki(data, "seq") if seq == 0: seq = 1 mm = media.get_media_by_seq(dbo, media.ANIMAL, utils.cint(animalid), seq) if len(mm) == 0: return ("image/jpeg", 86400, dbfs.get_string(dbo, "nopic.jpg", "/reports")) else: return ("image/jpeg", 86400, dbfs.get_string(dbo, mm[0]["MEDIANAME"])) elif method =="extra_image": return ("image/jpeg", 86400, dbfs.get_string(dbo, title, "/reports")) elif method == "json_adoptable_animals": pc = publish.PublishCriteria(configuration.publisher_presets(dbo)) rs = publish.get_animal_data(dbo, pc, True) return set_cached_response(cache_key, "application/json", 3600, html.json(rs)) elif method == "xml_adoptable_animals": pc = publish.PublishCriteria(configuration.publisher_presets(dbo)) rs = publish.get_animal_data(dbo, pc, True) return set_cached_response(cache_key, "application/xml", 3600, html.xml(rs)) elif method == "json_recent_adoptions": rs = movement.get_recent_adoptions(dbo) return set_cached_response(cache_key, "application/json", 3600, html.json(rs)) elif method == "xml_recent_adoptions": rs = movement.get_recent_adoptions(dbo) return set_cached_response(cache_key, "application/xml", 3600, html.xml(rs)) elif method == "html_report": crid = reports.get_id(dbo, title) p = reports.get_criteria_params(dbo, crid, data) rhtml = reports.execute(dbo, crid, username, p) return set_cached_response(cache_key, "text/html", 3600, rhtml) elif method == "jsonp_shelter_animals": sa = animal.get_animal_find_simple(dbo, "", "shelter") return set_cached_response(cache_key, "application/javascript", 3600, str(utils.df_ks(data, "callback")) + "(" + html.json(sa) + ")") elif method == "json_shelter_animals": sa = animal.get_animal_find_simple(dbo, "", "shelter") return set_cached_response(cache_key, "application/json", 3600, html.json(sa)) elif method == "xml_shelter_animals": sa = animal.get_animal_find_simple(dbo, "", "shelter") return set_cached_response(cache_key, "application/xml", 3600, html.json(sa)) elif method == "upload_animal_image": media.attach_file_from_form(dbo, username, media.ANIMAL, int(animalid), data) return ("text/plain", 0, "OK") elif method == "online_form_html": if formid == 0: raise utils.ASMError("method online_form_html requires a valid formid") return set_cached_response(cache_key, "text/html", 120, onlineform.get_onlineform_html(dbo, formid)) elif method == "online_form_post": onlineform.insert_onlineformincoming_from_form(dbo, data, remoteip) redirect = utils.df_ks(data, "redirect") if redirect == "": redirect = BASE_URL + "/static/pages/form_submitted.html" return ("redirect", 0, redirect) else: al.error("invalid method '%s'" % method, "service.handler", dbo) raise utils.ASMError("Invalid method '%s'" % method)
def handler(post, remoteip, referer): """ Handles the various service method types. data: The GET/POST parameters return value is a tuple containing MIME type, max-age, content """ # Database info dbo = db.DatabaseInfo() # Get service parameters account = post["account"] username = post["username"] password = post["password"] method = post["method"] animalid = post.integer("animalid") formid = post.integer("formid") seq = post.integer("seq") title = post["title"] cache_key = "a" + account + "u" + username + "p" + password + "m" + method + \ "i" + str(animalid) + "s" + str(seq) + "f" + str(formid) + "t" + title # cache keys aren't allowed spaces cache_key = cache_key.replace(" ", "") # Do we have a cached response for these parameters? cached_response = get_cached_response(cache_key) if cached_response is not None: al.debug("cache hit for %s/%s/%s/%s" % (account, method, animalid, title), "service.handler") return cached_response # Are we dealing with multiple databases, but no account was specified? if account == "" and MULTIPLE_DATABASES: return ("text/plan", 0, "ERROR: No database/alias specified") # Are we dealing with multiple databases and an account was specified? if account != "": if MULTIPLE_DATABASES: if MULTIPLE_DATABASES_TYPE == "smcom": # Is this sheltermanager.com? If so, we need to get the # database connection info (dbo) before we can login. dbo = smcom.get_database_info(account) else: # Look up the database info from our map dbo = db.get_multiple_database_info(account) if dbo.database == "FAIL" or dbo.database == "DISABLED": al.error("auth failed - invalid smaccount %s from %s" % (account, remoteip), "service.handler", dbo) return ("text/plain", 0, "ERROR: Invalid database") # If the database has disabled the service API, stop now if not configuration.service_enabled(dbo): al.error("Service API is disabled (%s)" % method, "service.handler", dbo) return ("text/plain", 0, "ERROR: Service API is disabled") # Do any database updates need doing in this db? if dbupdate.check_for_updates(dbo): dbupdate.perform_updates(dbo) # Does the method require us to authenticate? If so, do it. user = None securitymap = "" if method in AUTH_METHODS: # If the database has authenticated service methods disabled, stop now if not configuration.service_auth_enabled(dbo): al.error("Service API for auth methods is disabled (%s)" % method, "service.handler", dbo) return ("text/plain", 0, "ERROR: Service API for authenticated methods is disabled") user = users.authenticate(dbo, username, password) if user is None: al.error("auth failed - %s/%s is not a valid username/password from %s" % (username, password, remoteip), "service.handler", dbo) return ("text/plain", 0, "ERROR: Invalid username and password") securitymap = users.get_security_map(dbo, user["USERNAME"]) # Get the preferred locale and timezone for the site l = configuration.locale(dbo) dbo.locale = l dbo.timezone = configuration.timezone(dbo) al.info("call %s->%s [%s %s]" % (username, method, str(animalid), title), "service.handler", dbo) if method =="animal_image": hotlink_protect("animal_image", referer) if animalid == "" or utils.cint(animalid) == 0: al.error("animal_image failed, %s is not an animalid" % str(animalid), "service.handler", dbo) return ("text/plain", 0, "ERROR: Invalid animalid") else: if seq == 0: seq = 1 mm = media.get_media_by_seq(dbo, media.ANIMAL, utils.cint(animalid), seq) if len(mm) == 0: return set_cached_response(cache_key, "image/jpeg", 86400, 120, dbfs.get_string(dbo, "nopic.jpg", "/reports")) else: return set_cached_response(cache_key, "image/jpeg", 86400, 120, dbfs.get_string(dbo, mm[0]["MEDIANAME"])) elif method == "animal_view": if animalid == "" or utils.cint(animalid) == 0: al.error("animal_view failed, %s is not an animalid" % str(animalid), "service.handler", dbo) return ("text/plain", 0, "ERROR: Invalid animalid") else: return set_cached_response(cache_key, "text/html", 120, 120, publish.get_animal_view(dbo, int(animalid))) elif method =="dbfs_image": hotlink_protect("dbfs_image", referer) return set_cached_response(cache_key, "image/jpeg", 86400, 120, dbfs.get_string_filepath(dbo, title)) elif method =="extra_image": hotlink_protect("extra_image", referer) return set_cached_response(cache_key, "image/jpeg", 86400, 120, dbfs.get_string(dbo, title, "/reports")) elif method == "json_adoptable_animals": users.check_permission_map(l, user["SUPERUSER"], securitymap, users.VIEW_ANIMAL) pc = publish.PublishCriteria(configuration.publisher_presets(dbo)) rs = publish.get_animal_data(dbo, pc, True) return set_cached_response(cache_key, "application/json", 3600, 3600, html.json(rs)) elif method == "jsonp_adoptable_animals": users.check_permission_map(l, user["SUPERUSER"], securitymap, users.VIEW_ANIMAL) pc = publish.PublishCriteria(configuration.publisher_presets(dbo)) rs = publish.get_animal_data(dbo, pc, True) return ("application/javascript", 0, "%s(%s);" % (post["callback"], html.json(rs))) elif method == "xml_adoptable_animals": users.check_permission_map(l, user["SUPERUSER"], securitymap, users.VIEW_ANIMAL) pc = publish.PublishCriteria(configuration.publisher_presets(dbo)) rs = publish.get_animal_data(dbo, pc, True) return set_cached_response(cache_key, "application/xml", 3600, 3600, html.xml(rs)) elif method == "json_recent_adoptions": users.check_permission_map(l, user["SUPERUSER"], securitymap, users.VIEW_ANIMAL) rs = movement.get_recent_adoptions(dbo) return set_cached_response(cache_key, "application/json", 3600, 3600, html.json(rs)) elif method == "jsonp_recent_adoptions": users.check_permission_map(l, user["SUPERUSER"], securitymap, users.VIEW_ANIMAL) rs = movement.get_recent_adoptions(dbo) return ("application/javascript", 0, "%s(%s);" % (post["callback"], html.json(rs))) elif method == "xml_recent_adoptions": users.check_permission_map(l, user["SUPERUSER"], securitymap, users.VIEW_ANIMAL) rs = movement.get_recent_adoptions(dbo) return set_cached_response(cache_key, "application/xml", 3600, 3600, html.xml(rs)) elif method == "html_report": users.check_permission_map(l, user["SUPERUSER"], securitymap, users.VIEW_REPORT) crid = reports.get_id(dbo, title) p = reports.get_criteria_params(dbo, crid, post) rhtml = reports.execute(dbo, crid, username, p) return set_cached_response(cache_key, "text/html", 3600, 3600, rhtml) elif method == "csv_mail" or method == "csv_report": users.check_permission_map(l, user["SUPERUSER"], securitymap, users.VIEW_REPORT) crid = reports.get_id(dbo, title) p = reports.get_criteria_params(dbo, crid, post) rows, cols = reports.execute_query(dbo, crid, username, p) mcsv = utils.csv(l, rows, cols, True) return set_cached_response(cache_key, "text/csv", 3600, 3600, mcsv) elif method == "jsonp_shelter_animals": users.check_permission_map(l, user["SUPERUSER"], securitymap, users.VIEW_ANIMAL) sa = animal.get_animal_find_simple(dbo, "", "shelter") return ("application/javascript", 0, "%s(%s);" % (post["callback"], html.json(sa))) elif method == "json_shelter_animals": users.check_permission_map(l, user["SUPERUSER"], securitymap, users.VIEW_ANIMAL) sa = animal.get_animal_find_simple(dbo, "", "shelter") return set_cached_response(cache_key, "application/json", 3600, 3600, html.json(sa)) elif method == "xml_shelter_animals": users.check_permission_map(l, user["SUPERUSER"], securitymap, users.VIEW_ANIMAL) sa = animal.get_animal_find_simple(dbo, "", "shelter") return set_cached_response(cache_key, "application/xml", 3600, 3600, html.xml(sa)) elif method == "rss_timeline": users.check_permission_map(l, user["SUPERUSER"], securitymap, users.VIEW_ANIMAL) return set_cached_response(cache_key, "application/rss+xml", 3600, 3600, html.timeline_rss(dbo)) elif method == "upload_animal_image": users.check_permission_map(l, user["SUPERUSER"], securitymap, users.ADD_MEDIA) media.attach_file_from_form(dbo, username, media.ANIMAL, int(animalid), post) return ("text/plain", 0, "OK") elif method == "online_form_html": if formid == 0: raise utils.ASMError("method online_form_html requires a valid formid") return set_cached_response(cache_key, "text/html; charset=utf-8", 120, 120, onlineform.get_onlineform_html(dbo, formid)) elif method == "online_form_json": if formid == 0: raise utils.ASMError("method online_form_json requires a valid formid") return set_cached_response(cache_key, "text/json; charset=utf-8", 30, 30, onlineform.get_onlineform_json(dbo, formid)) elif method == "online_form_post": flood_protect("online_form_post", remoteip, 15) onlineform.insert_onlineformincoming_from_form(dbo, post, remoteip) redirect = post["redirect"] if redirect == "": redirect = BASE_URL + "/static/pages/form_submitted.html" return ("redirect", 0, redirect) elif method == "sign_document": if formid == 0: raise utils.ASMError("method sign_document requires a valid formid") if post["sig"] == "": return set_cached_response(cache_key, "text/html", 2, 2, sign_document_page(dbo, formid)) else: media.sign_document(dbo, "service", formid, post["sig"], post["signdate"]) return ("text/plain", 0, "OK") else: al.error("invalid method '%s'" % method, "service.handler", dbo) raise utils.ASMError("Invalid method '%s'" % method)