Initial commit from monorepo
This commit is contained in:
367
teams_app/schemas/team_schema.py
Normal file
367
teams_app/schemas/team_schema.py
Normal file
@@ -0,0 +1,367 @@
|
||||
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)
|
||||
Reference in New Issue
Block a user