Skip to content
Snippets Groups Projects
Unverified Commit d91dae2f authored by Sumner Evans's avatar Sumner Evans
Browse files

connector: implement sending edits

parent a9fc6d27
No related branches found
No related tags found
No related merge requests found
Pipeline #16458 passed
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
* Matrix → LinkedIn * Matrix → LinkedIn
* [ ] Message content * [ ] Message content
* [ ] Text * [x] Text
* [ ] Media * [ ] Media
* [ ] Files * [ ] Files
* [ ] Images * [ ] Images
...@@ -12,9 +12,9 @@ ...@@ -12,9 +12,9 @@
* [ ] ~~Stickers~~ (unsupported) * [ ] ~~Stickers~~ (unsupported)
* [ ] ~~Formatting~~ (LinkedIn does not support rich formatting) * [ ] ~~Formatting~~ (LinkedIn does not support rich formatting)
* [ ] Replies * [ ] Replies
* [ ] Mentions * [x] Mentions
* [ ] Emotes * [ ] Emotes
* [ ] Message edits * [x] Message edits
* [ ] Message redactions * [ ] Message redactions
* [ ] Message reactions * [ ] Message reactions
* [ ] Presence * [ ] Presence
......
...@@ -48,7 +48,7 @@ var formattingCaps = event.FormattingFeatureMap{ ...@@ -48,7 +48,7 @@ var formattingCaps = event.FormattingFeatureMap{
event.FmtSyntaxHighlighting: event.CapLevelDropped, event.FmtSyntaxHighlighting: event.CapLevelDropped,
event.FmtBlockquote: event.CapLevelDropped, event.FmtBlockquote: event.CapLevelDropped,
event.FmtInlineLink: event.CapLevelDropped, event.FmtInlineLink: event.CapLevelDropped,
event.FmtUserLink: event.CapLevelDropped, event.FmtUserLink: event.CapLevelFullySupported,
event.FmtUnorderedList: event.CapLevelDropped, event.FmtUnorderedList: event.CapLevelDropped,
event.FmtOrderedList: event.CapLevelDropped, event.FmtOrderedList: event.CapLevelDropped,
event.FmtListStart: event.CapLevelDropped, event.FmtListStart: event.CapLevelDropped,
...@@ -145,7 +145,7 @@ func (*LinkedInClient) GetCapabilities(ctx context.Context, portal *bridgev2.Por ...@@ -145,7 +145,7 @@ func (*LinkedInClient) GetCapabilities(ctx context.Context, portal *bridgev2.Por
MaxTextLength: MaxTextLength, MaxTextLength: MaxTextLength,
LocationMessage: event.CapLevelDropped, LocationMessage: event.CapLevelDropped,
Reply: event.CapLevelDropped, Reply: event.CapLevelDropped,
Edit: event.CapLevelDropped, Edit: event.CapLevelFullySupported, // TODO note that edits are restricted to specific msgtypes
Delete: event.CapLevelDropped, Delete: event.CapLevelDropped,
Reaction: event.CapLevelDropped, Reaction: event.CapLevelDropped,
ReactionCount: 1, ReactionCount: 1,
......
...@@ -48,8 +48,8 @@ type LinkedInClient struct { ...@@ -48,8 +48,8 @@ type LinkedInClient struct {
} }
var ( var (
_ bridgev2.NetworkAPI = (*LinkedInClient)(nil) _ bridgev2.NetworkAPI = (*LinkedInClient)(nil)
// _ bridgev2.EditHandlingNetworkAPI = (*LinkedInClient)(nil) _ bridgev2.EditHandlingNetworkAPI = (*LinkedInClient)(nil)
// _ bridgev2.ReactionHandlingNetworkAPI = (*LinkedInClient)(nil) // _ bridgev2.ReactionHandlingNetworkAPI = (*LinkedInClient)(nil)
// _ bridgev2.RedactionHandlingNetworkAPI = (*LinkedInClient)(nil) // _ bridgev2.RedactionHandlingNetworkAPI = (*LinkedInClient)(nil)
// _ bridgev2.ReadReceiptHandlingNetworkAPI = (*LinkedInClient)(nil) // _ bridgev2.ReadReceiptHandlingNetworkAPI = (*LinkedInClient)(nil)
...@@ -432,6 +432,10 @@ func (l *LinkedInClient) HandleMatrixMessage(ctx context.Context, msg *bridgev2. ...@@ -432,6 +432,10 @@ func (l *LinkedInClient) HandleMatrixMessage(ctx context.Context, msg *bridgev2.
}, nil }, nil
} }
func (l *LinkedInClient) HandleMatrixEdit(ctx context.Context, msg *bridgev2.MatrixEdit) error {
return l.client.EditMessage(ctx, types.NewURN(string(msg.EditTarget.ID)), matrixfmt.Parse(ctx, l.matrixParser, msg.Content))
}
func (l *LinkedInClient) IsLoggedIn() bool { func (l *LinkedInClient) IsLoggedIn() bool {
return l.userLogin.Metadata.(*UserLoginMetadata).Cookies.GetCookie(linkedingo.LinkedInCookieJSESSIONID) != "" return l.userLogin.Metadata.(*UserLoginMetadata).Cookies.GetCookie(linkedingo.LinkedInCookieJSESSIONID) != ""
} }
......
...@@ -28,6 +28,7 @@ const ( ...@@ -28,6 +28,7 @@ const (
const LinkedInCookieJSESSIONID = "JSESSIONID" const LinkedInCookieJSESSIONID = "JSESSIONID"
const ( const (
contentTypeJSON = "application/json"
contentTypeJSONLinkedInNormalized = "application/vnd.linkedin.normalized+json+2.1" contentTypeJSONLinkedInNormalized = "application/vnd.linkedin.normalized+json+2.1"
contentTypeGraphQL = "application/graphql" contentTypeGraphQL = "application/graphql"
contentTypeTextEventStream = "text/event-stream" contentTypeTextEventStream = "text/event-stream"
......
...@@ -5,6 +5,7 @@ import ( ...@@ -5,6 +5,7 @@ import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"net/http" "net/http"
"net/url"
"github.com/google/uuid" "github.com/google/uuid"
"go.mau.fi/util/random" "go.mau.fi/util/random"
...@@ -70,3 +71,35 @@ func (c *Client) SendMessage(ctx context.Context, payload SendMessagePayload) (* ...@@ -70,3 +71,35 @@ func (c *Client) SendMessage(ctx context.Context, payload SendMessagePayload) (*
var messageSentResponse MessageSentResponse var messageSentResponse MessageSentResponse
return &messageSentResponse, json.NewDecoder(resp.Body).Decode(&messageSentResponse) return &messageSentResponse, json.NewDecoder(resp.Body).Decode(&messageSentResponse)
} }
type GraphQLPatchBody struct {
Patch Patch `json:"patch,omitempty"`
}
// TODO: genericise?
type Patch struct {
Set any `json:"$set,omitempty"`
}
type EditMessagePayload struct {
Body SendMessageBody `json:"body,omitempty"`
}
func (c *Client) EditMessage(ctx context.Context, messageURN types.URN, p SendMessageBody) error {
url, err := url.JoinPath(linkedInVoyagerMessagingDashMessengerMessagesURL, messageURN.URLEscaped())
if err != nil {
return err
}
resp, err := c.newAuthedRequest(http.MethodPost, url).
WithCSRF().
WithJSONPayload(GraphQLPatchBody{Patch: Patch{Set: EditMessagePayload{Body: p}}}).
WithHeader("accept", contentTypeJSON).
WithRealtimeHeaders().
Do(ctx)
if err != nil {
return err
} else if resp.StatusCode != http.StatusNoContent {
return fmt.Errorf("failed to edit message with urn %s (statusCode=%d)", messageURN, resp.StatusCode)
}
return nil
}
...@@ -3,6 +3,7 @@ package types ...@@ -3,6 +3,7 @@ package types
import ( import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"net/url"
"strings" "strings"
) )
...@@ -32,6 +33,10 @@ func (u URN) String() string { ...@@ -32,6 +33,10 @@ func (u URN) String() string {
return strings.Join(u.parts, ":") return strings.Join(u.parts, ":")
} }
func (u URN) URLEscaped() string {
return url.PathEscape(u.String())
}
func (u URN) IsEmpty() bool { func (u URN) IsEmpty() bool {
return len(u.parts) == 0 return len(u.parts) == 0
} }
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment