예제 #1
0
 def set_inventory_config(cls,
                          name: str = None,
                          org_name: str = None,
                          org_id: str = None,
                          tag_url: boltons.urlutils.URL = None,
                          tag_token: uuid.UUID = None):
     try:
         inventory = Inventory.current
     except ResourceNotFound:  # No inventory defined in db yet
         inventory = Inventory(id=current_app.id,
                               name=name,
                               tag_provider=tag_url,
                               tag_token=tag_token)
         db.session.add(inventory)
     if org_name or org_id:
         from ereuse_devicehub.resources.agent.models import Organization
         try:
             org = Organization.query.filter_by(tax_id=org_id, name=org_name).one()
         except ResourceNotFound:
             org = Organization(tax_id=org_id, name=org_name)
         org.default_of = inventory
     if tag_url:
         inventory.tag_provider = tag_url
     if tag_token:
         inventory.tag_token = tag_token
예제 #2
0
    def printable(self) -> bool:
        """Can the tag be printed by the user?

        Only tags that are from the default organization can be
        printed by the user.
        """
        return self.org_id == Organization.get_default_org_id()
예제 #3
0
def test_membership():
    """Tests assigning an Individual to an Organization."""
    person = Person(name='Timmy')
    org = Organization(name='ACME')
    person.member_of.add(Membership(org, person, id='acme-1'))
    db.session.add(person)
    db.session.flush()
예제 #4
0
def test_get_tags_endpoint(user: UserClient, app: Devicehub,
                           requests_mock: requests_mock.mocker.Mocker):
    """Performs GET /tags after creating 3 tags, 2 printable and one
    not. Only the printable ones are returned.
    """
    # Prepare test
    with app.app_context():
        org = Organization(name='bar', tax_id='bartax')
        tag = Tag(id='bar-1', org=org, provider=URL('http://foo.bar'), owner_id=user.user['id'])
        db.session.add(tag)
        db.session.commit()
        assert not tag.printable

    requests_mock.post('https://example.com/',
                       # request
                       request_headers={
                           'Authorization': 'Basic {}'.format(DevicehubClient.encode_token(
                               '52dacef0-6bcb-4919-bfed-f10d2c96ecee'))
                       },
                       # response
                       json=['tag1id', 'tag2id'],
                       status_code=201)
    user.post({}, res=Tag, query=[('num', 2)])

    # Test itself
    data, _ = user.get(res=Tag)
    assert len(data['items']) == 2, 'Only 2 tags are printable, thus retreived'
    # Order is created descending
    assert data['items'][0]['id'] == 'tag2id'
    assert data['items'][0]['printable']
    assert data['items'][1]['id'] == 'tag1id'
    assert data['items'][1]['printable'], 'Tags made this way are printable'
예제 #5
0
def test_membership_repeated():
    person = Person(name='Timmy')
    org = Organization(name='ACME')
    person.member_of.add(Membership(org, person, id='acme-1'))
    db.session.add(person)

    person.member_of.add(Membership(org, person))
    with pytest.raises(DBError):
        db.session.flush()
예제 #6
0
def test_tag_create_tags_cli(app: Devicehub, user: UserClient):
    """Checks creating tags with the CLI endpoint."""
    owner_id = user.user['id']
    runner = app.test_cli_runner()
    runner.invoke('tag', 'add', 'id1', '-u', owner_id)
    with app.app_context():
        tag = Tag.query.one()  # type: Tag
        assert tag.id == 'id1'
        assert tag.org.id == Organization.get_default_org_id()
예제 #7
0
def test_create_tag(user: UserClient):
    """Creates a tag specifying a custom organization."""
    org = Organization(name='bar', tax_id='bartax')
    tag = Tag(id='bar-1', org=org, provider=URL('http://foo.bar'), owner_id=user.user['id'])
    db.session.add(tag)
    db.session.commit()
    tag = Tag.query.one()
    assert tag.id == 'bar-1'
    assert tag.provider == URL('http://foo.bar')
    res, _ = user.get(res=Tag, item=tag.code, status=422)
    assert res['type'] == 'TagNotLinked'
예제 #8
0
def test_membership_repeating_id():
    person = Person(name='Timmy')
    org = Organization(name='ACME')
    person.member_of.add(Membership(org, person, id='acme-1'))
    db.session.add(person)
    db.session.flush()

    person2 = Person(name='Tommy')
    person2.member_of.add(Membership(org, person2, id='acme-1'))
    db.session.add(person2)
    with pytest.raises(DBError) as e:
        db.session.flush()
    assert 'One member id per organization' in str(e)
예제 #9
0
def test_organization():
    """Tests creating an organization."""
    org = Organization(name='ACME',
                       tax_id='xyz',
                       country=Country.ES,
                       email='*****@*****.**')
    db.session.add(org)
    db.session.commit()

    o = schemas.Organization().dump(org)
    assert o['name'] == org.name == 'ACME'
    assert o['taxId'] == org.tax_id == 'xyz'
    assert org.country.name == o['country'] == 'ES'
예제 #10
0
def test_create_two_same_tags(user: UserClient):
    """Ensures there cannot be two tags with the same ID and organization."""

    db.session.add(Tag(id='foo-bar', owner_id=user.user['id']))
    db.session.add(Tag(id='foo-bar', owner_id=user.user['id']))

    with raises(DBError):
        db.session.commit()
    db.session.rollback()
    # And it works if tags are in different organizations
    db.session.add(Tag(id='foo-bar', owner_id=user.user['id']))
    org2 = Organization(name='org 2', tax_id='tax id org 2')
    db.session.add(Tag(id='foo-bar', org=org2, owner_id=user.user['id']))
    with raises(DBError):
        db.session.commit()
예제 #11
0
def test_delete_tags(user: UserClient, client: Client):
    """Delete a named tag."""
    # Delete Tag Named
    g.user = User.query.one()
    pc = Desktop(serial_number='sn1', chassis=ComputerChassis.Tower, owner_id=user.user['id'])
    db.session.add(pc)
    db.session.commit()
    tag = Tag(id='bar', owner_id=user.user['id'], device_id=pc.id)
    db.session.add(tag)
    db.session.commit()
    tag = Tag.query.all()[-1]
    assert tag.id == 'bar'
    # Is not possible delete one tag linked to one device
    res, _ = user.delete(res=Tag, item=tag.id, status=422)
    msg = 'The tag bar is linked to device'
    assert msg in res['message'][0]

    tag.device_id = None
    db.session.add(tag)
    db.session.commit()
    # Is not possible delete one tag from an anonymous user
    client.delete(res=Tag, item=tag.id, status=401)

    # Is possible delete one normal tag
    user.delete(res=Tag, item=tag.id)
    user.get(res=Tag, item=tag.id, status=404)

    # Delete Tag UnNamed
    org = Organization(name='bar', tax_id='bartax')
    tag = Tag(id='bar-1', org=org, provider=URL('http://foo.bar'), owner_id=user.user['id'])
    db.session.add(tag)
    db.session.commit()
    tag = Tag.query.all()[-1]
    assert tag.id == 'bar-1'
    res, _ = user.delete(res=Tag, item=tag.id, status=422)
    msg = 'This tag {} is unnamed tag. It is imposible delete.'.format(tag.id)
    assert msg in res['message']
    tag = Tag.query.all()[-1]
    assert tag.id == 'bar-1'
예제 #12
0
class Tag(Thing):
    id = Column(db.CIText(), primary_key=True)
    id.comment = """The ID of the tag."""
    org_id = Column(UUID(as_uuid=True),
                    ForeignKey(Organization.id),
                    primary_key=True,
                    # If we link with the Organization object this instance
                    # will be set as persistent and added to session
                    # which is something we don't want to enforce by default
                    default=lambda: Organization.get_default_org_id())
    org = relationship(Organization,
                       backref=backref('tags', lazy=True),
                       primaryjoin=Organization.id == org_id,
                       collection_class=set)
    """The organization that issued the tag."""
    provider = Column(URL())
    provider.comment = """
        The tag provider URL. If None, the provider is this Devicehub.
    """
    device_id = Column(BigInteger,
                       # We don't want to delete the tag on device deletion, only set to null
                       ForeignKey(Device.id, ondelete=DB_CASCADE_SET_NULL))
    device = relationship(Device,
                          backref=backref('tags', lazy=True, collection_class=Tags),
                          primaryjoin=Device.id == device_id)
    """The device linked to this tag."""
    secondary = Column(db.CIText(), index=True)
    secondary.comment = """
        A secondary identifier for this tag. It has the same
        constraints as the main one. Only needed in special cases.
    """

    __table_args__ = (
        db.Index('device_id_index', device_id, postgresql_using='hash'),
    )

    def __init__(self, id: str, **kwargs) -> None:
        super().__init__(id=id, **kwargs)

    def like_etag(self):
        """Checks if the tag conforms to the `eTag spec <http:
        //devicehub.ereuse.org/tags.html#etags>`_.
        """
        with suppress(ValueError):
            provider, id = self.id.split('-')
            if len(provider) == 2 and 5 <= len(id) <= 10:
                return True
        return False

    @classmethod
    def from_an_id(cls, id: str) -> Query:
        """Query to look for a tag from a possible identifier."""
        return cls.query.filter((cls.id == id) | (cls.secondary == id))

    @validates('id', 'secondary')
    def does_not_contain_slash(self, _, value: str):
        if '/' in value:
            raise ValidationError('Tags cannot contain slashes (/).')
        return value

    @validates('provider')
    def use_only_domain(self, _, url: URL):
        if url.path:
            raise ValidationError('Provider can only contain scheme and host',
                                  field_names=['provider'])
        return url

    __table_args__ = (
        UniqueConstraint(id, org_id, name='one tag id per organization'),
        UniqueConstraint(secondary, org_id, name='one secondary tag per organization')
    )

    @property
    def type(self) -> str:
        return self.__class__.__name__

    @property
    def url(self) -> urlutils.URL:
        """The URL where to GET this device."""
        # todo this url only works for printable internal tags
        return urlutils.URL(url_for_resource(Tag, item_id=self.id))

    @property
    def printable(self) -> bool:
        """Can the tag be printed by the user?

        Only tags that are from the default organization can be
        printed by the user.
        """
        return self.org_id == Organization.get_default_org_id()

    @classmethod
    def is_printable_q(cls):
        """Return a SQLAlchemy filter expression for printable queries"""
        return cls.org_id == Organization.get_default_org_id()

    def __repr__(self) -> str:
        return '<Tag {0.id} org:{0.org_id} device:{0.device_id}>'.format(self)

    def __str__(self) -> str:
        return '{0.id} org: {0.org.name} device: {0.device}'.format(self)

    def __format__(self, format_spec: str) -> str:
        return '{0.org.name} {0.id}'.format(self)
예제 #13
0
 def is_printable_q(cls):
     """Return a SQLAlchemy filter expression for printable queries"""
     return cls.org_id == Organization.get_default_org_id()
예제 #14
0
def test_organization_no_slash_name():
    with pytest.raises(ValidationError):
        Organization(name='/')