-
Notifications
You must be signed in to change notification settings - Fork 5
startchat: support creating group #43
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
c031f22
c9c8472
c5bd86c
cea8622
71d31be
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,120 @@ | ||
| package connector | ||
|
|
||
| import ( | ||
| "context" | ||
| "encoding/base64" | ||
| "fmt" | ||
|
|
||
| "go.mau.fi/util/ptr" | ||
| "maunium.net/go/mautrix/bridgev2" | ||
| "maunium.net/go/mautrix/bridgev2/database" | ||
| "maunium.net/go/mautrix/bridgev2/networkid" | ||
| "maunium.net/go/mautrix/event" | ||
|
|
||
| "go.mau.fi/mautrix-linkedin/pkg/linkedingo" | ||
| ) | ||
|
|
||
| var ( | ||
| _ bridgev2.GhostDMCreatingNetworkAPI = (*LinkedInClient)(nil) | ||
| _ bridgev2.GroupCreatingNetworkAPI = (*LinkedInClient)(nil) | ||
| _ bridgev2.IdentifierValidatingNetwork = (*LinkedInConnector)(nil) | ||
| ) | ||
|
|
||
| func (l *LinkedInConnector) ValidateUserID(uid networkid.UserID) bool { | ||
| id := string(uid) | ||
| _, err := base64.StdEncoding.DecodeString(id) | ||
| return err == nil && len(id) >= 36 | ||
| } | ||
|
|
||
| func (l *LinkedInClient) ResolveIdentifier(ctx context.Context, identifier string, createChat bool) (*bridgev2.ResolveIdentifierResponse, error) { | ||
| id := networkid.UserID(identifier) | ||
| if !l.main.ValidateUserID(id) { | ||
| return nil, fmt.Errorf("invalid identifier: %s", identifier) | ||
| } | ||
| ghost, err := l.main.Bridge.GetGhostByID(ctx, id) | ||
| if err != nil { | ||
| return nil, err | ||
| } | ||
| var chat *bridgev2.CreateChatResponse | ||
| if createChat { | ||
| portal, _ := ghost.Bridge.GetDMPortal(ctx, l.userLogin.ID, id) | ||
| if portal != nil { | ||
| chat = &bridgev2.CreateChatResponse{ | ||
| PortalKey: portal.PortalKey, | ||
| } | ||
| } else { | ||
| chatInfo := &bridgev2.ChatInfo{ | ||
| Type: ptr.Ptr(database.RoomTypeDM), | ||
| Members: &bridgev2.ChatMemberList{ | ||
| MemberMap: map[networkid.UserID]bridgev2.ChatMember{}, | ||
| }, | ||
| } | ||
| participants := []networkid.UserID{ | ||
| networkid.UserID(identifier), | ||
| } | ||
| var err error | ||
| chat, err = l.createChat(ctx, chatInfo, participants) | ||
| if err != nil { | ||
| return nil, fmt.Errorf("failed to create dm chat: %w", err) | ||
| } | ||
| } | ||
| } | ||
| return &bridgev2.ResolveIdentifierResponse{ | ||
| UserID: id, | ||
| Ghost: ghost, | ||
| Chat: chat, | ||
| }, nil | ||
| } | ||
|
|
||
| func (l *LinkedInClient) CreateChatWithGhost(ctx context.Context, ghost *bridgev2.Ghost) (*bridgev2.CreateChatResponse, error) { | ||
| resp, err := l.ResolveIdentifier(ctx, string(ghost.ID), true) | ||
| if err != nil { | ||
| return nil, err | ||
| } else if resp == nil { | ||
| return nil, nil | ||
| } | ||
| return resp.Chat, nil | ||
| } | ||
|
|
||
| func (l *LinkedInClient) CreateGroup(ctx context.Context, params *bridgev2.GroupCreateParams) (*bridgev2.CreateChatResponse, error) { | ||
| chatInfo := &bridgev2.ChatInfo{ | ||
| Type: ptr.Ptr(database.RoomTypeDefault), | ||
| Name: ptr.Ptr(params.Name.Name), | ||
| Members: &bridgev2.ChatMemberList{ | ||
| MemberMap: map[networkid.UserID]bridgev2.ChatMember{}, | ||
| }, | ||
| } | ||
| chat, err := l.createChat(ctx, chatInfo, params.Participants) | ||
| if err != nil { | ||
| return nil, fmt.Errorf("failed to create group chat: %w", err) | ||
| } | ||
| return chat, nil | ||
| } | ||
|
|
||
| func (l *LinkedInClient) createChat(ctx context.Context, chatInfo *bridgev2.ChatInfo, _participants []networkid.UserID) (*bridgev2.CreateChatResponse, error) { | ||
| participants := make([]linkedingo.URN, len(_participants)) | ||
| for i, participant := range _participants { | ||
| participants[i] = linkedingo.NewURN(participant).AsFsdProfile() | ||
| sender := l.makeSender(linkedingo.MessagingParticipant{ | ||
| EntityURN: participants[i], | ||
| }) | ||
| chatInfo.Members.MemberMap[sender.Sender] = bridgev2.ChatMember{ | ||
| EventSender: sender, | ||
| Membership: event.MembershipJoin, | ||
| } | ||
| } | ||
| resp, err := l.client.NewChat(ctx, ptr.Val(chatInfo.Name), participants) | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do we get the proper conversation info from this? I don't like the way this ChatInfo is formed completely separately from the code in chatinfo.go, would be preferable to reuse (if we don't get the info, then this is fine for now)
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. we only get conversation urn
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Then the current code is fine for now |
||
|
|
||
| if err != nil { | ||
| return nil, err | ||
| } | ||
|
|
||
| portalKey := networkid.PortalKey{ | ||
| ID: networkid.PortalID(resp.Data.ConversationURN.String()), | ||
| Receiver: l.userLogin.ID, | ||
| } | ||
| return &bridgev2.CreateChatResponse{ | ||
| PortalKey: portalKey, | ||
| PortalInfo: chatInfo, | ||
| }, nil | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The input can be absolutely anything, so this needs to validate that it looks like a linkedin identifier. Implementing ValidateUserID on the network connector and calling that should be sufficient