def cache_extra_strings(): """ Caches strings from the all the extra XML string files. The extra string files look like this: <?xml version="1.0" encoding="UTF-8"?> <resources> <task name="TASK_1"> <string name="NAME_1">VALUE</string> <string name="NAME_2">VALUE WITH\nNEWLINE</string> <!-- ... --> </task> <!-- ... --> </resources> """ if cc_pls.pls.extraStringDicts is not None: return if cc_pls.pls.EXTRA_STRING_FILES is None: raise AssertionError( "pls.EXTRA_STRING_FILES is None -- likely use of " "XSTRING/WXSTRING in classmethod, before initialization via " "the WSGI application entry point") cc_pls.pls.extraStringDicts = {} for filename in cc_pls.pls.EXTRA_STRING_FILES: logger.debug("Loading XML file: " + filename) parser = ElementTree.XMLParser(encoding="UTF-8") tree = ElementTree.parse(filename, parser=parser) root = tree.getroot() for taskroot in root.findall("./task[@name]"): taskname = taskroot.attrib.get("name") if taskname not in cc_pls.pls.extraStringDicts: cc_pls.pls.extraStringDicts[taskname] = {} for e in taskroot.findall("./string[@name]"): stringname = e.attrib.get("name") value = e.text cc_pls.pls.extraStringDicts[taskname][stringname] = value
def cache_strings(): """ Caches strings from the main XML string file. The string file looks like this: <?xml version="1.0" encoding="UTF-8"?> <resources> <string name="NAME">VALUE</string> <!-- ... --> </resources> """ if cc_pls.pls.stringDict is not None: return if cc_pls.pls.CAMCOPS_STRINGS_FILE_ABSOLUTE is None: raise AssertionError( "pls.CAMCOPS_STRINGS_FILE_ABSOLUTE is None -- likely use of " "LSTRING/WSTRING in classmethod, before initialization via " "the WSGI application entry point") logger.debug("Loading XML file: " + cc_pls.pls.CAMCOPS_STRINGS_FILE_ABSOLUTE) parser = ElementTree.XMLParser(encoding="UTF-8") tree = ElementTree.parse(cc_pls.pls.CAMCOPS_STRINGS_FILE_ABSOLUTE, parser=parser) cc_pls.pls.stringDict = {} # find all children of the root with tag "string" and attribute "name" for e in tree.findall("./string[@name]"): cc_pls.pls.stringDict[e.attrib.get("name")] = e.text
def get_current_blob_by_client_info(device, clientpk, era): """Returns the current Blob object, or None.""" serverpk = cc_db.get_current_server_pk_by_client_info( Blob.TABLENAME, device, clientpk, era) if serverpk is None: logger.debug("FAILED TO FIND BLOB: " + str(clientpk)) return None return Blob(serverpk)
def send_analytics_if_necessary(): """Send analytics to the CamCOPS base server, if required. If analytics reporting is enabled, and analytics have not been sent recently, collate and send them to the CamCOPS base server in Cambridge, UK. """ if not pls.SEND_ANALYTICS: # User has disabled analytics reporting. return lastSentVar = cc_storedvar.ServerStoredVar("lastAnalyticsSentAt", "text", None) lastSentVal = lastSentVar.getValue() if lastSentVal: elapsed = pls.NOW_UTC_WITH_TZ - cc_dt.get_datetime_from_string( lastSentVal) if elapsed < ANALYTICS_PERIOD: # We sent analytics recently. return # Compile analytics now_as_utc_iso_string = cc_dt.format_datetime(pls.NOW_UTC_WITH_TZ, DATEFORMAT.ISO8601) (table_names, record_counts) = get_all_tables_with_record_counts() # This is what's sent: d = { "source": "server", "now": now_as_utc_iso_string, "camcops_version": str(cc_version.CAMCOPS_SERVER_VERSION), "server": pls.SERVER_NAME, "table_names": ",".join(table_names), "record_counts": ",".join([str(x) for x in record_counts]), } # The HTTP_HOST variable might provide some extra information, but is # per-request rather than per-server, making analytics involving it that # bit more intrusive for little extra benefit, so let's not send it. # See http://stackoverflow.com/questions/2297403 for details. # Send it. encoded_dict = urllib.urlencode(d) request = urllib2.Request(ANALYTICS_URL, encoded_dict) try: urllib2.urlopen(request, timeout=ANALYTICS_TIMEOUT_MS) # connection = urllib2.urlopen(request, timeout=ANALYTICS_TIMEOUT_MS) # response = connection.read() # we don't care except (urllib2.URLError, urllib2.HTTPError): # something broke; try again next time logger.info("Failed to send analytics to {}".format(ANALYTICS_URL)) return # Store current time as last-sent time logger.debug("Analytics sent.") lastSentVar.setValue(now_as_utc_iso_string)
def get_contemporaneous_blob_by_client_info(device, clientpk, era, referrer_added_utc, referrer_removed_utc): """Returns a contemporaneous Blob object, or None. Use particularly to look up BLOBs matching old task records. """ serverpk = cc_db.get_contemporaneous_server_pk_by_client_info( Blob.TABLENAME, device, clientpk, era, referrer_added_utc, referrer_removed_utc) if serverpk is None: logger.debug("FAILED TO FIND BLOB: " + str(clientpk)) return None return Blob(serverpk)
def establish_session(env): """Look up details from the HTTP environment. Load existing session or create a new one. Session is then stored in pls.session (pls being process-local storage).""" ip_address = env["REMOTE_ADDR"] try: cookie = Cookie.SimpleCookie(env["HTTP_COOKIE"]) session_id = cookie["session_id"].value session_token = cookie["session_token"].value #logger.debug("Found cookie token: ID {}, token {}".format( # session_id, session_token)) except (Cookie.CookieError, KeyError): logger.debug("No cookie yet. Creating new one.") session_id = None session_token = None pls.session = Session(session_id, session_token, ip_address)
def clear_dummy_login_failures_if_necessary(): """Clear dummy login failures if we haven't done so for a while. Not too often! See CLEAR_DUMMY_LOGIN_FREQUENCY_DAYS. """ lastClearedVar = cc_storedvar.ServerStoredVar( "lastDummyLoginFailureClearanceAt", "text", None) lastClearedVal = lastClearedVar.getValue() if lastClearedVal: elapsed = pls.NOW_UTC_WITH_TZ - cc_dt.get_datetime_from_string( lastClearedVal) if elapsed < CLEAR_DUMMY_LOGIN_PERIOD: # We cleared it recently. return clear_login_failures_for_nonexistent_users() logger.debug("Dummy login failures cleared.") now_as_utc_iso_string = cc_dt.format_datetime(pls.NOW_UTC_WITH_TZ, DATEFORMAT.ISO8601) lastClearedVar.setValue(now_as_utc_iso_string)
def establish_session_for_tablet(session_id, session_token, ip_address, username, password): """As for establish_session, but without using HTTP cookies. Resulting session is stored in pls.session.""" if not session_id or not session_token: logger.debug("No session yet for tablet. Creating new one.") session_id = None session_token = None pls.session = Session(session_id, session_token, ip_address) # Creates a new session if necessary if pls.session.userobject and pls.session.user != username: # We found a session, and it's associated with a user, but with # the wrong user. This is unlikely to happen! # Wipe the old one: pls.session.logout() # Create a fresh session. pls.session = Session(None, None, ip_address) if not pls.session.userobject and username: userobject = cc_user.get_user(username, password) # checks password if userobject is not None and (userobject.may_upload or userobject.may_use_webstorage): # Successful login. pls.session.login(userobject)