"""Generation-based write boundaries. Viewing and role grants are separate.""" from collections import deque LIMIT = 5 def generations(people, links, self_id): ids = {p['id'] for p in people} if self_id not in ids: return {}, False graph = {key: [] for key in ids} for edge in links: a, b = edge.get('fromId'), edge.get('toId') if not edge.get('active') or a not in ids or b not in ids: continue delta = 1 if edge.get('kind') == 'parent' else 0 if edge.get('kind') not in ('parent', 'spouse'): continue graph[a].append((b, delta)) graph[b].append((a, -delta)) levels, pending, conflict = {self_id: 0}, deque([self_id]), False while pending: current = pending.popleft() for other, delta in graph[current]: level = levels[current] + delta if other in levels: conflict |= levels[other] != level else: levels[other] = level pending.append(other) return levels, conflict def within(levels, person_id): return person_id in levels and abs(levels[person_id]) <= LIMIT def targets(kind, item): if kind == 'person': return [item['id']] if kind == 'link': return [item['fromId'], item['toId']] return item.get('personIds', [])