Cleanup: remove tracked pycache and db.sqlite3; add map membership backfill, new components, backups, docs
This commit is contained in:
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.
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),
|
||||
]
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -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
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user