Skip to content

Commit

Permalink
feat: use Slack blocks instead of attachments
Browse files Browse the repository at this point in the history
  • Loading branch information
believer committed Sep 21, 2019
1 parent bf8e383 commit cc96b1f
Show file tree
Hide file tree
Showing 11 changed files with 304 additions and 95 deletions.
8 changes: 4 additions & 4 deletions __tests__/NowPlaying_test.re
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ open Expect;

describe("#nowPlayingData", () => {
test("nothing is playing", () => {
let track: Sonos.Decode.currentTrackResponse = {
let sonos: Sonos.Decode.currentTrackResponse = {
album: Some("30 Seconds to Mars"),
albumArtURI: "",
albumArtURL: "",
Expand All @@ -15,11 +15,11 @@ describe("#nowPlayingData", () => {
position: 1200.0,
};

expect(NowPlaying.message(track)) |> toMatchSnapshot;
expect(NowPlaying.message(~sonos, ~cover="img")) |> toMatchSnapshot;
});

test("current track", () => {
let track: Sonos.Decode.currentTrackResponse = {
let sonos: Sonos.Decode.currentTrackResponse = {
album: Some("30 Seconds to Mars"),
albumArtURI: "",
albumArtURL: "",
Expand All @@ -31,6 +31,6 @@ describe("#nowPlayingData", () => {
position: 120.0,
};

expect(NowPlaying.message(track)) |> toMatchSnapshot;
expect(NowPlaying.message(~sonos, ~cover="img")) |> toMatchSnapshot;
});
});
80 changes: 76 additions & 4 deletions lib/js/__tests__/__snapshots__/NowPlaying_test.bs.js.snap
Original file line number Diff line number Diff line change
@@ -1,9 +1,81 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`#nowPlayingData current track 1`] = `
"*Currently playing*
30 Seconds to Mars - Echelon (30 Seconds to Mars)
Position in queue 1 - 2:00/6:00"
Array [
Object {
"accessory": Object {
"action_id": undefined,
"alt_text": "Album cover",
"image_url": "img",
"text": undefined,
"type": "image",
"value": undefined,
},
"elements": undefined,
"fields": Array [
Object {
"text": "*Artist*
30 Seconds to Mars",
"type": "mrkdwn",
},
Object {
"text": "*Track name*
Echelon",
"type": "mrkdwn",
},
Object {
"text": "*Album*
30 Seconds to Mars",
"type": "mrkdwn",
},
Object {
"text": "*Current position*
2:00 / 6:00",
"type": "mrkdwn",
},
],
"text": undefined,
"type": "section",
},
]
`;

exports[`#nowPlayingData nothing is playing 1`] = `"Nothing is currently playing, add a track using \`search <your track>\`"`;
exports[`#nowPlayingData nothing is playing 1`] = `
Array [
Object {
"accessory": Object {
"action_id": undefined,
"alt_text": "Album cover",
"image_url": "img",
"text": undefined,
"type": "image",
"value": undefined,
},
"elements": undefined,
"fields": Array [
Object {
"text": "*Artist*
30 Seconds to Mars",
"type": "mrkdwn",
},
Object {
"text": "*Track name*
Echelon",
"type": "mrkdwn",
},
Object {
"text": "*Album*
30 Seconds to Mars",
"type": "mrkdwn",
},
Object {
"text": "*Current position*
20:00 / 1:00:00",
"type": "mrkdwn",
},
],
"text": undefined,
"type": "section",
},
]
`;
2 changes: 1 addition & 1 deletion src/Commands.re
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ let make = text => {
| text => UnknownCommand(text)
}
}
| None => UnknownCommand("no text")
| None => UnhandledCommand
};
};

Expand Down
1 change: 1 addition & 0 deletions src/Decode.re
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@ module Action = {
[@decco]
type t = {
actions,
response_url: string,
channel,
user,
};
Expand Down
4 changes: 2 additions & 2 deletions src/Event.re
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,13 @@ let logCommand = (command, args, user) => {
};
};

let makeWithAttachment =
let makeWithBlocks =
(~command, ~args, ~user, ~subtype=Decode.Requester.Human, ()) => {
logCommand(command, args, user);

Js.Promise.(
switch (subtype, command) {
| (Human, NowPlaying) => NowPlaying.run()
| (Human, Search) => Spotify.search(args)
| (Human, _) =>
resolve(`Failed("This is not the command you are looking for"))
Expand All @@ -28,7 +29,6 @@ let make = (~command, ~args, ~user, ~subtype=Decode.Requester.Human, ()) => {
| Human =>
switch (command) {
| Blame => Blame.run()
| NowPlaying => NowPlaying.run()

/* Queue control */
| Clear => Queue.clear()
Expand Down
38 changes: 25 additions & 13 deletions src/Routes.re
Original file line number Diff line number Diff line change
Expand Up @@ -27,18 +27,18 @@ let message = request => {
);
};

let messageWithAttachment = request => {
let messageWithBlocks = request => {
let {subtype, channel, command, text: args, user}: Decode.Event.t = request;
let sendSearchResponse = Slack.Message.withAttachments(channel);
let sendSearchResponse = Slack.Message.withBlocks(channel);

Js.Promise.(
Event.makeWithAttachment(~command, ~args, ~user, ~subtype, ())
Event.makeWithBlocks(~command, ~args, ~user, ~subtype, ())
|> then_(response => {
switch (response) {
| `Ok(message, attachments) =>
sendSearchResponse(message, attachments)
| `Ok(message, blocks) => sendSearchResponse(message, blocks)
| `Failed(_) => ()
};

resolve();
})
|> ignore
Expand All @@ -49,7 +49,8 @@ let eventCallback = (event: option(Decode.Event.t), res) => {
switch (event) {
| Some(e) =>
switch (e.command) {
| Search => messageWithAttachment(e)
| Search
| NowPlaying => messageWithBlocks(e)
| _ => message(e)
};

Expand Down Expand Up @@ -78,12 +79,15 @@ let event =
)
);

let action =
PromiseMiddleware.from((_next, req, res) =>
Js.Promise.(
module Action = {
open Js.Promise;

let make =
PromiseMiddleware.from((_next, req, res) =>
switch (Request.bodyJSON(req)) {
| Some(body) =>
let {actions, user}: Decode.Action.t = body |> Decode.Action.make;
let {actions, response_url, user}: Decode.Action.t =
body |> Decode.Action.make;
let track = actions[0].value;

Queue.last(track)
Expand All @@ -95,14 +99,22 @@ let action =
);

switch (message) {
| `Ok(m) => res |> Response.sendString(m) |> resolve
| `Ok(m) =>
API.createRequest(
~url=response_url,
~_method="POST",
~data=Some({"text": m}),
(),
)
|> then_(_ => res |> Response.sendString(m) |> resolve)

| `Failed(_) => res |> failed |> resolve
};
});
| None => res |> failed |> resolve
}
)
);
);
};

let slackAuth =
Middleware.from((_next, _req, res) =>
Expand Down
2 changes: 1 addition & 1 deletion src/Server.re
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ App.use(app, Middleware.urlencoded(~extended=false, ()));

App.get(app, ~path="/") @@ Routes.index;
App.post(app, ~path="/event") @@ Routes.event;
App.post(app, ~path="/action") @@ Routes.action;
App.post(app, ~path="/action") @@ Routes.Action.make;
App.post(app, ~path="/cli") @@ CLI.route;
App.get(app, ~path="/slack/auth") @@ Routes.slackAuth;
App.get(app, ~path="/slack/token") @@ Routes.slackToken;
Expand Down
131 changes: 103 additions & 28 deletions src/adapters/Slack.re
Original file line number Diff line number Diff line change
@@ -1,31 +1,105 @@
module Attachment = {
[@bs.obj]
external field: (~title: string, ~value: string, ~short: bool) => _ = "";
module Block = {
[@bs.deriving {jsConverter: newType}]
type text = {
_type: string,
text: string,
};

[@bs.obj]
external action:
(
~name: [@bs.as "track"] _,
~text: [@bs.as "Queue"] _,
~_type: [@bs.as "button"] _,
~value: string,
unit
) =>
_ =
"";
[@bs.deriving {jsConverter: newType}]
type accessory = {
_type: string,
action_id: option(string),
alt_text: option(string),
image_url: option(string),
text: option(abs_text),
value: option(string),
};

[@bs.obj]
external make:
(
~color: [@bs.as "#efb560"] _,
~callback_id: [@bs.as "queue"] _,
~thumb_url: string,
~fields: array(Js.t('a)),
~actions: array(Js.t('b)),
unit
) =>
_ =
"";
[@bs.deriving jsConverter]
type section = {
_type: string,
elements: option(array(option(abs_accessory))),
fields: option(array(abs_text)),
accessory: option(abs_accessory),
text: option(abs_text),
};

let base =
(
~_type="section",
~fields=None,
~text=None,
~accessory=None,
~elements=None,
(),
) => {
sectionToJs({_type, fields, text, accessory, elements});
};

let baseAccessory =
(
~_type,
~image_url=None,
~alt_text=None,
~text=None,
~value=None,
~action_id=None,
(),
) => {
accessoryToJs({_type, image_url, alt_text, text, value, action_id});
};

module Text = {
let make = (~text, ~_type="mrkdwn", ()) => {
textToJs({_type, text});
};
};

module Image = {
let make = (~image_url, ~alt_text, ~_type="image", ()) => {
Some(
baseAccessory(
~_type,
~image_url=Some(image_url),
~alt_text=Some(alt_text),
(),
),
);
};
};

module Button = {
let make = (~text, ~value, ~action_id, ~_type="button", ()) => {
Some(
baseAccessory(
~_type,
~value=Some(value),
~action_id=Some(action_id),
~text=Some(Text.make(~text, ~_type="plain_text", ())),
(),
),
);
};
};

module Divider = {
let make = () => base(~_type="divider", ());
};

module Fields = {
let make = (~fields, ~accessory=None, ()) =>
base(~fields=Some(fields), ~accessory, ());
};

module Actions = {
let make = (~elements) =>
base(~_type="actions", ~elements=Some(elements), ());
};

module Section = {
let make = (~text, ~_type="mrkdwn", ~accessory=None, ()) =>
base(~accessory, ~text=Some(Text.make(~_type, ~text, ())), ());
};
};

let userId = id => "<@" ++ id ++ ">";
Expand Down Expand Up @@ -79,14 +153,15 @@ module Message = {
~username: [@bs.as "Wejay"] _,
~text: string,
~attachments: array(Js.t('a))=?,
~blocks: array(Js.t('a))=?,
~mrkdwn: bool,
unit
) =>
_ =
"";

let withAttachments = (channel, message, attachments) =>
slackMessage(~channel, ~text=message, ~attachments, ~mrkdwn=true, ())
let withBlocks = (channel, message, blocks) =>
slackMessage(~channel, ~text=message, ~blocks, ~mrkdwn=true, ())
|> sendPayload;

let regular = (channel: string, message: string) =>
Expand Down
Loading

0 comments on commit cc96b1f

Please sign in to comment.