Skip to content

Commit dc197a3

Browse files
committed
parse incoming unfurl links and try to construct supported GH types
Again, currently supports commit links but can be extended later on. We shouldn't unfurl if three or more links are present, or if the link type isn't supported for none of the urls.
1 parent 35a28b9 commit dc197a3

File tree

2 files changed

+85
-0
lines changed

2 files changed

+85
-0
lines changed

lib/action.ml

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -232,4 +232,42 @@ module Action (Github_api : Api.Github) (Slack_api : Api.Slack) = struct
232232
| Context.Context_error msg ->
233233
log#error "%s" msg;
234234
Lwt.return_unit
235+
236+
let process_link_shared_event (ctx : Context.t) (event : Slack_t.link_shared_event) =
237+
let process link =
238+
match Github.gh_link_of_string link with
239+
| None -> Lwt.return_none
240+
| Some gh_link ->
241+
match gh_link with
242+
| Commit (repo, sha) ->
243+
( match%lwt Github_api.get_api_commit ~ctx ~repo ~sha with
244+
| Error _ -> Lwt.return_none
245+
| Ok commit -> Lwt.return_some @@ (link, Slack_message.populate_commit repo commit)
246+
)
247+
in
248+
if List.length event.links > 2 then Lwt.return "ignored: more than two links present"
249+
else begin
250+
let links = List.map event.links ~f:(fun l -> l.url) in
251+
let%lwt unfurls = List.map links ~f:process |> Lwt.all |> Lwt.map List.filter_opt |> Lwt.map StringMap.of_list in
252+
if Map.is_empty unfurls then Lwt.return "ignored: no links to unfurl"
253+
else begin
254+
let req : Slack_j.chat_unfurl_req = { channel = event.channel; ts = event.message_ts; unfurls } in
255+
match%lwt Slack_api.send_chat_unfurl ~ctx req with
256+
| Ok () -> Lwt.return "ok"
257+
| Error e ->
258+
log#error "%s" e;
259+
Lwt.return "ignored: failed to unfurl links"
260+
end
261+
end
262+
263+
let process_slack_event (ctx : Context.t) headers body =
264+
let secrets = Context.get_secrets_exn ctx in
265+
match Slack_j.event_notification_of_string body with
266+
| Url_verification payload -> Lwt.return payload.challenge
267+
| Event_callback notification ->
268+
match Slack.validate_signature ?signing_key:secrets.slack_signing_secret ~headers body with
269+
| Error e -> action_error e
270+
| Ok () ->
271+
match notification.event with
272+
| Link_shared event -> process_link_shared_event ctx event
235273
end

lib/github.ml

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,3 +86,50 @@ let parse_exn ~secret headers body =
8686
| "commit_comment" -> Commit_comment (commit_comment_notification_of_string body)
8787
| "member" | "create" | "delete" | "release" -> Event (event_notification_of_string body)
8888
| event -> failwith @@ sprintf "unsupported event : %s" event
89+
90+
type gh_link = Commit of repository * commit_hash
91+
92+
(** `gh_link_of_string s` parses a URL string `s` to try to match a supported
93+
GitHub link type, generating repository endpoints if necessary *)
94+
let gh_link_of_string url_str =
95+
let url = Uri.of_string url_str in
96+
let path = Uri.path url in
97+
let gh_com_html_base owner name = sprintf "https://github.com/%s/%s" owner name in
98+
let gh_com_api_base owner name = sprintf "https://api.github.com/repos/%s/%s" owner name in
99+
let custom_html_base ?(scheme = "https") base owner name = sprintf "%s://%s/%s/%s" scheme base owner name in
100+
let custom_api_base ?(scheme = "https") base owner name =
101+
sprintf "%s://%s/api/v3/repos/%s/%s" scheme base owner name
102+
in
103+
let re = Re.Str.regexp {|^\(.*\)/\(.+\)/\(.+\)/\(commit\)/\([a-z0-9]+\)/?$|} in
104+
match Uri.host url with
105+
| None -> None
106+
| Some host ->
107+
match Re.Str.string_match re path 0 with
108+
| false -> None
109+
| true ->
110+
let base = host ^ Re.Str.matched_group 1 path in
111+
let owner = Re.Str.matched_group 2 path in
112+
let name = Re.Str.matched_group 3 path in
113+
let link_type = Re.Str.matched_group 4 path in
114+
let item = Re.Str.matched_group 5 path in
115+
let scheme = Uri.scheme url in
116+
let html_base, api_base =
117+
if String.is_suffix base ~suffix:"github.com" then gh_com_html_base owner name, gh_com_api_base owner name
118+
else custom_html_base ?scheme base owner name, custom_api_base ?scheme base owner name
119+
in
120+
let repo =
121+
{
122+
name;
123+
full_name = sprintf "%s/%s" owner name;
124+
url = html_base;
125+
commits_url = sprintf "%s/commits{/sha}" api_base;
126+
contents_url = sprintf "%s/contents/{+path}" api_base;
127+
}
128+
in
129+
begin
130+
try
131+
match link_type with
132+
| "commit" -> Some (Commit (repo, item))
133+
| _ -> None
134+
with _ -> None
135+
end

0 commit comments

Comments
 (0)