288 lines
9.2 KiB
Python
288 lines
9.2 KiB
Python
import graphene
|
||
from graphene_django import DjangoObjectType
|
||
from django.contrib.auth import get_user_model
|
||
from ..models import Team as TeamModel, TeamMember as TeamMemberModel, TeamInvitation as TeamInvitationModel, UserProfile
|
||
from .team_schema import SelectedLocation
|
||
|
||
UserModel = get_user_model()
|
||
|
||
|
||
def _get_or_create_user_with_profile(logto_id: str):
|
||
user, _ = UserModel.objects.get_or_create(
|
||
username=logto_id,
|
||
defaults={'email': ''}
|
||
)
|
||
profile, _ = UserProfile.objects.get_or_create(
|
||
logto_id=logto_id,
|
||
defaults={'user': user}
|
||
)
|
||
if profile.user_id != user.id:
|
||
profile.user = user
|
||
profile.save(update_fields=['user'])
|
||
# Attach profile to user for resolvers
|
||
user.profile = profile
|
||
return user
|
||
|
||
class Team(DjangoObjectType):
|
||
id = graphene.String()
|
||
logtoOrgId = graphene.String()
|
||
teamType = graphene.String()
|
||
selectedLocation = graphene.Field(SelectedLocation)
|
||
|
||
class Meta:
|
||
model = TeamModel
|
||
fields = ('uuid', 'name', 'logto_org_id', 'team_type', 'created_at')
|
||
|
||
def resolve_id(self, info):
|
||
return self.uuid
|
||
|
||
def resolve_logtoOrgId(self, info):
|
||
return self.logto_org_id
|
||
|
||
def resolve_teamType(self, info):
|
||
return self.team_type
|
||
|
||
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 User(DjangoObjectType):
|
||
id = graphene.String()
|
||
firstName = graphene.String()
|
||
lastName = graphene.String()
|
||
phone = graphene.String()
|
||
avatarId = graphene.String()
|
||
activeTeamId = graphene.String()
|
||
activeTeam = graphene.Field(Team)
|
||
teams = graphene.List(Team)
|
||
|
||
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_activeTeamId(self, info):
|
||
return self.profile.active_team.uuid if getattr(self, 'profile', None) and self.profile.active_team else None
|
||
|
||
def resolve_activeTeam(self, info):
|
||
return self.profile.active_team if getattr(self, 'profile', None) else None
|
||
|
||
def resolve_teams(self, info):
|
||
# Возвращаем Team объекты через TeamMember отношения
|
||
from ..models import TeamMember as TeamMemberModel
|
||
team_members = TeamMemberModel.objects.filter(user=self)
|
||
return [member.team for member in team_members]
|
||
|
||
class TeamMember(DjangoObjectType):
|
||
user = graphene.Field(User)
|
||
role = graphene.String()
|
||
joinedAt = graphene.String()
|
||
|
||
class Meta:
|
||
from ..models import TeamMember as TeamMemberModel
|
||
model = TeamMemberModel
|
||
fields = ('uuid', 'role')
|
||
|
||
def resolve_joinedAt(self, info):
|
||
return self.joined_at.isoformat() if self.joined_at else None
|
||
|
||
|
||
class TeamInvitation(DjangoObjectType):
|
||
email = graphene.String()
|
||
role = graphene.String()
|
||
status = graphene.String()
|
||
invitedBy = graphene.String()
|
||
expiresAt = graphene.String()
|
||
createdAt = graphene.String()
|
||
|
||
class Meta:
|
||
model = TeamInvitationModel
|
||
fields = ('uuid', 'email', 'role', 'status')
|
||
|
||
def resolve_invitedBy(self, info):
|
||
return self.invited_by
|
||
|
||
def resolve_expiresAt(self, info):
|
||
return self.expires_at.isoformat() if self.expires_at else None
|
||
|
||
def resolve_createdAt(self, info):
|
||
return self.created_at.isoformat() if self.created_at else None
|
||
|
||
|
||
class TeamWithMembers(DjangoObjectType):
|
||
id = graphene.String()
|
||
members = graphene.List(TeamMember)
|
||
invitations = graphene.List(TeamInvitation)
|
||
|
||
class Meta:
|
||
model = TeamModel
|
||
fields = ('uuid', 'name', 'created_at')
|
||
|
||
def resolve_id(self, info):
|
||
return self.uuid
|
||
|
||
def resolve_members(self, info):
|
||
return self.members.all()
|
||
|
||
def resolve_invitations(self, info):
|
||
return self.invitations.filter(status='PENDING')
|
||
|
||
|
||
class UserQuery(graphene.ObjectType):
|
||
me = graphene.Field(User)
|
||
get_team = graphene.Field(TeamWithMembers, team_id=graphene.String(required=True))
|
||
|
||
def resolve_me(self, info):
|
||
# Получаем user_id из ID Token
|
||
user_id = getattr(info.context, 'user_id', None)
|
||
if not user_id:
|
||
return None
|
||
|
||
try:
|
||
return _get_or_create_user_with_profile(user_id)
|
||
except Exception:
|
||
return None
|
||
|
||
def resolve_get_team(self, info, team_id):
|
||
try:
|
||
return TeamModel.objects.get(uuid=team_id)
|
||
except TeamModel.DoesNotExist:
|
||
return None
|
||
|
||
class CreateTeamInput(graphene.InputObjectType):
|
||
name = graphene.String(required=True)
|
||
teamType = graphene.String() # BUYER или SELLER
|
||
|
||
|
||
class UpdateUserInput(graphene.InputObjectType):
|
||
firstName = graphene.String()
|
||
lastName = graphene.String()
|
||
phone = graphene.String()
|
||
avatarId = graphene.String()
|
||
|
||
class CreateTeamMutation(graphene.Mutation):
|
||
class Arguments:
|
||
input = CreateTeamInput(required=True)
|
||
|
||
team = graphene.Field(Team)
|
||
|
||
def mutate(self, info, input):
|
||
# Получаем user_id из контекста (ID Token)
|
||
user_id = getattr(info.context, 'user_id', None)
|
||
if not user_id:
|
||
raise Exception("User not authenticated")
|
||
|
||
try:
|
||
owner = _get_or_create_user_with_profile(user_id)
|
||
|
||
team = TeamModel.objects.create(
|
||
name=input.name,
|
||
owner=owner,
|
||
team_type=input.teamType or 'BUYER'
|
||
)
|
||
|
||
# Добавляем owner как участника команды с ролью OWNER
|
||
TeamMemberModel.objects.create(
|
||
team=team,
|
||
user=owner,
|
||
role='OWNER'
|
||
)
|
||
|
||
# Устанавливаем как активную команду, если у пользователя её нет
|
||
if hasattr(owner, 'profile') and not owner.profile.active_team:
|
||
owner.profile.active_team = team
|
||
owner.profile.save(update_fields=['active_team'])
|
||
|
||
return CreateTeamMutation(team=team)
|
||
|
||
except Exception as e:
|
||
raise Exception(f"Failed to create team: {str(e)}")
|
||
|
||
|
||
class UpdateUserMutation(graphene.Mutation):
|
||
class Arguments:
|
||
userId = graphene.String(required=True)
|
||
input = UpdateUserInput(required=True)
|
||
|
||
user = graphene.Field(User)
|
||
|
||
def mutate(self, info, userId, input):
|
||
# Проверяем права - пользователь может редактировать только себя
|
||
context_user_id = getattr(info.context, 'user_id', None)
|
||
if context_user_id != userId:
|
||
return UpdateUserMutation(user=None)
|
||
|
||
try:
|
||
user = _get_or_create_user_with_profile(userId)
|
||
|
||
if input.firstName is not None:
|
||
user.first_name = input.firstName
|
||
if input.lastName is not None:
|
||
user.last_name = input.lastName
|
||
user.save()
|
||
if hasattr(user, 'profile'):
|
||
if input.phone is not None:
|
||
user.profile.phone = input.phone
|
||
if input.avatarId is not None:
|
||
user.profile.avatar_id = input.avatarId
|
||
user.profile.save()
|
||
return UpdateUserMutation(user=user)
|
||
|
||
except Exception:
|
||
return UpdateUserMutation(user=None)
|
||
|
||
|
||
class SwitchTeamMutation(graphene.Mutation):
|
||
class Arguments:
|
||
teamId = graphene.String(required=True)
|
||
|
||
user = graphene.Field(User)
|
||
|
||
def mutate(self, info, teamId):
|
||
user_id = getattr(info.context, 'user_id', None)
|
||
if not user_id:
|
||
raise Exception("User not authenticated")
|
||
|
||
try:
|
||
team = TeamModel.objects.get(uuid=teamId)
|
||
user = _get_or_create_user_with_profile(user_id)
|
||
if hasattr(user, 'profile'):
|
||
user.profile.active_team = team
|
||
user.profile.save(update_fields=['active_team'])
|
||
return SwitchTeamMutation(user=user)
|
||
except TeamModel.DoesNotExist:
|
||
raise Exception("Team not found")
|
||
|
||
|
||
class UserMutation(graphene.ObjectType):
|
||
create_team = CreateTeamMutation.Field()
|
||
update_user = UpdateUserMutation.Field()
|
||
switch_team = SwitchTeamMutation.Field()
|
||
|
||
user_schema = graphene.Schema(query=UserQuery, mutation=UserMutation)
|