Cleanup: remove tracked pycache and db.sqlite3; add map membership backfill, new components, backups, docs

This commit is contained in:
gitrusprus
2026-06-28 22:16:01 +03:00
parent 4eb4c145b6
commit ce4e9ac5e6
46 changed files with 12125 additions and 176 deletions
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,62 @@
from contacts.models import Contact, NetworkMap, NetworkMapMembership, Relation
def contact_ids_from_relations(relations_qs):
contact_ids = set()
for relation in relations_qs.only('source_id', 'target_id'):
contact_ids.add(relation.source_id)
contact_ids.add(relation.target_id)
return contact_ids
def backfill_map_memberships_for_owner(owner):
"""Добавляет на первую карту владельца контакты из его связей, если участников ещё нет."""
if owner is None:
maps = NetworkMap.objects.filter(owner__isnull=True).order_by('id')
relations = Relation.objects.filter(owner__isnull=True)
else:
maps = NetworkMap.objects.filter(owner=owner).order_by('id')
relations = Relation.objects.filter(owner=owner)
if not maps.exists():
return 0
if NetworkMapMembership.objects.filter(map__in=maps).exists():
return 0
contact_ids = contact_ids_from_relations(relations)
if not contact_ids:
return 0
if owner is None:
contacts = Contact.objects.filter(id__in=contact_ids, owner__isnull=True)
else:
contacts = Contact.objects.filter(id__in=contact_ids, owner=owner)
target_map = maps.first()
created = 0
for contact in contacts:
_, was_created = NetworkMapMembership.objects.get_or_create(
map=target_map,
contact=contact,
defaults={
'life_sphere': 'other',
'network_circle': 'productivity',
'importance': 3,
'conflict_involvement': 3,
},
)
if was_created:
created += 1
return created
def backfill_all_map_memberships():
from django.contrib.auth import get_user_model
User = get_user_model()
total = 0
total += backfill_map_memberships_for_owner(None)
for user in User.objects.all():
total += backfill_map_memberships_for_owner(user)
return total
@@ -0,0 +1,68 @@
from django.conf import settings
from django.db import migrations
def backfill_memberships(apps, schema_editor):
NetworkMap = apps.get_model('contacts', 'NetworkMap')
NetworkMapMembership = apps.get_model('contacts', 'NetworkMapMembership')
Relation = apps.get_model('contacts', 'Relation')
Contact = apps.get_model('contacts', 'Contact')
User = apps.get_model('auth', 'User')
def backfill_for_owner(owner_id):
if owner_id is None:
maps = NetworkMap.objects.filter(owner__isnull=True).order_by('id')
relations = Relation.objects.filter(owner__isnull=True)
contact_owner_filter = {'owner__isnull': True}
else:
maps = NetworkMap.objects.filter(owner_id=owner_id).order_by('id')
relations = Relation.objects.filter(owner_id=owner_id)
contact_owner_filter = {'owner_id': owner_id}
if not maps.exists():
return 0
if NetworkMapMembership.objects.filter(map__in=maps).exists():
return 0
contact_ids = set()
for relation in relations.only('source_id', 'target_id'):
contact_ids.add(relation.source_id)
contact_ids.add(relation.target_id)
if not contact_ids:
return 0
contacts = Contact.objects.filter(id__in=contact_ids, **contact_owner_filter)
target_map = maps.first()
created = 0
for contact in contacts:
_, was_created = NetworkMapMembership.objects.get_or_create(
map=target_map,
contact=contact,
defaults={
'life_sphere': 'other',
'network_circle': 'productivity',
'importance': 3,
'conflict_involvement': 3,
},
)
if was_created:
created += 1
return created
total = backfill_for_owner(None)
for user in User.objects.all():
total += backfill_for_owner(user.id)
if total:
print(f'Backfilled {total} network map memberships')
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('contacts', '0011_add_owner'),
]
operations = [
migrations.RunPython(backfill_memberships, migrations.RunPython.noop),
]
+1 -1
View File
@@ -142,7 +142,7 @@ class NetworkMapMembershipSerializer(serializers.ModelSerializer):
'map_angle', 'map_radius_ratio',
'created_at', 'updated_at',
]
read_only_fields = ['id', 'created_at', 'updated_at', 'contact_name', 'map_name']
read_only_fields = ['id', 'map', 'created_at', 'updated_at', 'contact_name', 'map_name']
class GraphSerializer(serializers.Serializer):
File diff suppressed because it is too large Load Diff
Binary file not shown.
+22 -17
View File
@@ -29,19 +29,20 @@ def _network_maps_qs(user):
return qs
def node_from_contact(contact):
def node_from_contact(contact, defaults=None):
defaults = defaults or {}
return {
'id': contact.id,
'label': contact.name,
'title': '\n'.join(filter(None, [contact.organization, contact.position, contact.email])),
'group': contact.organization or 'default',
**defaults,
}
def node_from_membership(membership):
contact = membership.contact
return {
**node_from_contact(contact),
return node_from_contact(contact, {
'life_sphere': membership.life_sphere,
'network_circle': membership.network_circle,
'importance': membership.importance,
@@ -49,7 +50,22 @@ def node_from_membership(membership):
'map_angle': membership.map_angle,
'map_radius_ratio': membership.map_radius_ratio,
'membership_id': membership.id,
}
})
def nodes_for_network_map(network_map, user):
memberships = list(
NetworkMapMembership.objects.filter(map_id=network_map.id)
.select_related('contact', 'map')
.order_by('contact__name')
)
if use_jwt_auth() and user and user.is_authenticated:
memberships = [
m for m in memberships
if m.map.owner_id == user.id and m.contact.owner_id == user.id
]
return [node_from_membership(m) for m in memberships]
def edge_from_relation(relation):
@@ -85,19 +101,8 @@ def build_network_map_graph(map_id=None, user=None):
if not network_map:
return {'nodes': [], 'edges': [], 'conflictology': False, 'conflict_subject': ''}
memberships = list(
NetworkMapMembership.objects.filter(map_id=map_id)
.select_related('contact', 'map')
.order_by('contact__name')
)
if use_jwt_auth() and user and user.is_authenticated:
memberships = [
m for m in memberships
if m.map.owner_id == user.id and m.contact.owner_id == user.id
]
allowed_ids = {m.contact_id for m in memberships}
nodes = [node_from_membership(m) for m in memberships]
nodes = nodes_for_network_map(network_map, user)
allowed_ids = {n['id'] for n in nodes}
relations = _relations_qs(user)
edges = [
edge_from_relation(r)