package logic import ( "context" "errors" "strings" "img_infinite_canvas/internal/domain/design" sharingmodule "img_infinite_canvas/internal/modules/sharing" "img_infinite_canvas/internal/svc" "img_infinite_canvas/internal/types" ) func ownedShareProject(ctx context.Context, svcCtx *svc.ServiceContext, projectID string) (design.Project, error) { return svcCtx.DesignService.GetProject(ctx, strings.TrimSpace(projectID)) } func verifiedShareOwner(ctx context.Context, svcCtx *svc.ServiceContext, project design.Project) (sharingmodule.Actor, error) { if svcCtx.AuthService == nil { return sharingmodule.Actor{}, errors.New("auth service is required for share management") } profile, err := svcCtx.AuthService.GetProfile(ctx, project.UserID) if err != nil { return sharingmodule.Actor{}, err } return sharingmodule.Actor{ Authenticated: true, UserID: project.UserID, Email: profile.Email, CountryCode: profile.CountryCode, Phone: profile.Phone, Name: profile.Name, AvatarURL: profile.AvatarURL, }, nil } func toShareSettingsResponse(ctx context.Context, svcCtx *svc.ServiceContext, project design.Project, settings sharingmodule.Settings) *types.ShareSettingsResponse { owner := types.SharePerson{ Id: project.UserID, UserId: project.UserID, Name: "Owner", Permission: string(sharingmodule.PermissionOwner), } ownerActor, ownerErr := verifiedShareOwner(ctx, svcCtx, project) if ownerErr == nil { owner.Name = firstShareIdentifier(ownerActor.Name, owner.Name) owner.AvatarUrl = ownerActor.AvatarURL owner.Identifier = firstShareIdentifier(ownerActor.Email, displayPhone(ownerActor.CountryCode, ownerActor.Phone)) } visibleMembers := filterShareMembers(settings.Members, ownerActor) members := make([]types.SharePerson, 0, len(visibleMembers)) for _, member := range visibleMembers { members = append(members, types.SharePerson{ Id: member.ID, Name: member.Identifier, Identifier: member.Identifier, Permission: string(member.Permission), CreatedAt: formatTime(member.CreatedAt), }) } return &types.ShareSettingsResponse{Settings: types.ShareSettings{ ProjectId: project.ID, ShareId: settings.ShareID, LinkPermission: string(settings.LinkPermission), Owner: owner, Members: members, VisitorCount: settings.VisitorCount, UpdatedAt: formatTime(settings.UpdatedAt), }} } func filterShareMembers(members []sharingmodule.Member, owner sharingmodule.Actor) []sharingmodule.Member { if owner.UserID == "" { return members } filtered := make([]sharingmodule.Member, 0, len(members)) for _, member := range members { if sharingmodule.ActorOwnsIdentifier(owner, member.Identifier) { continue } filtered = append(filtered, member) } return filtered } func toShareVisitorsResponse(ctx context.Context, svcCtx *svc.ServiceContext, visits []sharingmodule.VisitRecord) *types.ShareVisitorsResponse { items := make([]types.ShareVisitor, 0, len(visits)) for _, visit := range visits { item := types.ShareVisitor{ Id: visit.ID, UserId: visit.UserID, Name: "Anonymous visitor", VisitCount: visit.VisitCount, LastSeenAt: formatTime(visit.LastSeenAt), } if visit.UserID != "" && svcCtx.AuthService != nil { if profile, err := svcCtx.AuthService.GetProfile(ctx, visit.UserID); err == nil { item.Name = firstShareIdentifier(profile.Name, profile.Email, displayPhone(profile.CountryCode, profile.Phone), "Visitor") item.Identifier = firstShareIdentifier(profile.Email, displayPhone(profile.CountryCode, profile.Phone)) item.AvatarUrl = profile.AvatarURL } } items = append(items, item) } return &types.ShareVisitorsResponse{Visitors: items} } func toShareAccess(access sharingmodule.Access) types.ShareAccess { return types.ShareAccess{ Permission: string(access.Permission), Source: access.Source, Authenticated: access.Authenticated, IsOwner: access.IsOwner, Capabilities: types.ShareCapabilities{ CanViewCanvas: access.Capabilities.CanViewCanvas, CanViewChat: access.Capabilities.CanViewChat, CanEdit: access.Capabilities.CanEdit, CanManage: access.Capabilities.CanManage, }, } } func filterSharedProject(project design.Project, access sharingmodule.Access) design.Project { project.UserID = "" if !access.Capabilities.CanViewChat { project.Brief = "" project.LastThreadID = "" project.Messages = []design.Message{} } return project } func firstShareIdentifier(values ...string) string { for _, value := range values { if value = strings.TrimSpace(value); value != "" { return value } } return "" } func displayPhone(countryCode string, phone string) string { phone = strings.TrimSpace(phone) if phone == "" { return "" } countryCode = strings.TrimPrefix(strings.TrimSpace(countryCode), "+") if countryCode == "" || strings.HasPrefix(phone, "+") { return phone } return "+" + countryCode + phone }