Class: ChatSDK::Linear::Adapter

Inherits:
Adapter::Base
  • Object
show all
Defined in:
lib/chat_sdk/linear/adapter.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(api_key: nil, webhook_secret: nil, bot_username: nil) ⇒ Adapter

Returns a new instance of Adapter.

Raises:

  • (ChatSDK::ConfigurationError)


13
14
15
16
17
18
19
20
21
# File 'lib/chat_sdk/linear/adapter.rb', line 13

def initialize(api_key: nil, webhook_secret: nil, bot_username: nil)
  @api_key = api_key || ENV["LINEAR_API_KEY"]
  @webhook_secret = webhook_secret || ENV["LINEAR_WEBHOOK_SECRET"]
  @bot_username = bot_username || ENV["LINEAR_BOT_USERNAME"]
  raise ChatSDK::ConfigurationError, "Linear api_key required" unless @api_key
  raise ChatSDK::ConfigurationError, "Linear webhook_secret required" unless @webhook_secret

  @client = ApiClient.new(@api_key)
end

Instance Attribute Details

#clientObject (readonly)

Returns the value of attribute client.



11
12
13
# File 'lib/chat_sdk/linear/adapter.rb', line 11

def client
  @client
end

Instance Method Details

#ack_response(_rack_request) ⇒ Object



47
48
49
# File 'lib/chat_sdk/linear/adapter.rb', line 47

def ack_response(_rack_request)
  nil
end

#add_reaction(channel_id:, message_id:, emoji:) ⇒ Object

rubocop:disable Lint/UnusedMethodArgument



102
103
104
# File 'lib/chat_sdk/linear/adapter.rb', line 102

def add_reaction(channel_id:, message_id:, emoji:) # rubocop:disable Lint/UnusedMethodArgument
  @client.create_reaction(comment_id: message_id, emoji: emoji)
end

#delete_message(channel_id:, message_id:) ⇒ Object



98
99
100
# File 'lib/chat_sdk/linear/adapter.rb', line 98

def delete_message(channel_id:, message_id:)
  @client.delete_comment(comment_id: message_id)
end

#edit_message(channel_id:, message_id:, message:) ⇒ Object



92
93
94
95
96
# File 'lib/chat_sdk/linear/adapter.rb', line 92

def edit_message(channel_id:, message_id:, message:)
  msg = ChatSDK::PostableMessage.from(message)
  text = msg.text || msg.card&.fallback_text || ""
  @client.update_comment(comment_id: message_id, body: text)
end

#fetch_messages(channel_id:, thread_id: nil, limit: 50) ⇒ Object

rubocop:disable Lint/UnusedMethodArgument



110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
# File 'lib/chat_sdk/linear/adapter.rb', line 110

def fetch_messages(channel_id:, thread_id: nil, limit: 50) # rubocop:disable Lint/UnusedMethodArgument
  issue_id = channel_id
  parent_id = nil

  if thread_id&.include?(":c:")
    parts = thread_id.split(":c:")
    parent_id = parts.last
  end

  result = @client.fetch_comments(issue_id: issue_id, parent_id: parent_id)
  comments = result.dig("data", "comments", "nodes") || []

  messages = comments.map do |comment|
    user = comment["user"] || {}
    ChatSDK::Message.new(
      id: comment["id"],
      text: comment["body"] || "",
      author: ChatSDK::Author.new(id: user["id"] || "unknown", name: user["name"] || "unknown", platform: :linear, bot: false),
      thread_id: "linear:#{issue_id}:c:#{comment["id"]}",
      channel_id: channel_id,
      platform: :linear,
      raw: comment
    )
  end

  [messages, nil]
end

#mention(user_id) ⇒ Object



138
139
140
# File 'lib/chat_sdk/linear/adapter.rb', line 138

def mention(user_id)
  "@#{user_id}"
end

#nameObject



23
24
25
# File 'lib/chat_sdk/linear/adapter.rb', line 23

def name
  :linear
end

#parse_events(rack_request) ⇒ Object



51
52
53
54
55
56
# File 'lib/chat_sdk/linear/adapter.rb', line 51

def parse_events(rack_request)
  payload = read_json_body(rack_request)
  EventParser.parse(payload, bot_username: @bot_username)
rescue JSON::ParserError
  []
end

#post_message(channel_id:, message:, thread_id: nil) ⇒ Object

Outbound



59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
# File 'lib/chat_sdk/linear/adapter.rb', line 59

def post_message(channel_id:, message:, thread_id: nil)
  msg = ChatSDK::PostableMessage.from(message)
  text = msg.text || msg.card&.fallback_text || ""

  issue_id = channel_id
  parent_id = nil

  if thread_id&.include?(":c:")
    parts = thread_id.split(":c:")
    parent_id = parts.last
  end

  result = @client.create_comment(issue_id: issue_id, body: text, parent_id: parent_id)
  comment = result.dig("data", "commentCreate", "comment") || {}
  comment_id = comment["id"]
  user = comment["user"] || {}

  ChatSDK::Message.new(
    id: comment_id,
    text: text,
    author: ChatSDK::Author.new(
      id: user["id"] || "bot",
      name: user["name"] || "bot",
      platform: :linear,
      bot: true
    ),
    thread_id: "linear:#{issue_id}:c:#{comment_id}",
    channel_id: channel_id,
    platform: :linear,
    raw: result
  )
end

#remove_reaction(channel_id:, message_id:, emoji:) ⇒ Object

rubocop:disable Lint/UnusedMethodArgument



106
107
108
# File 'lib/chat_sdk/linear/adapter.rb', line 106

def remove_reaction(channel_id:, message_id:, emoji:) # rubocop:disable Lint/UnusedMethodArgument
  @client.delete_reaction(comment_id: message_id, emoji: emoji)
end

#render(postable_message) ⇒ Object



142
143
144
# File 'lib/chat_sdk/linear/adapter.rb', line 142

def render(postable_message)
  postable_message.text
end

#verify_request!(rack_request) ⇒ Object

Inbound



28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
# File 'lib/chat_sdk/linear/adapter.rb', line 28

def verify_request!(rack_request)
  body = rack_request.body.read
  rack_request.body.rewind

  signature = rack_request.get_header("HTTP_LINEAR_SIGNATURE")

  unless signature
    raise ChatSDK::SignatureVerificationError, "Missing Linear signature header"
  end

  expected = OpenSSL::HMAC.hexdigest("SHA256", @webhook_secret, body)

  unless Rack::Utils.secure_compare(signature, expected)
    raise ChatSDK::SignatureVerificationError, "Invalid Linear signature"
  end

  true
end