Files
teams/teams_app/schemas/team_schema.py
2026-01-07 09:17:34 +07:00

368 lines
13 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import graphene
from django.utils import timezone
from datetime import timedelta
from graphene_django import DjangoObjectType
from django.contrib.auth import get_user_model
from ..models import Team as TeamModel, TeamMember as TeamMemberModel, TeamAddress as TeamAddressModel
from ..permissions import require_scopes
UserModel = get_user_model()
class User(DjangoObjectType):
id = graphene.String()
firstName = graphene.String()
lastName = graphene.String()
phone = graphene.String()
avatarId = graphene.String()
createdAt = graphene.String()
class Meta:
model = UserModel
fields = ('username', 'first_name', 'last_name', 'email')
def resolve_id(self, info):
if hasattr(self, 'profile') and self.profile:
return self.profile.logto_id
return self.username
def resolve_firstName(self, info):
return self.first_name
def resolve_lastName(self, info):
return self.last_name
def resolve_phone(self, info):
return getattr(self.profile, 'phone', None)
def resolve_avatarId(self, info):
return getattr(self.profile, 'avatar_id', None)
def resolve_createdAt(self, info):
return self.date_joined.isoformat() if self.date_joined else None
class TeamMember(DjangoObjectType):
user = graphene.Field(User)
joinedAt = graphene.String()
class Meta:
model = TeamMemberModel
fields = ('role', 'joined_at')
def resolve_user(self, info):
return self.user
def resolve_joinedAt(self, info):
return self.joined_at.isoformat() if self.joined_at else None
class TeamAddress(DjangoObjectType):
isDefault = graphene.Boolean()
createdAt = graphene.String()
graphNodeId = graphene.String()
processedAt = graphene.String()
countryCode = graphene.String()
class Meta:
model = TeamAddressModel
fields = ('uuid', 'name', 'address', 'latitude', 'longitude', 'is_default', 'created_at', 'country_code')
def resolve_isDefault(self, info):
return self.is_default
def resolve_createdAt(self, info):
return self.created_at.isoformat() if self.created_at else None
def resolve_graphNodeId(self, info):
return self.graph_node_id
def resolve_processedAt(self, info):
return self.processed_at.isoformat() if self.processed_at else None
def resolve_countryCode(self, info):
return self.country_code
class SelectedLocation(graphene.ObjectType):
type = graphene.String()
uuid = graphene.String()
name = graphene.String()
latitude = graphene.Float()
longitude = graphene.Float()
class Team(DjangoObjectType):
id = graphene.String()
ownerId = graphene.String()
members = graphene.List(TeamMember)
addresses = graphene.List(lambda: TeamAddress)
selectedLocation = graphene.Field(SelectedLocation)
class Meta:
model = TeamModel
fields = ('uuid', 'name', 'logto_org_id', 'owner', 'created_at', 'updated_at')
def resolve_id(self, info):
return self.uuid
def resolve_ownerId(self, info):
if self.owner and hasattr(self.owner, 'profile'):
return self.owner.profile.logto_id
return self.owner.username if self.owner else None
def resolve_members(self, info):
return self.members.all()
def resolve_addresses(self, info):
return self.addresses.all()
def resolve_selectedLocation(self, info):
loc_type = getattr(self, 'selected_location_type', None)
loc_uuid = getattr(self, 'selected_location_uuid', None)
if loc_type and loc_uuid:
return SelectedLocation(
type=loc_type,
uuid=loc_uuid,
name=getattr(self, 'selected_location_name', None),
latitude=getattr(self, 'selected_location_latitude', None),
longitude=getattr(self, 'selected_location_longitude', None)
)
return None
class TeamQuery(graphene.ObjectType):
team = graphene.Field(Team)
getTeam = graphene.Field(Team, teamId=graphene.String(required=True))
team_members = graphene.List(TeamMember)
team_addresses = graphene.List(TeamAddress)
@require_scopes("teams:member")
def resolve_team(self, info):
team_uuid = getattr(info.context, 'team_uuid', None)
if not team_uuid:
return None
try:
return TeamModel.objects.get(uuid=team_uuid)
except TeamModel.DoesNotExist:
return None
@require_scopes("teams:member")
def resolve_getTeam(self, info, teamId):
# Получаем конкретную команду по ID
try:
return TeamModel.objects.get(uuid=teamId)
except TeamModel.DoesNotExist:
return None
@require_scopes("teams:member")
def resolve_team_members(self, info):
# Получаем участников команды
team_uuid = getattr(info.context, 'team_uuid', None)
if not team_uuid:
return []
try:
team = TeamModel.objects.get(uuid=team_uuid)
return team.members.all()
except TeamModel.DoesNotExist:
return []
@require_scopes("teams:member")
def resolve_team_addresses(self, info):
team_uuid = getattr(info.context, 'team_uuid', None)
if not team_uuid:
return []
try:
team = TeamModel.objects.get(uuid=team_uuid)
return team.addresses.all()
except TeamModel.DoesNotExist:
return []
class InviteMemberInput(graphene.InputObjectType):
email = graphene.String(required=True)
role = graphene.String()
class InviteMemberMutation(graphene.Mutation):
class Arguments:
input = InviteMemberInput(required=True)
success = graphene.Boolean()
message = graphene.String()
@require_scopes("teams:member")
def mutate(self, info, input):
from ..temporal_client import start_invite_workflow
# Проверяем права - только owner может приглашать
team_uuid = getattr(info.context, 'team_uuid', None)
user_id = getattr(info.context, 'user_id', None)
if not team_uuid or not user_id:
return InviteMemberMutation(success=False, message="Недостаточно прав")
try:
team = TeamModel.objects.get(uuid=team_uuid)
# Проверяем что пользователь - owner команды
if not team.owner:
return InviteMemberMutation(success=False, message="Только owner может приглашать")
owner_identifier = team.owner.profile.logto_id if hasattr(team.owner, 'profile') and team.owner.profile else team.owner.username
if owner_identifier != user_id:
return InviteMemberMutation(success=False, message="Только owner может приглашать")
expires_at = timezone.now() + timedelta(days=7)
start_invite_workflow(
team_uuid=str(team.uuid),
email=input.email,
role=input.role or 'MEMBER',
invited_by=owner_identifier,
expires_at=expires_at.isoformat(),
)
return InviteMemberMutation(success=True, message="Приглашение отправлено")
except TeamModel.DoesNotExist:
return InviteMemberMutation(success=False, message="Команда не найдена")
class CreateTeamAddressInput(graphene.InputObjectType):
name = graphene.String(required=True)
address = graphene.String(required=True)
latitude = graphene.Float()
longitude = graphene.Float()
countryCode = graphene.String()
isDefault = graphene.Boolean()
class CreateTeamAddressMutation(graphene.Mutation):
class Arguments:
input = CreateTeamAddressInput(required=True)
success = graphene.Boolean()
message = graphene.String()
workflowId = graphene.String()
@require_scopes("teams:member")
def mutate(self, info, input):
from ..temporal_client import start_address_workflow
team_uuid = getattr(info.context, 'team_uuid', None)
if not team_uuid:
return CreateTeamAddressMutation(success=False, message="Не авторизован")
try:
team = TeamModel.objects.get(uuid=team_uuid)
# Запускаем workflow - он сам создаст адрес через M2M мутацию
workflow_id, _ = start_address_workflow(
team_uuid=str(team.uuid),
name=input.name,
address=input.address,
latitude=input.get('latitude'),
longitude=input.get('longitude'),
country_code=input.get('countryCode'),
is_default=input.get('isDefault', False),
)
return CreateTeamAddressMutation(
success=True,
message="Адрес создается",
workflowId=workflow_id,
)
except TeamModel.DoesNotExist:
return CreateTeamAddressMutation(success=False, message="Команда не найдена")
except Exception as e:
return CreateTeamAddressMutation(success=False, message=str(e))
class DeleteTeamAddressMutation(graphene.Mutation):
class Arguments:
uuid = graphene.String(required=True)
success = graphene.Boolean()
message = graphene.String()
@require_scopes("teams:member")
def mutate(self, info, uuid):
team_uuid = getattr(info.context, 'team_uuid', None)
if not team_uuid:
return DeleteTeamAddressMutation(success=False, message="Не авторизован")
try:
team = TeamModel.objects.get(uuid=team_uuid)
address = team.addresses.get(uuid=uuid)
address.delete()
return DeleteTeamAddressMutation(success=True, message="Адрес удален")
except TeamModel.DoesNotExist:
return DeleteTeamAddressMutation(success=False, message="Команда не найдена")
except TeamAddressModel.DoesNotExist:
return DeleteTeamAddressMutation(success=False, message="Адрес не найден")
class SetSelectedLocationInput(graphene.InputObjectType):
type = graphene.String(required=True) # 'address' или 'hub'
uuid = graphene.String(required=True)
name = graphene.String(required=True)
latitude = graphene.Float(required=True)
longitude = graphene.Float(required=True)
class SetSelectedLocationMutation(graphene.Mutation):
class Arguments:
input = SetSelectedLocationInput(required=True)
success = graphene.Boolean()
message = graphene.String()
selectedLocation = graphene.Field(SelectedLocation)
@require_scopes("teams:member")
def mutate(self, info, input):
team_uuid = getattr(info.context, 'team_uuid', None)
if not team_uuid:
return SetSelectedLocationMutation(success=False, message="Не авторизован")
location_type = input.type
if location_type not in ('address', 'hub'):
return SetSelectedLocationMutation(success=False, message="Неверный тип локации")
try:
team = TeamModel.objects.get(uuid=team_uuid)
team.selected_location_type = location_type
team.selected_location_uuid = input.uuid
team.selected_location_name = input.name
team.selected_location_latitude = input.latitude
team.selected_location_longitude = input.longitude
team.save(update_fields=[
'selected_location_type',
'selected_location_uuid',
'selected_location_name',
'selected_location_latitude',
'selected_location_longitude'
])
return SetSelectedLocationMutation(
success=True,
message="Локация выбрана",
selectedLocation=SelectedLocation(
type=location_type,
uuid=input.uuid,
name=input.name,
latitude=input.latitude,
longitude=input.longitude
)
)
except TeamModel.DoesNotExist:
return SetSelectedLocationMutation(success=False, message="Команда не найдена")
class TeamMutation(graphene.ObjectType):
invite_member = InviteMemberMutation.Field()
create_team_address = CreateTeamAddressMutation.Field()
delete_team_address = DeleteTeamAddressMutation.Field()
set_selected_location = SetSelectedLocationMutation.Field()
team_schema = graphene.Schema(query=TeamQuery, mutation=TeamMutation)