Add JWT auth with per-user data isolation and account settings.
Users can register, log in, and manage profile/password in a personal account page; server data is scoped by owner across contacts, maps, tags, and import. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -1,8 +1,17 @@
|
||||
from rest_framework import serializers
|
||||
|
||||
from core.access import use_jwt_auth
|
||||
from .models import Contact, Relation, NetworkMap, NetworkMapMembership, NetworkMapType
|
||||
from .map_type_validation import validate_map_type_payload
|
||||
|
||||
|
||||
def scoped_map_types_queryset(request):
|
||||
qs = NetworkMapType.objects.all()
|
||||
if use_jwt_auth() and request and request.user.is_authenticated:
|
||||
return qs.filter(owner=request.user)
|
||||
return qs
|
||||
|
||||
|
||||
class ContactSerializer(serializers.ModelSerializer):
|
||||
relations_count = serializers.SerializerMethodField()
|
||||
|
||||
@@ -37,10 +46,22 @@ class RelationSerializer(serializers.ModelSerializer):
|
||||
read_only_fields = ['id', 'created_at', 'source_name', 'target_name']
|
||||
|
||||
def validate(self, data):
|
||||
if data.get('source') == data.get('target'):
|
||||
request = self.context.get('request')
|
||||
source = data.get('source') or getattr(self.instance, 'source', None)
|
||||
target = data.get('target') or getattr(self.instance, 'target', None)
|
||||
|
||||
if source and target and source == target:
|
||||
raise serializers.ValidationError(
|
||||
'Нельзя создать связь контакта с самим собой.'
|
||||
)
|
||||
|
||||
if use_jwt_auth() and request and request.user.is_authenticated:
|
||||
user = request.user
|
||||
for contact in (source, target):
|
||||
if contact and contact.owner_id != user.id:
|
||||
raise serializers.ValidationError(
|
||||
'Контакт не принадлежит текущему пользователю.'
|
||||
)
|
||||
return data
|
||||
|
||||
|
||||
@@ -61,8 +82,13 @@ class NetworkMapTypeSerializer(serializers.ModelSerializer):
|
||||
raise serializers.ValidationError(errors)
|
||||
return data
|
||||
|
||||
def _default_exists(self):
|
||||
request = self.context.get('request')
|
||||
qs = scoped_map_types_queryset(request)
|
||||
return qs.filter(is_default=True).exists()
|
||||
|
||||
def create(self, validated_data):
|
||||
if NetworkMapType.objects.filter(is_default=True).exists():
|
||||
if self._default_exists():
|
||||
validated_data['is_default'] = False
|
||||
return super().create(validated_data)
|
||||
|
||||
@@ -82,12 +108,22 @@ class NetworkMapSerializer(serializers.ModelSerializer):
|
||||
]
|
||||
read_only_fields = ['id', 'created_at', 'updated_at', 'memberships_count']
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
request = self.context.get('request')
|
||||
self.fields['map_type'].queryset = scoped_map_types_queryset(request)
|
||||
|
||||
def validate(self, data):
|
||||
request = self.context.get('request')
|
||||
if not data.get('map_type') and not getattr(self.instance, 'map_type_id', None):
|
||||
default_type = NetworkMapType.objects.filter(is_default=True).first()
|
||||
default_type = scoped_map_types_queryset(request).filter(is_default=True).first()
|
||||
if not default_type:
|
||||
raise serializers.ValidationError({'map_type': 'Нет типа карты по умолчанию.'})
|
||||
data['map_type'] = default_type
|
||||
map_type = data.get('map_type') or getattr(self.instance, 'map_type', None)
|
||||
if use_jwt_auth() and request and request.user.is_authenticated and map_type:
|
||||
if map_type.owner_id != request.user.id:
|
||||
raise serializers.ValidationError({'map_type': 'Тип карты не принадлежит текущему пользователю.'})
|
||||
return data
|
||||
|
||||
def get_memberships_count(self, obj):
|
||||
|
||||
Reference in New Issue
Block a user