Exemple #1
0
    def get(self, email):
        # Get values
        server = request.headers.get('server')

        # Validate required fields
        validation = Validation()
        validation.add_required_field('email', email)
        validation.add_required_field('server', server)
        validation.check_email('email', email)
        if not validation.is_valid():
            return validation.get_validation_response()

        # Validate user exits
        user = user_service.get_user_by_email(email)
        if user is None:
            return Failures.unknown_user_email(email)

        if user.auth_source != 'local':
            return Failures.wrong_auth_source(user.auth_source)

        success, code, message = user_service.send_email_confirm(
            user.id, server)

        db.session.commit()

        if success:
            logging.info('LocalUser-controller: RequestConfirm: success: %s',
                         user.id)

            return {'success': True}
        else:
            if code == 10:
                return Failures.rate_exceeded()
            return {'success': False, 'message': message, 'code': 520}
Exemple #2
0
def loadFromQuery(lat, lng, radiusKM = 5):

    if radiusKM > MAX_SAFE_QUERY_DIST_KM:
        raise RuntimeError("Queries with radii greater than " + str(MAX_SAFE_QUERY_DIST_KM) + " may cause data loss due to webserver limitations")

    outProjectionCode = 4326

    lineURL = "https://hydro.nationalmap.gov/arcgis/rest/services/NHDPlus_HR/MapServer/2/query?geometry=" + str(lng) + "," + str(lat) + "&outFields=GNIS_NAME%2C+LENGTHKM%2C+STREAMLEVE%2C+FCODE%2C+OBJECTID%2C+ARBOLATESU&geometryType=esriGeometryPoint&inSR=4326&outSR=" + str(outProjectionCode) + "&distance=" + str(radiusKM*1000) + "&units=esriSRUnit_Meter&returnGeometry=true&f=geojson"
    req = queryWithAttempts(lineURL, QUERY_ATTEMPTS, queryName="lineData", timeout = TIMEOUT)
    
    if Failures.isFailureCode(req):
        if __debug__:
            print("could not read query")
        return req
    try:
        lineLayer = json.loads(req.text)["features"]
    except:
        if __debug__:
            print("could not read query")
        return Failures.QUERY_PARSE_FAILURE_CODE
    
    if len(lineLayer) == 0:
        return Failures.EMPTY_QUERY_CODE

    sites = loadSitesFromQuery(lat, lng, radiusKM)
    
    if Failures.isFailureCode(sites):
        return sites
    
    dataBoundary = DataBoundary(point=(lng, lat), radius = Helpers.approxKmToDegrees(radiusKM - DATA_PADDING))

    data = BaseData(lineLayer = lineLayer, siteLayer = sites, dataBoundary = dataBoundary)

    return data
Exemple #3
0
    def post(self):
        # Get values
        server = request.headers.get('server')
        email = request.form.get('email')
        source = request.form.get('source')

        # Validate required fields
        validation = Validation()
        validation.add_required_field('server', server)
        validation.add_required_field('email', email)
        validation.add_required_field('source', source)
        validation.check_email('email', email)
        if not validation.is_valid():
            return validation.get_validation_response()

        # Validate user exits
        user = user_service.get_user_by_email(email)
        if user is None:
            return Failures.unknown_user_email(email)

        # Validate auth source
        if user.auth_source != source:
            return Failures.wrong_auth_source(user.auth_source)

        logging.info('OAuth-controller: Validate: success: %s', user.id)

        return {'success': True, 'user': {
            'id': user.id,
            'email': user.email,
            'locale': user.locale,
            'screenname': user.screen_name
        }}
    def get(self, id_user):
        # Parse numbers
        try:
            id_user = int(id_user)
        except:
            return Failures.not_a_number('idUser', id_user)

        # Validate user exists, is validated and is not blocked
        user = user_service.get_user(id_user)
        if user is None:
            return Failures.unknown_user_id(id_user)

        logging.info('User-controller: getUserById: success: %s (%s)', id_user,
                     user.screen_name)

        return {
            'success': True,
            'user': {
                'id': user.id,
                'email': user.email,
                'locale': user.locale,
                'screenname': user.screen_name,
                'authentication-source': user.auth_source
            }
        }
    def get(id_user):
        # Parse numbers
        try:
            id_user = int(id_user)

        except ValueError:
            return Failures.not_a_number('idUser', id_user)

        # Validate user exists, is validated and is not blocked
        user = user_service.get_user(id_user)

        if user is None:
            return Failures.unknown_user_id(id_user)

        logging.info('User-controller: getUserById: success: %s (%s)', id_user, user.screen_name)

        return {'success': True, 'user': {
            'id': user.id,
            'email': user.email,
            'locale': user.locale,
            'screenname': user.screen_name,
            'authentication-source': user.auth_source,
            'bdmonth': user.birth_month,
            'bdyear': user.birth_year,
            'parent-email': user.parent_email,
            'parent-email-source': user.parent_email_source
        }}
    def post(self):
        # Get values
        server = request.headers.get('server')
        id_user = request.form.get('idUser')
        browser = request.form.get('browser')
        ip_address = request.form.get('ipAddress')

        # Validate required fields
        validation = Validation()
        validation.add_required_field('server', server)
        validation.add_required_field('idUser', id_user)
        validation.add_required_field('browser', browser)
        validation.add_required_field('ipAddress', ip_address)
        if not validation.is_valid():
            return validation.get_validation_response()

        # Parse numbers
        try:
            id_user = int(id_user)
        except:
            return Failures.not_a_number('idUser', id_user)

        # Validate user exists, is validated and is not blocked
        user = user_service.get_user(id_user)
        if user is None:
            return Failures.unknown_user_id(id_user)
        if not user.confirmed:
            return Failures.email_not_confirmed()
        if user.blocked:
            return Failures.user_blocked()

        # Delete expired tokens
        AuthenticationToken.query.filter(
            AuthenticationToken.validity < datetime.datetime.now()).delete()
        db.session.flush()

        # Generate token
        token = str(uuid.uuid1())

        # Save token and browser information
        authentication_token = AuthenticationToken()
        authentication_token.id_user = id_user
        authentication_token.browser = browser
        authentication_token.server = server
        authentication_token.ip_address = ip_address
        authentication_token.validity = datetime.datetime.now(
        ) + datetime.timedelta(minutes=120)
        authentication_token.token = token
        db.session.add(authentication_token)
        db.session.commit()

        logging.info(
            'AuthToken-controller: Request auth token: success: %s -> %s*****',
            user.id, token[0:6])

        return {'success': True, 'token': token}
Exemple #7
0
    def post(self, email):
        # Get values
        token = request.form.get('token')
        password = request.form.get('password')
        password_confirm = request.form.get('password-confirm')

        # Validate required fields
        validation = Validation()
        validation.add_required_field('email', email)
        validation.add_required_field('token', token)
        validation.add_required_field('password', password)
        validation.add_required_field('password-confirm', password_confirm)
        validation.check_email('email', email)
        if not validation.is_valid():
            return validation.get_validation_response()

        # Validate user exits
        user = user_service.get_user_by_email(email)
        if user is None:
            return Failures.unknown_user_email(email)

        if user.auth_source != 'local':
            return Failures.wrong_auth_source(user.auth_source)

        # Validate password strength and confirm
        if password != password_confirm:
            return Failures.passwords_do_not_match()
        if not user_service.check_password_complexity(password):
            return Failures.password_complexity()

        # Delete expired tokens
        ResetToken.query.filter(
            ResetToken.validity < datetime.datetime.now()).delete()
        db.session.flush()

        reset_token = ResetToken.query.filter_by(token=token).first()
        if reset_token is None:
            # Unkown token
            return {'success': False, 'code': 510}
        if reset_token.id_user != user.id:
            # Token is not for this user
            return {'success': False, 'code': 510}

        salt, password_hash = user_service.get_password_hash(password)
        user.password = password_hash
        user.salt = salt

        db.session.delete(reset_token)
        db.session.commit()

        logging.info('LocalUser-controller: DoPasswordReset: success: %s',
                     user.id)

        return {'success': True}
    def post(self, email):
        # Get values
        token = request.form.get('token')
        password = request.form.get('password')
        password_confirm = request.form.get('password-confirm')

        # Validate required fields
        validation = Validation()
        validation.add_required_field('email', email)
        validation.add_required_field('token', token)
        validation.add_required_field('password', password)
        validation.add_required_field('password-confirm', password_confirm)
        validation.check_email('email', email)
        if not validation.is_valid():
            return validation.get_validation_response()

        # Validate user exits
        user = user_service.get_user_by_email(email)
        if user is None:
            return Failures.unknown_user_email(email)

        if user.auth_source != 'local':
            return Failures.wrong_auth_source(user.auth_source)

        # Validate password strength and confirm
        if password != password_confirm:
            return Failures.passwords_do_not_match()
        if not user_service.check_password_complexity(password):
            return Failures.password_complexity()

        # Delete expired tokens
        ResetToken.query.filter(ResetToken.validity < datetime.datetime.now()).delete()
        db.session.flush()

        reset_token = ResetToken.query.filter_by(token=token).first()
        if reset_token is None:
            # Unkown token
            return {'success': False, 'code': 510}
        if reset_token.id_user != user.id:
            # Token is not for this user
            return {'success': False, 'code': 510}

        salt, password_hash = user_service.get_password_hash(password)
        user.password = password_hash
        user.salt = salt

        db.session.delete(reset_token)
        db.session.commit()

        logging.info('LocalUser-controller: DoPasswordReset: success: %s', user.id)

        return {'success': True}
Exemple #9
0
    def post(id_user):
        screen_name = request.form.get('screenname')

        # Validate required fields
        validation = Validation()
        validation.add_required_field('id-user', id_user)
        validation.add_required_field('screenname', screen_name)
        if not validation.is_valid():
            return validation.get_validation_response()

        # Validate the id parameter as an integer
        try:
            id_user = int(id_user)

        except ValueError:
            return Failures.not_a_number('idUser', id_user)

        # Validate user exists, is validated and is not blocked
        user = user_service.get_user(id_user)

        if user is None:
            return Failures.unknown_user_id(id_user)

        # Attempt to retrieve the proposed screen name to ensure that it is available
        user_by_email = user_service.get_user_by_screen_name(screen_name)

        if user_by_email is not None:
            if user.id != user_by_email.id:
                return Failures.screen_name_already_in_use(screen_name)

        # The screen name is available, Assign it to the user profile
        user.screen_name = screen_name
        db.session.commit()

        logging.info('User-controller: doInfoChange: success: %s (%s)',
                     id_user, user.screen_name)

        return {
            'success': True,
            'user': {
                'id': user.id,
                'email': user.email,
                'locale': user.locale,
                'screenname': user.screen_name,
                'authentication-source': user.auth_source,
                'bdmonth': user.birth_month,
                'bdyear': user.birth_year,
                'parent-email': user.parent_email,
                'parent-email-source': user.parent_email_source
            }
        }
Exemple #10
0
    def post(self):
        # Get values
        email = request.form.get('email')  # User account email address
        token = request.form.get(
            'token')  # Token assigned to account during account registration

        # Validate required fields
        validation = Validation()
        validation.add_required_field('email', email)
        validation.add_required_field('token', token)
        validation.check_email('email', email)
        if not validation.is_valid():
            return validation.get_validation_response()

        # Validate user exits
        user = user_service.get_user_by_email(email)
        if user is None:
            return Failures.unknown_user_email(email)

        if user.auth_source != 'local':
            return Failures.wrong_auth_source(user.auth_source)

        # Delete expired tokens
        ConfirmToken.query.filter(
            ConfirmToken.validity < datetime.datetime.now()).delete()
        db.session.flush()

        confirm_token = ConfirmToken.query.filter_by(token=token).first()
        if confirm_token is None:
            # Unknown token
            return {'success': False, 'code': 510}

        if confirm_token.id_user != user.id:
            # Token is not for this user
            return {'success': False, 'code': 510}

        # Set user account status to 'Confirmed'
        user.confirmed = True

        # Delete the account confirmation token; it is no longer required
        db.session.delete(confirm_token)

        # Commit the user account changes
        db.session.commit()

        logging.info('LocalUser-controller: DoConfirm: success: %s', user.id)

        return {'success': True}
Exemple #11
0
    def get(email):
        # TODO: Validate the format of the email address before attempting database IO

        # Validate user exists, is validated and is not blocked
        user = user_service.get_user_by_email(email)

        if user is None:
            return Failures.unknown_user_email(email)

        logging.info('User-controller: getUserByEmail: success: %s (%s)',
                     email, user.screen_name)

        return {
            'success': True,
            'user': {
                'id': user.id,
                'email': user.email,
                'locale': user.locale,
                'screenname': user.screen_name,
                'authentication-source': user.auth_source,
                'bdmonth': user.birth_month,
                'bdyear': user.birth_year,
                'parent-email': user.parent_email,
                'parent-email-source': user.parent_email_source
            }
        }
Exemple #12
0
def getNearestPlace (lat, lng, timeout = 5):
    locationsUrl = "https://carto.nationalmap.gov/arcgis/rest/services/geonames/MapServer/18/query?geometry=" + str(lng) +"," + str(lat) + "&geometryType=esriGeometryPoint&inSR=4326&outSR=4326&distance=7000&units=esriSRUnit_Meter&outFields=*&returnGeometry=true&f=geojson"
    result = queryWithAttempts(locationsUrl, QUERY_ATTEMPTS, timeout = timeout, queryName="nearPlaces")
    
    if Failures.isFailureCode(result):
        return result

    try:
        data = json.loads(result.text)
    except:
        return Failures.QUERY_PARSE_FAILURE_CODE

    features = data["features"]

    nearestFeatureDistance = sys.maxsize
    nearestFeature = None
    for feature in features:
        attrib = feature["properties"]

        point = feature["geometry"]["coordinates"][0]
        distance = Helpers.fastMagDist(point[1], point[0], lat, lng)
        if distance < nearestFeatureDistance:
            nearestFeatureDistance = distance
            nearestFeature = feature
    
    attrib = nearestFeature["properties"]
    stateAlpha = attrib["state_alpha"]
    placeName = attrib["gaz_name"]

    nearestPoint = nearestFeature["geometry"]["coordinates"][0]
    distance = Helpers.degDistance(nearestPoint[1], nearestPoint[0], lat, lng)

    return {"distanceToPlace":distance, "placeName":placeName, "state":stateAlpha}
Exemple #13
0
    def getXNeighborIDs(self, siteID, huc, numNeighbors):
        """ Get numNeighbors neighboring IDs above and below siteID
    
        :param siteID: The siteID.
        :param huc: The 2 digit huc code that the site is within.
        :param numNeighbors: The number of neighbors to get above and below siteID.

        :return: A list of all site IDs within the range. """

        hucCode = huc[:2]

        loadResults = self.loadHucWeb(hucCode)
        if Failures.isFailureCode(loadResults):
            return loadResults

        numIds = len(self.ids[hucCode])

        matchIndex = numIds - 1
        for i, thisID in enumerate(self.ids[hucCode]):
            if thisID[:2] == siteID[:2]:
                if thisID == siteID or Helpers.siteIDCompare(thisID,
                                                             siteID) > 0:
                    testcmp = Helpers.siteIDCompare(thisID, siteID)
                    matchIndex = i
                    break

        minIndex = max(0, matchIndex - numNeighbors)
        upperIndex = min(numIds - 1, matchIndex + numNeighbors)

        return self.ids[hucCode][minIndex:upperIndex]
Exemple #14
0
    def getNeighborIDs(self, siteID, huc):
        """ Get the two nearest sequential neighbors to a siteID.

        Upstream neighbor meaning the site with the next lower DSN number than the input ID. 
        
        :param siteID: The siteID.
        :param huc: The 2 digit huc code that the site is within.
        
        :return: (upstream neighbor, downstream neighbor) """
        hucCode = huc[:2]

        loadResults = self.loadHucWeb(hucCode)
        if Failures.isFailureCode(loadResults):
            return loadResults

        matchIndex = self.ids[hucCode].index(siteID)

        if matchIndex == -1:
            return Failures.MISSING_SITEID_CODE

        numIds = len(self.ids[hucCode])
        if matchIndex < numIds - 1:
            downstreamNeighbor = self.ids[hucCode][matchIndex + 1]
            if downstreamNeighbor[:2] != siteID[:2]:
                #if this neighbor is a different part code it's not valid
                downstreamNeighbor = None
        if matchIndex > 0:
            upstreamNeighbor = self.ids[hucCode][matchIndex - 1]
            if upstreamNeighbor[:2] != siteID[:2]:
                upstreamNeighbor = None
        #lower neighbor is lower in number, not in terms of downstream, vice versa
        return (upstreamNeighbor, downstreamNeighbor)
Exemple #15
0
def getNearestBridges (lat, lng, timeout = 5):
    locationsUrl = "https://carto.nationalmap.gov/arcgis/rest/services/geonames/MapServer/10/query?geometry=" + str(lng) +"," + str(lat) + "&geometryType=esriGeometryPoint&inSR=4326&outSR=4326&distance=7000&units=esriSRUnit_Meter&outFields=*&returnGeometry=true&f=geojson"
    result = queryWithAttempts(locationsUrl, QUERY_ATTEMPTS, timeout = timeout, queryName="nearBridges")
    
    if Failures.isFailureCode(result):
        return result

    try:
        data = json.loads(result.text)
    except:
        return Failures.QUERY_PARSE_FAILURE_CODE

    features = data["features"]

    bridges = []
    for feature in features:
        attrib = feature["properties"]

        point = feature["geometry"]["coordinates"][0]

        distance = Helpers.degDistance(point[1], point[0], lat, lng)
        name = attrib["gaz_name"]
        bridges.append(PointOfContext(point=point, distance=distance, name=name))
    
    return bridges
Exemple #16
0
    def getNextUpstreamSite(self, segment, downstreamPositionOnSegment):
        """ Find the next upstream site using backtracking if required.
        
        :param segment: The segment to search downstream from.
        :param downStreamPositionOnSegment: The position on the segment the search started from. This is used to get accurate distance measurements.
        :return: The found site or an error code."""
        #get the first upstream site
        upstreamSitesInfo = self.collectSortedUpstreamSites(
            segment, downstreamPositionOnSegment, siteLimit=1)

        #if this failed, return failure code now
        if Failures.isFailureCode(upstreamSitesInfo):
            return upstreamSitesInfo

        upstreamSites = upstreamSitesInfo[0]
        # we are only looking for one upstream site here, but, we only need this distance variable in the case
        # where we don't find any upstream sites and have to backtrack. Thus, in that case, collectSortedUp... will have explored all of the graph
        # upstream from segment
        totalDistance = upstreamSitesInfo[1]

        foundSite = None
        if upstreamSites is not None and len(upstreamSites) > 0:
            foundSite = upstreamSites[
                0]  #get the first upstream site / distance tuple

        if foundSite is not None:  #we found a site. Great! return it
            #return (siteID, distance upstream to site)
            return (foundSite[0], foundSite[1])
            #return (foundSite.siteID, summedDistance)
        else:  #no site found upstream...
            #find the next major branch by backtracking
            nextUpstreamSegment = self.findNextLowerStreamLevelPath(segment)

            if Failures.isFailureCode(nextUpstreamSegment):
                return nextUpstreamSegment
            else:  #we found a mainstream branch!
                if __debug__:
                    print("successful backtrack. Found next main branch")
                #recursively call this function again starting at the first node of the next mainstream branch
                #the next mainstream branch should be the continuation of our trib in ID space
                newSearch = self.getNextUpstreamSite(
                    nextUpstreamSegment[0], nextUpstreamSegment[0].length)
                if Failures.isFailureCode(newSearch):
                    return newSearch
                else:  #we found a site in the new search!
                    #we want to return the new site and the distance to it plus the distance upstream along our trib
                    return (newSearch[0], newSearch[1] + totalDistance)
    def post(self):
        # Get values
        server = request.headers.get('server')
        email = request.form.get('email')
        password = request.form.get('password')
        password_confirm = request.form.get('password-confirm')
        locale = request.form.get('locale')
        screen_name = request.form.get('screenname')

        # Validate required fields
        validation = Validation()
        validation.add_required_field('server', server)
        validation.add_required_field('email', email)
        validation.add_required_field('password', password)
        validation.add_required_field('password-confirm', password_confirm)
        validation.add_required_field('locale', locale)
        validation.add_required_field('screenname', screen_name)
        validation.check_email('email', email)
        if not validation.is_valid():
            return validation.get_validation_response()

        # Validate email is not yet used
        existing_user = user_service.get_user_by_email(email)
        if existing_user is not None:
            return Failures.email_already_in_use(email)

        # Validate screen name is not yet used
        existing_user = user_service.get_user_by_screen_name(screen_name)
        if existing_user is not None:
            return Failures.screen_name_already_in_use(screen_name)

        # Validate password strength and confirm
        if password != password_confirm:
            return Failures.passwords_do_not_match()
        if not user_service.check_password_complexity(password):
            return Failures.password_complexity()

        id_user = user_service.create_local_user(server, email, password,
                                                 locale, screen_name)
        user_service.send_email_confirm(id_user, server)

        db.session.commit()

        logging.info('User-controller: register success: %s', id_user)

        # Create user
        return {'success': True, 'user': id_user}
    def post(id_user):
        screen_name = request.form.get('screenname')

        # Validate required fields
        validation = Validation()
        validation.add_required_field('id-user', id_user)
        validation.add_required_field('screenname', screen_name)
        if not validation.is_valid():
            return validation.get_validation_response()

        # Validate the id parameter as an integer
        try:
            id_user = int(id_user)

        except ValueError:
            return Failures.not_a_number('idUser', id_user)

        # Validate user exists, is validated and is not blocked
        user = user_service.get_user(id_user)

        if user is None:
            return Failures.unknown_user_id(id_user)

        # Attempt to retrieve the proposed screen name to ensure that it is available
        user_by_email = user_service.get_user_by_screen_name(screen_name)

        if user_by_email is not None:
            if user.id != user_by_email.id:
                return Failures.screen_name_already_in_use(screen_name)

        # The screen name is available, Assign it to the user profile
        user.screen_name = screen_name
        db.session.commit()

        logging.info('User-controller: doInfoChange: success: %s (%s)', id_user, user.screen_name)

        return {'success': True, 'user': {
            'id': user.id,
            'email': user.email,
            'locale': user.locale,
            'screenname': user.screen_name,
            'authentication-source': user.auth_source,
            'bdmonth': user.birth_month,
            'bdyear': user.birth_year,
            'parent-email': user.parent_email,
            'parent-email-source': user.parent_email_source
        }}
    def post(self):
        # Get values
        email = request.form.get('email')   # User account email address
        token = request.form.get('token')   # Token assigned to account during account registration

        # Validate required fields
        validation = Validation()
        validation.add_required_field('email', email)
        validation.add_required_field('token', token)
        validation.check_email('email', email)
        if not validation.is_valid():
            return validation.get_validation_response()

        # Validate user exits
        user = user_service.get_user_by_email(email)
        if user is None:
            return Failures.unknown_user_email(email)

        if user.auth_source != 'local':
            return Failures.wrong_auth_source(user.auth_source)

        # Delete expired tokens
        ConfirmToken.query.filter(ConfirmToken.validity < datetime.datetime.now()).delete()
        db.session.flush()

        confirm_token = ConfirmToken.query.filter_by(token=token).first()
        if confirm_token is None:
            # Unknown token
            return {'success': False, 'code': 510}

        if confirm_token.id_user != user.id:
            # Token is not for this user
            return {'success': False, 'code': 510}

        # Set user account status to 'Confirmed'
        user.confirmed = True

        # Delete the account confirmation token; it is no longer required
        db.session.delete(confirm_token)

        # Commit the user account changes
        db.session.commit()

        logging.info('LocalUser-controller: DoConfirm: success: %s', user.id)

        return {'success': True}
Exemple #20
0
    def collectSortedUpstreamSites (self, segment, downStreamPositionOnSegment, siteLimit = 1, autoExpand = True):
        # contains tuples of the form (site, dist to site)
        foundSites = []

        # reverse order of segment.sites since normally it is ordered upstream->downstream
        # since we are collecting sites from downstream->upstream
        for site in reversed(segment.sites):
            if site.distDownstreamAlongSegment < downStreamPositionOnSegment and len(foundSites) < siteLimit:
                foundSites.append((site, downStreamPositionOnSegment - site.distDownstreamAlongSegment)) 

        if len(foundSites) >= siteLimit:
            #return the list of found sites and the distance upstream of the last site found
            return (foundSites, foundSites[-1][1])

        #get upstream tributaries of this path
        stack = []
        stack.append(segment)

        summedDistance = 0
        firstSegment = True
        
        while len(stack) > 0:
            thisSegment = stack.pop()

            # if there was a site on the first segment, we would catch it in 
            # our first case at the beginning
            # we avoid this if passing on a site below our query on the first segment by checking
            # if this is the first segment we are looking at
            if firstSegment is False:
                for site in reversed(thisSegment.sites):
                    if len(foundSites) < siteLimit:
                        foundSites.append((site, summedDistance + (thisSegment.length - site.distDownstreamAlongSegment)))
                    else:
                        break
                summedDistance += thisSegment.length
            else:
                summedDistance += downStreamPositionOnSegment
            
            if len(foundSites) >= siteLimit:
                break

            #reverse the list. We want the lowest priority tribs to be looked at first
            newBranches = thisSegment.upStreamNode.getSortedUpstreamBranches()
            stack.extend(reversed(newBranches))
            
            #expand graph if necessary 
            thisSegmentPosition = thisSegment.upStreamNode.position
            #if during navigation, we reach edge of safe data boundary, expand with new query
            if autoExpand is True and not self.streamGraph.pointWithinSafeDataBoundary(thisSegmentPosition):
                graphExpansion = self.streamGraph.expandGraph(thisSegmentPosition[1], thisSegmentPosition[0])
                if Failures.isFailureCode(graphExpansion):
                    return graphExpansion
                elif self.terminateSearchOnQuery is True:
                    return Failures.QUERY_TERMINATE_CODE
            
            firstSegment = False

        return (foundSites, summedDistance)
    def get(self, email):
        # Get server URL
        server = request.headers.get('server')

        logging.info("Requesting email confirmation for %s from server %s", email, server)

        # Validate required fields
        validation = Validation()
        validation.add_required_field('email', email)
        validation.add_required_field('server', server)
        validation.check_email('email', email)
        if not validation.is_valid():
            return validation.get_validation_response()

        # Validate user exits
        user = user_service.get_user_by_email(email)
        if user is None:
            return Failures.unknown_user_email(email)

        if user.auth_source != 'local':
            return Failures.wrong_auth_source(user.auth_source)

        success, code, message = user_service.send_email_confirm(user.id, server)

        db.session.commit()

        if success:
            logging.info('LocalUser-controller: RequestConfirm: success: %s', user.id)

            return {'success': True}
        else:
            if code == 10:
                return Failures.rate_exceeded()
            elif code == 99:
                return {
                    'success': False,
                    'message': message,
                    'code': 540
                }
            else:
                return {
                    'success': False,
                    'message': message,
                    'code': 520
                }
Exemple #22
0
    def post(self):
        # Get values
        server = request.headers.get('server')
        email = request.form.get('email')
        password = request.form.get('password')

        # Validate required fields
        validation = Validation()
        validation.add_required_field('server', server)
        validation.add_required_field('email', email)
        validation.add_required_field('password', password)

        if not validation.is_valid():
            return validation.get_validation_response()

        # Validate user exists, is validated and is not blocked
        user = user_services.get_user_by_email(email)

        if user is None:
            return Failures.unknown_user_email(email)

        if not user.confirmed:
            return Failures.email_not_confirmed(email)

        if user.blocked:
            return Failures.user_blocked(email)

        if user.auth_source != 'local':
            return Failures.wrong_auth_source(user.auth_source)

        if not rate_limiting_services.has_sufficient_tokens(user.id, 'failed-password', 1):
            return Failures.rate_exceeded()

        # The password might not be encoded correctly when submitted. This
        # could cause the check_password method to fault. We trap that
        # possibility and address it here.
        try:
            if not user_services.check_password(user.id, password):
                rate_limiting_services.consume_tokens(user.id, 'failed-password', 1)
                return Failures.wrong_password(email)
        except TypeError:
            return Failures.password_unknown_format("Unicode-objects must be encoded before hashing")

        db.session.commit()
        logging.info('Authenticate-controller: Authenticate: success: %s', email)

        return {
            'success': True,
            'user': {
                'id': user.id,
                'email': user.email,
                'locale': user.locale,
                'screenname': user.screen_name,
                'authentication-source': user.auth_source,
                'bdmonth': user.birth_month,
                'bdyear': user.birth_year,
                'parent-email': user.parent_email,
                'parent-email-source': user.parent_email_source
            }}
Exemple #23
0
 def expandGraph(self, lat, lng):
     if __debug__:
         print("Expanding graph!")
     baseData = loadFromQuery(lat, lng)
     if Failures.isFailureCode(baseData):
         if __debug__:
             print("could not expand graph")
         return baseData
     self.addGeom(baseData)
     return True
Exemple #24
0
    def post(self, id_user):
        # Get values
        old_password = request.form.get('old-password')
        password = request.form.get('password')
        password_confirm = request.form.get('password-confirm')

        # Validate required fields
        validation = Validation()
        validation.add_required_field('id_user', id_user)
        validation.add_required_field('old-password', old_password)
        validation.add_required_field('password', password)
        validation.add_required_field('password_confirm', password_confirm)
        if not validation.is_valid():
            return validation.get_validation_response()

        # Validate user exits
        user = user_service.get_user(id_user)
        if user is None:
            return Failures.unknown_user_id(id_user)

        if user.auth_source != 'local':
            return Failures.wrong_auth_source(user.auth_source)

        # Validate password strength and confirm
        if password != password_confirm:
            return Failures.passwords_do_not_match()
        if not user_service.check_password_complexity(password):
            return Failures.password_complexity()

        if not user_service.check_password(id_user, old_password):
            # Token is not for this user
            return {'success': False, 'code': 530}

        salt, password_hash = user_service.get_password_hash(password)
        user.password = password_hash
        user.salt = salt

        db.session.commit()

        logging.info('LocalUser-controller: PasswordChange: success: %s',
                     user.id)

        return {'success': True}
    def post(self, id_user):
        # Get values
        old_password = request.form.get('old-password')
        password = request.form.get('password')
        password_confirm = request.form.get('password-confirm')

        # Validate required fields
        validation = Validation()
        validation.add_required_field('id_user', id_user)
        validation.add_required_field('old-password', old_password)
        validation.add_required_field('password', password)
        validation.add_required_field('password_confirm', password_confirm)
        if not validation.is_valid():
            return validation.get_validation_response()

        # Validate user exits
        user = user_service.get_user(id_user)
        if user is None:
            return Failures.unknown_user_id(id_user)

        if user.auth_source != 'local':
            return Failures.wrong_auth_source(user.auth_source)

        # Validate password strength and confirm
        if password != password_confirm:
            return Failures.passwords_do_not_match()
        if not user_service.check_password_complexity(password):
            return Failures.password_complexity()

        if not user_service.check_password(id_user, old_password):
            # Token is not for this user
            return {'success': False, 'code': 530}

        salt, password_hash = user_service.get_password_hash(password)
        user.password = password_hash
        user.salt = salt

        db.session.commit()

        logging.info('LocalUser-controller: PasswordChange: success: %s', user.id)

        return {'success': True}
Exemple #26
0
 def expandGraph(self, lat, lng):
     """ Expand the graph at x,y with queried data. Return true if successful """
     if __debug__:
         print("Expanding graph!")
     baseData = loadFromQuery(lat, lng)
     if Failures.isFailureCode(baseData):
         if __debug__:
             print("could not expand graph")
         return baseData
     self.addGeom(baseData)
     return True
    def post(self, id_user):
        screen_name = request.form.get('screenname')
        # Validate required fields
        validation = Validation()
        validation.add_required_field('id-user', id_user)
        validation.add_required_field('screenname', screen_name)
        if not validation.is_valid():
            return validation.get_validation_response()

        # Parse numbers
        try:
            id_user = int(id_user)
        except:
            return Failures.not_a_number('idUser', id_user)

        # Validate user exists, is validated and is not blocked
        user = user_service.get_user(id_user)
        if user is None:
            return Failures.unknown_user_id(id_user)

        user_by_email = user_service.get_user_by_screen_name(screen_name)
        if user_by_email is not None:
            if user.id != user_by_email.id:
                return Failures.screen_name_already_in_use(screen_name)

        user.screen_name = screen_name
        db.session.commit()

        logging.info('User-controller: doInfoChange: success: %s (%s)',
                     id_user, user.screen_name)

        return {
            'success': True,
            'user': {
                'id': user.id,
                'email': user.email,
                'locale': user.locale,
                'screenname': user.screen_name,
                'authentication-source': user.auth_source
            }
        }
Exemple #28
0
    def post(id_user):
        locale = request.form.get('locale')

        # Validate required fields
        validation = Validation()
        validation.add_required_field('id-user', id_user)
        validation.add_required_field('locale', locale)
        if not validation.is_valid():
            return validation.get_validation_response()

        # Parse numbers
        try:
            id_user = int(id_user)
        except ValueError:
            return Failures.not_a_number('idUser', id_user)

        # Validate user exists, is validated and is not blocked
        user = user_service.get_user(id_user)
        if user is None:
            return Failures.unknown_user_id(id_user)

        user.locale = locale
        db.session.commit()

        logging.info('User-controller: doLocaleChange: success: %s (%s)',
                     id_user, user.screen_name)

        return {
            'success': True,
            'user': {
                'id': user.id,
                'email': user.email,
                'locale': user.locale,
                'screenname': user.screen_name,
                'authentication-source': user.auth_source,
                'bdmonth': user.birth_month,
                'bdyear': user.birth_year,
                'parent-email': user.parent_email,
                'parent-email-source': user.parent_email_source
            }
        }
Exemple #29
0
    def loadHucWeb(self, code):
        """ Load all sites from a given huc code into the manager object.
        
        :param code: The HUC code being loaded. """
        if code in self.ids:
            return True
        ids = GDALData.loadHUCSites(code)
        if Failures.isFailureCode(ids):
            return ids

        self.ids[code] = sorted(ids, key=lambda id: Helpers.getFullID(id))

        return True
Exemple #30
0
    def findNextLowerStreamLevelPath(self,
                                     segment,
                                     downStreamPositionOnSegment=0,
                                     expand=True):
        """ Navigate downstream until a path with lower streamlevel is found.
        
        :param segment: The segment to search downstream from.
        :param downStreamPositionOnSegment: The position on the segment the search started from. This is used to get accurate distance measurements.
        :param expand: Do we expand the graph to help fulfil this query?
        
        :return: This function returns the first segment directly upstream from the junction of the main path and the tributary that 'segment' is on. """
        tribLevel = segment.streamLevel

        dist = -downStreamPositionOnSegment  #when we sum dist up, we must subtract
        #this from the first segment's length

        queue = []
        queue.append(segment)

        nextMainPath = None
        while len(queue) > 0:
            current = queue.pop(0)
            dist += current.length
            if current.streamLevel < tribLevel:
                #if we find a lower stream level it is downstream from the trib we started on
                # so to find the next main stream path, we have to go up from this segment along the matching streamlevel neighbor
                upstreamNeighbors = current.upStreamNode.getUpstreamNeighbors()
                for neighbor in upstreamNeighbors:
                    if neighbor.streamLevel == current.streamLevel:
                        nextMainPath = neighbor
                        break
            else:
                downstreamPoint = current.downStreamNode.position
                if not self.streamGraph.pointWithinSafeDataBoundary(
                        downstreamPoint) and expand:
                    graphExpansion = self.streamGraph.expandGraph(
                        downstreamPoint[1], downstreamPoint[0])

                    if Failures.isFailureCode(graphExpansion):
                        return graphExpansion
                    elif self.terminateSearchOnQuery is True:
                        return Failures.QUERY_TERMINATE_CODE

                nextSegments = current.downStreamNode.getDownstreamNeighbors(
                )  #getCodedNeighbors(DOWNSTREAM)#most likely only one such segment unless there is a fork in the river
                queue.extend(nextSegments)

        if nextMainPath is not None:
            return (nextMainPath, dist)
        else:
            return Failures.END_OF_BASIN_CODE
def beautifyID (siteID, lowerBound, upperBound, warningLog):
    siteID = str(siteID)
    shortenedID = siteID[:7]
    DSN = int(Helpers.getFullID(siteID)[2:])
    partCode = siteID[:2]

    lowerBoundDSN = int(Helpers.getFullID(lowerBound)[2:])
    upperBoundDSN = int(Helpers.getFullID(upperBound)[2:])
    
    roundingPrecisions = [100, 50, 20, 10, 5, 2, 1]

    #now check if this number exists already
    idsInfo = GDALData.getSiteIDsStartingWith(shortenedID)
    if Failures.isFailureCode(idsInfo):
        warningLog.addWarning(WarningLog.LOW_PRIORITY, "Cannot verify if this site number already exists(" + idsInfo + "). Ensure this step is manually completed.")
        return siteID
    
    siteLayer = idsInfo

    existingNumbers = set()
    for site in siteLayer:
        siteNumber = site["properties"]["site_no"]
        existingNumbers.add(siteNumber)
    
    for roundTo in roundingPrecisions:
        roundedDSN = Helpers.roundTo(DSN, roundTo)
        fullRounded = Helpers.buildFullID(partCode, roundedDSN)
        if fullRounded not in existingNumbers and Helpers.betweenBounds(roundedDSN, lowerBoundDSN, upperBoundDSN):
            return Helpers.shortenID(fullRounded)

    #if we haven't returned yet we have a problem.
    idMinusExtension = siteID[:8]

    #as a last ditch effort, try all extensions to find one that's unique
    if len(existingNumbers) > 0:
        #if the ID we want is taken, try all possible extensions until one is free
        for i in range(0, 100):
            testExtension = str(i)

            if len(testExtension) == 1:
                testExtension = "0" + testExtension

            testNewID = idMinusExtension + testExtension

            testNewDSN = int(testNewID[2:])

            if testNewID not in existingNumbers and Helpers.betweenBounds(testNewDSN, lowerBoundDSN, upperBoundDSN):
                return testNewID
    
    warningLog.addWarning(WarningLog.MED_PRIORITY, "Failed to find gap in ID space for new ID. This ID already exists.")
    return siteID    
    def get(self, email):
        # Get values
        server = request.headers.get('server')

        # Validate required fields
        validation = Validation()
        validation.add_required_field('email', email)
        validation.add_required_field('server', server)
        validation.check_email('email', email)
        if not validation.is_valid():
            return validation.get_validation_response()

        # Validate user exits
        user = user_service.get_user_by_email(email)
        if user is None:
            return Failures.unknown_user_email(email)

        if user.auth_source != 'local':
            return Failures.wrong_auth_source(user.auth_source)

        if not user.confirmed:
            return Failures.email_not_confirmed(user.email)

        success, code, message = user_service.send_password_reset(user.id, server)

        db.session.commit()

        if success:
            logging.info('LocalUser-controller: RequestPasswordReset: success: %s', user.id)
            return {'success': True}
        else:
            if code == 10:
                return Failures.rate_exceeded()
            return {
                'success': False,
                'message': message,
                'code': 520
            }
    def post(id_user):
        locale = request.form.get('locale')

        # Validate required fields
        validation = Validation()
        validation.add_required_field('id-user', id_user)
        validation.add_required_field('locale', locale)
        if not validation.is_valid():
            return validation.get_validation_response()

        # Parse numbers
        try:
            id_user = int(id_user)
        except ValueError:
            return Failures.not_a_number('idUser', id_user)

        # Validate user exists, is validated and is not blocked
        user = user_service.get_user(id_user)
        if user is None:
            return Failures.unknown_user_id(id_user)

        user.locale = locale
        db.session.commit()

        logging.info('User-controller: doLocaleChange: success: %s (%s)', id_user, user.screen_name)

        return {'success': True, 'user': {
            'id': user.id,
            'email': user.email,
            'locale': user.locale,
            'screenname': user.screen_name,
            'authentication-source': user.auth_source,
            'bdmonth': user.birth_month,
            'bdyear': user.birth_year,
            'parent-email': user.parent_email,
            'parent-email-source': user.parent_email_source
        }}
Exemple #34
0
    def post(self):
        # Get values
        server = request.headers.get('server')
        email = request.form.get('email')
        locale = request.form.get('locale')
        screen_name = request.form.get('screenname')
        source = request.form.get('source')

        # Validate required fields
        validation = Validation()
        validation.add_required_field('server', server)
        validation.add_required_field('email', email)
        validation.add_required_field('locale', locale)
        validation.add_required_field('screenname', screen_name)
        validation.add_required_field('source', source)
        validation.check_email('email', email)
        if not validation.is_valid():
            return validation.get_validation_response()

        # Validate email is not yet used
        existing_user = user_service.get_user_by_email(email)
        if existing_user is not None:
            return Failures.email_already_in_use(email)

        # Validate screen name is not yet used
        existing_user = user_service.get_user_by_screen_name(screen_name)
        if existing_user is not None:
            return Failures.screen_name_already_in_use(screen_name)

        id_user = user_service.create_oauth_user(server, email, source, locale, screen_name)

        db.session.commit()

        logging.info('OAuth-controller: create success: %s', id_user)

        # Create user
        return {'success': True, 'user': id_user}
Exemple #35
0
def getSiteIDsStartingWith (siteID, timeout = TIMEOUT):
    similarSitesQuery = "https://waterdata.usgs.gov/nwis/inventory?search_site_no=" + siteID + "&search_site_no_match_type=beginning&site_tp_cd=ST&group_key=NONE&format=sitefile_output&sitefile_output_format=xml&column_name=site_no&column_name=station_nm&column_name=site_tp_cd&column_name=dec_lat_va&column_name=dec_long_va&column_name=huc_cd&list_of_search_criteria=search_site_no%2Csite_tp_cd"
    result = queryWithAttempts (similarSitesQuery, QUERY_ATTEMPTS, timeout = timeout, queryName="similarSiteIds")
    
    if Failures.isFailureCode(result):
        return result

    geoJsonResults = buildGeoJson(result.text)
    try:
        sitesLayer = json.loads(geoJsonResults)["features"]
    except:
        if __debug__:
            print("could not read query")
        return Failures.QUERY_PARSE_FAILURE_CODE
    return (sitesLayer)  
Exemple #36
0
    def get(self, bucket_type, id_user, count):
        # Validate required fields
        validation = Validation()
        validation.add_required_field('bucket_type', bucket_type)
        validation.add_required_field('id_user', id_user)
        validation.add_required_field('count', count)
        if not validation.is_valid():
            return validation.get_validation_response()

        # Parse numbers
        try:
            id_user = int(id_user)
        except ValueError:
            return Failures.not_a_number('idUser', id_user)

        try:
            count = int(count)
        except ValueError:
            return Failures.not_a_number('count', count)

        # Validate user exists, is validated and is not blocked
        user = user_services.get_user(id_user)

        if user is None:
            return Failures.unknown_user_id(id_user)
        if user.blocked:
            return Failures.user_blocked()
        if not user.confirmed:
            return Failures.email_not_confirmed()

        bucket_types = app.config['CLOUD_SESSION_PROPERTIES'][
            'bucket.types'].split(',')

        if bucket_type not in bucket_types:
            return Failures.unknown_bucket_type(bucket_type)

        result, next_time = rate_limiting_services.consume_tokens(
            user.id, bucket_type, 1)

        if not result:
            db.session.commit()
            return Failures.rate_exceeded(
                next_time.strftime("%Y-%m-%d %H:%M:%S"))

        db.session.commit()

        logging.info(
            'RateLimiting-controller: ConsumeMultiple: success: %s (%s - %s)',
            id_user, bucket_type, count)

        return {'success': True}
    def post(self):
        # Get values
        server = request.headers.get('server')
        email = request.form.get('email')
        password = request.form.get('password')
        #browser = request.form.get('browser')
        #ip_address = request.form.get('ipAddress')

        # Validate required fields
        validation = Validation()
        validation.add_required_field('server', server)
        validation.add_required_field('email', email)
        validation.add_required_field('password', password)
        #validation.add_required_field('browser', browser)
        #validation.add_required_field('ipAddress', ip_address)
        if not validation.is_valid():
            return validation.get_validation_response()

        # Validate user exists, is validated and is not blocked
        user = user_services.get_user_by_email(email)
        if user is None:
            return Failures.unknown_user_email(email)
        if not user.confirmed:
            return Failures.email_not_confirmed()
        if user.blocked:
            return Failures.user_blocked()
        if user.auth_source != 'local':
            return Failures.wrong_auth_source(user.auth_source)

        if not rate_limiting_services.has_sufficient_tokens(
                user.id, 'failed-password', 1):
            return Failures.rate_exceeded()

        if not user_services.check_password(user.id, password):
            rate_limiting_services.consume_tokens(user.id, 'failed-password',
                                                  1)
            db.session.commit()
            return Failures.wrong_password()

        db.session.commit()

        logging.info('Authenticate-controller: Authenticate: success: %s',
                     user.id)

        return {
            'success': True,
            'user': {
                'id': user.id,
                'email': user.email,
                'locale': user.locale,
                'screenname': user.screen_name,
                'authentication-source': user.auth_source
            }
        }
    def post(self):
        # Get values
        server = request.headers.get('server')
        email = request.form.get('email')
        password = request.form.get('password')

        # Validate required fields
        validation = Validation()
        validation.add_required_field('server', server)
        validation.add_required_field('email', email)
        validation.add_required_field('password', password)

        if not validation.is_valid():
            return validation.get_validation_response()

        # Validate user exists, is validated and is not blocked
        user = user_services.get_user_by_email(email)

        if user is None:
            return Failures.unknown_user_email(email)

        if not user.confirmed:
            return Failures.email_not_confirmed(email)

        if user.blocked:
            return Failures.user_blocked(email)

        if user.auth_source != 'local':
            return Failures.wrong_auth_source(user.auth_source)

        if not rate_limiting_services.has_sufficient_tokens(user.id, 'failed-password', 1):
            return Failures.rate_exceeded()

        if not user_services.check_password(user.id, password):
            rate_limiting_services.consume_tokens(user.id, 'failed-password', 1)
            db.session.commit()
            return Failures.wrong_password(email)

        db.session.commit()

        logging.info('Authenticate-controller: Authenticate: success: %s', email)

        return {'success': True, 'user': {
            'id': user.id,
            'email': user.email,
            'locale': user.locale,
            'screenname': user.screen_name,
            'authentication-source': user.auth_source,
            'bdmonth': user.birth_month,
            'bdyear': user.birth_year,
            'parent-email': user.parent_email,
            'parent-email-source': user.parent_email_source
        }}
Exemple #39
0
    def __init__(self, lat, lng, withheldSites=[]):
        self.lat = lat
        self.lng = lng
        self.warningLog = WarningLog.WarningLog(lat, lng)
        self.streamGraph = StreamGraph(withheldSites=withheldSites,
                                       warningLog=self.warningLog)
        self.siteIDManager = SiteIDManager()
        self.context = None
        self.baseData = GDALData.loadFromQuery(self.lat, self.lng)

        if Failures.isFailureCode(self.baseData):
            if __debug__:
                print("could not get data")
            self.warningLog.addWarning(WarningLog.HIGH_PRIORITY, self.baseData)
        else:
            self.streamGraph.addGeom(self.baseData)

        self.siteNameContext = None
    def get(self, bucket_type, id_user, count):
        # Validate required fields
        validation = Validation()
        validation.add_required_field('bucket_type', bucket_type)
        validation.add_required_field('id_user', id_user)
        validation.add_required_field('count', count)
        if not validation.is_valid():
            return validation.get_validation_response()

        # Parse numbers
        try:
            id_user = int(id_user)
        except ValueError:
            return Failures.not_a_number('idUser', id_user)

        try:
            count = int(count)
        except ValueError:
            return Failures.not_a_number('count', count)

        # Validate user exists, is validated and is not blocked
        user = user_services.get_user(id_user)

        if user is None:
            return Failures.unknown_user_id(id_user)
        if user.blocked:
            return Failures.user_blocked()
        if not user.confirmed:
            return Failures.email_not_confirmed()

        bucket_types = app.config['CLOUD_SESSION_PROPERTIES']['bucket.types'].split(',')

        if bucket_type not in bucket_types:
            return Failures.unknown_bucket_type(bucket_type)

        result, next_time = rate_limiting_services.consume_tokens(user.id, bucket_type, 1)

        if not result:
            db.session.commit()
            return Failures.rate_exceeded(next_time.strftime("%Y-%m-%d %H:%M:%S"))

        db.session.commit()

        logging.info('RateLimiting-controller: ConsumeMultiple: success: %s (%s - %s)', id_user, bucket_type, count)

        return {'success': True}
    def get(screen_name):
        # Validate user exists, is validated and is not blocked
        user = user_service.get_user_by_screen_name(screen_name)

        if user is None:
            return Failures.unknown_user_screen_name(screen_name)

        logging.info('User-controller: getUserByScreenname: success: %s (%s)', screen_name, user.screen_name)

        return {'success': True, 'user': {
            'id': user.id,
            'email': user.email,
            'locale': user.locale,
            'screenname': user.screen_name,
            'authentication-source': user.auth_source,
            'bdmonth': user.birth_month,
            'bdyear': user.birth_year,
            'parent-email': user.parent_email,
            'parent-email-source': user.parent_email_source
        }}
    def get(email):
        # TODO: Validate the format of the email address before attempting database IO

        # Validate user exists, is validated and is not blocked
        user = user_service.get_user_by_email(email)

        if user is None:
            return Failures.unknown_user_email(email)

        logging.info('User-controller: getUserByEmail: success: %s (%s)', email, user.screen_name)

        return {'success': True, 'user': {
            'id': user.id,
            'email': user.email,
            'locale': user.locale,
            'screenname': user.screen_name,
            'authentication-source': user.auth_source,
            'bdmonth': user.birth_month,
            'bdyear': user.birth_year,
            'parent-email': user.parent_email,
            'parent-email-source': user.parent_email_source
        }}
    def post():
        # Get values
        server = request.headers.get('server')
        email = request.form.get('email')
        password = request.form.get('password')
        password_confirm = request.form.get('password-confirm')
        locale = request.form.get('locale')
        screen_name = request.form.get('screenname')

        # COPPA support
        birth_month = request.form.get('bdmonth')
        birth_year = request.form.get('bdyear')
        parent_email = request.form.get('parent-email')
        parent_email_source = request.form.get('parent-email-source')

        # Validate required fields
        validation = Validation()
        validation.add_required_field('server', server)
        validation.add_required_field('email', email)
        validation.add_required_field('password', password)
        validation.add_required_field('password-confirm', password_confirm)
        validation.add_required_field('locale', locale)
        validation.add_required_field('screenname', screen_name)

        # COPPA support
        validation.add_required_field('bdmonth', birth_month)
        validation.add_required_field('bdyear', birth_year)
        if parent_email:
            validation.check_email('parent-email', parent_email)
            if not validation.is_valid():
                return validation.get_validation_response()

        # Verify user email address
        validation.check_email('email', email)
        if not validation.is_valid():
            return validation.get_validation_response()

        # Validate email is not yet used
        existing_user = user_service.get_user_by_email(email)
        if existing_user is not None:
            return Failures.email_already_in_use(email)

        # Validate screen name is not yet used
        existing_user = user_service.get_user_by_screen_name(screen_name)
        if existing_user is not None:
            return Failures.screen_name_already_in_use(screen_name)

        # Validate password strength and confirm
        if password != password_confirm:
            return Failures.passwords_do_not_match()
        if not user_service.check_password_complexity(password):
            return Failures.password_complexity()

        # Write user details to the database
        id_user = user_service.create_local_user(
            server, email, password, locale, screen_name,
            birth_month, birth_year, parent_email, parent_email_source)

        # Send a confirmation request email to user or parent
        (result, errno, mesg) = user_service.send_email_confirm(id_user, server)
        if result:
            # Commit the database record
            db.session.commit()
            logging.info('User-controller: register success: %s', id_user)

            # Create user
            return {'success': True, 'user': id_user}
        else:
            logging.error("Unable to register user. Error %s: %s", errno, mesg)
            return {'success': False, 'user': 0}