コード例 #1
0
 def assertMembershipIntervalsEqual(self, expected):
     memberships = session.session.query(Membership).filter_by(
         user=self.user, group=self.group)
     got = IntervalSet(closed(m.begins_at, m.ends_at) for m in memberships)
     assert expected == got, "IntervalSets differ: " \
                             "expected {0!r}" \
                             "got      {1!r}".format(expected, got)
コード例 #2
0
    def test_adding_single_membership(self):
        begins_at = session.utcnow()
        ends_at = begins_at + timedelta(hours=1)
        during = closed(begins_at, ends_at)

        self.add_membership(during)
        self.assertMembershipIntervalsEqual(IntervalSet(during))
コード例 #3
0
 def assertMembershipIntervalsEqual(self, expected):
     memberships = session.session.query(Membership).filter_by(
         user=self.user, group=self.group)
     got = IntervalSet(m.active_during.closure for m in memberships)
     assert expected == got, "IntervalSets differ: " \
                             "expected {!r}" \
                             "got      {!r}".format(expected, got)
コード例 #4
0
def make_member_of(user, group, processor, during=UnboundedInterval):
    """
    Makes a user member of a group in a given interval. If the given interval
    overlaps with an existing membership, this method will join the overlapping
    intervals together, so that there will be at most one membership for
    particular user in particular group at any given point in time.

    :param User user: the user
    :param Group group: the group
    :param User processor: User issuing the addition
    :param Interval during:
    """
    memberships = session.session.query(Membership).filter(
        Membership.user == user, Membership.group == group,
        Membership.active(during)).all()
    intervals = IntervalSet(
        closed(m.begins_at, m.ends_at) for m in memberships).union(during)
    for m in memberships:
        session.session.delete(m)
    session.session.add_all(
        Membership(begins_at=i.begin, ends_at=i.end, user=user, group=group)
        for i in intervals)
    message = deferred_gettext(u"Added to group {group} during {during}.")
    log_user_event(message=message.format(group=group.name,
                                          during=during).to_json(),
                   user=user,
                   author=processor)
コード例 #5
0
def remove_member_of(user, group, processor, during=UnboundedInterval):
    """Remove a user from a group in a given interval.

    The interval defaults to the unbounded interval, so that the user
    will be removed from the group at any point in time, **removing
    all memberships** in this group retroactively.

    However, a common use case is terminating a membership by setting
    ``during=closedopen(now, None)``.

    :param User user: the user
    :param Group group: the group
    :param User processor: User issuing the removal
    :param Interval during:
    """
    memberships = session.session.query(Membership).filter(
        Membership.user == user, Membership.group == group,
        Membership.active(during)).all()
    intervals = IntervalSet(
        closed(m.begins_at, m.ends_at) for m in memberships).difference(during)
    for m in memberships:
        session.session.delete(m)
    session.session.add_all(
        Membership(begins_at=i.begin, ends_at=i.end, user=user, group=group)
        for i in intervals)
    message = deferred_gettext(u"Removed from group {group} during {during}.")
    log_user_event(message=message.format(group=group.name,
                                          during=during).to_json(),
                   user=user,
                   author=processor)
コード例 #6
0
def make_member_of(user, group, processor, during=UnboundedInterval):
    """
    Makes a user member of a group in a given interval. If the given interval
    overlaps with an existing membership, this method will join the overlapping
    intervals together, so that there will be at most one membership for
    particular user in particular group at any given point in time.

    :param User user: the user
    :param Group group: the group
    :param User processor: User issuing the addition
    :param Interval during:
    """

    if group.permission_level > processor.permission_level:
        raise PermissionError("cannot create a membership for a group with a"
                              " higher permission level")

    memberships: list[Membership] = [
        m for m in user.active_memberships(when=during) if m.group == group
    ]
    intervals = IntervalSet(m.active_during.closure
                            for m in memberships).union(during)
    for m in memberships:
        session.session.delete(m)
    session.session.flush()
    session.session.add_all(
        Membership(active_during=i, user=user, group=group) for i in intervals)
    message = deferred_gettext("Added to group {group} during {during}.")
    log_user_event(message=message.format(group=group.name,
                                          during=during).to_json(),
                   user=user,
                   author=processor)
コード例 #7
0
ファイル: test_interval.py プロジェクト: JuKu/pycroft
 def assertIntervalSetOperationEquals(cls, operation, args_and_expected):
     """
     :param callable operation:
     :param iterable[iterable[IntervalSet], unknown)] args_and_expected:
     """
     cls.assertIntervalSetMethodEquals(
         operation, ((args, IntervalSet(expected))
                     for args, expected in args_and_expected))
コード例 #8
0
ファイル: test_interval.py プロジェクト: JuKu/pycroft
 def test_sort_join(self):
     self.assertEqual(
         IntervalSet([
             closed(2, 3),
             closed(2, None),
             closed(None, 1),
             closed(1, 3),
             closed(2, 3),
             closed(-10, None)
         ]), IntervalSet([closed(None, None)]))
     self.assertEqual(
         IntervalSet([
             empty(6),
             closedopen(1, 2),
             empty(0),
             closedopen(2, 3),
             open(4, 5)
         ]),
         IntervalSet([closedopen(1, 3), open(4, 5)]),
     )
コード例 #9
0
ファイル: test_interval.py プロジェクト: JuKu/pycroft
 def assertIntervalSetMethodEquals(cls, method, args_and_expected):
     """
     :param callable method:
     :param iterable[iterable[IntervalSet], unknown)] args_and_expected:
     """
     for args, expected in args_and_expected:
         args = [IntervalSet(intervals) for intervals in args]
         got = method(*args)
         assert got == expected, (
             "Evaluating {0}({1}) failed: expected {2}, got {3}".format(
                 method.__name__, ', '.join(map(str, args)), expected, got))
コード例 #10
0
    def test_join_overlapping_memberships(self):
        begins_at1 = session.utcnow()
        ends_at1 = begins_at1 + timedelta(hours=2)
        during1 = closed(begins_at1, ends_at1)
        begins_at2 = begins_at1 + timedelta(hours=1)
        ends_at2 = begins_at1 + timedelta(hours=3)
        during2 = closed(begins_at2, ends_at2)

        self.add_membership(during1)
        self.add_membership(during2)
        self.assertMembershipIntervalsEqual(IntervalSet(closed(begins_at1, ends_at2)))
コード例 #11
0
 def test_removing_memberships(self):
     t0 = session.utcnow()
     t1 = t0 + timedelta(hours=1)
     t2 = t0 + timedelta(hours=2)
     t3 = t0 + timedelta(hours=3)
     t4 = t0 + timedelta(hours=4)
     t5 = t0 + timedelta(hours=5)
     self.add_membership(closed(t0, t2))
     self.add_membership(closed(t3, t5))
     self.remove_membership(closed(t1, t4))
     self.assertMembershipIntervalsEqual(IntervalSet(
         (closed(t0, t1), closed(t4, t5))))
コード例 #12
0
    def test_removing_all_memberships(self):
        begins_at1 = session.utcnow()
        ends_at1 = begins_at1 + timedelta(hours=1)
        during1 = closed(begins_at1, ends_at1)
        begins_at2 = begins_at1 + timedelta(hours=2)
        ends_at2 = begins_at1 + timedelta(hours=3)
        during2 = closed(begins_at2, ends_at2)

        self.add_membership(during1)
        self.add_membership(during2)
        self.remove_membership()
        self.assertMembershipIntervalsEqual(IntervalSet())
コード例 #13
0
ファイル: user.py プロジェクト: JuKu/pycroft
 def property_intervals(self, name, when=UnboundedInterval):
     """
     Get the set of intervals in which the user was granted a given property
     :param str name:
     :param Interval when:
     :returns: The set of intervals in which the user was granted the
     property
     :rtype: IntervalSet
     """
     property_assignments = object_session(self).query(
         Property.granted, Membership.begins_at, Membership.ends_at).filter(
             Property.name == name,
             Property.property_group_id == PropertyGroup.id,
             PropertyGroup.id == Membership.group_id,
             Membership.user_id == self.id).all()
     granted_intervals = IntervalSet(
         closed(begins_at, ends_at)
         for granted, begins_at, ends_at in property_assignments if granted)
     denied_intervals = IntervalSet(
         closed(begins_at, ends_at)
         for granted, begins_at, ends_at in property_assignments
         if not granted)
     return (granted_intervals - denied_intervals).intersect(when)
コード例 #14
0
 def test_type_mangling(self):
     # TODO one test per assertion and `target` / `base` as fixtures
     target = IntervalSet([closed(0, 1)])
     # Creation
     assert target == IntervalSet(closed(0, 1))
     assert target == IntervalSet([closed(0, 1)])
     with pytest.raises(TypeError):
         IntervalSet(0)
     # Union
     base = IntervalSet(())
     assert target == base | IntervalSet(closed(0, 1))
     assert target == base | closed(0, 1)
     assert target == base | [closed(0, 1)]
     # Intersection
     base = target | closed(1, 2)
     assert target == base & IntervalSet(openclosed(0, 1))
     assert target == base & openclosed(0, 1)
     assert target == base & [openclosed(0, 1)]
     # Difference
     assert target == base - IntervalSet(openclosed(1, 2))
     assert target == base - openclosed(1, 2)
     assert target == base - [openclosed(1, 2)]
コード例 #15
0
ファイル: test_interval.py プロジェクト: JuKu/pycroft
 def test_type_mangling(self):
     target = IntervalSet([closed(0, 1)])
     # Creation
     self.assertEqual(target, IntervalSet(closed(0, 1)))
     self.assertEqual(target, IntervalSet([closed(0, 1)]))
     self.assertRaises(TypeError, IntervalSet, 0)
     # Union
     base = IntervalSet(())
     self.assertEqual(target, base | IntervalSet(closed(0, 1)))
     self.assertEqual(target, base | closed(0, 1))
     self.assertEqual(target, base | [closed(0, 1)])
     # Intersection
     base = target | closed(1, 2)
     self.assertEqual(target, base & IntervalSet(openclosed(0, 1)))
     self.assertEqual(target, base & openclosed(0, 1))
     self.assertEqual(target, base & [openclosed(0, 1)])
     # Difference
     self.assertEqual(target, base - IntervalSet(openclosed(1, 2)))
     self.assertEqual(target, base - openclosed(1, 2))
     self.assertEqual(target, base - [openclosed(1, 2)])
コード例 #16
0
def remove_member_of(user, group, processor, during=UnboundedInterval):
    """Remove a user from a group in a given interval.

    The interval defaults to the unbounded interval, so that the user
    will be removed from the group at any point in time, **removing
    all memberships** in this group retroactively.

    However, a common use case is terminating a membership by setting
    ``during=closedopen(now, None)``.

    :param User user: the user
    :param Group group: the group
    :param User processor: User issuing the removal
    :param Interval during:
    """

    if group.permission_level > processor.permission_level:
        raise PermissionError("cannot delete a membership for a group with a"
                              " higher permission level")

    memberships: list[Membership] = [
        m for m in user.active_memberships(when=during) if m.group == group
    ]
    intervals = IntervalSet(m.active_during.closure
                            for m in memberships).difference(during)
    for m in memberships:
        session.session.delete(m)
    # flush necessary because we otherwise don't have any control
    # over the order of deletion vs. addition
    session.session.flush()
    session.session.add_all(
        Membership(active_during=i, user=user, group=group) for i in intervals)

    message = deferred_gettext("Removed from group {group} during {during}.")
    log_user_event(message=message.format(group=group.name,
                                          during=during).to_json(),
                   user=user,
                   author=processor)
コード例 #17
0
def _to_date_intervals(intervals):
    """
    :param IntervalSet[datetime] intervals:
    :rtype: IntervalSet[date]
    """
    return IntervalSet(_to_date_interval(i) for i in intervals)
コード例 #18
0
def test_constructor(one: list[Interval], other: list[Interval]):
    assert IntervalSet(one) == IntervalSet(other)
コード例 #19
0
def test_complement(intervals: list[Interval], expected: IntervalSet):
    assert IntervalSet(intervals).complement() == IntervalSet(expected)
コード例 #20
0
def test_union(one: list[Interval], other: list[Interval],
               expected: IntervalSet):
    assert IntervalSet(one).union(IntervalSet(other)) == IntervalSet(expected)
コード例 #21
0
def test_intersect(one: list[Interval], other: list[Interval],
                   expected: IntervalSet):
    assert IntervalSet(one).intersect(
        IntervalSet(other)) == IntervalSet(expected)
コード例 #22
0
def test_difference(one: list[Interval], other: list[Interval],
                    expected: IntervalSet):
    assert IntervalSet(one).difference(
        IntervalSet(other)) == IntervalSet(expected)
コード例 #23
0
def test_length(intervals: list[Interval], expected: IntervalSet):
    assert IntervalSet(intervals).length == expected