Пример #1
0
 def __init__(self, app):
     for database in app.config['DATABASES']:
         # We need to have an active request to 'trick' set_database and work with the database we want
         with app.test_request_context('/{}/devices'.format(database)):
             print(('Starting update process for database {}'.format(
                 AccountDomain.get_requested_database())))
             app.auth._set_database(True)
             self.materialize_component_info()
             print(('Database {} successfully updated.'.format(
                 AccountDomain.get_requested_database())))
Пример #2
0
 def __init__(self, app):
     for database in app.config['DATABASES']:
         # We need to have an active request to 'trick' set_database and work with the database we want
         with app.test_request_context('/{}/devices'.format(database)):
             print('Starting update process for database {}'.format(AccountDomain.get_requested_database()))
             app.auth._set_database(True)
             self.set_prefix()
             self.re_materialize_events()
             self.re_materialize_owners()
             print('Database {} successfully updated.'.format(AccountDomain.get_requested_database()))
Пример #3
0
def login():
    """
    Performs a login. We make this out of eve, being totally open.
    :return:
    """
    try:
        account = AccountDomain.get_one({'email': request.json['email']})
        if not AccountDomain.verify_password(request.json['password'], account['password']):
            raise WrongCredentials()
        account['token'] = AccountDomain.hash_token(account['token'])
        account['_id'] = str(account['_id'])
        return jsonify(account)
    except (KeyError, TypeError, UserNotFound):
        raise WrongCredentials()
Пример #4
0
def login():
    """
    Performs a login. We make this out of eve, being totally open.
    :return:
    """
    try:
        account = AccountDomain.get_one({'email': request.json['email']})
        if not AccountDomain.verify_password(request.json['password'],
                                             account['password']):
            raise WrongCredentials()
        account['token'] = AccountDomain.hash_token(account['token'])
        account['_id'] = str(account['_id'])
        return jsonify(account)
    except (KeyError, TypeError, UserNotFound):
        raise WrongCredentials()
Пример #5
0
def set_organization(deallocates: list):
    for deallocate in deallocates:
        with suppress(
                UserNotFound,
                KeyError):  # todo ensure organization is not always needed
            deallocate['fromOrganization'] = AccountDomain.get_one(
                deallocate['from'])['organization']
Пример #6
0
 def clean_device(device: dict):
     """Removes values that are not supposed to be sent, like materialized or readonly ones."""
     schema = current_app.config['DOMAIN'][Naming.resource(device['@type'])]['schema']
     _id = device['_id']
     for field in copy.copy(device):
         if '_' in field or not {'materialized', 'readonly'}.isdisjoint(set(schema[field].keys())):
             del device[field]
     device['url'] = DeviceDomain.url_agent_for(AccountDomain.get_requested_database(), _id)
Пример #7
0
def set_organization(receives: list):
    """
    This method needs to execute after add_or_get_inactive_account
    :param receives:
    :return:
    """
    for receive in receives:
        with suppress(UserNotFound):
            receive['receiverOrganization'] = AccountDomain.get_one(receive['receiver']).get('organization')
Пример #8
0
def _add_or_get_inactive_account_id(event, field_name):
    """
    We need to execute after insert and insert_resource.
    """
    if field_name in event and type(event[field_name]) is dict:
        try:
            # We look for just accounts that share our database
            _id = AccountDomain.get_one(
                {
                    "email": event[field_name]["email"]
                    # 'databases': {'$in': AccountDomain.actual['databases']} todo review this
                }
            )["_id"]
        except UserNotFound:
            event[field_name]["databases"] = [AccountDomain.get_requested_database()]
            event[field_name]["active"] = False
            event[field_name]["@type"] = "Account"
            _id = execute_post_internal("accounts", event[field_name], True)["_id"]
        event[field_name] = _id
Пример #9
0
def set_organization(receives: list):
    """
    This method needs to execute after add_or_get_inactive_account
    :param receives:
    :return:
    """
    for receive in receives:
        with suppress(UserNotFound):
            receive['receiverOrganization'] = AccountDomain.get_one(
                receive['receiver']).get('organization')
Пример #10
0
 def clean_device(device: dict):
     """Removes values that are not supposed to be sent, like materialized or readonly ones."""
     schema = current_app.config['DOMAIN'][Naming.resource(
         device['@type'])]['schema']
     _id = device['_id']
     for field in copy.copy(device):
         if '_' in field or not {'materialized', 'readonly'}.isdisjoint(
                 set(schema[field].keys())):
             del device[field]
     device['url'] = DeviceDomain.url_agent_for(
         AccountDomain.get_requested_database(), _id)
Пример #11
0
def _add_or_get_inactive_account_id(event, field_name):
    """
    We need to execute after insert and insert_resource.
    """
    if field_name in event and type(event[field_name]) is dict:
        try:
            # We look for just accounts that share our database
            _id = AccountDomain.get_one({
                'email': event[field_name]['email']
                # 'databases': {'$in': AccountDomain.actual['databases']} todo review this
            })['_id']
        except UserNotFound:
            event[field_name]['databases'] = [
                AccountDomain.get_requested_database()
            ]
            event[field_name]['active'] = False
            event[field_name]['@type'] = 'Account'
            _id = execute_post_internal('accounts', event[field_name],
                                        True)['_id']
        event[field_name] = _id
Пример #12
0
 def create_self_machine_account(self):
     email, password = self.app.config['AGENT_ACCOUNTS']['self']
     self.db.accounts.insert(
         {
             'role': 'superuser',
             'token': 'QYADFBPNZZDFJEWAFGGF',
             'databases': self.app.config['DATABASES'],
             '@type': 'Account',
             'email': email,
             'password': AccountDomain.encrypt_password(password)
         }
     )
Пример #13
0
 def get_device(self, device_id: str) -> dict:
     """Gets the device ready to be sent to another database."""
     # It is just so easy to load stuff (through permissions, etc) through Python-Eve's API
     embedded = json.dumps({'components': 1})
     projection = json.dumps({'events': 0})
     token = AccountDomain.hash_token(AccountDomain.actual_token)
     url = '{}/devices/{}?embedded={}&projection={}'.format(self.database, device_id, embedded, projection)
     device = execute_get(url, token)
     self.clean_device(device)
     for component in device.get('components', []):
         self.clean_device(component)
     return device
Пример #14
0
 def get_device(self, device_id: str) -> dict:
     """Gets the device ready to be sent to another database."""
     # It is just so easy to load stuff (through permissions, etc) through Python-Eve's API
     embedded = json.dumps({'components': 1})
     projection = json.dumps({'events': 0})
     token = AccountDomain.hash_token(AccountDomain.actual_token)
     url = '{}/devices/{}?embedded={}&projection={}'.format(
         self.database, device_id, embedded, projection)
     device = execute_get(url, token)
     self.clean_device(device)
     for component in device.get('components', []):
         self.clean_device(component)
     return device
Пример #15
0
 def create_dummy_user(self):
     self.db.accounts.insert(
         {
             'email': "[email protected]",
             'password': AccountDomain.encrypt_password('1234'),
             'role': 'admin',
             'token': 'NOFATDNNUB',
             'databases': self.app.config['DATABASES'],
             'defaultDatabase': self.app.config['DATABASES'][0],
             '@type': 'Account'
         }
     )
     self.account = self.db.accounts.find_one({'email': '[email protected]'})
Пример #16
0
def create_account(email: str, password: str, databases: list,
                   role: str = None, name: str = None, organization: str = None, blocked: bool = False,
                   default_database: str = None, mongo_host: str = None, mongo_port: int = None,
                   db_name: str = 'dh__accounts'):
    """
    Creates an account. You can call the file directly::

        create_account.py [email protected] 123 [\'db1\'] superuser

    :param email:
    :param password:
    :param databases: The databases the user has access to
    :param mongo_host: Leave empty to use default.
    :param mongo_port: Leave empty to use default.
    :param db_name: The name of the database to create the account to. Leave empty to use default.
    :param default_database: if none we use the first database of *databases*.
    :param role: the role of the user, if none, we use the default set in Account type.
    :param name:
    :param organization:
    :param blocked: False if it is not set
    :throws UserAlreadyExists:
    :return: The account with the *base256* token and *hashed* password.
    """
    connection = MongoClient(mongo_host, mongo_port)
    db = connection[db_name]
    if db.accounts.find_one({'email': email}):
        raise UserAlreadyExists()
    account = {
        'email': email,
        'password': password,
        'databases': databases,
        'defaultDatabase': default_database or databases[0],
        '@type': 'Account',
        'blocked': eval(blocked) if type(blocked) is str else blocked,
        'active': True
    }
    if role is not None:
        account['role'] = role
    if name is not None:
        account['name'] = name
    if organization is not None:
        account['organization'] = organization
    token = generate_token()
    while db.accounts.find_one({'token': token}) is not None:
        token = generate_token()
    account["token"] = token
    hash_password([account])
    db.accounts.insert(account)
    returned_account = db.accounts.find_one({'email': email})
    return returned_account, AccountDomain.hash_token(returned_account['token'])
Пример #17
0
def export(db, resource):
    try:
        file_type = FILE_TYPE_MIME_TABLE[request.accept_mimetypes.best]
    except KeyError:
        raise NotAcceptable()
    ids = request.args.getlist('ids')
    token = AccountDomain.hash_token(AccountDomain.actual_token)
    group_by = request.args.get('groupBy')
    default_group = request.args.get('defaultGroup', 'Others')
    embedded = {'byUser': 1, 'events': 1, 'components': 1, 'place': 1, 'owners': 1}
    translator = SpreadsheetTranslator(current_app.config, group_by=group_by, default_group=default_group)
    exporter = Exporter(translator, embedded, token)
    spreadsheets, _ = exporter.export(ids, db, resource)[0]
    return excel.make_response_from_book_dict(spreadsheets, file_type, file_name=resource)
Пример #18
0
    def generate_returned_same_as(self):
        """
        Populates self.returned_same_as with a dict where the URL of devices in the caller agent as keys and a copy of
        'sameAs' in this agent.

        This value will be returned to the caller agent (see
        :py:func:`ereuse_devicehub.resources.event.device.migrate.hooks.return_same_as`) which can use it to update
        its 'sameAs' values with new references.
        """
        for device, url in zip([self.device] + self.components, self.urls):
            device = DeviceDomain.get_one(device['_id'])
            same_as = set(device['sameAs'])
            same_as.remove(url)
            same_as.add(
                DeviceDomain.url_agent_for(
                    AccountDomain.get_requested_database(), device['_id']))
            self.returned_same_as[url] = list(same_as)
Пример #19
0
def submit_migrate(migrates: dict):
    """
    Sends a Migrate event to the other DeviceHub.
    Note as the other DeviceHub requires the url of this event,
    this method needs to be executed after reaching the Database.
    """
    for migrate in migrates:
        if 'to' in migrate:
            auth = AgentAuth(migrate['to']['baseUrl'])
            submitter = MigrateSubmitter(current_app, MigrateTranslator(current_app.config), auth=auth)
            try:
                response, *_ = submitter.submit(migrate, AccountDomain.get_requested_database())
                migrate['to']['url'] = migrate['to']['baseUrl'] + response['_links']['self']['href']
                _update_same_as(response['returnedSameAs'])
            except InnerRequestError as e:
                execute_delete(Migrate.resource_name, migrate['_id'])
                raise e
            else:
                _remove_devices_from_places(migrate)
                update = {'$set': {'to.url': migrate['to']['url'], 'devices': [_id for _id in migrate['devices']]}}
                DeviceEventDomain.update_one_raw(migrate['_id'], update)
Пример #20
0
def submit_migrate(migrates: dict):
    """
    Sends a Migrate event to the other DeviceHub.
    Note as the other DeviceHub requires the url of this event,
    this method needs to be executed after reaching the Database.
    """
    for migrate in migrates:
        if 'to' in migrate:
            auth = AgentAuth(migrate['to']['baseUrl'])
            submitter = MigrateSubmitter(current_app, MigrateTranslator(current_app.config), auth=auth)
            try:
                response, *_ = submitter.submit(migrate, AccountDomain.get_requested_database())
                migrate['to']['url'] = migrate['to']['baseUrl'] + response['_links']['self']['href']
                _update_same_as(response['returnedSameAs'])
            except InnerRequestError as e:
                execute_delete(Migrate.resource_name, migrate['_id'])
                raise e
            else:
                _remove_devices_from_places(migrate)
                update = {'$set': {'to.url': migrate['to']['url'], 'devices': [_id for _id in migrate['devices']]}}
                DeviceEventDomain.update_one_raw(migrate['_id'], update)
Пример #21
0
 def _set_database(self, force: bool = False):
     """
     Sets the actual database according of the value in the URL.
     :param force: Sets the database even if the user has no access to it
     :raises NotADatabase: When the URL is malformed or doesn't contain an existing database
     :raises UnauthorizedToUseDatabase: If force is true this won't raise
     """
     try:
         requested_database = AccountDomain.get_requested_database()
     except NotADatabase as e:
         try:
             if e.body['requested_path'] not in current_app.config['RESOURCES_NOT_USING_DATABASES'] \
                     and not current_app.config['DOMAIN'][e.body['requested_path']]['use_default_database']:
                 raise e
         except KeyError:
             raise e
     else:
         if force or (requested_database in AccountDomain.actual['databases']
                      or AccountDomain.actual['role'] == Role.SUPERUSER):
             self.set_mongo_prefix(requested_database.replace("-", "").upper())
         else:
             raise UnauthorizedToUseDatabase()
Пример #22
0
def export(db, resource):
    try:
        file_type = FILE_TYPE_MIME_TABLE[request.accept_mimetypes.best]
    except KeyError:
        raise NotAcceptable()
    ids = request.args.getlist('ids')
    token = AccountDomain.hash_token(AccountDomain.actual_token)
    group_by = request.args.get('groupBy')
    default_group = request.args.get('defaultGroup', 'Others')
    embedded = {
        'byUser': 1,
        'events': 1,
        'components': 1,
        'place': 1,
        'owners': 1
    }
    translator = SpreadsheetTranslator(current_app.config,
                                       group_by=group_by,
                                       default_group=default_group)
    exporter = Exporter(translator, embedded, token)
    spreadsheets, _ = exporter.export(ids, db, resource)[0]
    return excel.make_response_from_book_dict(spreadsheets,
                                              file_type,
                                              file_name=resource)
Пример #23
0
def set_organization(deallocates: list):
    for deallocate in deallocates:
        with suppress(UserNotFound, KeyError):  # todo ensure organization is not always needed
            deallocate['fromOrganization'] = AccountDomain.get_one(deallocate['from'])['organization']
Пример #24
0
 def set_superuser(self):
     with self.app.app_context():
         AccountDomain.update_raw(self.account['_id'], {'$set': {'role': 'superuser'}})
Пример #25
0
def set_organization(allocates: list):
    for allocate in allocates:
        with suppress(UserNotFound, KeyError):
            allocate['toOrganization'] = AccountDomain.get_one(
                allocate['to'])['organization']
Пример #26
0
def create_account(
    email: str,
    password: str,
    databases: list,
    role: str = None,
    name: str = None,
    organization: str = None,
    blocked: bool = False,
    default_database: str = None,
    mongo_host: str = None,
    mongo_port: int = None,
    db_name: str = "dh__accounts",
):
    """
    Creates an account. You can call the file directly::

        create_account.py [email protected] 123 [\'db1\'] superuser

    :param email:
    :param password:
    :param databases: The databases the user has access to
    :param mongo_host: Leave empty to use default.
    :param mongo_port: Leave empty to use default.
    :param db_name: The name of the database to create the account to. Leave empty to use default.
    :param default_database: if none we use the first database of *databases*.
    :param role: the role of the user, if none, we use the default set in Account type.
    :param name:
    :param organization:
    :param blocked: False if it is not set
    :throws UserAlreadyExists:
    :return: The account with the *base256* token and *hashed* password.
    """
    connection = MongoClient(mongo_host, mongo_port)
    db = connection[db_name]
    if db.accounts.find_one({"email": email}):
        raise UserAlreadyExists()
    databases = eval(databases)
    if type(databases) is not list:
        raise TypeError("databases has to be a list")
    account = {
        "email": email,
        "password": password,
        "databases": databases,
        "defaultDatabase": default_database or databases[0],
        "@type": "Account",
        "blocked": eval(blocked) if type(blocked) is str else blocked,
        "active": True,
    }
    if role is not None:
        account["role"] = role
    if name is not None:
        account["name"] = name
    if organization is not None:
        account["organization"] = organization
    token = generate_token()
    while db.accounts.find_one({"token": token}) is not None:
        token = generate_token()
    account["token"] = token
    hash_password([account])
    db.accounts.insert(account)
    returned_account = db.accounts.find_one({"email": email})
    return returned_account, AccountDomain.hash_token(returned_account["token"])
Пример #27
0
def set_organization(allocates: list):
    for allocate in allocates:
        with suppress(UserNotFound, KeyError):
            allocate['toOrganization'] = AccountDomain.get_one(allocate['to'])['organization']