コード例 #1
0
ファイル: upload_images.py プロジェクト: viahoon/Data_API
def set_profile_picture(user_uuid, picture_url):
    query = datastore.get_client().query(kind='Users')
    query.add_filter('user_uuid', '=', user_uuid)
    user = list(query.fetch(1))[0]

    user['profile_image'] = picture_url
    datastore.get_client().put(user)
コード例 #2
0
def submit_horticulture_measurements():
    """Save horticulture measurements from a device.

    .. :quickref: Horticulture; Save horticulture measurements

    :reqheader Accept: application/json
    :<json string user_token: User Token returned from the /login API.
    :<json string device_uuid: Device UUID in which plant was measured
    :<json string leaves_count: Leaf count
    :<json string plant_height: Plant height in cm

    **Example response**:

        .. sourcecode:: json

          {
            "message": "Measurements saved.",
            "response_code": 200
          }
    """
    received_form_response = json.loads(request.data.decode('utf-8'))
    user_token = received_form_response.get('user_token')
    device_uuid = received_form_response.get('device_uuid')

    user_uuid = get_user_uuid_from_token(user_token)
    if user_uuid is None or device_uuid is None:
        return error_response(message='Invalid User: Unauthorized.')

    leaves_count = received_form_response.get("leaves_count")
    plant_height = received_form_response.get("plant_height")
    horticulture_notes = received_form_response.get("horticulture_notes")
    if leaves_count == None and plant_height == None and horticulture_notes == None:
        return error_response()

    # Add the user to the users kind of entity
    key = datastore.get_client().key('HorticultureMeasurements')

    # Indexes every other column except the description
    horitculture_reg_task = gcds.Entity(key, exclude_from_indexes=[])

    horitculture_reg_task.update({
        'device_uuid':
        device_uuid,
        'measurement':
        json.dumps({
            "leaves_count": leaves_count,
            "plant_height": plant_height,
            "horticulture_notes": horticulture_notes,
        }),
        "modified_at":
        datetime.now()
    })

    datastore.get_client().put(horitculture_reg_task)

    return success_response(message="Measurements saved.")
コード例 #3
0
def delete_recipe():
    """Delete a users recipe.

    .. :quickref: Recipe; Delete recipe

    :reqheader Accept: application/json
    :<json string user_token: User's Token.
    :<json string recipe_uuid: Recipe UUID.

    **Example response**:

        .. sourcecode:: json

          {
            "message": "success",
            "response_code": 200
          }
    """
    received_form_response = json.loads(request.data.decode('utf-8'))
    user_token = received_form_response.get("user_token", "")
    recipe_uuid = received_form_response.get("recipe_uuid")
    testing = received_form_response.get("testing")

    if user_token is None or recipe_uuid is None:
        return error_response(
            message="Please make sure you have added values for all the fields"
        )

    # Get user uuid associated with this sesssion token
    user_uuid = get_user_uuid_from_token(user_token)
    if user_uuid is None:
        return error_response(message="Invalid User: Unauthorized")

    # If pytest is calling this, don't actually save a recipe
    if testing:
        return success_response(message="test worked")

    # Get the recipe
    recipe = datastore.get_one_from_DS('Recipes', 'recipe_uuid', recipe_uuid)
    if recipe is None:
        return error_response(message="Invalid recipe uuid.")

    # Only delete the recipe if it has the users user_uuid
    if recipe.get('user_uuid') != user_uuid:
        return error_response(message="User does not own this recipe.")

    # Delete it.
    datastore.get_client().delete(key=recipe.key)

    return success_response(message="Successfully saved.")
コード例 #4
0
def verify_user_session():
    """Verify the user's session token is still valid.
    .. :quickref: Authentication; Verify user's session

    :reqheader Accept: application/json
    :<json string user_token: User Token returned from the /login API.

    **Example response**:

        .. sourcecode:: json

          {
            "message": "Successful",
            "is_expired": "True",
            "response_code": 200
          }
    """
    received_form_response = json.loads(request.data.decode('utf-8'))
    user_token = received_form_response.get("user_token", None)
    query_session = datastore.get_client().query(kind="UserSession")
    query_session.add_filter('session_token', '=', user_token)
    query_session_result = list(query_session.fetch())
    expired = True
    user_uuid = None
    if len(query_session_result) > 0:
        user_uuid = query_session_result[0].get("user_uuid", None)
        session_expiration = query_session_result[0].get("expiration_date")
        if session_expiration is not None:
            expired = is_expired(session_expiration)

    return success_response(
        message="Successful",
        is_expired=expired,
        user_uuid=user_uuid
    )
コード例 #5
0
ファイル: user_authenticate.py プロジェクト: viahoon/Data_API
def signup_user_oauth():
    username = g.user_info["sub"]
    email_address = g.user_info["email"]
    password = ''.join([
        random.choice(string.ascii_letters + string.digits) for n in range(32)
    ])  # received_form_response.get("password")
    organization = None  #received_form_response.get("organization")
    testing = False  # received_form_response.get("testing")

    if not (username and email_address):
        return error_response(
            message="Please make sure you have added values for all the fields"
        )

    if not is_email(email_address, check_dns=True):
        return error_response(message="Invalid email.")

    if testing:  # our pytest is hitting this API, so don't create the user
        return success_response()

    new_user = User(username=username,
                    password=password,
                    email_address=email_address,
                    organization=organization)
    user_uuid = new_user.insert_into_db(datastore.get_client())
    return new_user
コード例 #6
0
 def remove_command(self, device_ID: str, command: str) -> None:
     # get any existing entity for this command and delete it.
     entity = self.get_command_entity(device_ID, command)
     if entity is not None:
         # delete this entity
         DS = datastore.get_client()
         DS.delete(key=entity.key)
     logging.debug(f'{self.name}.remove_command {command}')
コード例 #7
0
def get_device_peripherals():
    """Get peripherals. Used for recipe editor.

    .. :quickref: Recipe; Get peripherals

    :reqheader Accept: application/json
    :<json string user_token: User Token returned from the /login API.
    :<json string selected_peripherals: Comma separated list of peripheral UUIDs

    **Example Response**:

      .. sourcecode:: json

        {
          "results":[{
            "name": "Name",
            "sensor_name": "Sensor Name",
            "type": "Sensor Type",
            "color": "#FFAA00",
            "inputs": "inputs"
          }]
        }

    """
    received_form_response = json.loads(request.data.decode('utf-8'))
    user_token = received_form_response.get("user_token")
    peripherals_string = received_form_response.get("selected_peripherals")
    if user_token is None or peripherals_string is None:
        return error_response(
            message="Access denied."
        )

    peripheral_details = []
    peripherals_array = peripherals_string.split(",")

    for peripheral in peripherals_array:
        if len(peripheral) == 0:
            return error_response()

        query = datastore.get_client().query(kind='Peripherals')
        query.add_filter('uuid', '=', str(peripheral))
        peripheraldetails = list(query.fetch())

        if len(peripheraldetails) == 0:
            return error_response()

        peripheral_detail_json = {
            "name":peripheraldetails[0]["name"],
            "sensor_name":peripheraldetails[0]["sensor_name"],
            "type":peripheraldetails[0]["type"],
            "color":"#"+peripheraldetails[0]["color"],
            "inputs": peripheraldetails[0]["inputs"]
        }
        peripheral_details.append(peripheral_detail_json)

    return success_response(
        results=peripheral_details
    )
コード例 #8
0
ファイル: user_authenticate.py プロジェクト: viahoon/Data_API
def login():
    """Log a user into this API, returns a session token.

    .. :quickref: Authentication; Log in

    :reqheader Accept: application/json
    :<json string username: Users username (from the /api/signup API call)
    :<json string password: Users password (from the /api/signup API call)

    **Example response**:

        .. sourcecode:: json

          {
            "user_uuid": "Users UUID from the registration process",
            "user_token": "token string",
            "is_admin": False
            "message": "Login Successful"
            "response_code": 200
          }
    """
    received_form_response = json.loads(request.data.decode('utf-8'))

    username = received_form_response.get("username")
    password = received_form_response.get("password")

    if not (username and password):
        return error_response(
            message="Please make sure you have added values for all the fields"
        )

    user = User(username=username, password=password)
    user_uuid, is_admin = user.login_user(client=datastore.get_client())
    if user_uuid is None:
        return error_response(
            message="Login failed. Please check your credentials.")

    session_token = UserSession(user_uuid=user_uuid).insert_into_db(
        client=datastore.get_client())
    return success_response(user_uuid=user_uuid,
                            user_token=session_token,
                            is_admin=is_admin,
                            message="Login Successful")
コード例 #9
0
 def remove_all_commands(self, device_ID: str) -> None:
     # get list of all entities by time
     entities = datastore.get_sharded_entities(
         datastore.DS_device_data_KIND, self.schedule_property, device_ID)
     if 0 == len(entities):
         return None
     DS = datastore.get_client()
     for e in entities:
         DS.delete(key=e.key)
     logging.debug(f'{self.name}.remove_all_commands done.')
コード例 #10
0
def save_user_profile_changes():
    """Update the users' profile information.

    .. :quickref: User; Update profile 

    :reqheader Accept: application/json
    :<json string user_token: User Token returned from the /login API.
    :<json string email_address: Users email address
    :<json string username: Users username (and login name)
    :<json string organization: The organizaion the user is associated with

    **Example response**:

        .. sourcecode:: json

          {
            "profile_image": "previously saved profile image",
            "username": "******",
            "email_address": "saved email address",
            "organization": "saved organization",
            "response_code": 200
          }
    """
    received_form_response = request.get_json()

    user_token = received_form_response.get("user_token")
    if user_token is None:
        return error_response(
            message="Please make sure you have added values for all the fields"
        )

    user_uuid = get_user_uuid_from_token(user_token)
    if user_uuid is None:
        return error_response(message="Invalid User: Unauthorized")

    query = datastore.get_client().query(kind='Users')
    query.add_filter('user_uuid', '=', user_uuid)
    user = list(query.fetch(1))[0]

    # This checks if inputs are empty strings as well.
    email_address = get_non_empty(received_form_response, 'email_address',
                                  user['email_address'])
    username = get_non_empty(received_form_response, 'username',
                             user['username'])
    org = get_non_empty(received_form_response, 'organization',
                        user['organization'])

    if not datastore.update_user(user_uuid, username, email_address, org):
        return error_response("nope")

    return success_response(profile_image=user.get('profile_image'),
                            username=user.get('username'),
                            email_address=user.get('email_address'),
                            organization=user.get('organization'))
コード例 #11
0
 def ack(self, device_ID: str, notification_ID: str) -> None:
     entities = datastore.get_sharded_entities(
         datastore.DS_device_data_KIND, self.dd_property, device_ID)
     for e in entities:
         data = e.get(datastore.DS_DeviceData_data_Property, {})
         if data.get(self.ID_key) == notification_ID:
             # delete this entity (as a form of acknowledging it and
             # keeping the list of notifications from growing without
             # bounds).
             DS = datastore.get_client()
             DS.delete(key=e.key)
             break
コード例 #12
0
def get_device_images():
    """Returns all images associated with device.

    .. :quickref: Sensor Data; Image list

    :reqheader Accept: application/json
    :<json string user_token: User Token returned from the /login API.
    :<json string device_uuid: Device UUID

    **Example response**:

        .. sourcecode:: json

          {
            "image_urls": ["URL1", "URL2"],
            "response_code": 200 
          }
    """
    parameters = request.get_json()

    user_token = parameters.get('user_token')
    user_uuid = get_user_uuid_from_token(user_token)
    if user_uuid is None:
        return error_response(
            message='Invalid token. Unauthorized.'
        )

    device_uuid = parameters.get('device_uuid')
    if device_uuid is None:
        return error_response(
            message='No device_uuid submitted.'
        )

    # Sort by date descending and take the first 50
    # This is equivalent to taking the most recent 50 images
    # Then, reverse the order so it's chronological
    image_query = datastore.get_client().query(kind="Images",
                                         order=['-creation_date'])
    image_query.add_filter('device_uuid', '=', device_uuid)
    images = list(image_query.fetch(100))[::-1]

    if not images:
        return error_response(
            message='No images associated with device.'
        )

    image_urls = list(map(decode_url, images))

    return success_response(
        image_urls=image_urls
    )
コード例 #13
0
def get_devices_for_user(user_uuid):
    query = datastore.get_client().query(kind='Devices')
    query.add_filter('user_uuid', '=', user_uuid)
    query_results = list(query.fetch())

    devices = []
    for device in query_results:
        device_json = pre_serialize_device(device)
        print('    {}, {}, {}'.format(device_json['device_uuid'],
                                      device_json['device_reg_no'],
                                      device_json['device_name']))
        devices.append(device_json)

    return devices
コード例 #14
0
ファイル: user_authenticate.py プロジェクト: viahoon/Data_API
def oauth_login():
    client = datastore.get_client()
    query = client.query(kind='Users')
    query.add_filter('email_address', '=', g.user_info['email'])
    query_result = list(query.fetch(1))
    if not query_result:
        user = signup_user_oauth()
        user_uuid = user.user_uuid
        is_admin = False  # TODO: This shouldn't come from here but from the tokens...
    else:
        user = query_result[0]
        user_uuid = user.get('user_uuid')
        is_admin = user.get('is_admin', False)

    if user_uuid is None:
        return error_response(
            message="Login failed. Please check your credentials.")
    session_token = UserSession(user_uuid=user_uuid).insert_into_db(
        client=datastore.get_client())
    return success_response(user_uuid=user_uuid,
                            user_token=session_token,
                            is_admin=is_admin,
                            message="Login Successful")
コード例 #15
0
ファイル: user_authenticate.py プロジェクト: viahoon/Data_API
def signup():
    """Create a user account.

    .. :quickref: Authentication; Create account

    :reqheader Accept: application/json
    :<json string username: Users login name
    :<json string email_address: Users email address
    :<json string password: Users password
    :<json string organization: Users organization (self chosen)

    **Example response**:

        .. sourcecode:: json

          {
            "response_code": 200
          }
    """
    received_form_response = json.loads(request.data.decode('utf-8'))
    username = received_form_response.get("username")
    email_address = received_form_response.get("email_address")
    password = received_form_response.get("password")
    organization = received_form_response.get("organization")
    testing = received_form_response.get("testing")

    if not (username and email_address and password):
        return error_response(
            message="Please make sure you have added values for all the fields"
        )

    if not is_email(email_address, check_dns=True):
        return error_response(message="Invalid email.")

    if testing:  # our pytest is hitting this API, so don't create the user
        return success_response()

    user_uuid = User(username=username,
                     password=password,
                     email_address=email_address,
                     organization=organization).insert_into_db(
                         datastore.get_client())

    if user_uuid:
        return success_response()
    else:
        return error_response(message="User creation failed.")
コード例 #16
0
ファイル: get_user_info.py プロジェクト: viahoon/Data_API
def get_user_image():
    """Get user profile information.

    .. :quickref: User; User profile

    :reqheader Accept: application/json
    :<json string user_token: User Token returned from the /login API.

    **Example Response**:

      .. sourcecode:: json

        {
            "profile_image": null,
            "username": "******",
            "email_address": "*****@*****.**",
            "organization": "Example Foundation",
            "response_code": 200
        }

    """
    received_form_response = request.get_json()

    user_token = received_form_response.get("user_token")
    if user_token is None:
        return error_response(
            message="Please make sure you have added values for all the fields"
        )

    user_uuid = get_user_uuid_from_token(user_token)
    if user_uuid is None:
        return error_response(
            message="Invalid User: Unauthorized"
        )

    query = datastore.get_client().query(kind='Users')
    query.add_filter('user_uuid', '=', user_uuid)
    user = list(query.fetch(1))[0]

    return success_response(
        profile_image=user.get('profile_image'),
        username=user.get('username'),
        email_address=user.get('email_address'),
        organization=user.get('organization')
    )
コード例 #17
0
    def stop(self, device_ID: str) -> None:
        # have to get the datastore entity to update it.
        entities = datastore.get_sharded_entities(
                datastore.DS_device_data_KIND, 
                self.runs_property, device_ID, count=1)
        if 0 == len(entities):
            logging.error(f'{self.name}.stop no current run for {device_ID}')
            return

        e = entities[0] # only one entity in the list
        # get this entities data property and update it
        run = e.get(datastore.DS_DeviceData_data_Property, {})
        run[self.end_key] = dt.datetime.utcnow().strftime('%FT%XZ')

        # put entity back in datastore
        DS = datastore.get_client()
        DS.put(e)
        logging.debug(f'{self.name}.stopped run {run}')
コード例 #18
0
def get_plant_types():
    """Get known plant types.  For the recipe editor.

    .. :quickref: Utility; Plant types 

    **Example Response**:

      .. sourcecode:: json

        {
          "results": [
                        {
                          "name": "Basil",
                          "variants": "Sweet Basil, Purple Basil"
                        },
                        {
                          "name": "Lettuce",
                          "variants": "Iceberg, Butterhead, Rocket, Mizuna, Romaine"
                        }
                    ],
          "response_code": 200
        }

    """
    received_form_response = request.get_json()
    user_token = received_form_response.get("user_token")
    if user_token is None:
        return error_response(message="Access denied.")

    query = datastore.get_client().query(kind='Plants')
    query_result = list(query.fetch())
    results = list(query_result)

    results_array = []
    for result in results:
        plant_type_json = {
            'name': result['name'],
            'variants': result['variants']
        }
        results_array.append(plant_type_json)

    return success_response(results=results_array)
コード例 #19
0
ファイル: get_device_types.py プロジェクト: viahoon/Data_API
def get_device_types():
    """Get a list of all device types.

    .. :quickref: Utility; Device types

    :reqheader Accept: application/json
    :<json string user_token: User Token returned from the /login API.

    **Example Response**:

      .. sourcecode:: json

        {
          "results": [{
              "name": "EDU",
              "device_type_id": "Type-UUID",
              "peripherals": ["P1-UUID", "P2-UUID", "P3-UUID"]
            }],
          "response_code": 200
        }

    """
    received_form_response = request.get_json()
    user_token = received_form_response.get("user_token")
    if user_token is None:
        return error_response(message="Access denied.")

    query = datastore.get_client().query(kind='DeviceType')
    query_result = list(query.fetch())
    results = list(query_result)

    results_array = []
    for result in results:
        device_type_json = {
            'peripherals': result['peripherals'],
            'device_type_id': result['id'],
            'name': result['name']
        }
        results_array.append(device_type_json)

    return success_response(results=results_array)
コード例 #20
0
def get_recipe_by_uuid():
    """Return the recipe. Used to build an editor to modify this recipe.  

    .. :quickref: Recipe; Recipe details 

    :reqheader Accept: application/json
    :<json string user_token: User Token returned from the /login API.
    :<json string recipe_uuid: Recipe UUID to look up

    **Example response**:

        .. sourcecode:: json

            "recipe": "recipe JSON string",
            "devices": "user devices",
            "response_code": 200
          }
    """
    received_form_response = request.get_json()
    user_token = received_form_response.get("user_token")
    recipe_uuid = received_form_response.get("recipe_uuid")
    if user_token is None or recipe_uuid is None:
        return error_response(
            message="Please make sure you have added values for all the fields"
        )

    user_uuid = get_user_uuid_from_token(user_token)
    if user_uuid is None:
        return error_response(message="Invalid User: Unauthorized")

    devices = get_devices_for_user(user_uuid)

    # Get queried recipe
    recipes_query = datastore.get_client().query(kind='Recipes')
    recipes_query.add_filter("recipe_uuid", "=", recipe_uuid)
    recipes_query_results = list(recipes_query.fetch())
    if 0 < len(recipes_query_results):
        return success_response(recipe=recipes_query_results[0]["recipe"],
                                devices=devices)

    return error_response(message="No recipe with that UUID")
コード例 #21
0
ファイル: database.py プロジェクト: viahoon/cloud_common
def get_current_horticulture_log(device_uuid):
    # Initialize variables
    plant_height = None
    leaf_count = None
    submitted_at = None
    horticulture_notes = None

    # Query datastore
    query = datastore.get_client().query(kind="DailyHorticultureLog")
    query.add_filter("device_uuid", "=", device_uuid)
    query_result = list(query.fetch())

    # Validate results
    if len(query_result) == 0:
        return {
            "leaf_count": None,
            "plant_height": None,
            "submitted_at": None,
            "horticulture_notes": None
        }

    # Parse results
    for result in query_result:
        if not plant_height and "plant_height" in result:
            plant_height = result["plant_height"]
        if not leaf_count and "leaf_count" in result:
            leaf_count = result["leaf_count"]
        if not submitted_at and "submitted_at" in result:
            submitted_at = result["submitted_at"]
        if not horticulture_notes and "horticulture_notes" in result:
            horticulture_notes = result["horticulture_notes"]
        if plant_height and leaf_count and submitted_at and horticulture_notes:
            break
    return {
        "plant_height": plant_height,
        "leaf_count": leaf_count,
        "submitted_at": submitted_at,
        "horticulture_notes": horticulture_notes,
    }
コード例 #22
0
ファイル: apply_to_device.py プロジェクト: viahoon/Data_API
def apply_to_device():
    """Run a recipe on a device.

    .. :quickref: Recipe; Run recipe, run

    :reqheader Accept: application/json
    :<json string user_token: User Token returned from the /login API.
    :<json string device_uuid: UUID of device to apply recipe to
    :<json string recipe_uuid: UUID of recipe to run

    **Example response**:

        .. sourcecode:: json

          {
            "response_code": 200
          }

    """

    # Get request parameters
    request_json = json.loads(request.data.decode("utf-8"))
    device_uuid = request_json.get("device_uuid", None)
    recipe_uuid = request_json.get("recipe_uuid", None)
    user_token = request_json.get("user_token", None)

    # Validate parameters
    if device_uuid is None:
        return Response(json.dumps({"message": "Device UUID is required"}), 400)
    if recipe_uuid is None:
        return Response(json.dumps({"message": "Recipe UUID is required"}), 400)
    if user_token is None:
        return Response(json.dumps({"message": "User token is required"}), 400)

    # Get user from token
    user_uuid = get_user_uuid_from_token(user_token)
    if user_uuid is None:
        return Response(json.dumps({"message": "User token is invalid"}), 400)

    # Get recipe entry from datastore
    recipe_dict = {}
    query = datastore.get_client().query(kind="Recipes")
    query.add_filter("recipe_uuid", "=", recipe_uuid)
    results = list(query.fetch())

    # Verify recipe entry exists
    if len(results) < 0:
        return Response(json.dumps({"message": "Recipe uuid is invalid"}), 400)

    # Get recipe versions
    # NOTE: Versioning should not be done like this...
    device_software_version = datastore.get_device_software_version(device_uuid)
    versioned_recipe = results[0].get(f"recipe_v{device_software_version}")
    unversioned_recipe = results[0].get("recipe")

    # Get recipe dict
    if versioned_recipe is not None:
        recipe_dict = json.loads(versioned_recipe)
    else:
        recipe_dict = json.loads(unversioned_recipe)

    # Send recipe to device
    try:
        iot.send_start_recipe_command(device_uuid, recipe_uuid, recipe_dict)
        return Response(json.dumps({"message": "Sent recipe to device"}), 200)
    except iot.SendCommandError as e:
        print(f"Unable to send recipe to device: {e.message}")
        return Response(json.dumps({"message": e.message}), 503)
コード例 #23
0
def submit_recipe():
    """Save a recipe created or modified in the editor.

    .. :quickref: Recipe; Save recipe

    :reqheader Accept: application/json
    :<json string user_token: User's Token.
    :<json string recipe: JSON recipe.
    :<json string shared: 'true' if this is a shared recipe.

    **Example response**:

        .. sourcecode:: json

          {
            "message": "success",
            "response_code": 200
          }
    """
    received_form_response = json.loads(request.data.decode('utf-8'))
    user_token = received_form_response.get("user_token", "")
    recipe_json = received_form_response.get("recipe")
    shared = received_form_response.get("shared", 'false')
    testing = received_form_response.get("testing")

    print(f'recipe_json: {recipe_json}')

    if user_token is None or recipe_json is None:
        return error_response(
            message="Please make sure you have added values for all the fields"
        )

    # Get user uuid associated with this sesssion token
    user_uuid = get_user_uuid_from_token(user_token)
    if user_uuid is None:
        return error_response(
            message="Invalid User: Unauthorized"
        )

    # if pytest is calling this, don't actually save a recipe
    if testing:
        return success_response(message="test worked")

    # Make sure this recipe has a UUID, it could be null meaning a new recipe.
    current_ts = datetime.utcnow().strftime('%Y-%m-%dT%H:%M:%S:%f')[:-4] + 'Z'
    recipe_dict = json.loads(recipe_json)       # json > dict
    is_new = False
    if recipe_dict.get('uuid') is None:         # if no uuid, make one
        is_new = True
        new_uuid = str(uuid.uuid4())
        recipe_dict["uuid"] = new_uuid
        recipe_dict["creation_timestamp_utc"] = current_ts
        if 0 < len(recipe_dict["authors"]):
            recipe_dict["authors"][0]["uuid"] = user_uuid
    recipe_json = json.dumps(recipe_dict)       # dict > json

    # put a new recipe into the collection
    if is_new:
        entity = datastore.get_client().key('Recipes')
        recipe_reg_task = gcds.Entity(entity, exclude_from_indexes=["recipe"])

        recipe_reg_task.update({
            "recipe_uuid": recipe_dict.get("uuid"),
            "user_uuid": user_uuid,
            "recipe": recipe_json,
            "date_created": current_ts,
            "device_type": "PFC_EDU",
            "format": recipe_dict.get("format"),
            "version": recipe_dict.get("version"),
            "shared": shared,
            "image_url": recipe_dict.get("image_url"),
        })
        datastore.get_client().put(recipe_reg_task)
    else: # recipe exists, so update it
        query = datastore.get_client().query(kind='Recipes')
        query.add_filter('recipe_uuid', '=', recipe_dict.get("uuid"))
        recipes = list(query.fetch(1))
        if 0 == len(recipes):
            return error_response(message="No matching recipe in collection")
        recipe = recipes[0]
        recipe["recipe"] = recipe_json
        recipe["date_created"] = current_ts
        recipe["shared"] = shared
        datastore.get_client().put(recipe)

    return success_response(
        message="Successfully saved.",
        modified=current_ts,
        recipe_uuid=recipe_dict.get("uuid")
    )
コード例 #24
0
def save_horticulture_measurements():
    """Save horitculture measurements for a device.

    .. :quickref: Horticulture; Save horitculture measurements

    :reqheader Accept: application/json
    :<json string user_token: User Token returned from the /login API.
    :<json string device_uuid: Device UUID
    :<json string plant_height: plant_height
    :<json string leaf_count: leaf_count
    :<json string leaf_colors: leaf_colors
    :<json string leaf_withering: leaf_withering
    :<json string flavors: flavors
    :<json string root_colors: root_colors
    :<json string horticulture_notes: horticulture_notes
    :<json string submission_name: submission_name

    **Example response**:

        .. sourcecode:: json

          {
            "response_code": 200
          }

    """
    received_form_json = json.loads(request.data.decode('utf-8'))
    user_token = received_form_json.get("user_token")
    device_uuid = received_form_json.get("device_uuid")
    plant_height = received_form_json.get("plant_height", "")
    leaf_count = received_form_json.get("leaf_count", "")
    leaf_colors = received_form_json.get("leaf_colors", "")
    leaf_withering = received_form_json.get("leaf_withering", "")
    flavors = received_form_json.get("flavors", "")
    root_colors = received_form_json.get("root_colors", "")
    horticulture_notes = received_form_json.get("horticulture_notes", "")
    submission_name = received_form_json.get("submission_name", "")
    #print(received_form_json)
    if device_uuid is None:
        return error_response(message="Access denied.")

    # Add the user to the users kind of entity
    key = datastore.get_client().key('DailyHorticultureLog')
    # Indexes every other column except the description
    horticulture_task = gcds.Entity(key, exclude_from_indexes=[])

    horticulture_task.update({
        "device_uuid":
        device_uuid,
        "plant_height":
        str(plant_height),
        "leaf_count":
        str(leaf_count),
        "leaf_colors":
        ",".join(x for x in leaf_colors),
        "leaf_withering":
        ",".join(x for x in leaf_withering),
        "flavors":
        ",".join(x for x in flavors),
        "root_colors":
        ",".join(x for x in root_colors),
        "horticulture_notes":
        str(horticulture_notes),
        "submission_name":
        str(submission_name),
        "submitted_at":
        datetime.utcnow().isoformat().split('.')[0] + "Z",
    })

    datastore.get_client().put(horticulture_task)

    if horticulture_task.key:
        return success_response()
    else:
        return error_response()
コード例 #25
0
ファイル: get_all_recipes.py プロジェクト: viahoon/Data_API
def get_all_recipes():
    """Retrieve all recipes for a user account.

    .. :quickref: Recipe; Get all recipes 

    :reqheader Accept: application/json
    :<json string user_token: User Token returned from the /login API.

    **Example response**:

        .. sourcecode:: json

          {
              "results": ["recipe", "recipe"],
              "devices": ["device", "device"],
              "user_uuid": "UUID-For-User",
              "response-code": 200
          }

    **Example Recipe**:

        .. sourcecode:: json

          {
            "name": "Get Growing - Basil Recipe",
            "description": "Grows basil.",
            "recipe_uuid": "e6085be7-d496-43cc-8bd3-3a40a79e854e",
            "recipe_json": {"Recipe in": "JSON format"},
            "user_uuid": "1e91ef7d-e9c2-4b0d-8904-f262a9eda70d",
            "image_url": "http://via.placeholder.com/200x200",
            "saved": true
          }

    **Example Device**:

        .. sourcecode:: json

          {
            "device_name": "Green-Frog-Bates",
            "device_notes": "",
            "device_reg_no": "F3D9051D",
            "device_type": "EDU",
            "device_uuid": "EDU-F3D9051D-b8-27-eb-0a-43-ee",
            "registration_date": "2019-04-08 13:18:58",
            "user_uuid": "d2c7fe68-e857-4c4a-98b4-7e88154ddaa6"
          }

    """
    received_form_response = json.loads(request.data.decode('utf-8'))
    user_token = received_form_response.get("user_token", None)
    if user_token is None:
        return error_response(
            message="Please make sure you have added values for all the fields"
        )

    user_uuid = get_user_uuid_from_token(user_token)
    if user_uuid is None:
        return error_response(
            message="Invalid User: Unauthorized"
        )

    #Get all user devices
    query = datastore.get_client().query(kind='Devices')
    query.add_filter('user_uuid', '=', user_uuid)
    query_result = list(query.fetch())
    results = list(query_result)
    devices_array = []
    if len(results) > 0:
        for result_row in results:
            device_id = result_row.get("device_uuid", "")
            device_reg_no = result_row.get("device_reg_no", "")
            device_name = result_row.get("device_name", "")
            print('  {}, {}, {}'.format(
                device_id, device_reg_no, device_name))
            result_json = {
                'device_uuid': device_id,
                'device_notes': result_row.get("device_notes", ""),
                'device_type': result_row.get("device_type", ""),
                'device_reg_no': device_reg_no,
                'registration_date': result_row.get("registration_date", "").strftime("%Y-%m-%d %H:%M:%S"),
                'user_uuid': result_row.get("user_uuid", ""),
                'device_name': device_name
            }
            devices_array.append(result_json)


    # Get all the common AND shared AND user owned recipes.
    recipe_query = datastore.get_client().query(kind='Recipes')
    query.add_filter('user_uuid', '=', user_uuid) # users' recipes
    query.add_filter('user_uuid', '=', 'all')     # AND 'all' common recipes
    query.add_filter('shared', '=', 'true')       # AND shared recipes
    query_result = list(recipe_query.fetch())
    results = list(query_result)

    results_array = []
    for result in results:
        recipe_dict = json.loads(result["recipe"])

        # Get the username who owns this recipe
        username = ''
        query = datastore.get_client().query(kind='Users')
        query.add_filter('user_uuid', '=', result['user_uuid'])
        user_list = list(query.fetch(1))
        if 1 == len(user_list):
            user = user_list[0]
            username = user.get('username', '')

        results_array.append({
            'name': recipe_dict.get('name'),
            'description': result.get('description', ''),
            'recipe_uuid': result.get("recipe_uuid", ""),
            "recipe_json": recipe_dict,
            "user_uuid": result.get('user_uuid', ""),
            "image_url": result.get("image_url", ""),
            "shared": result.get("shared", ""),
            "username": username
        })

    return success_response(
        results=results_array,
        devices=devices_array,
        user_uuid=user_uuid
    )
コード例 #26
0
def register():
    """Register a Food Computer and associate it with a user account.

    .. :quickref: Device; Register device

    :reqheader Accept: application/json
    :<json string user_token: User Token, to associate this device with
    :<json string device_name: User specified name for the device ('mine!')
    :<json string device_reg_no: Key from the device registration process
    :<json string device_notes: User specified notes about the device ('blue')
    :<json string device_type: PFC_EDU, FS, etc.

    **Example response**:

        .. sourcecode:: json

          {
            "response_code": 200 
          }
    """
    received_form_response = json.loads(request.data.decode('utf-8'))
    print('register API received_form_response={}'.format(
        received_form_response))

    user_token = received_form_response.get("user_token", None)
    device_name = received_form_response.get("device_name", None)
    device_reg_no = received_form_response.get("device_reg_no", None)
    device_notes = received_form_response.get("device_notes", None)
    device_type = received_form_response.get("device_type", None)
    testing = received_form_response.get("testing")
    time_stamp = datetime.now()

    if user_token is None or device_reg_no is None:
        return error_response(
            message="Please make sure you have added values for all the fields"
        )

    if device_type is None:
        device_type = 'EDU'

    user_uuid = get_user_uuid_from_token(user_token)
    if user_uuid is None:
        return error_response(message="Invalid User: Unauthorized")

    if testing:  # our pytest is hitting this API, so don't create the user
        return success_response()

    # Create a google IoT device registry entry for this device.
    # The method returns the device ID we need for IoT communications.
    try:
        device_uuid, device_software_version = \
                iot.create_iot_device_registry_entry(device_reg_no,
                                                 device_name,
                                                 device_notes,
                                                 device_type,
                                                 user_uuid)
    except ValueError as e:
        return error_response(message=str(e))
    except errors.HttpError as e:
        return error_response(message=e._get_reason())

    if device_uuid is None:
        return error_response(message="Could not register this IoT device.")

    # Add the device to the Devices datastore collection
    key = datastore.get_client().key('Devices')
    device_reg_task = gcds.Entity(key, exclude_from_indexes=[])

    device_reg_task.update({
        'device_uuid': device_uuid,
        'device_name': device_name,
        'device_reg_no': device_reg_no,
        'device_notes': device_notes,
        'user_uuid': user_uuid,
        'device_type': device_type,
        'registration_date': time_stamp,
        'device_software_version': device_software_version
    })

    datastore.get_client().put(device_reg_task)

    if device_reg_task.key:
        return success_response()

    else:
        return error_response(message="Sorry there was an error.")
コード例 #27
0
ファイル: database.py プロジェクト: viahoon/cloud_common
def get_all_historical_values(device_uuid, start_timestamp, end_timestamp):
    print("Getting all historical values")
    co2 = []
    temp = []
    RH = []
    leaf_count = []
    plant_height = []
    horticulture_notes = []

    if device_uuid is None or device_uuid is "None":
        print(f"get_all_historical_values: No device_uuid")
        return temp, RH, co2, leaf_count, plant_height

    co2_vals = datastore.get_device_data(datastore.DS_co2_KEY,
                                         device_uuid,
                                         count=1000)
    temp_vals = datastore.get_device_data(datastore.DS_temp_KEY,
                                          device_uuid,
                                          count=1000)
    rh_vals = datastore.get_device_data(datastore.DS_rh_KEY,
                                        device_uuid,
                                        count=1000)
    if 0 == len(co2_vals) and 0 == len(temp_vals) and 0 == len(rh_vals):
        print(f"get_all_historical_values: No DeviceData for {device_uuid}")
        return temp, RH, co2, leaf_count, plant_height

    # handle None values for date range, in which case we return all
    start, end = None, None
    try:
        start = dt.strptime(start_timestamp, "%Y-%m-%dT%H:%M:%SZ")
        end = dt.strptime(end_timestamp, "%Y-%m-%dT%H:%M:%SZ")
        print(
            f"get_all_historical_values: using date range: {str(start)} to {str(end)}"
        )
    except:
        start, end = None, None
        print(f"get_all_historical_values: no date range")

    # make sure the time column is the first entry in each dict
    for val in co2_vals:
        ts_str = utils.bytes_to_string(val["timestamp"])
        ts = dt.strptime(ts_str, "%Y-%m-%dT%H:%M:%SZ")
        if start is not None and end is not None and (ts < start or ts > end):
            continue  # this value is not in our start / end range
        value = utils.bytes_to_string(val["value"])
        co2.append({"time": ts_str, "value": value})

    for val in temp_vals:
        ts_str = utils.bytes_to_string(val["timestamp"])
        ts = dt.strptime(ts_str, "%Y-%m-%dT%H:%M:%SZ")
        if start is not None and end is not None and (ts < start or ts > end):
            continue  # this value is not in our start / end range
        value = utils.bytes_to_string(val["value"])
        temp.append({"time": ts_str, "value": value})

    for val in rh_vals:
        ts_str = utils.bytes_to_string(val["timestamp"])
        ts = dt.strptime(ts_str, "%Y-%m-%dT%H:%M:%SZ")
        if start is not None and end is not None and (ts < start or ts > end):
            continue  # this value is not in our start / end range
        value = utils.bytes_to_string(val["value"])
        RH.append({"time": ts_str, "value": value})

    # get horticulture measurements: leaf_count, plant_height
    query = datastore.get_client().query(kind="DailyHorticultureLog")
    query.add_filter("device_uuid", "=", device_uuid)
    query_result = list(query.fetch())
    if 0 < len(query_result):
        for result in query_result:
            ts_str = str(utils.bytes_to_string(result["submitted_at"]))
            ts_str = ts_str.split(".")[0]
            try:
                ts = dt.strptime(ts_str, "%Y-%m-%dT%H:%M:%SZ")
                if start is not None and end is not None and (ts < start
                                                              or ts > end):
                    continue  # this value is not in our start / end range
                if "leaf_count" in result:
                    leaf_count.append({
                        "time": ts_str,
                        "value": result["leaf_count"]
                    })
                if "plant_height" in result:
                    plant_height.append({
                        "time": ts_str,
                        "value": result["plant_height"]
                    })
                if "horticulture_notes" in result:
                    horticulture_notes.append({
                        "time":
                        ts_str,
                        "value":
                        result["horticulture_notes"]
                    })

            except:
                print("Invalid string format:", ts_str)
                continue

    return temp, RH, co2, leaf_count, plant_height, horticulture_notes