def stage_attributes(self, attribute: str, unit_value: str,
                      bespoke_unit_tag: int, bespoke_sub_theme: int,
                      description: str) -> db.Model:
     """
     Stage Attributes
     :param attribute: Attribute
     :param unit_value: Unit Value
     :param bespoke_unit_tag: Unit Id
     :param bespoke_sub_theme: SubTheme Id
     :param description: Attributes Description
     :return: Attribute instance
     """
     _a = Attributes._get_by_name_unit_unitvalue(attribute,
                                                 bespoke_unit_tag,
                                                 unit_value)
     if _a:
         logger.info(
             '{} attribute with Unit ID: {} and Unit Value: {} already exists'
             .format(attribute, str(bespoke_unit_tag), unit_value))
         return _a
     a = Attributes(id=str(uuid.uuid4()),
                    name=attribute,
                    table_name=(attribute + '_' +
                                str(uuid.uuid4()).replace('-', '_')),
                    sub_theme=bespoke_sub_theme,
                    unit=bespoke_unit_tag,
                    unit_value=str(unit_value),
                    description=description)
     a = a.save()
     return a
Пример #2
0
    def test_return_attribute_of_subtheme(self):
        """
        Adding a theme and subtheme to the database and then testing to see if it's data is
        retrieved correctly
        """

        theme = Theme("Test_Theme")
        theme.save()
        theme.commit()

        sub_theme = SubTheme(theme.id, "Test_Sub_Theme")
        sub_theme.save()
        sub_theme.commit()

        attributes = Attributes("1234567890-123456789-123456789",
                                "_test_attribute_", "_table_name_",
                                sub_theme.id, 1)
        attributes.save()
        attributes.commit()

        response = self.testing_client.get('/data',
                                           data=dict(subtheme=theme.id))

        self.assertEqual(theme.json(), response.get_json())

        attributes.delete()
        attributes.commit()

        sub_theme.delete()
        sub_theme.commit()

        theme.delete()
        theme.commit()
Пример #3
0
 def attribute_to_commit(self, attribute_data):
     # Stage Attribute commit
     for attr in attribute_data:
         a = Attributes(name=attr.attribute, sub_theme=attr.sub_theme, table_name=str(uuid.uuid4()), unit_value=attr.unit_value, description=attr.description, unit=attr.unit_type)
         a.save()
         attr.id = a.id
     
     self._print_in_middle('Saved Attributes')
	def get(self):
		args = self.parser.parse_args()
		sensor, sensor_name, sensor_attribute = None, None, None


		if 'sensor' in args and args['sensor'] is not None:
			sensor = args['sensor']
			if sensor != '':
				if sensor == 'all':
					sensors = Sensor.get_all()
					return [a.json() for a in sensors], 200
				else:
					return (Sensor.get_by_id(sensor)).json(), 200

		if 'sensorname' in args and args['sensorname'] is not None:
			sensor_name = args['sensorname']
			if sensor_name != '':
				_sensors = sensor_name.split(',')
				_by_name = Sensor.get_by_name_in(_sensors)
				return [a.json() for a in _by_name], 200

		if 'sensorattribute' in args and args['sensorattribute'] is not None:
			sensor_attribute = args['sensorattribute']
			if sensor_attribute != '':
				_sen_attrs_ids = sensor_attribute.split(',')
				_sen_attrs = SensorAttribute.get_by_id_in(_sen_attrs_ids)
				attrs_ids = [_id.a_id for _id in _sen_attrs]
				_attributes = Attributes.get_by_id_in(attrs_ids)
				return [a.json() for a in _attributes], 200

		

		return {
			"error": "error occured while processing request"
		}, 400
Пример #5
0
    def test_update_on_new_import(self):
        """
        Test whether a AttributeRange entry is updated when new values are
        imported
        """
        o3 = Attributes.get_by_name("O3")[0]
        o3_attr_range = AttributeRange.get_by_attr_id(o3.id)
        before_import_latest_update = o3_attr_range.latest_update
        self.sess.execute(
            "INSERT INTO {} VALUES('A','99999999','{}','{}')".format(
                o3.table_name.lower(), datetime.now(), datetime.now()))
        self.sess.commit()

        response = self.testing_client.post('/importer_retry', data=dict(
            api_id=1), headers=self.access_token_header)
        self.assertEqual(response.status_code, 200)
        time.sleep(1)
        new_o3_attr_range = AttributeRange.get_by_attr_id(o3.id)
        self.assertEqual(new_o3_attr_range.maximum, 99999999)
        after_import_latest_update = new_o3_attr_range.latest_update
        self.assertGreater(after_import_latest_update,
                           before_import_latest_update)

        self.sess.execute(
            "delete from {} where s_id='A'".format(o3.table_name.lower()))
        self.sess.commit()
    def run():
        """ Schedule main_task to execute once a day """
        apis = Scheduler.get_apis()
        for api in apis:
            if not ImporterStatuses.find_by_api_id(api.id):
                class_name = api.api_class.split('.')[2]
                new_entry = ImporterStatuses(api.id, class_name, 'pending', '',
                                             '', False, datetime.now())
                new_entry.save()
                new_entry.commit()

        all_attribute = Attributes.get_all()
        for attribute in all_attribute:
            if not AttributeRange.get_by_attr_id(attribute.id):
                attr_min = Attributes.attribute_min(attribute.table_name)
                attr_max = Attributes.attribute_max(attribute.table_name)
                try:
                    new_range = AttributeRange(attribute.id, attr_min.s_id,
                                               attr_min.value,
                                               attr_min.timestamp,
                                               attr_max.s_id, attr_max.value,
                                               attr_max.timestamp,
                                               datetime.now())
                except AttributeError:
                    new_range = AttributeRange(attribute.id, None, None,
                                               None, None, None, None,
                                               datetime.now())

                new_range.save()
                new_range.commit()

        sched.add_job(Scheduler.main_task,
                      'interval',
                      start_date=datetime.now() + timedelta(seconds=5),
                      days=1,
                      name='Primary_Scheduler',
                      replace_existing=True,
                      id='Primary_Scheduler',
                      jobstore='sqlalchemy')

        try:
            # This is here to simulate application activity (which keeps
            # the main thread alive).
            while True:
                time.sleep(2)
        except (KeyboardInterrupt, SystemExit):
            sched.shutdown()
Пример #7
0
 def setUp(self) -> None:
     """
     Setup FlaskClient for tests, create an admin user and create the authorization header for requests to
     the FlaskClient
     """
     self.clean_up = []
     self.client, self.app_context = self.create_test_client()
     self.user = self.create_admin_user()
     self.theme = self.create_dummy_theme()
     self.subtheme = self.create_dummy_subtheme()
     self.unit = self.get_dummy_unit()
     self.attribute = Attributes("A_TEST_ATTRIBUTE_ID_",
                                 "_TEST_ATTR_NAME_",
                                 "_A_TABLE_NAME",
                                 self.subtheme.id,
                                 self.unit.id,
                                 description="_A_CUSTOM_DESCRIPTION_")
     self.attribute.save()
     self.attribute.commit()
     self.clean_up.append(self.attribute)
Пример #8
0
    def tearDown(self) -> None:
        """ Clean up all dependencies after tests"""

        for alias in self.aliases:
            try:
                if AttrAlias.get_by_user_id(self.user.id):
                    alias.delete()
                    alias.commit()
            except Exception:
                pass

        for attr in self.attributes:
            try:
                if Attributes.get_by_id(attr.id):
                    attr.delete()
                    attr.commit()
            except Exception:
                pass

        for sub_theme in self.sub_themes:
            try:
                if SubTheme.get_by_id(sub_theme.id):
                    sub_theme.delete()
                    sub_theme.commit()
            except Exception:
                pass

        for unit in self.units:
            try:
                if Unit.get_by_id(unit.id):
                    unit.delete()
                    unit.commit()
            except Exception:
                pass

        try:
            if Theme.get_by_id(self.theme.id):
                self.theme.delete()
                self.theme.commit()
        except Exception:
            pass

        self.client.post('/logout', headers=self.auth_header)

        if self.user:
            if Users.find_by_id(self.user.id):
                try:
                    self.user.delete()
                    self.user.commit()
                except Exception:
                    pass

        self.app_context.pop()
    def setUp(self):
        """
        Setup a FlaskClient, AppContext, Admin user, Authorization header for requests to
        the Flask Client and a dummy Theme
        """
        self.client, self.app_context = self.create_test_client()
        self.user = self.create_admin_user()
        self.auth_header = self.get_auth_header()
        self.unit = Unit("_test_unit_type_", "A test unit")
        self.unit.save()
        self.unit.commit()
        self.attribute = Attributes.get_by_name("_test_attribute_")
        self.theme = self.create_dummy_theme()
        self.subtheme = self.create_dummy_subtheme()
        if not self.attribute:
            self.attribute = Attributes("1234567890-123456789-123456789", "_test_attribute_", "_table_name_",
                                        self.subtheme.id, self.unit.id)
            self.attribute.save()
            self.attribute.commit()

        self.clean_up = [self.user, self.attribute, self.theme, self.subtheme, self.theme, self.unit]
Пример #10
0
    def stage_attributes(self, attribute: str, unit_value: str,
                         bespoke_unit_tag: int, bespoke_sub_theme: int,
                         description: str):
        _a = Attributes._get_by_name_unit_unitvalue(attribute,
                                                    bespoke_unit_tag,
                                                    unit_value)
        if _a:
            print(attribute, 'attribute with Unit ID:', str(bespoke_unit_tag),
                  'and Unit Value:', unit_value, 'already exists')
            return _a

        a = Attributes(id=str(uuid.uuid4()),
                       name=attribute,
                       table_name=(attribute + '_' +
                                   str(uuid.uuid4()).replace('-', '_')),
                       sub_theme=bespoke_sub_theme,
                       unit=bespoke_unit_tag,
                       unit_value=str(unit_value),
                       description=description)
        a = a.save()
        return a
Пример #11
0
    def create_attributes(self, count: int) -> None:
        """
        Create Attributes for SubThemes
        :param count: Number of Attributes per SubTheme
        """
        number_attributes = len(self.sub_themes) * count

        try:
            index = 0
            sub_theme = self.sub_themes[index]
            for num in range(0, number_attributes):

                unit = self.create_unit(num)
                attr = Attributes(
                    "attribute_id_{}".format(num),
                    "attribute_name_{}".format(num),
                    "b3_heat_value_bffc4e56_20e2_41a5_84d8_de725a3f875b",
                    sub_theme.id, unit.id, "_test_description_{}".format(num),
                    "1")
                attr.save()
                attr.commit()
                self.attributes.append(attr)

                if num % count:
                    index += 1
                    if index >= len(self.sub_themes):
                        return
                    sub_theme = self.sub_themes[index]

        except Exception as exp:
            logger.error(exp)
            self.fail()
    def get(self) -> [db.Model]:
        """
        Fetch Attributes from the database
        :param attribute_id:    Attribute id
        :param subtheme_id:    SubTheme id
        :return:   A list of Attributes with an HTTPstatus code OK (200) or an error message and a the appropriate
                    HTTPStatus code
        """
        args = self.reqpaser.parse_args()

        # Fetch by attribute_id
        if "attribute_id" in args and "subtheme_id" not in args:
            attribute = Attributes.get_by_id(args["attribute_id"])
            if not attribute:
                return {
                    "error": "Attribute not found",
                    "id": args["attribute_id"]
                }, HTTPStatus.NOT_FOUND
            content = [attribute]
            return [attr.json() for attr in content], HTTPStatus.OK

        # Fetch by subtheme_id
        elif "attribute_id" not in args and "subtheme_id" in args:
            attributes = Attributes.get_by_sub_theme_id(args["subtheme_id"])
            if not attributes:
                return {
                    "error": "Attributes not found",
                    "subtheme_id": args["subtheme_id"]
                }, HTTPStatus.NOT_FOUND
            if isinstance(attributes, Attributes):
                content = [attributes]
                return [attr.json() for attr in content], HTTPStatus.OK
            return [attr.json() for attr in attributes], HTTPStatus.OK

        # Fetch all attribute
        attributes = Attributes.get_all()
        return [attr.json() for attr in attributes], HTTPStatus.OK
    def get(self) -> (dict, HTTPStatus):
        """
        Check for triggered alerts.
        :return: On success, an HTTP response with a JSON body content
        containing the maximum and minimum alerts that have been exceeded with
        an HTTP status code of 200 (OK), otherwise an HTTP response with a JSON
        body content containing an appropriate error message and appropriate an
        HTTP status code
        """
        args = self.reqparser.parse_args()

        # Use current user_id if not user_id was parsed
        if "user_id" not in args:
            user = Users.find_by_email(get_jwt_identity())
            if user:
                args["user_id"] = user.id
            else:
                # Return Error current user id not found
                return (dict(error="User id not found for Current user, "
                             "User session may have timed out"),
                        HTTPStatus.INTERNAL_SERVER_ERROR)
        else:
            user = Users.find_by_id(args["user_id"])
            if not user:
                # Return error Parsed User Id not found
                return dict(error="User with id {} not found.".format(
                    args["user_id"])), HTTPStatus.NOT_FOUND

        # Check Attribute exists
        if not Attributes.get_by_id(args["attribute_id"]):
            # Return Error Attribute ID not found
            return dict(error="Attribute id {} not found.".format(
                args["attribute_id"])), HTTPStatus.NOT_FOUND

        # Get Attribute Max and Minimums
        attribute_range = AttributeRange.get_by_attr_id(args["attribute_id"])

        if not attribute_range:
            # Return eroor Attribute range not found
            return (dict(error="Attribute range not found",
                         **args), HTTPStatus.NOT_FOUND)

        # Check Alerts
        max_alerts = AlertWidgetModel.get_max_alerts(attribute_range,
                                                     user_id=user.id)
        min_alerts = AlertWidgetModel.get_min_alerts(attribute_range,
                                                     user_id=user.id)

        return dict(max=max_alerts, min=min_alerts), 200
Пример #14
0
    def test_min_max_for_all_attributes(self):
        """
        Test whether an AttributeRange entry is created for all Attribute
        entries
        """

        response = self.testing_client.post('/importer_retry', data=dict(
            api_id=1), headers=self.access_token_header)
        self.assertEqual(response.status_code, 200)

        attributes = Attributes.get_all()
        attribute_range_entries = AttributeRange.get_all()
        attribute_ids = [attr_range.attribute_id for attr_range in
                         attribute_range_entries]

        for attr in attributes:
            self.assertIn(attr.id, attribute_ids)
    def get(self):
        args = self.parser.parse_args()
        theme, subtheme = None, None

        if "subtheme" in args:
            subtheme = args['subtheme']
            if subtheme is not None and subtheme != '':
                attributes = Attributes.get_by_sub_theme_id(subtheme)
                return [a.json() for a in attributes], 200
        elif "theme" in args:
            theme = args['theme']
            if theme != "":
                subthemes = SubTheme.get_by_theme_id(theme)
                return [a.json() for a in subthemes], 200

        if theme is None and subtheme is None:
            themes = Theme.get_all()
            return [a.json() for a in themes], 200

        return {"error": "error occured while processing request"}, 400
Пример #16
0
    def post(self) -> ({str: str}, HTTPStatus):
        """
        Update AttrAlias (Attribute Alias) if it exists otherwise create an AttrAlias
        :param attribute_id:    Parent Attribute id to alias
        :param user_id:    Owner user id
        :param name:    Alias for Attribute name
        :param table_name:  Alias for Attribute table_name
        :param unit_id: Id of unit to be used
        :param description: Custom user description for Attribute
        :return:   AttrAlias with an HTTPstatus code OK (200) or an error message and a the appropriate HTTPStatus code
        """
        args = self.reqpaser.parse_args()

        attribute = Attributes.get_by_id(args["attribute_id"])
        if not attribute:
            return {"error": "Attribute Not Found."}, HTTPStatus.NOT_FOUND

        user = Users.find_by_id(args["user_id"])
        if not user:
            return {"error": "User Not Found."}, HTTPStatus.NOT_FOUND

        alias = AttrAlias.get_by(user_id=args["user_id"], attribute_id=args["attribute_id"])
        if alias:
            alias.name = args["name"] if "name" in args else alias.name
            alias.table_name = args["table_name"] if "table_name" in args else alias.table_name
            alias.unit_id = args["unit_id"] if "unit_id" in args else alias.unit_id
            alias.description = args["description"] if "description" in args else alias.description
        else:
            alias = AttrAlias(args["attribute_id"], args["user_id"],
                              name=args.get("name"),
                              table_name=args.get("table_name"),
                              description=args.get("description"))
        try:
            alias.save()
            alias.commit()
        except Exception as e:
            logger.error("failed to persist attribute alias", e)
            return {"error": "Failed to commit attribute alias to database",
                    "exception": e}, HTTPStatus.INTERNAL_SERVER_ERROR

        return alias.json(), HTTPStatus.OK
Пример #17
0
    def get(self) -> ({str: str}, HTTPStatus):
        """
        Fetch AttrAlias (Attribute Alias) from the database
        :param attribute_id:    Parent Attribute id
        :param user_id:    Owner user id
        :return:   AttrAlias with an HTTPstatus code OK (200) or an error message and a the appropriate HTTPStatus code
        """
        args = self.reqpaser.parse_args()

        attribute = Attributes.get_by_id(args["attribute_id"])
        if not attribute:
            return {"error": "Attribute Not Found."}, HTTPStatus.NOT_FOUND

        user = Users.find_by_id(args["user_id"])
        if not user:
            return {"error": "User Not Found."}, HTTPStatus.NOT_FOUND

        alias = AttrAlias.get_by(user_id=args["user_id"], attribute_id=args["attribute_id"])
        if not alias:
            return attribute.json(), HTTPStatus.OK

        return alias.json(), HTTPStatus.OK
Пример #18
0
    def post(self) -> ({str: str}, HTTPStatus):
        """
        Update Attributes SubTheme
        :param attribute_id: Attributes identification number
        :param sub_theme_id: SubTheme identification number
        :type attribute_id: str
        :type sub_theme_id: int
        :return: A JSON containing a message, Attribute id, SubTheme id and a HTTPStatus 200 (OK) on success
                otherwise a JSON with a error message and a HTTPStatus 404 (NotFound)
        """
        args = self.reqpaser.parse_args()

        attribute = AttrAlias.get_by_attr_id(args["attribute_id"])
        if not attribute:
            attribute = Attributes.get_by_id(args["attribute_id"])

        if not attribute:
            return {
                "error": "Attribute not found",
                "id": args["attribute_id"]
            }, HTTPStatus.NOT_FOUND

        sub_theme = SubTheme.get_by(id=args["sub_theme_id"])
        if not sub_theme:
            return {
                "error": "SubTheme not found",
                "id": args["sub_theme_id"]
            }, HTTPStatus.NOT_FOUND

        attribute.sub_theme_id(sub_theme.id)
        attribute.save()
        attribute.commit()

        return {
            "message": "Attribute SubTheme updated",
            "attribute_id": args["attribute_id"],
            "sub_theme_id": args["sub_theme_id"]
        }, HTTPStatus.OK
	def get(self):
		args = self.parser.parse_args()
		theme, subtheme, attribute_data, sensor, sensor_name, sensor_attribute, attributes, sensorid, n_predictions, predictions, grouped, harmonising_method, per_sensor, freq = None, None, None, None, None, None, [], None, 100, None, None, None, None, '1H'

		if 'theme' in args:
			theme = args['theme']

		if 'subtheme' in args:
			subtheme = args['subtheme']

		if 'attributedata' in args:
			attribute_data = args['attributedata']

		if 'attribute' in args and args['attribute'] is not None:
			_attributes = args['attribute']
			if _attributes != '':
				attributes = _attributes.split(',')

		if 'sensor' in args and args['sensor'] is not None:
			sensor = args['sensor']
			if sensor != '':
				if sensor == 'all':
					sensors = Sensor.get_all()
					return [a.json() for a in sensors], 200
				else:
					return (Sensor.get_by_id(sensor)).json(), 200

		if 'sensorname' in args and args['sensorname'] is not None:
			sensor_name = args['sensorname']
			if sensor_name != '':
				_sensors = sensor_name.split(',')
				_by_name = Sensor.get_by_name_in(_sensors)
				return [a.json() for a in _by_name], 200

		if 'sensorattribute' in args and args['sensorattribute'] is not None:
			sensor_attribute = args['sensorattribute']
			if sensor_attribute != '':
				_sen_attrs_ids = sensor_attribute.split(',')
				_sen_attrs = SensorAttribute.get_by_id_in(_sen_attrs_ids)
				attrs_ids = [_id.a_id for _id in _sen_attrs]
				_attributes = Attributes.get_by_id_in(attrs_ids)
				return [a.json() for a in _attributes], 200

		if 'grouped' in args:
			grouped = args['grouped']

		if 'harmonising_method' in args:
			harmonising_method = args['harmonising_method']

		if 'per_sensor' in args:
			per_sensor = args['per_sensor']

		if 'freq' in args:
			freq = args['freq']

		if 'predictions' in args:
			predictions = args['predictions']
			if predictions >=100:
				predictions = 100

		if 'n_predictions' in args:
			n_predictions = args['n_predictions']

		if 'sensorid' in args:
			sensorid = args['sensorid']

		if theme is None and subtheme is None \
			and len(attributes) == 0 and attribute_data is None \
			and sensor is None and sensor_name is None and sensor_attribute is None:
			themes = Theme.get_all()
			return [a.json() for a in themes], 200

		if attribute_data is not None:
			global LIMIT, OFFSET
			data = None
			operation = None
			if 'limit' in args and args['limit'] is not None:
				LIMIT = args['limit']

			if 'offset' in args and args['offset'] is not None:
				OFFSET = args['offset']

			if 'operation' in args and args['operation'] is not None:
				operation = args['operation']

			if ('fromdate' in args and args['fromdate'] is not None 
				and 'todate' in args and args['todate'] is not None):
				data = self.get_attribute_data(attribute_data, LIMIT, OFFSET, 
												args['fromdate'], args['todate'], operation)
				if predictions:
					data.append(self.get_predictions(attribute_table = data[0]["Attribute_Table"],
														sensor_id = sensorid,
														n_pred = n_predictions))
			else:
				if grouped:
					if harmonising_method:
						data = self.get_attribute_data(attribute_data, LIMIT, OFFSET, operation=operation)
						data = request_harmonised_data(data, harmonising_method=harmonising_method)
					else:
						data = self.get_attribute_data(attribute_data, LIMIT, OFFSET, operation=operation)
						data = request_grouped_data(data, per_sensor=per_sensor, freq=freq)
				else:
					data = self.get_attribute_data(attribute_data, LIMIT, OFFSET, operation=operation)

				if predictions:
					#### Ceck for data
					if data[0]["Total_Records"] != 0:
					#### Check for non numeric data
						if is_number(data[0]["Attribute_Values"][0]["Value"]):
							data.append(self.get_predictions(attribute_table = data[0]["Attribute_Table"],
																sensor_id = sensorid,
																n_pred = n_predictions))
						else:
							print("Cannot predict non-numeric data")
							pass
					else:
						pass
			return data, 200

		if attributes:
			_attrs = []
			attr = Attributes.get_by_name_in(attributes)
			for a in attr:
				_attrs.append(a.json())
			return _attrs, 200

		if subtheme is not None and subtheme != '':
			attributes = Attributes.get_by_sub_theme_id(subtheme)
			return [a.json() for a in attributes], 200

		if theme is not None and theme != '':
			subthemes = SubTheme.get_by_theme_id(theme)
			return [a.json() for a in subthemes], 200

		return {
			"error": "error occured while processing request"
		}, 400
	def get_attribute_data(self, attribute_name, limit, offset,
							fromdate=None, todate=None, operation=None):
		# clearing previous metadata
		db.metadata.clear()
		attrs = attribute_name.split(',')

		attributes = Attributes.get_by_name_in(attrs)
		data = []
		for attribute in attributes:
			model = ModelClass(attribute.table_name.lower())
			count = db.session.query(model).count()
			values = []
			if fromdate is not None and todate is not None:
				if operation is None:
					values = db.session.query(model) \
							.filter(model.api_timestamp >= fromdate) \
							.filter(model.api_timestamp <= todate) \
							.limit(limit).offset(abs(count - offset)) \
							.all()
				else:
					values = db.session.query(model) \
							.filter(model.api_timestamp >= fromdate) \
							.filter(model.api_timestamp <= todate) \
							.all()
			else:
				if operation is None:

					### refactored the query to fetch the latest values by default
					values = db.session.query(model).order_by(desc(model.api_timestamp)).limit(limit).all() # \

					# values = db.session.query(model).limit(limit) \
					# 				.offset(abs(count - offset)).all()

				else:
					values = db.session.query(model).all()



			_common = {
					'Attribute_Table': attribute.table_name,
					'Attribute_Name': attribute.name,
					'Attribute_Description': attribute.description,
					'Attribute_Unit_Value': attribute.unit_value,
					'Total_Records': count
					}
			temp = []
			if operation is None:
				for i in range(len(values)-1, -1, -1):
					temp.append({
						'Sensor_id': values[i].s_id,
						'Value': values[i].value,
						'Timestamp': str(values[i].api_timestamp)
					})
				_common['Attribute_Values'] = temp
			else:
				_values = [v.value for v in values]
				_int_values = list(map(float, _values))
				_operation_result = 0
				if operation == 'sum':
					_operation_result = sum(_int_values)
				elif operation == 'mean':
					_operation_result = sum(_int_values) / len(_int_values)
				elif operation == 'median':
					_operation_result = statistics.median(_int_values)
				_common['Result_' + operation] = _operation_result
			data.append(_common)

		return data
Пример #21
0
	def get(self):
		args = self.parser.parse_args()
		attribute_data, attributes, sensorid, n_predictions, predictions, grouped, harmonising_method, per_sensor, freq = None, [], None, 100, None, None, None, None, '1H'

		if 'attributedata' in args:
			attribute_data = args['attributedata']

		if 'attribute' in args and args['attribute'] is not None:
			_attributes = args['attribute']
			if _attributes != '':
				attributes = _attributes.split(',')

		if 'grouped' in args:
			grouped = args['grouped']

		if 'harmonising_method' in args:
			harmonising_method = args['harmonising_method']

		if 'per_sensor' in args:
			per_sensor = args['per_sensor']

		if 'freq' in args:
			freq = args['freq']

		if 'predictions' in args:
			predictions = args['predictions']
			if predictions >=100:
				predictions = 100

		if 'n_predictions' in args:
			n_predictions = args['n_predictions']

		if 'sensorid' in args:
			sensorid = args['sensorid']

		if attribute_data is not None:
			global LIMIT, OFFSET
			data = None
			operation = None
			if 'limit' in args and args['limit'] is not None:
				LIMIT = args['limit']

			if 'offset' in args and args['offset'] is not None:
				OFFSET = args['offset']

			if 'operation' in args and args['operation'] is not None:
				operation = args['operation']

			if ('fromdate' in args and args['fromdate'] is not None 
				and 'todate' in args and args['todate'] is not None):
				data = self.get_attribute_data(attribute_data, LIMIT, OFFSET, 
												args['fromdate'], args['todate'], operation)
				if predictions:
					data.append(self.get_predictions(attribute_table = data[0]["Attribute_Table"],
														sensor_id = sensorid,
														n_pred = n_predictions))
			else:
				if grouped:
					if harmonising_method:
						data = self.get_attribute_data(attribute_data, LIMIT, OFFSET, operation=operation)
						data = request_harmonised_data(data, harmonising_method=harmonising_method)
					else:
						data = self.get_attribute_data(attribute_data, LIMIT, OFFSET, operation=operation)
						data = request_grouped_data(data, per_sensor=per_sensor, freq=freq)
				else:
					data = self.get_attribute_data(attribute_data, LIMIT, OFFSET, operation=operation)

				if predictions:
					#### Ceck for data
					if data[0]["Total_Records"] != 0:
					#### Check for non numeric data
						if is_number(data[0]["Attribute_Values"][0]["Value"]):
							data.append(self.get_predictions(attribute_table = data[0]["Attribute_Table"],
																sensor_id = sensorid,
																n_pred = n_predictions))
						else:
							print("Cannot predict non-numeric data")
							pass
					else:
						pass
			return data, 200

		if attributes:
			_attrs = []
			attr = Attributes.get_by_name_in(attributes)
			for a in attr:
				_attrs.append(a.json())
			return _attrs, 200

		return {
			"error": "error occured while processing request"
		}, 400
class TestAttrAlias(TestCase):
    """
    Unittest Attribute Alias, Test Endpoints and Database persistence.
    """

    def setUp(self):
        """
        Setup a FlaskClient, AppContext, Admin user, Authorization header for requests to
        the Flask Client and a dummy Theme
        """
        self.client, self.app_context = self.create_test_client()
        self.user = self.create_admin_user()
        self.auth_header = self.get_auth_header()
        self.unit = Unit("_test_unit_type_", "A test unit")
        self.unit.save()
        self.unit.commit()
        self.attribute = Attributes.get_by_name("_test_attribute_")
        self.theme = self.create_dummy_theme()
        self.subtheme = self.create_dummy_subtheme()
        if not self.attribute:
            self.attribute = Attributes("1234567890-123456789-123456789", "_test_attribute_", "_table_name_",
                                        self.subtheme.id, self.unit.id)
            self.attribute.save()
            self.attribute.commit()

        self.clean_up = [self.user, self.attribute, self.theme, self.subtheme, self.theme, self.unit]

    def create_test_client(self) -> (FlaskClient, AppContext):
        """
        Create FlaskClient and AppContext
        :return:    FlaskClient and AppContext
        """
        test_app = create_app(DATABASE_NAME='test_analysis', TESTING=True)
        testing_client = test_app.test_client()
        test_app_context = test_app.app_context()
        test_app_context.push()
        return testing_client, test_app_context

    def create_dummy_theme(self) -> Theme:
        """
        Create a Theme
        :return: a Theme
        """
        theme = Theme.get_by_name("_test_add_theme_")
        if not theme:
            theme = Theme("_test_add_theme_")
            theme.save()
            theme.commit()
            return theme
        return theme

    def create_dummy_subtheme(self) -> SubTheme:
        """
        Create SubTheme
        :return: SubTheme
        """
        subtheme = SubTheme.get_by_name('_TEST_SUB_THEME_')
        if not subtheme:
            subtheme = SubTheme(self.theme.id, '_TEST_SUB_THEME_')
            subtheme.save()
            subtheme.commit()
            subtheme = SubTheme.get_by_name('_TEST_SUB_THEME_')
        return subtheme

    def create_admin_user(self) -> Users:
        """
        Create Admin user
        :return: an admin user
        """
        password_hash = bcrypt.hashpw("wfnbqk".encode("utf-8"), bcrypt.gensalt())
        user = Users.find_by_email("*****@*****.**")
        if not user:
            user = Users("Admin", "*****@*****.**", password_hash.decode("utf8"), True, True)
            try:
                user.save()
                user.commit()
            except Exception as e:
                pass
        return user

    def get_auth_header(self) -> {str: str}:
        """
        Create an Authorization header
        :return: An authorization header
        """
        response_login = self.client.post('/login', data=dict(email=self.user.email, password="******", remember=True),
                                          follow_redirects=True)
        response_login_json = response_login.get_json()
        return {'Authorization': 'Bearer {}'.format(response_login_json["access_token"])}

    def get_dummy_alias(self) -> db.Model:
        """
        Create dummy AttrAlias
        :return: A AttrAlias
        """
        alias = AttrAlias.get_by(name="_custom_name")
        if not alias:
            alias = AttrAlias(self.attribute.id, self.user.id, name="_custom_name", table_name="_table_name_",
                              description="a custon description")
            alias.save()
            alias.commit()
            self.clean_up.append(alias)
        return alias

    def test_create_alias(self) -> None:
        """
        Create AttrAlias database entry using database session
        """
        alias = AttrAlias(self.attribute.id, self.user.id, name="_custom_name", table_name="_table_name_",
                          description="a custon description")
        self.assertTrue(alias, msg="test_create_alias(): Failed to create Alias")
        if alias:
            self.clean_up.append(alias)

    def test_create_alias(self) -> None:
        """ Create AttrAlias using endpoint and check client response for https status code 200"""
        json_payload = {"user_id": self.user.id, "attribute_id": self.attribute.id, "name": "A_Custom_Name_12890",
                        "table_name": "_A_TaBlE_NaMe_"}
        response = self.client.post('/admin/attributes/alias', json=json_payload, headers=self.auth_header)
        if response.status_code == HTTPStatus.OK:
            alias = AttrAlias.get_by(user_id=self.user.id, name="A_Custom_Name_12890")
            if alias:
                self.clean_up.append(alias)
        self.assertEqual(response.status_code, HTTPStatus.OK)

    def test_update_alias(self) -> None:
        """ Update AttrAlias using endpoint, Check client response for https status code 200 and update table_name"""
        alias = self.get_dummy_alias()
        json_payload = {"user_id": self.user.id, "attribute_id": self.attribute.id, "name": "A_Custom_Name_12890",
                        "table_name": "_UpDaTeD_TaBlE_NaMe_"}
        response = self.client.post('/admin/attributes/alias', json=json_payload, headers=self.auth_header)
        if response.status_code == HTTPStatus.OK:
            alias = AttrAlias.get_by(user_id=self.user.id, name="A_Custom_Name_12890")
            if alias:
                self.clean_up.append(alias)
        self.assertEqual(response.status_code, HTTPStatus.OK)
        self.assertEqual(alias.table_name, "_UpDaTeD_TaBlE_NaMe_")

    def test_delete_alias(self) -> None:
        """Delete AttrAlias using endpoint and check client response for https status code 204"""
        alias = self.get_dummy_alias()
        self.assertTrue(alias)
        json_payload = {"user_id": self.user.id, "attribute_id": self.attribute.id}
        response = self.client.post('/admin/attributes/delete_alias', json=json_payload, headers=self.auth_header)
        self.assertEqual(response.status_code, HTTPStatus.NO_CONTENT)

    def delete(self, module: db.Model) -> None:
        module.delete()
        module.commit()

    def tearDown(self) -> None:
        """
        Clean up dependencies
        """
        self.subtheme.delete()
        self.subtheme.commit()

        self.theme.delete()
        self.theme.commit()
        db.engine.execute("DELETE FROM attributes WHERE id = 'A_TEST_ATTRIBUTE_ID_'")
        # self.delete(self.attribute)

        self.unit.delete()
        self.unit.commit()

        self.user.delete()
        self.user.commit()

        map(self.delete,self.clean_up)
        self.app_context.pop()
Пример #23
0
class TestGetAttributes(TestCase):
    """ Test get_attribute endpoint """
    def setUp(self) -> None:
        """
        Setup FlaskClient for tests, create an admin user and create the authorization header for requests to
        the FlaskClient
        """
        self.clean_up = []
        self.client, self.app_context = self.create_test_client()
        self.user = self.create_admin_user()
        self.theme = self.create_dummy_theme()
        self.subtheme = self.create_dummy_subtheme()
        self.unit = self.get_dummy_unit()
        self.attribute = Attributes("A_TEST_ATTRIBUTE_ID_",
                                    "_TEST_ATTR_NAME_",
                                    "_A_TABLE_NAME",
                                    self.subtheme.id,
                                    self.unit.id,
                                    description="_A_CUSTOM_DESCRIPTION_")
        self.attribute.save()
        self.attribute.commit()
        self.clean_up.append(self.attribute)

    def create_test_client(self) -> (FlaskClient, AppContext):
        """
        Create FlaskClient and AppContext
        :return:    FlaskClient and AppContext
        """
        test_app = create_app(DATABASE_NAME='test_analysis', TESTING=True)
        testing_client = test_app.test_client()
        test_app_context = test_app.app_context()
        test_app_context.push()
        return testing_client, test_app_context

    def create_dummy_theme(self) -> Theme:
        """
        Create a Theme
        :return: a Theme
        """
        theme = Theme.get_by_name("_test_add_theme_")
        if not theme:
            theme = Theme("_test_add_theme_")
            theme.save()
            theme.commit()
            self.clean_up.append(theme)
            return theme
        return theme

    def create_dummy_subtheme(self) -> SubTheme:
        """
        Create SubTheme
        :return: SubTheme
        """
        subtheme = SubTheme.get_by_name('_TEST_SUB_THEME_')
        if not subtheme:
            subtheme = SubTheme(self.theme.id, '_TEST_SUB_THEME_')
            subtheme.save()
            subtheme.commit()
            self.clean_up.append(subtheme)
            subtheme = SubTheme.get_by_name('_TEST_SUB_THEME_')
        return subtheme

    def get_dummy_unit(self):
        unit = Unit.get_by_symbol("_A_UNIT_FOR_TESTING")
        if not unit:
            unit = Unit("_A_UNIT_FOR_TESTING", "_A_TEST_UNIT_DESCRIPTION_")
            unit.save()
            unit.commit()
        if unit not in self.clean_up:
            self.clean_up.append(unit)

        return unit

    def create_admin_user(self) -> Users:
        """
        Create Admin user
        :return: an admin user
        """
        password_hash = bcrypt.hashpw("wfnbqk".encode("utf-8"),
                                      bcrypt.gensalt())
        user = Users.find_by_email("*****@*****.**")
        if not user:
            user = Users("Admin", "*****@*****.**",
                         password_hash.decode("utf8"), True, True)
            try:
                user.save()
                user.commit()
            except Exception as e:
                pass
        self.clean_up.append(user)
        return user

    def get_auth_header(self) -> {str: str}:
        """
        Create an Authorization header
        :return: An authorization header
        """
        response_login = self.client.post('/login',
                                          data=dict(email=self.user.email,
                                                    password="******",
                                                    remember=True),
                                          follow_redirects=True)
        response_login_json = response_login.get_json()
        return {
            'Authorization':
            'Bearer {}'.format(response_login_json["access_token"])
        }

    def test_get_all_attributes(self) -> None:
        """ Fetch all Attributes using endpoint"""
        response = self.client.get('/admin/attributes/get_attributes')
        self.assertEqual(response.status_code, HTTPStatus.OK)

    def test_get_attribute_by_id(self) -> None:
        """ Fetch Attribute by id using endpoint"""
        query_string_data = {"attribute_id": self.attribute.id}
        response = self.client.get('/admin/attributes/get_attributes',
                                   data=query_string_data)
        self.assertEqual(response.status_code, HTTPStatus.OK)
        json_response = response.get_json()
        self.assertEqual(json_response[0]["id"],
                         self.attribute.id,
                         msg="Attribute id does not match")
        self.assertEqual(json_response[0]["name"],
                         self.attribute.name,
                         msg="Attribute name does not match")

    def delete(self, module: db.Model) -> None:
        """
        Delete db>Model instances from the database
        :param module: Model to be deleted
        :type module: db>Model
        """
        module.delete()
        module.commit()

    def tearDown(self) -> None:
        """
        Clean up dependencies
        """
        self.subtheme.delete()
        self.subtheme.commit()

        self.theme.delete()
        self.theme.commit()
        db.engine.execute(
            "DELETE FROM attributes WHERE id = 'A_TEST_ATTRIBUTE_ID_'")
        # self.delete(self.attribute)

        self.unit.delete()
        self.unit.commit()

        self.user.delete()
        self.user.commit()

        map(self.delete, self.clean_up)
        self.app_context.pop()
Пример #24
0
    def range_wrapper(*args: Any, **kwargs: dict):
        """
        Execute importer function and then compute minimum and maximum
        values of attributes
        :param args: Arguments of import_function parameter
        :param kwargs: Keyword Arguments of import_function parameter
        """
        import_function(*args, **kwargs)

        attribute_entries = Attributes.get_all()
        for attribute in attribute_entries:
            attribute_range = AttributeRange.get_by_attr_id(attribute.id)
            if attribute_range:
                most_recent_entry = Attributes.most_recent_timestamp(
                    attribute.table_name)
                if most_recent_entry:
                    if attribute_range.latest_update < most_recent_entry:
                        attr_min = Attributes.attribute_min(
                            attribute.table_name)
                        attr_max = Attributes.attribute_max(
                            attribute.table_name)
                        try:
                            attribute_range.minimum_sensor_id = \
                                attr_min.s_id
                            attribute_range.minimum = attr_min.value
                            attribute_range.minimum_recorded_date = \
                                attr_min.timestamp
                            attribute_range.maximum_sensor_id = \
                                attr_max.s_id
                            attribute_range.maximum = attr_max.value
                            attribute_range.maximum_recorded_date = \
                                attr_max.timestamp
                            attribute_range.latest_update = datetime.now()
                            attribute_range.save()
                            attribute_range.commit()

                            PushAlert.check_alerts(attribute_range)
                            check_min_and_max_alert_widgets(attribute_range)
                        except AttributeError:
                            pass
            else:
                attr_min = Attributes.attribute_min(attribute.table_name)
                attr_max = Attributes.attribute_max(attribute.table_name)
                try:
                    new_range_entry = \
                        AttributeRange(attribute.id,
                                       attr_min.s_id,
                                       attr_min.value,
                                       attr_min.timestamp,
                                       attr_max.s_id,
                                       attr_max.value,
                                       attr_max.timestamp,
                                       datetime.now())
                    new_range_entry.save()
                    new_range_entry.commit()
                    check_min_and_max_alert_widgets(new_range_entry)
                    PushAlert.check_alerts(new_range_entry)
                except AttributeError:
                    new_range_entry = AttributeRange(attribute.id, None, None,
                                                     None, None, None, None,
                                                     datetime.now())
                    new_range_entry.save()
                    new_range_entry.commit()
Пример #25
0
def check_min_and_max_alert_widgets(attribute_range_entry: db.Model):
    """
    Send emails to users for alert widgets that have been triggered
    :param attribute_range_entry: Entry in the attribute range table
    """

    if attribute_range_entry.maximum:
        max_alerts = AlertWidgetModel.get_max_alerts(attribute_range_entry)
        for alert in max_alerts:
            user_details = Users.find_by_id(alert["user_id"])
            if user_details:
                attr = Attributes.get_by_id(attribute_range_entry.attribute_id)
                if attr:
                    if not send_alert_email(
                            user_details.email, user_details.fullname,
                            attr.name, attribute_range_entry.maximum,
                            attribute_range_entry.maximum_recorded_date,
                            attribute_range_entry.maximum_sensor_id,
                            alert["max_threshold"], "exceeded"):
                        logger.error("Server error prevented the  "
                                     "sending of a max alert email "
                                     "to {} regarding attribute with "
                                     "id {}".format(
                                         user_details.email,
                                         attribute_range_entry.attribute_id))
                else:
                    logger.error("Could not send max alert email to "
                                 "user with id {} as the attribute with "
                                 "id {} does not exist ".format(
                                     alert["user_id"],
                                     attribute_range_entry.attribute_id))
            else:
                logger.error("Could not send max alert email to "
                             "user with id {} as the user does "
                             "not exist ".format(alert["user_id"]))

    if attribute_range_entry.minimum:
        min_alerts = AlertWidgetModel.get_min_alerts(attribute_range_entry)
        for alert in min_alerts:
            user_details = Users.find_by_id(alert["user_id"])
            if user_details:
                attr = Attributes.get_by_id(attribute_range_entry.attribute_id)
                if attr:
                    if not send_alert_email(
                            user_details.email, user_details.fullname,
                            attr.name, attribute_range_entry.minimum,
                            attribute_range_entry.minimum_recorded_date,
                            attribute_range_entry.minimum_sensor_id,
                            alert["min_threshold"], "fell short of"):
                        logger.error("Server error prevented the sending of "
                                     "a  min alert email to {} regarding  "
                                     "attribute with id {}".format(
                                         user_details.email,
                                         attribute_range_entry.attribute_id))
                else:
                    logger.error("Could not send min alert email to "
                                 "user with id {} as the attribute with "
                                 "id {} does not exist ".format(
                                     alert["user_id"],
                                     attribute_range_entry.attribute_id))
            else:
                logger.error("Could not send min alert email to "
                             "user with id {} as the user does "
                             "not exist ".format(alert["user_id"]))