示例#1
0
    def target_summary(
        self,
        request: _RequestObjectProxy,
        context: _Context,
    ) -> str:
        """
        Get a summary report for a target.

        Fake implementation of
        https://library.vuforia.com/articles/Solution/How-To-Use-the-Vuforia-Web-Services-API.html#How-To-Retrieve-a-Target-Summary-Report
        """
        try:
            run_services_validators(
                request_headers=request.headers,
                request_body=request.body,
                request_method=request.method,
                request_path=request.path,
                databases=self._target_manager.databases,
            )
        except ValidatorException as exc:
            context.headers = exc.headers
            context.status_code = exc.status_code
            return exc.response_text

        database = get_database_matching_server_keys(
            request_headers=request.headers,
            request_body=request.body,
            request_method=request.method,
            request_path=request.path,
            databases=self._target_manager.databases,
        )
        assert isinstance(database, VuforiaDatabase)
        target_id = request.path.split('/')[-1]
        target = database.get_target(target_id=target_id)

        assert isinstance(database, VuforiaDatabase)
        date = email.utils.formatdate(None, localtime=False, usegmt=True)
        body = {
            'status': target.status,
            'transaction_id': uuid.uuid4().hex,
            'result_code': ResultCodes.SUCCESS.value,
            'database_name': database.database_name,
            'target_name': target.name,
            'upload_date': target.upload_date.strftime('%Y-%m-%d'),
            'active_flag': target.active_flag,
            'tracking_rating': target.tracking_rating,
            'total_recos': target.total_recos,
            'current_month_recos': target.current_month_recos,
            'previous_month_recos': target.previous_month_recos,
        }
        body_json = json_dump(body)
        context.headers = {
            'Connection': 'keep-alive',
            'Content-Type': 'application/json',
            'Content-Length': str(len(body_json)),
            'Server': 'nginx',
            'Date': date,
        }

        return body_json
示例#2
0
    def add_target(
        self,
        request: _RequestObjectProxy,
        context: _Context,
    ) -> str:
        """
        Add a target.

        Fake implementation of
        https://library.vuforia.com/articles/Solution/How-To-Use-the-Vuforia-Web-Services-API.html#How-To-Add-a-Target
        """
        name = request.json()['name']
        database = get_database_matching_server_keys(
            request_headers=request.headers,
            request_body=request.body,
            request_method=request.method,
            request_path=request.path,
            databases=self.databases,
        )

        assert isinstance(database, VuforiaDatabase)

        targets = (
            target for target in database.targets if not target.delete_date
        )
        if any(target.name == name for target in targets):
            context.status_code = HTTPStatus.FORBIDDEN
            body = {
                'transaction_id': uuid.uuid4().hex,
                'result_code': ResultCodes.TARGET_NAME_EXIST.value,
            }
            return json_dump(body)

        active_flag = request.json().get('active_flag')
        if active_flag is None:
            active_flag = True

        image = request.json()['image']
        decoded = base64.b64decode(image)
        image_file = io.BytesIO(decoded)

        new_target = Target(
            name=request.json()['name'],
            width=request.json()['width'],
            image=image_file,
            active_flag=active_flag,
            processing_time_seconds=self._processing_time_seconds,
            application_metadata=request.json().get('application_metadata'),
        )
        database.targets.add(new_target)

        context.status_code = HTTPStatus.CREATED
        body = {
            'transaction_id': uuid.uuid4().hex,
            'result_code': ResultCodes.TARGET_CREATED.value,
            'target_id': new_target.target_id,
        }
        return json_dump(body)
示例#3
0
    def target_list(
        self,
        request: _RequestObjectProxy,
        context: _Context,
    ) -> str:
        """
        Get a list of all targets.

        Fake implementation of
        https://library.vuforia.com/articles/Solution/How-To-Use-the-Vuforia-Web-Services-API.html#How-To-Get-a-Target-List-for-a-Cloud-Database
        """
        try:
            run_services_validators(
                request_headers=request.headers,
                request_body=request.body,
                request_method=request.method,
                request_path=request.path,
                databases=self._target_manager.databases,
            )
        except ValidatorException as exc:
            context.headers = exc.headers
            context.status_code = exc.status_code
            return exc.response_text

        database = get_database_matching_server_keys(
            request_headers=request.headers,
            request_body=request.body,
            request_method=request.method,
            request_path=request.path,
            databases=self._target_manager.databases,
        )

        assert isinstance(database, VuforiaDatabase)
        date = email.utils.formatdate(None, localtime=False, usegmt=True)

        results = [target.target_id for target in database.not_deleted_targets]
        body: Dict[str, str | list[str]] = {
            'transaction_id': uuid.uuid4().hex,
            'result_code': ResultCodes.SUCCESS.value,
            'results': results,
        }
        body_json = json_dump(body)
        context.headers = {
            'Connection': 'keep-alive',
            'Content-Type': 'application/json',
            'Server': 'nginx',
            'Date': date,
            'Content-Length': str(len(body_json)),
        }
        return body_json
def _requests_mock_callback(
    request: _RequestObjectProxy,
    context: _Context,
    flask_app: Flask,
) -> str:
    """
    Given a request to the flask app, send an equivalent request to an in
    memory fake of the flask app and return some key details of the
    response.

    :param request: The incoming request to pass onto the flask app.
    :param context: An object containing the collected known data about this
        response.
    :param flask_app: The Flask application to pass requests to.
    :return: A tuple of status code, response headers and response data
        from the flask app.
    """
    test_client = flask_app.test_client()
    # See parameters at
    # https://werkzeug.palletsprojects.com/en/0.15.x/test/#werkzeug.test.EnvironBuilder
    cookie_string = request.headers.get('Cookie', '')
    cookie_list = cookie_string.split(';')
    cookie_list_no_empty = [item for item in cookie_list if item]
    request_cookies = [
        list(parse_cookie(cookie).items())[0]
        for cookie in cookie_list_no_empty
    ]
    cookies_dict = dict(request_cookies)

    for key, value in cookies_dict.items():
        test_client.set_cookie(
            server_name='',
            key=key,
            value=value,
        )

    environ_builder = werkzeug.test.EnvironBuilder(
        path=request.path_url,
        method=request.method,
        headers=dict(request.headers),
        data=request.body,
    )
    environ = environ_builder.get_environ()
    if 'Content-Length' in request.headers:
        environ['CONTENT_LENGTH'] = request.headers['Content-Length']
    response = test_client.open(environ)

    context.headers = response.headers
    context.status_code = response.status_code
    return str(response.data.decode())
示例#5
0
    def query(
        self,
        request: _RequestObjectProxy,
        context: _Context,
    ) -> str:
        """
        Perform an image recognition query.
        """
        try:
            run_query_validators(
                request_path=request.path,
                request_headers=request.headers,
                request_body=request.body,
                request_method=request.method,
                databases=self._target_manager.databases,
            )
        except ValidatorException as exc:
            context.headers = exc.headers
            context.status_code = exc.status_code
            return exc.response_text

        try:
            response_text = get_query_match_response_text(
                request_headers=request.headers,
                request_body=request.body,
                request_method=request.method,
                request_path=request.path,
                databases=self._target_manager.databases,
                query_processes_deletion_seconds=(
                    self._query_processes_deletion_seconds),
                query_recognizes_deletion_seconds=(
                    self._query_recognizes_deletion_seconds),
            )
        except ActiveMatchingTargetsDeleteProcessing:
            deleted_target_matched_exception = DeletedTargetMatched()
            context.headers = deleted_target_matched_exception.headers
            context.status_code = deleted_target_matched_exception.status_code
            return deleted_target_matched_exception.response_text

        date = email.utils.formatdate(None, localtime=False, usegmt=True)
        context.headers = {
            'Connection': 'keep-alive',
            'Content-Type': 'application/json',
            'Server': 'nginx',
            'Date': date,
            'Content-Length': str(len(response_text)),
        }
        return response_text
示例#6
0
    def delete_target(
        self,
        request: _RequestObjectProxy,
        context: _Context,
    ) -> str:
        """
        Delete a target.

        Fake implementation of
        https://library.vuforia.com/articles/Solution/How-To-Use-the-Vuforia-Web-Services-API.html#How-To-Delete-a-Target
        """
        body: Dict[str, str] = {}
        target = _get_target_from_request(
            request_path=request.path,
            databases=self.databases,
        )

        if target.status == TargetStatuses.PROCESSING.value:
            context.status_code = HTTPStatus.FORBIDDEN
            body = {
                'transaction_id': uuid.uuid4().hex,
                'result_code': ResultCodes.TARGET_STATUS_PROCESSING.value,
            }
            return json_dump(body)

        target.delete()

        body = {
            'transaction_id': uuid.uuid4().hex,
            'result_code': ResultCodes.SUCCESS.value,
        }
        return json_dump(body)
示例#7
0
    def query(
        self,
        request: _RequestObjectProxy,
        context: _Context,
    ) -> str:
        """
        Perform an image recognition query.
        """
        try:
            response_text = get_query_match_response_text(
                request_headers=request.headers,
                request_body=request.body,
                request_method=request.method,
                request_path=request.path,
                databases=self.databases,
                query_processes_deletion_seconds=(
                    self._query_processes_deletion_seconds),
                query_recognizes_deletion_seconds=(
                    self._query_recognizes_deletion_seconds),
            )
        except (
                ActiveMatchingTargetsDeleteProcessing,
                MatchingTargetsWithProcessingStatus,
        ):
            # We return an example 500 response.
            # Each response given by Vuforia is different.
            #
            # Sometimes Vuforia will ignore matching targets with the
            # processing status, but we choose to:
            # * Do the most unexpected thing.
            # * Be consistent with every response.
            resources_dir = Path(__file__).parent.parent / 'resources'
            filename = 'match_processing_response.html'
            match_processing_resp_file = resources_dir / filename
            context.status_code = HTTPStatus.INTERNAL_SERVER_ERROR
            cache_control = 'must-revalidate,no-cache,no-store'
            context.headers['Cache-Control'] = cache_control
            content_type = 'text/html; charset=ISO-8859-1'
            context.headers['Content-Type'] = content_type
            return Path(match_processing_resp_file).read_text()

        return response_text
示例#8
0
    def update_target(
        self,
        request: _RequestObjectProxy,
        context: _Context,
    ) -> str:
        """
        Update a target.

        Fake implementation of
        https://library.vuforia.com/articles/Solution/How-To-Use-the-Vuforia-Web-Services-API.html#How-To-Update-a-Target
        """
        try:
            run_services_validators(
                request_headers=request.headers,
                request_body=request.body,
                request_method=request.method,
                request_path=request.path,
                databases=self._target_manager.databases,
            )
        except ValidatorException as exc:
            context.headers = exc.headers
            context.status_code = exc.status_code
            return exc.response_text

        database = get_database_matching_server_keys(
            request_headers=request.headers,
            request_body=request.body,
            request_method=request.method,
            request_path=request.path,
            databases=self._target_manager.databases,
        )

        assert isinstance(database, VuforiaDatabase)

        target_id = request.path.split('/')[-1]
        target = database.get_target(target_id=target_id)
        body: Dict[str, str] = {}

        date = email.utils.formatdate(None, localtime=False, usegmt=True)

        if target.status != TargetStatuses.SUCCESS.value:
            exception = TargetStatusNotSuccess()
            context.headers = exception.headers
            context.status_code = exception.status_code
            return exception.response_text

        width = request.json().get('width', target.width)
        name = request.json().get('name', target.name)
        active_flag = request.json().get('active_flag', target.active_flag)
        application_metadata = request.json().get(
            'application_metadata',
            target.application_metadata,
        )

        image_value = target.image_value
        if 'image' in request.json():
            image_value = base64.b64decode(request.json()['image'])

        if 'active_flag' in request.json() and active_flag is None:
            fail_exception = Fail(status_code=HTTPStatus.BAD_REQUEST)
            context.headers = fail_exception.headers
            context.status_code = fail_exception.status_code
            return fail_exception.response_text

        if (
            'application_metadata' in request.json()
            and application_metadata is None
        ):
            fail_exception = Fail(status_code=HTTPStatus.BAD_REQUEST)
            context.headers = fail_exception.headers
            context.status_code = fail_exception.status_code
            return fail_exception.response_text

        # In the real implementation, the tracking rating can stay the same.
        # However, for demonstration purposes, the tracking rating changes but
        # when the target is updated.
        available_values = list(set(range(6)) - {target.tracking_rating})
        processed_tracking_rating = random.choice(available_values)

        gmt = ZoneInfo('GMT')
        last_modified_date = datetime.datetime.now(tz=gmt)

        new_target = dataclasses.replace(
            target,
            name=name,
            width=width,
            active_flag=active_flag,
            application_metadata=application_metadata,
            image_value=image_value,
            processed_tracking_rating=processed_tracking_rating,
            last_modified_date=last_modified_date,
        )

        database.targets.remove(target)
        database.targets.add(new_target)

        body = {
            'result_code': ResultCodes.SUCCESS.value,
            'transaction_id': uuid.uuid4().hex,
        }
        body_json = json_dump(body)
        context.headers = {
            'Connection': 'keep-alive',
            'Content-Type': 'application/json',
            'Server': 'nginx',
            'Date': date,
            'Content-Length': str(len(body_json)),
        }
        return body_json
示例#9
0
    def get_duplicates(
        self,
        request: _RequestObjectProxy,
        context: _Context,
    ) -> str:
        """
        Get targets which may be considered duplicates of a given target.

        Fake implementation of
        https://library.vuforia.com/articles/Solution/How-To-Use-the-Vuforia-Web-Services-API.html#How-To-Check-for-Duplicate-Targets
        """
        try:
            run_services_validators(
                request_headers=request.headers,
                request_body=request.body,
                request_method=request.method,
                request_path=request.path,
                databases=self._target_manager.databases,
            )
        except ValidatorException as exc:
            context.headers = exc.headers
            context.status_code = exc.status_code
            return exc.response_text

        database = get_database_matching_server_keys(
            request_headers=request.headers,
            request_body=request.body,
            request_method=request.method,
            request_path=request.path,
            databases=self._target_manager.databases,
        )
        assert isinstance(database, VuforiaDatabase)
        target_id = request.path.split('/')[-1]
        target = database.get_target(target_id=target_id)

        other_targets = set(database.targets) - {target}

        similar_targets: list[str] = [
            other.target_id
            for other in other_targets
            if other.image_value == target.image_value
            and TargetStatuses.FAILED.value
            not in (target.status, other.status)
            and TargetStatuses.PROCESSING.value != other.status
            and other.active_flag
        ]

        date = email.utils.formatdate(None, localtime=False, usegmt=True)
        body = {
            'transaction_id': uuid.uuid4().hex,
            'result_code': ResultCodes.SUCCESS.value,
            'similar_targets': similar_targets,
        }
        body_json = json_dump(body)
        context.headers = {
            'Connection': 'keep-alive',
            'Content-Type': 'application/json',
            'Server': 'nginx',
            'Date': date,
            'Content-Length': str(len(body_json)),
        }

        return body_json
示例#10
0
    def database_summary(
        self,
        request: _RequestObjectProxy,
        context: _Context,
    ) -> str:
        """
        Get a database summary report.

        Fake implementation of
        https://library.vuforia.com/articles/Solution/How-To-Use-the-Vuforia-Web-Services-API.html#How-To-Get-a-Database-Summary-Report
        """
        try:
            run_services_validators(
                request_headers=request.headers,
                request_body=request.body,
                request_method=request.method,
                request_path=request.path,
                databases=self._target_manager.databases,
            )
        except ValidatorException as exc:
            context.headers = exc.headers
            context.status_code = exc.status_code
            return exc.response_text

        body: Dict[str, str | int] = {}

        database = get_database_matching_server_keys(
            request_headers=request.headers,
            request_body=request.body,
            request_method=request.method,
            request_path=request.path,
            databases=self._target_manager.databases,
        )

        assert isinstance(database, VuforiaDatabase)
        date = email.utils.formatdate(None, localtime=False, usegmt=True)
        body = {
            'result_code': ResultCodes.SUCCESS.value,
            'transaction_id': uuid.uuid4().hex,
            'name': database.database_name,
            'active_images': len(database.active_targets),
            'inactive_images': len(database.inactive_targets),
            'failed_images': len(database.failed_targets),
            'target_quota': database.target_quota,
            'total_recos': database.total_recos,
            'current_month_recos': database.current_month_recos,
            'previous_month_recos': database.previous_month_recos,
            'processing_images': len(database.processing_targets),
            'reco_threshold': database.reco_threshold,
            'request_quota': database.request_quota,
            'request_usage': 0,
        }
        body_json = json_dump(body)
        context.headers = {
            'Connection': 'keep-alive',
            'Content-Type': 'application/json',
            'Server': 'nginx',
            'Date': date,
            'Content-Length': str(len(body_json)),
        }
        return body_json
示例#11
0
    def delete_target(
        self,
        request: _RequestObjectProxy,
        context: _Context,
    ) -> str:
        """
        Delete a target.

        Fake implementation of
        https://library.vuforia.com/articles/Solution/How-To-Use-the-Vuforia-Web-Services-API.html#How-To-Delete-a-Target
        """
        try:
            run_services_validators(
                request_headers=request.headers,
                request_body=request.body,
                request_method=request.method,
                request_path=request.path,
                databases=self._target_manager.databases,
            )
        except ValidatorException as exc:
            context.headers = exc.headers
            context.status_code = exc.status_code
            return exc.response_text

        body: Dict[str, str] = {}
        database = get_database_matching_server_keys(
            request_headers=request.headers,
            request_body=request.body,
            request_method=request.method,
            request_path=request.path,
            databases=self._target_manager.databases,
        )

        assert isinstance(database, VuforiaDatabase)
        target_id = request.path.split('/')[-1]
        target = database.get_target(target_id=target_id)

        if target.status == TargetStatuses.PROCESSING.value:
            target_processing_exception = TargetStatusProcessing()
            context.headers = target_processing_exception.headers
            context.status_code = target_processing_exception.status_code
            return target_processing_exception.response_text

        now = datetime.datetime.now(tz=target.upload_date.tzinfo)
        new_target = dataclasses.replace(target, delete_date=now)
        database.targets.remove(target)
        database.targets.add(new_target)
        date = email.utils.formatdate(None, localtime=False, usegmt=True)

        body = {
            'transaction_id': uuid.uuid4().hex,
            'result_code': ResultCodes.SUCCESS.value,
        }
        body_json = json_dump(body)
        context.headers = {
            'Connection': 'keep-alive',
            'Content-Type': 'application/json',
            'Server': 'nginx',
            'Date': date,
            'Content-Length': str(len(body_json)),
        }
        return body_json
示例#12
0
    def add_target(
        self,
        request: _RequestObjectProxy,
        context: _Context,
    ) -> str:
        """
        Add a target.

        Fake implementation of
        https://library.vuforia.com/articles/Solution/How-To-Use-the-Vuforia-Web-Services-API.html#How-To-Add-a-Target
        """
        try:
            run_services_validators(
                request_headers=request.headers,
                request_body=request.body,
                request_method=request.method,
                request_path=request.path,
                databases=self._target_manager.databases,
            )
        except ValidatorException as exc:
            context.headers = exc.headers
            context.status_code = exc.status_code
            return exc.response_text

        database = get_database_matching_server_keys(
            request_headers=request.headers,
            request_body=request.body,
            request_method=request.method,
            request_path=request.path,
            databases=self._target_manager.databases,
        )

        assert isinstance(database, VuforiaDatabase)

        given_active_flag = request.json().get('active_flag')
        active_flag = {
            None: True,
            True: True,
            False: False,
        }[given_active_flag]

        application_metadata = request.json().get('application_metadata')

        new_target = Target(
            name=request.json()['name'],
            width=request.json()['width'],
            image_value=base64.b64decode(request.json()['image']),
            active_flag=active_flag,
            processing_time_seconds=self._processing_time_seconds,
            application_metadata=application_metadata,
        )
        database.targets.add(new_target)

        date = email.utils.formatdate(None, localtime=False, usegmt=True)
        context.status_code = HTTPStatus.CREATED
        body = {
            'transaction_id': uuid.uuid4().hex,
            'result_code': ResultCodes.TARGET_CREATED.value,
            'target_id': new_target.target_id,
        }
        body_json = json_dump(body)
        context.headers = {
            'Connection': 'keep-alive',
            'Content-Type': 'application/json',
            'Server': 'nginx',
            'Date': date,
            'Content-Length': str(len(body_json)),
        }
        return body_json
示例#13
0
    def update_target(
        self,
        request: _RequestObjectProxy,
        context: _Context,
    ) -> str:
        """
        Update a target.

        Fake implementation of
        https://library.vuforia.com/articles/Solution/How-To-Use-the-Vuforia-Web-Services-API.html#How-To-Update-a-Target
        """
        target = _get_target_from_request(
            request_path=request.path,
            databases=self.databases,
        )
        body: Dict[str, str] = {}
        database = get_database_matching_server_keys(
            request_headers=request.headers,
            request_body=request.body,
            request_method=request.method,
            request_path=request.path,
            databases=self.databases,
        )

        assert isinstance(database, VuforiaDatabase)

        if target.status != TargetStatuses.SUCCESS.value:
            context.status_code = HTTPStatus.FORBIDDEN
            body = {
                'transaction_id': uuid.uuid4().hex,
                'result_code': ResultCodes.TARGET_STATUS_NOT_SUCCESS.value,
            }
            return json_dump(body)

        if 'width' in request.json():
            target.width = request.json()['width']

        if 'active_flag' in request.json():
            active_flag = request.json()['active_flag']
            if active_flag is None:
                body = {
                    'transaction_id': uuid.uuid4().hex,
                    'result_code': ResultCodes.FAIL.value,
                }
                context.status_code = HTTPStatus.BAD_REQUEST
                return json_dump(body)
            target.active_flag = active_flag

        if 'application_metadata' in request.json():
            if request.json()['application_metadata'] is None:
                body = {
                    'transaction_id': uuid.uuid4().hex,
                    'result_code': ResultCodes.FAIL.value,
                }
                context.status_code = HTTPStatus.BAD_REQUEST
                return json_dump(body)
            application_metadata = request.json()['application_metadata']
            target.application_metadata = application_metadata

        if 'name' in request.json():
            name = request.json()['name']
            other_targets = set(database.targets) - set([target])
            if any(
                other.name == name
                for other in other_targets
                if not other.delete_date
            ):
                context.status_code = HTTPStatus.FORBIDDEN
                body = {
                    'transaction_id': uuid.uuid4().hex,
                    'result_code': ResultCodes.TARGET_NAME_EXIST.value,
                }
                return json_dump(body)
            target.name = name

        if 'image' in request.json():
            image = request.json()['image']
            decoded = base64.b64decode(image)
            image_file = io.BytesIO(decoded)
            target.image = image_file

        # In the real implementation, the tracking rating can stay the same.
        # However, for demonstration purposes, the tracking rating changes but
        # when the target is updated.
        available_values = list(set(range(6)) - set([target.tracking_rating]))
        target.processed_tracking_rating = random.choice(available_values)

        gmt = ZoneInfo('GMT')
        now = datetime.datetime.now(tz=gmt)
        target.last_modified_date = now

        body = {
            'result_code': ResultCodes.SUCCESS.value,
            'transaction_id': uuid.uuid4().hex,
        }
        return json_dump(body)