def setUp(self): from get_database import get_profile_db, get_uuid_db, get_client_db, get_pending_signup_db # Make sure we start with a clean slate every time get_client_db().remove() get_profile_db().remove() get_pending_signup_db().remove() get_uuid_db().remove()
def fromEmail(userEmail): email2UUID = get_uuid_db().find_one({'user_email': userEmail}) if email2UUID is None: return None user = User(email2UUID['uuid']) user.__email = userEmail return user
def getUUID(request, inHeader=False): retUUID = None if skipAuth: if 'User' in request.headers or 'user' in request.json: # skipAuth = true, so the email will be sent in plaintext userEmail = __getToken__(request, inHeader) retUUID = __getUUIDFromEmail__(userEmail) logging.debug( "skipAuth = %s, returning UUID directly from email %s" % (skipAuth, retUUID)) else: # Return a random user to make it easy to experiment without having to specify a user # TODO: Remove this if it is not actually used from get_database import get_uuid_db user_uuid = get_uuid_db().find_one()['uuid'] retUUID = user_uuid logging.debug("skipAuth = %s, returning arbitrary UUID %s" % (skipAuth, retUUID)) if Client("choice").getClientKey() is None: Client("choice").update(createKey=True) else: userToken = __getToken__(request, inHeader) retUUID = getUUIDFromToken(userToken) request.params.user_uuid = retUUID return retUUID
def setUp(self): # Make sure we start with a clean slate every time self.serverName = 'localhost' common.dropAllCollections(get_db()) logging.info("After setup, client count = %d, profile count = %d, uuid count = %d" % (get_client_db().find().count(), get_profile_db().count(), get_uuid_db().count())) load_database_json.loadTable(self.serverName, "Stage_Modes", "tests/data/modes.json")
def getUUID(request): retUUID = None if skipAuth: from uuid import UUID from get_database import get_uuid_db if get_uuid_db().find().count() == 1: user_uuid = get_uuid_db().find_one()['uuid'] else: # TODO: Figure out what we really want to do here user_uuid = UUID('{3a307244-ecf1-3e6e-a9a7-3aaf101b40fa}') retUUID = user_uuid logging.debug("skipAuth = %s, returning fake UUID %s" % (skipAuth, user_uuid)) else: userToken = request.json['user'] retUUID = getUUIDFromToken(userToken) request.params.user_uuid = retUUID return retUUID
def getUUID(request, inHeader=False): retUUID = None if skipAuth: from uuid import UUID from get_database import get_uuid_db user_uuid = get_uuid_db().find_one()['uuid'] retUUID = user_uuid logging.debug("skipAuth = %s, returning fake UUID %s" % (skipAuth, user_uuid)) else: if inHeader: userToken = request.headers.get('User').split()[1] else: userToken = request.json['user'] retUUID = getUUIDFromToken(userToken) request.params.user_uuid = retUUID return retUUID
def getResult(user_uuid): # This is in here, as opposed to the top level as recommended by the PEP # because then we don't have to worry about loading bottle in the unit tests from bottle import template (prevScore, currScore) = getStoredScore(User.fromUUID(user_uuid)) (level, sublevel) = getLevel(currScore) otherCurrScoreList = [] for user_uuid_dict in get_uuid_db().find({}, {'uuid': 1, '_id': 0}): (currPrevScore, currCurrScore) = getStoredScore(User.fromUUID(user_uuid_dict['uuid'])) otherCurrScoreList.append(currCurrScore) otherCurrScoreList.sort() renderedTemplate = template("clients/leaderboard/result_template.html", level_picture_filename = getFileName(level, sublevel), prevScore = prevScore, currScore = currScore, otherCurrScoreList = otherCurrScoreList) return renderedTemplate
def getUUID(request, inHeader=False): retUUID = None if skipAuth: if 'User' in request.headers or 'user' in request.json: # skipAuth = true, so the email will be sent in plaintext userEmail = __getToken__(request, inHeader) retUUID = __getUUIDFromEmail__(userEmail) logging.debug("skipAuth = %s, returning UUID directly from email %s" % (skipAuth, retUUID)) else: # Return a random user to make it easy to experiment without having to specify a user # TODO: Remove this if it is not actually used from get_database import get_uuid_db user_uuid = get_uuid_db().find_one()['uuid'] retUUID = user_uuid logging.debug("skipAuth = %s, returning arbitrary UUID %s" % (skipAuth, retUUID)) if Client("choice").getClientKey() is None: Client("choice").update(createKey = True) else: userToken = __getToken__(request, inHeader) retUUID = getUUIDFromToken(userToken) request.params.user_uuid = retUUID return retUUID
from __future__ import print_function from __future__ import unicode_literals from __future__ import division from __future__ import absolute_import from future import standard_library standard_library.install_aliases() from builtins import * from pymongo import MongoClient from get_database import get_uuid_db, get_moves_db, get_profile_db from datetime import datetime for entry in get_moves_db().find(): print("%s -> %s" % (entry['user'], entry['uuid'])) userEmail = entry['user'] userUUID = entry['uuid'] userUUIDEntry = \ { 'user_email': userEmail, 'uuid': userUUID, 'update_ts': datetime.now() } get_uuid_db().update({'user_email': userEmail}, userUUIDEntry, upsert=True) profileUpdateObj = {'user_id': userUUID, 'study_list': [], 'update_ts': datetime.now()} get_profile_db().update({'user_id': userUUID}, {'$set': profileUpdateObj}, upsert=True) get_moves_db().update({'uuid': userUUID}, {'$set': {'our_uuid': userUUID}}) get_moves_db().update({'uuid': userUUID}, {'$unset': {'uuid': "", 'user': ""}})
def unregister(userEmail): user = User.fromEmail(userEmail) uuid = user.uuid get_uuid_db().remove({'user_email': userEmail}) get_profile_db().remove({'user_id': uuid}) return uuid
def isRegistered(userEmail): email2UUID = get_uuid_db().find_one({'user_email': userEmail}) if email2UUID is None: return False else: return True
def register(userEmail): import uuid from datetime import datetime from dao.client import Client # We are accessing three databases here: # - The list of pending registrations (people who have filled out demographic # information but not installed the app) # - The mapping from the userEmail to the user UUID # - The mapping from the UUID to other profile information about the user # The first two are indexed by the user email. We will use the same field # name in both to indicate that it is a shared key. This also allows us to # have a simple query that we can reuse. userEmailQuery = {'user_email': userEmail} # First, we construct the email -> uuid mapping and store it in the appropriate database. # At this point, we don't know or care whether the user is part of a study # We also store a create timestamp just because that's always a good idea # What happens if the user calls register() again? Do we want to generate a new UUID? # Do we want to update the create timestamp? # For now, let's assume that the answer to both of those questions is yes, # because that allows us to use upsert :) # A bonus fix is that if something is messed up in the DB, calling create again will fix it. # This is the UUID that will be stored in the trip database # in order to do some fig leaf of anonymity # If we have an existing entry, should we change the UUID or not? If we # change the UUID, then there will be a break in the trip history. Let's # change for now since it makes the math easier. anonUUID = uuid.uuid3(uuid.NAMESPACE_URL, "mailto:%s" % userEmail.encode("UTF-8")) emailUUIDObject = { 'user_email': userEmail, 'uuid': anonUUID, 'update_ts': datetime.now() } writeResultMap = get_uuid_db().update(userEmailQuery, emailUUIDObject, upsert=True) # Note, if we did want the create_ts to not be overwritten, we can use the # writeResult to decide how to deal with the values # Now, we look to see if the user is part of a study. We can either store # this information in the profile database, or the mapping, or both. For now, # let us store this in the profile database since it is sufficient for it to # be associated with the UUID, we anticipate using it for customization, and # we assume that other customization stuff will be stored in the profile. # We could also assume that we will create the profile if we created the map # and update if we updated. But that has some reliability issues. For # example, what if creating the map succeeded but creating the profile # failed? Subsequently calling the method again to try and fix the profile # will continue to fail because we will be trying to update. # Much better to deal with it separately by doing a separate upsert # Second decision: what do we do if the user is not part of a study? Create a # profile anyway with an empty list, or defer the creation of the profile? # # Decision: create profile with empty list for two reasons: # a) for most of the functions, we want to use the profile data. We should # only use the email -> uuid map in the API layer to get the UUID, and use # the UUID elsewhere. So we need to have profiles for non-study participants # as well. # b) it will also make the scripts to update the profile in the background # easier to write. They won't have to query the email -> UUID database and # create the profile if it doesn't exist - they can just work off the profile # database. # TODO: Write a script that periodically goes through and identifies maps # that don't have an associated profile and fix them study_list = Client.getPendingClientRegs(userEmail) writeResultProfile = User.createProfile(anonUUID, datetime.now(), study_list) if 'err' not in writeResultProfile: # update was successful! # Either upserted or updatedExisting will be true # We can now cleanup the entry from the pending database # Note that we could also move this to a separate cleanup script because # eventual consistency is good enough for us # If there is a profile entry for a particular signup, then delete it Client.deletePendingClientRegs(userEmail) return User.fromUUID(anonUUID)
def register(userEmail): import uuid from datetime import datetime from dao.client import Client # We are accessing three databases here: # - The list of pending registrations (people who have filled out demographic # information but not installed the app) # - The mapping from the userEmail to the user UUID # - The mapping from the UUID to other profile information about the user # The first two are indexed by the user email. We will use the same field # name in both to indicate that it is a shared key. This also allows us to # have a simple query that we can reuse. userEmailQuery = {'user_email': userEmail} # First, we construct the email -> uuid mapping and store it in the appropriate database. # At this point, we don't know or care whether the user is part of a study # We also store a create timestamp just because that's always a good idea # What happens if the user calls register() again? Do we want to generate a new UUID? # Do we want to update the create timestamp? # For now, let's assume that the answer to both of those questions is yes, # because that allows us to use upsert :) # A bonus fix is that if something is messed up in the DB, calling create again will fix it. # This is the UUID that will be stored in the trip database # in order to do some fig leaf of anonymity # If we have an existing entry, should we change the UUID or not? If we # change the UUID, then there will be a break in the trip history. Let's # change for now since it makes the math easier. anonUUID = uuid.uuid3(uuid.NAMESPACE_URL, "mailto:%s" % userEmail.encode("UTF-8")) emailUUIDObject = {'user_email': userEmail, 'uuid': anonUUID, 'update_ts': datetime.now()} writeResultMap = get_uuid_db().update(userEmailQuery, emailUUIDObject, upsert=True) # Note, if we did want the create_ts to not be overwritten, we can use the # writeResult to decide how to deal with the values # Now, we look to see if the user is part of a study. We can either store # this information in the profile database, or the mapping, or both. For now, # let us store this in the profile database since it is sufficient for it to # be associated with the UUID, we anticipate using it for customization, and # we assume that other customization stuff will be stored in the profile. # We could also assume that we will create the profile if we created the map # and update if we updated. But that has some reliability issues. For # example, what if creating the map succeeded but creating the profile # failed? Subsequently calling the method again to try and fix the profile # will continue to fail because we will be trying to update. # Much better to deal with it separately by doing a separate upsert # Second decision: what do we do if the user is not part of a study? Create a # profile anyway with an empty list, or defer the creation of the profile? # # Decision: create profile with empty list for two reasons: # a) for most of the functions, we want to use the profile data. We should # only use the email -> uuid map in the API layer to get the UUID, and use # the UUID elsewhere. So we need to have profiles for non-study participants # as well. # b) it will also make the scripts to update the profile in the background # easier to write. They won't have to query the email -> UUID database and # create the profile if it doesn't exist - they can just work off the profile # database. # TODO: Write a script that periodically goes through and identifies maps # that don't have an associated profile and fix them study_list = Client.getPendingClientRegs(userEmail) writeResultProfile = User.createProfile(anonUUID, datetime.now(), study_list) if 'err' not in writeResultProfile: # update was successful! # Either upserted or updatedExisting will be true # We can now cleanup the entry from the pending database # Note that we could also move this to a separate cleanup script because # eventual consistency is good enough for us # If there is a profile entry for a particular signup, then delete it Client.deletePendingClientRegs(userEmail) return User.fromUUID(anonUUID)
# Unfortunately, this model broke for the "choice" client, because we wanted to # store multiple results at the same time. # So now, I have moved the field access code into the specific clients. # But I need to go through and fix the existing users # For all users who are not in the "gamified" group, we need to move their # carbon footprint from the currentScore field to the carbon_footprint field, # and delete the currentScore and previousScore fields from get_database import get_uuid_db, get_profile_db from dao.user import User from clients.default import default import logging logging.basicConfig(level=logging.DEBUG) for user_uuid_dict in get_uuid_db().find({}, {'uuid': 1, '_id': 0}): currUUID = user_uuid_dict['uuid'] logging.info("Fixing results for %s" % currUUID) currUser = User.fromUUID(currUUID) if currUser.getFirstStudy() is None: currFootprint = currUser.getProfile().get("currentScore", None) default.setCarbonFootprint(currUser, currFootprint) get_profile_db().update( {'user_id': currUUID}, {'$unset': { 'previousScore': "", 'currentScore': "" }}) logging.debug("After change, currentScore = %s, currFootprint = %s" % (currUser.getProfile().get("currentScore"), default.getCarbonFootprint(currUser)))
def precomputeResults(self): # TODO: Ensure that the default client is "default", which will make # life much easier overall for user_uuid_dict in get_uuid_db().find({}, {'uuid': 1, '_id': 0}): logging.info("Computing precomputed results for %s" % user_uuid_dict['uuid']) userclient.runClientSpecificBackgroundTasks(user_uuid_dict['uuid'])
# Unfortunately, this model broke for the "choice" client, because we wanted to # store multiple results at the same time. # So now, I have moved the field access code into the specific clients. # But I need to go through and fix the existing users # For all users who are not in the "gamified" group, we need to move their # carbon footprint from the currentScore field to the carbon_footprint field, # and delete the currentScore and previousScore fields from get_database import get_uuid_db, get_profile_db from dao.user import User from clients.default import default import logging logging.basicConfig(level=logging.DEBUG) for user_uuid_dict in get_uuid_db().find({}, {'uuid': 1, '_id': 0}): currUUID = user_uuid_dict['uuid'] logging.info("Fixing results for %s" % currUUID) currUser = User.fromUUID(currUUID) if currUser.getFirstStudy() is None: currFootprint = currUser.getProfile().get("currentScore", None) default.setCarbonFootprint(currUser, currFootprint) get_profile_db().update({'user_id': currUUID}, {'$unset': {'previousScore': "", 'currentScore': ""}}) logging.debug("After change, currentScore = %s, currFootprint = %s" % ( currUser.getProfile().get("currentScore"), default.getCarbonFootprint(currUser))) # Informal testing from the command line since this is a one-time script # Can be pulled out into a unit test if reworked # Test setup steps from the REPL:
def precomputeResults(self): for user_uuid_dict in get_uuid_db().find({}, {'uuid': 1, '_id': 0}): logging.info("Computing precomputed results for %s" % user_uuid_dict['uuid']) userclient.runClientSpecificBackgroundTasks(user_uuid_dict['uuid'])