diff --git a/.ocamlformat b/.ocamlformat
new file mode 100644
index 0000000..9c00f44
--- /dev/null
+++ b/.ocamlformat
@@ -0,0 +1,2 @@
+version=0.26.1
+profile=conventional
diff --git a/src/cli/dune b/src/cli/dune
index c835954..72b47eb 100644
--- a/src/cli/dune
+++ b/src/cli/dune
@@ -1,4 +1,4 @@
(executable
- (name slack_notify)
- (public_name slack-notify)
- (libraries slacko cmdliner))
+ (name slack_notify)
+ (public_name slack-notify)
+ (libraries slacko cmdliner))
diff --git a/src/cli/slack_notify.ml b/src/cli/slack_notify.ml
index 6ea1c62..a9d85f0 100644
--- a/src/cli/slack_notify.ml
+++ b/src/cli/slack_notify.ml
@@ -20,27 +20,35 @@
let base_url =
let doc = "The Slack API base URL" in
- Cmdliner.Arg.(value & opt (some string) None & info ["base-url"] ~docv:"URL" ~doc)
+ Cmdliner.Arg.(
+ value & opt (some string) None & info [ "base-url" ] ~docv:"URL" ~doc)
let token =
let doc = "The Slack API access token" in
- Cmdliner.Arg.(required & opt (some string) None & info ["t"; "token"] ~docv:"TOKEN" ~doc)
+ Cmdliner.Arg.(
+ required & opt (some string) None & info [ "t"; "token" ] ~docv:"TOKEN" ~doc)
let username =
let doc = "Name of the bot in the chat" in
- Cmdliner.Arg.(value & opt (some string) None & info ["u"; "username"] ~docv:"USERNAME" ~doc)
+ Cmdliner.Arg.(
+ value
+ & opt (some string) None
+ & info [ "u"; "username" ] ~docv:"USERNAME" ~doc)
let icon_url =
let doc = "URL to an image to use as the icon for this message" in
- Cmdliner.Arg.(value & opt (some string) None & info ["icon-url"] ~docv:"URL" ~doc)
+ Cmdliner.Arg.(
+ value & opt (some string) None & info [ "icon-url" ] ~docv:"URL" ~doc)
let icon_emoji =
let doc = "Emoji to use as the icon for this message. Overrides icon-url" in
- Cmdliner.Arg.(value & opt (some string) None & info ["icon-emoji"] ~docv:"EMOJI" ~doc)
+ Cmdliner.Arg.(
+ value & opt (some string) None & info [ "icon-emoji" ] ~docv:"EMOJI" ~doc)
let channel =
let doc = "Name of the channel to post to" in
- Cmdliner.Arg.(required & pos 0 (some string) None & info [] ~docv:"CHANNEL" ~doc)
+ Cmdliner.Arg.(
+ required & pos 0 (some string) None & info [] ~docv:"CHANNEL" ~doc)
let message =
let doc = "Message to send" in
@@ -48,16 +56,18 @@ let message =
let attachment =
let doc = "Attachment text" in
- Cmdliner.Arg.(value & opt (some string) None & info ["attachment"] ~docv:"MSG" ~doc)
+ Cmdliner.Arg.(
+ value & opt (some string) None & info [ "attachment" ] ~docv:"MSG" ~doc)
let info =
let doc = "Posts messages to Slack" in
Cmdliner.Cmd.info "slack-notify" ~doc
-let execute base_url token username channel icon_url icon_emoji attachment_text msg =
+let execute base_url token username channel icon_url icon_emoji attachment_text
+ msg =
"Your token is " ^ token ^ ", the channel is " ^ channel
- ^ " and the message is '" ^ msg ^ "'."
- |> print_endline;
+ ^ " and the message is '" ^ msg ^ "'."
+ |> print_endline;
let string_or_bust = function
| `Success _ -> "Message posted"
@@ -77,21 +87,17 @@ let execute base_url token username channel icon_url icon_emoji attachment_text
let attachments =
match attachment_text with
| None -> None
- | Some text -> Some [Slacko.attachment ~text ()]
+ | Some text -> Some [ Slacko.attachment ~text () ]
in
- Slacko.chat_post_message session chat
- ?username:(username)
- ?icon_emoji:(icon_emoji)
- ?icon_url:(icon_url)
- ?attachments:(attachments)
- msg
- >|= (fun c ->
- print_endline @@ string_or_bust c)
+ Slacko.chat_post_message session chat ?username ?icon_emoji ?icon_url
+ ?attachments msg
+ >|= (fun c -> print_endline @@ string_or_bust c)
|> Lwt_main.run
-let execute_t = Cmdliner.Term.(
- const execute $ base_url $ token $ username $ channel $ icon_url $ icon_emoji
- $ attachment $ message)
+let execute_t =
+ Cmdliner.Term.(
+ const execute $ base_url $ token $ username $ channel $ icon_url
+ $ icon_emoji $ attachment $ message)
let () =
let cmd = Cmdliner.Cmd.v info execute_t in
diff --git a/src/lib/dune b/src/lib/dune
index 61ebba3..3c9b714 100644
--- a/src/lib/dune
+++ b/src/lib/dune
@@ -1,7 +1,8 @@
(library
- (name slacko)
- (public_name slacko)
- (synopsis "A neat interface for Slack")
- (private_modules Timestamp)
- (libraries lwt cohttp-lwt-unix yojson ppx_deriving_yojson.runtime ptime)
- (preprocess (pps ppx_deriving_yojson)))
+ (name slacko)
+ (public_name slacko)
+ (synopsis "A neat interface for Slack")
+ (private_modules Timestamp)
+ (libraries lwt cohttp-lwt-unix yojson ppx_deriving_yojson.runtime ptime)
+ (preprocess
+ (pps ppx_deriving_yojson)))
diff --git a/src/lib/slacko.ml b/src/lib/slacko.ml
index a901bab..9d2562a 100644
--- a/src/lib/slacko.ml
+++ b/src/lib/slacko.ml
@@ -23,193 +23,81 @@ open Lwt.Syntax
module Cohttp_unix = Cohttp_lwt_unix
module Cohttp_body = Cohttp_lwt.Body
-type api_error = [
- | `Unhandled_error of string
- | `Unknown_error
-]
-
-type parsed_api_error = [
- | `ParseFailure of string
- | api_error
-]
-
-type auth_error = [
- | `Not_authed
- | `Invalid_auth
- | `Account_inactive
-]
-
-type timestamp_error = [
- | `Invalid_ts_latest
- | `Invalid_ts_oldest
-]
-
-type channel_error = [
- | `Channel_not_found
-]
-
-type user_error = [
- | `User_not_found
-]
-
-type invite_error = [
- | `Cant_invite_self
- | `Cant_invite
-]
-
-type not_in_channel_error = [
- | `Not_in_channel
-]
-
-type already_in_channel_error = [
- | `Already_in_channel
-]
-
-type archive_error = [
- | `Is_archived
-]
-
-type name_error = [
- | `Name_taken
-]
-
-type kick_error = [
- | `Cant_kick_self
-]
-
-type channel_kick_error = [
- | kick_error
- | `Cant_kick_from_general
- | `Cant_kick_from_last_channel
-]
-
-type restriction_error = [
- | `Restricted_action
-]
-
-type leave_general_error = [
- | `Cant_leave_general
-]
-
-type message_error = [
- | `Cant_delete_message
- | `Message_not_found
-]
-
-type message_length_error = [
- | `Msg_too_long
-]
-
-type attachments_error = [
- | `Too_many_attachments
-]
-
-type rate_error = [
- | `Rate_limited
-]
-
-type message_update_error = [
- | `Message_not_found
- | `Cant_update_message
- | `Edit_window_closed
-]
-
-type file_error = [
- | `File_not_found
- | `File_deleted
-]
-
-type unknown_type_error = [
- | `Unknown_type
-]
-
-type already_archived_error = [
- | `Already_archived
-]
-
-type not_in_group_error = [
- | `Not_in_group
-]
-
-type leave_last_channel_error = [
- | `Cant_leave_last_channel
-]
-
-type last_member_error = [
- | `Last_member
-]
-
-type oauth_error = [
- | `Invalid_client_id
+type api_error = [ `Unhandled_error of string | `Unknown_error ]
+type parsed_api_error = [ `ParseFailure of string | api_error ]
+type auth_error = [ `Not_authed | `Invalid_auth | `Account_inactive ]
+type timestamp_error = [ `Invalid_ts_latest | `Invalid_ts_oldest ]
+type channel_error = [ `Channel_not_found ]
+type user_error = [ `User_not_found ]
+type invite_error = [ `Cant_invite_self | `Cant_invite ]
+type not_in_channel_error = [ `Not_in_channel ]
+type already_in_channel_error = [ `Already_in_channel ]
+type archive_error = [ `Is_archived ]
+type name_error = [ `Name_taken ]
+type kick_error = [ `Cant_kick_self ]
+
+type channel_kick_error =
+ [ kick_error | `Cant_kick_from_general | `Cant_kick_from_last_channel ]
+
+type restriction_error = [ `Restricted_action ]
+type leave_general_error = [ `Cant_leave_general ]
+type message_error = [ `Cant_delete_message | `Message_not_found ]
+type message_length_error = [ `Msg_too_long ]
+type attachments_error = [ `Too_many_attachments ]
+type rate_error = [ `Rate_limited ]
+
+type message_update_error =
+ [ `Message_not_found | `Cant_update_message | `Edit_window_closed ]
+
+type file_error = [ `File_not_found | `File_deleted ]
+type unknown_type_error = [ `Unknown_type ]
+type already_archived_error = [ `Already_archived ]
+type not_in_group_error = [ `Not_in_group ]
+type leave_last_channel_error = [ `Cant_leave_last_channel ]
+type last_member_error = [ `Last_member ]
+
+type oauth_error =
+ [ `Invalid_client_id
| `Bad_client_secret
| `Invalid_code
| `Bad_redirect_uri
- | `Unknown_error
-]
+ | `Unknown_error ]
-type presence_error = [
- | `Invalid_presence
-]
+type presence_error = [ `Invalid_presence ]
+type user_visibility_error = [ `User_not_visible ]
+type invalid_name_error = [ `Invalid_name ]
+type bot_error = [ `User_is_bot ]
+type parsed_auth_error = [ parsed_api_error | auth_error ]
-type user_visibility_error = [
- | `User_not_visible
-]
-
-type invalid_name_error = [
- | `Invalid_name
-]
-
-type bot_error = [
- | `User_is_bot
-]
-
-type parsed_auth_error = [
- | parsed_api_error
- | auth_error
-]
-
-type topic_result = [
- | `Success of string
+type topic_result =
+ [ `Success of string
| parsed_auth_error
| channel_error
| archive_error
| not_in_channel_error
- | `User_is_restricted
-]
+ | `User_is_restricted ]
type timestamp = Ptime.t
type session = {
- base_url: string;
- token: string;
- (* Mutable id cache goes here? *)
+ base_url : string;
+ token : string; (* Mutable id cache goes here? *)
}
type token = session
-
type topic = string
-
type message = string
-
type channel = ChannelId of string | ChannelName of string
-
type conversation = string
-
type im = string
-
type user = UserId of string | UserName of string
-
type bot = BotId of string
-
type group = GroupId of string | GroupName of string
(* TODO: Sure about user? *)
type chat = Channel of channel | Im of im | User of user | Group of group
-
type sort_criterion = Score | Timestamp
-
type sort_direction = Ascending | Descending
-
type presence = Auto | Away
let user_of_yojson = function
@@ -223,7 +111,6 @@ let bot_of_yojson = function
| `String x -> Ok (bot_of_string x)
| _ -> Error "Couldn't parse bot type"
-
let channel_of_yojson = function
| `String x -> Ok (ChannelId x)
| _ -> Error "Couldn't parse channel type"
@@ -240,495 +127,475 @@ let im_of_yojson = function
| `String x -> Ok x
| _ -> Error "Couldn't parse im type"
-type topic_obj = {
- value: string;
- creator: user;
- last_set: Timestamp.t;
-} [@@deriving of_yojson]
+type topic_obj = { value : string; creator : user; last_set : Timestamp.t }
+[@@deriving of_yojson]
type channel_obj = {
- id: channel;
- name: string;
- is_channel: bool;
- created: Timestamp.t;
- creator: user;
- is_archived: bool;
- is_general: bool;
- name_normalized: string;
- is_member: bool;
- members: user list;
- topic: topic_obj;
- purpose: topic_obj;
- last_read: Timestamp.t option [@default None];
- latest: Yojson.Safe.t option [@default None];
- unread_count: int option [@default None];
- unread_count_display: int option [@default None];
- num_members: int option [@default None];
-} [@@deriving of_yojson { strict = false }]
+ id : channel;
+ name : string;
+ is_channel : bool;
+ created : Timestamp.t;
+ creator : user;
+ is_archived : bool;
+ is_general : bool;
+ name_normalized : string;
+ is_member : bool;
+ members : user list;
+ topic : topic_obj;
+ purpose : topic_obj;
+ last_read : Timestamp.t option; [@default None]
+ latest : Yojson.Safe.t option; [@default None]
+ unread_count : int option; [@default None]
+ unread_count_display : int option; [@default None]
+ num_members : int option; [@default None]
+}
+[@@deriving of_yojson { strict = false }]
type conversation_obj = {
- id: conversation;
- name: string;
- is_channel: bool;
- created: Timestamp.t;
- creator: user;
- is_archived: bool;
- is_general: bool;
- name_normalized: string;
- is_member: bool;
- topic: topic_obj;
- purpose: topic_obj;
- last_read: Timestamp.t option [@default None];
- latest: string option [@default None];
- unread_count: int option [@default None];
- unread_count_display: int option [@default None];
- num_members: int option [@default None];
-} [@@deriving of_yojson { strict = false }]
-
+ id : conversation;
+ name : string;
+ is_channel : bool;
+ created : Timestamp.t;
+ creator : user;
+ is_archived : bool;
+ is_general : bool;
+ name_normalized : string;
+ is_member : bool;
+ topic : topic_obj;
+ purpose : topic_obj;
+ last_read : Timestamp.t option; [@default None]
+ latest : string option; [@default None]
+ unread_count : int option; [@default None]
+ unread_count_display : int option; [@default None]
+ num_members : int option; [@default None]
+}
+[@@deriving of_yojson { strict = false }]
type user_obj = {
- id: user;
- name: string;
- deleted: bool;
- color: string option [@default None];
- real_name: string option [@default None];
- tz: string option [@default None];
- tz_label: string option [@default None];
- tz_offset: int [@default 0];
- profile: Yojson.Safe.t;
- is_admin: bool [@default false];
- is_owner: bool [@default false];
- is_primary_owner: bool [@default false];
- is_restricted: bool [@default false];
- is_ultra_restricted: bool [@default false];
- is_bot: bool;
- has_files: bool [@default false];
-} [@@deriving of_yojson { strict = false } ]
+ id : user;
+ name : string;
+ deleted : bool;
+ color : string option; [@default None]
+ real_name : string option; [@default None]
+ tz : string option; [@default None]
+ tz_label : string option; [@default None]
+ tz_offset : int; [@default 0]
+ profile : Yojson.Safe.t;
+ is_admin : bool; [@default false]
+ is_owner : bool; [@default false]
+ is_primary_owner : bool; [@default false]
+ is_restricted : bool; [@default false]
+ is_ultra_restricted : bool; [@default false]
+ is_bot : bool;
+ has_files : bool; [@default false]
+}
+[@@deriving of_yojson { strict = false }]
type group_obj = {
- id: group;
- name: string;
- is_group: bool;
- created: Timestamp.t;
- creator: user;
- is_archived: bool;
- members: user list;
- topic: topic_obj;
- purpose: topic_obj;
- is_open: bool option [@default None];
- last_read: Timestamp.t option [@default None];
- unread_count: int option [@default None];
- unread_count_display: int option [@default None];
- latest: Yojson.Safe.t option [@default None];
-} [@@deriving of_yojson { strict = false }]
+ id : group;
+ name : string;
+ is_group : bool;
+ created : Timestamp.t;
+ creator : user;
+ is_archived : bool;
+ members : user list;
+ topic : topic_obj;
+ purpose : topic_obj;
+ is_open : bool option; [@default None]
+ last_read : Timestamp.t option; [@default None]
+ unread_count : int option; [@default None]
+ unread_count_display : int option; [@default None]
+ latest : Yojson.Safe.t option; [@default None]
+}
+[@@deriving of_yojson { strict = false }]
type file_obj = {
(* TODO file id type *)
- id: string;
- created: Timestamp.t;
+ id : string;
+ created : Timestamp.t;
(* deprecated *)
- timestamp: Timestamp.t;
-
- name: string option [@default None];
- title: string;
- mimetype: string;
- pretty_type: string;
- user: user;
-
- mode: string;
- editable: bool;
- is_external: bool;
- external_type: string;
-
- size: int;
-
- url_private: string;
- url_private_download: string;
-
- thumb_64: string option [@default None];
- thunb_80: string option [@default None];
- thumb_360: string option [@default None];
- thumb_360_gif: string option [@default None];
- thumb_360_w: int option [@default None];
- thumb_360_h: int option [@default None];
-
- permalink: string;
- edit_link: string option [@default None];
- preview: string option [@default None];
- preview_highlight: string option [@default None];
- lines: int option [@default None];
- lines_more: int option [@default None];
-
- is_public: bool;
+ timestamp : Timestamp.t;
+ name : string option; [@default None]
+ title : string;
+ mimetype : string;
+ pretty_type : string;
+ user : user;
+ mode : string;
+ editable : bool;
+ is_external : bool;
+ external_type : string;
+ size : int;
+ url_private : string;
+ url_private_download : string;
+ thumb_64 : string option; [@default None]
+ thunb_80 : string option; [@default None]
+ thumb_360 : string option; [@default None]
+ thumb_360_gif : string option; [@default None]
+ thumb_360_w : int option; [@default None]
+ thumb_360_h : int option; [@default None]
+ permalink : string;
+ edit_link : string option; [@default None]
+ preview : string option; [@default None]
+ preview_highlight : string option; [@default None]
+ lines : int option; [@default None]
+ lines_more : int option; [@default None]
+ is_public : bool;
(*public_url_shared: ???;*)
- channels: channel list;
- groups: group list;
- ims: im list;
- initial_comment: Yojson.Safe.t option [@default None];
- num_stars: int option [@default None];
-} [@@deriving of_yojson { strict = false }]
+ channels : channel list;
+ groups : group list;
+ ims : im list;
+ initial_comment : Yojson.Safe.t option; [@default None]
+ num_stars : int option; [@default None]
+}
+[@@deriving of_yojson { strict = false }]
type field_obj = {
- title: string option [@default None];
- value: string [@default ""];
- short: bool [@default false];
-} [@@deriving to_yojson { strict = false }]
-
-let field ?title ?(short=false) value = {
- title;
- value;
- short;
+ title : string option; [@default None]
+ value : string; [@default ""]
+ short : bool; [@default false]
}
+[@@deriving to_yojson { strict = false }]
+
+let field ?title ?(short = false) value = { title; value; short }
type attachment_obj = {
- fallback: string option [@default None];
- color: string option [@default None];
- pretext: string option [@default None];
- author_name: string option [@default None];
- author_link: string option [@default None];
- author_icon: string option [@default None];
- title: string option [@default None];
- title_link: string option [@default None];
- text: string option [@default None];
- fields: field_obj list option [@default None];
- image_url: string option [@default None];
- thumb_url: string option [@default None];
- footer: string option [@default None];
- footer_icon: string option [@default None];
- ts: Timestamp.t option [@default None];
- mrkdwn_in: string list option [@default None];
-} [@@deriving to_yojson { strict = false }]
-
-let if_none a b =
- match a with
- | Some v -> Some v
- | None -> b
-
-let attachment
- ?fallback ?color ?pretext
- ?author_name ?author_link ?author_icon
- ?title ?title_link
- ?text ?fields
- ?image_url ?thumb_url
- ?footer ?footer_icon
- ?ts ?mrkdwn_in
- () = {
- fallback = if_none fallback text;
- color;
- pretext;
- author_name;
- author_link;
- author_icon;
- title;
- title_link;
- text;
- fields;
- image_url;
- thumb_url;
- footer;
- footer_icon;
- ts;
- mrkdwn_in;
+ fallback : string option; [@default None]
+ color : string option; [@default None]
+ pretext : string option; [@default None]
+ author_name : string option; [@default None]
+ author_link : string option; [@default None]
+ author_icon : string option; [@default None]
+ title : string option; [@default None]
+ title_link : string option; [@default None]
+ text : string option; [@default None]
+ fields : field_obj list option; [@default None]
+ image_url : string option; [@default None]
+ thumb_url : string option; [@default None]
+ footer : string option; [@default None]
+ footer_icon : string option; [@default None]
+ ts : Timestamp.t option; [@default None]
+ mrkdwn_in : string list option; [@default None]
}
+[@@deriving to_yojson { strict = false }]
+
+let if_none a b = match a with Some v -> Some v | None -> b
+
+let attachment ?fallback ?color ?pretext ?author_name ?author_link ?author_icon
+ ?title ?title_link ?text ?fields ?image_url ?thumb_url ?footer ?footer_icon
+ ?ts ?mrkdwn_in () =
+ {
+ fallback = if_none fallback text;
+ color;
+ pretext;
+ author_name;
+ author_link;
+ author_icon;
+ title;
+ title_link;
+ text;
+ fields;
+ image_url;
+ thumb_url;
+ footer;
+ footer_icon;
+ ts;
+ mrkdwn_in;
+ }
type message_obj = {
- type': string [@key "type"];
- ts: Timestamp.t;
- user: user option [@default None];
- bot_id: bot option [@default None];
- text: string option;
- is_starred: bool option [@default None];
-} [@@deriving of_yojson { strict = false }]
+ type' : string; [@key "type"]
+ ts : Timestamp.t;
+ user : user option; [@default None]
+ bot_id : bot option; [@default None]
+ text : string option;
+ is_starred : bool option; [@default None]
+}
+[@@deriving of_yojson { strict = false }]
type history_obj = {
- latest: Timestamp.t option [@default None];
- messages: message_obj list;
- has_more: bool;
-} [@@deriving of_yojson { strict = false }]
+ latest : Timestamp.t option; [@default None]
+ messages : message_obj list;
+ has_more : bool;
+}
+[@@deriving of_yojson { strict = false }]
type authed_obj = {
- url: string;
- team: string;
- user: string;
- team_id: string;
- user_id: user;
-} [@@deriving of_yojson { strict = false }]
+ url : string;
+ team : string;
+ user : string;
+ team_id : string;
+ user_id : user;
+}
+[@@deriving of_yojson { strict = false }]
-type channel_leave_obj = {
- not_in_channel: bool option [@default None];
-} [@@deriving of_yojson { strict = false }]
+type channel_leave_obj = { not_in_channel : bool option [@default None] }
+[@@deriving of_yojson { strict = false }]
type channel_rename_obj = {
- id: channel;
- is_channel: bool;
- name: string;
- created: Timestamp.t;
-} [@@deriving of_yojson { strict = false }]
+ id : channel;
+ is_channel : bool;
+ name : string;
+ created : Timestamp.t;
+}
+[@@deriving of_yojson { strict = false }]
let chat_of_yojson = function
- | `String c -> (match c.[0] with
- | 'C' -> Ok (Channel (ChannelId c))
- | 'D' -> Ok (Im c)
- | 'G' -> Ok (Group (GroupId c))
- | _ -> Error "Failed to parse chat")
+ | `String c -> (
+ match c.[0] with
+ | 'C' -> Ok (Channel (ChannelId c))
+ | 'D' -> Ok (Im c)
+ | 'G' -> Ok (Group (GroupId c))
+ | _ -> Error "Failed to parse chat")
| _ -> Error "Failed to parse chat"
type chat_obj = {
- ts: Timestamp.t;
- chat: chat [@key "channel"];
- text: string option [@default None];
-} [@@deriving of_yojson { strict = false }]
+ ts : Timestamp.t;
+ chat : chat; [@key "channel"]
+ text : string option; [@default None]
+}
+[@@deriving of_yojson { strict = false }]
-type emoji = (string * string)
-type emoji_list_obj = {
- emoji: (string * string) list;
-} [@@deriving of_yojson]
+type emoji = string * string
+type emoji_list_obj = { emoji : (string * string) list } [@@deriving of_yojson]
type chat_close_obj = {
- no_op: bool option [@default None];
- already_closed: bool option [@default None];
-} [@@deriving of_yojson { strict = false }]
+ no_op : bool option; [@default None]
+ already_closed : bool option; [@default None]
+}
+[@@deriving of_yojson { strict = false }]
type groups_invite_obj = {
- already_in_group: bool option [@default None];
- group: group_obj;
-} [@@deriving of_yojson { strict = false }]
+ already_in_group : bool option; [@default None]
+ group : group_obj;
+}
+[@@deriving of_yojson { strict = false }]
type groups_open_obj = {
- no_op: bool option [@default None];
- already_open: bool option [@default None];
-} [@@deriving of_yojson { strict = false }]
+ no_op : bool option; [@default None]
+ already_open : bool option; [@default None]
+}
+[@@deriving of_yojson { strict = false }]
type groups_rename_obj = {
- id: channel;
- is_group: bool;
- name: string;
- created: Timestamp.t
-} [@@deriving of_yojson { strict = false }]
+ id : channel;
+ is_group : bool;
+ name : string;
+ created : Timestamp.t;
+}
+[@@deriving of_yojson { strict = false }]
type im_obj = {
- id: string;
- is_im: bool;
- user: user;
- created: Timestamp.t;
- is_user_deleted: bool;
- is_open: bool option [@default None];
- last_read: Timestamp.t option [@default None];
- unread_count: int option [@default None];
- unread_count_display: int option [@default None];
-} [@@deriving of_yojson { strict = false }]
-
-type im_channel_obj = {
- id: string;
-} [@@deriving of_yojson { strict = false }]
+ id : string;
+ is_im : bool;
+ user : user;
+ created : Timestamp.t;
+ is_user_deleted : bool;
+ is_open : bool option; [@default None]
+ last_read : Timestamp.t option; [@default None]
+ unread_count : int option; [@default None]
+ unread_count_display : int option; [@default None]
+}
+[@@deriving of_yojson { strict = false }]
+
+type im_channel_obj = { id : string } [@@deriving of_yojson { strict = false }]
type im_open_obj = {
- no_op: bool option [@default None];
- already_open: bool option [@default None];
- channel: im_channel_obj;
-} [@@deriving of_yojson { strict = false }]
+ no_op : bool option; [@default None]
+ already_open : bool option; [@default None]
+ channel : im_channel_obj;
+}
+[@@deriving of_yojson { strict = false }]
-type oauth_obj = {
- access_token: string;
- scope: string;
-} [@@deriving of_yojson { strict = false }]
+type oauth_obj = { access_token : string; scope : string }
+[@@deriving of_yojson { strict = false }]
type comment_obj = {
- id: string;
- timestamp: Timestamp.t;
- user: user;
- comment: string;
-} [@@deriving of_yojson { strict = false }]
-
-type paging_obj = {
- count: int;
- total: int;
- page: int;
- pages: int;
-} [@@deriving of_yojson { strict = false }]
+ id : string;
+ timestamp : Timestamp.t;
+ user : user;
+ comment : string;
+}
+[@@deriving of_yojson { strict = false }]
+
+type paging_obj = { count : int; total : int; page : int; pages : int }
+[@@deriving of_yojson { strict = false }]
type files_info_obj = {
- file: file_obj;
- comments: comment_obj list;
- paging: paging_obj;
-} [@@deriving of_yojson { strict = false }]
+ file : file_obj;
+ comments : comment_obj list;
+ paging : paging_obj;
+}
+[@@deriving of_yojson { strict = false }]
-type files_list_obj = {
- files: file_obj list;
- paging: paging_obj;
-} [@@deriving of_yojson { strict = false }]
+type files_list_obj = { files : file_obj list; paging : paging_obj }
+[@@deriving of_yojson { strict = false }]
type stars_list_obj = {
(* TODO proper types *)
- items: Yojson.Safe.t list;
- paging: paging_obj;
-} [@@deriving of_yojson { strict = false }]
+ items : Yojson.Safe.t list;
+ paging : paging_obj;
+}
+[@@deriving of_yojson { strict = false }]
type message_search_obj = {
- total: int;
- paging: paging_obj;
- matches: message_obj list;
-} [@@deriving of_yojson { strict = false }]
+ total : int;
+ paging : paging_obj;
+ matches : message_obj list;
+}
+[@@deriving of_yojson { strict = false }]
type file_search_obj = {
- total: int;
- paging: paging_obj;
- matches: file_obj list;
-} [@@deriving of_yojson { strict = false }]
+ total : int;
+ paging : paging_obj;
+ matches : file_obj list;
+}
+[@@deriving of_yojson { strict = false }]
type search_obj = {
- query: string;
- messages: message_search_obj option [@default None];
- files: file_search_obj option [@default None];
-} [@@deriving of_yojson { strict = false }]
+ query : string;
+ messages : message_search_obj option; [@default None]
+ files : file_search_obj option; [@default None]
+}
+[@@deriving of_yojson { strict = false }]
type team_obj = {
(* TODO team id *)
- id: string;
- name: string;
- domain: string;
- email_domain: string;
- icon: Yojson.Safe.t;
-} [@@deriving of_yojson { strict = false }]
+ id : string;
+ name : string;
+ domain : string;
+ email_domain : string;
+ icon : Yojson.Safe.t;
+}
+[@@deriving of_yojson { strict = false }]
type login_obj = {
- user_id: user;
- username: string;
- date_first: Timestamp.t;
- date_last: Timestamp.t;
- count: int;
- ip: string;
- user_agent: string;
- isp: string;
- country: string;
- region: string;
-} [@@deriving of_yojson { strict = false }]
-
-type team_access_log_obj = {
- logins: login_obj list;
- paging: paging_obj;
-} [@@deriving of_yojson { strict = false }]
-
-type history_result = [
- | `Success of history_obj
+ user_id : user;
+ username : string;
+ date_first : Timestamp.t;
+ date_last : Timestamp.t;
+ count : int;
+ ip : string;
+ user_agent : string;
+ isp : string;
+ country : string;
+ region : string;
+}
+[@@deriving of_yojson { strict = false }]
+
+type team_access_log_obj = { logins : login_obj list; paging : paging_obj }
+[@@deriving of_yojson { strict = false }]
+
+type history_result =
+ [ `Success of history_obj
| parsed_auth_error
| channel_error
- | timestamp_error
-]
+ | timestamp_error ]
(* internal *)
let default_base_url = "https://slack.com/api/"
-type api_request = {
- method': string;
- arguments: (string * string) list
-}
+type api_request = { method' : string; arguments : (string * string) list }
let api_request method' = { method'; arguments = [] }
-let optionally_add key value request = match value with
+let optionally_add key value request =
+ match value with
| None -> request
- | Some value -> { request with arguments = (key, value)::request.arguments }
+ | Some value -> { request with arguments = (key, value) :: request.arguments }
let definitely_add key value = optionally_add key (Some value)
(* private API return type *)
(* the strict is important here, because we just match ok & error and
* deliberately ignore the rest *)
-type api_answer = {
- ok: bool;
- error: string option [@default None]
-} [@@deriving of_yojson { strict = false }]
+type api_answer = { ok : bool; error : string option [@default None] }
+[@@deriving of_yojson { strict = false }]
let validate json =
match api_answer_of_yojson json with
| Error str -> `ParseFailure str
- | Ok parsed -> match parsed.ok, parsed.error with
- | true, _ -> `Json_response json
- | _, Some "account_inactive" -> `Account_inactive
- | _, Some "already_archived" -> `Already_archived
- | _, Some "already_in_channel" -> `Already_in_channel
- | _, Some "bad_client_secret" -> `Bad_client_secret
- | _, Some "bad_redirect_uri" -> `Bad_redirect_uri
- | _, Some "cant_archive_general" -> `Cant_archive_general
- | _, Some "cant_invite" -> `Cant_invite
- | _, Some "cant_invite_self" -> `Cant_invite_self
- | _, Some "cant_delete_file" -> `Cant_delete_file
- | _, Some "cant_delete_message" -> `Cant_delete_message
- | _, Some "cant_kick_from_general" -> `Cant_kick_from_general
- | _, Some "cant_kick_from_last_channel" -> `Cant_kick_from_last_channel
- | _, Some "cant_kick_self" -> `Cant_kick_self
- | _, Some "cant_leave_general" -> `Cant_leave_general
- | _, Some "cant_leave_last_channel" -> `Cant_leave_last_channel
- | _, Some "cant_update_message" -> `Cant_update_message
- | _, Some "channel_not_found" -> `Channel_not_found
- | _, Some "edit_window_closed" -> `Edit_window_closed
- | _, Some "file_deleted" -> `File_deleted
- | _, Some "file_not_found" -> `File_not_found
- | _, Some "invalid_auth" -> `Invalid_auth
- | _, Some "invalid_client_id" -> `Invalid_client_id
- | _, Some "invalid_code" -> `Invalid_code
- | _, Some "invalid_name" -> `Invalid_name
- | _, Some "invalid_presence" -> `Invalid_presence
- | _, Some "invalid_ts_latest" -> `Invalid_ts_latest
- | _, Some "invalid_ts_oldest" -> `Invalid_ts_oldest
- | _, Some "is_archived" -> `Is_archived
- | _, Some "last_member" -> `Last_member
- | _, Some "last_ra_channel" -> `Last_restricted_channel
- | _, Some "message_not_found" -> `Message_not_found
- (* not supposed to happen *)
- | _, Some "msg_too_long" -> `Msg_too_long
- | _, Some "too_many_attachments" -> `Too_many_attachments
- | _, Some "name_taken" -> `Name_taken
- (* can't really happen *)
- | _, Some "no_channel" -> `No_channel
- (* can't really happen either *)
- | _, Some "no_text" -> `No_text
- | _, Some "not_archived" -> `Not_archived
- | _, Some "not_authed" -> `Not_authed
- | _, Some "not_authorized" -> `Not_authorized
- | _, Some "not_in_channel" -> `Not_in_channel
- | _, Some "paid_only" -> `Paid_only
- | _, Some "rate_limited" -> `Rate_limited
- | _, Some "restricted_action" -> `Restricted_action
- | _, Some "too_long" -> `Too_long
- | _, Some "unknown_type" -> `Unknown_type
- | _, Some "user_does_not_own_channel" -> `User_does_not_own_channel
- | _, Some "user_is_bot" -> `User_is_bot
- | _, Some "user_is_restricted" -> `User_is_restricted
- (* lolwat, I'm not making this up *)
- | _, Some "user_is_ultra_restricted" -> `User_is_ultra_restricted
- | _, Some "user_not_found" -> `User_not_found
- | _, Some "user_not_visible" -> `User_not_visible
- (* when the API changes and introduces new, yet unhandled error types *)
- | _, Some err -> `Unhandled_error err
- | _ -> `Unknown_error
+ | Ok parsed -> (
+ match (parsed.ok, parsed.error) with
+ | true, _ -> `Json_response json
+ | _, Some "account_inactive" -> `Account_inactive
+ | _, Some "already_archived" -> `Already_archived
+ | _, Some "already_in_channel" -> `Already_in_channel
+ | _, Some "bad_client_secret" -> `Bad_client_secret
+ | _, Some "bad_redirect_uri" -> `Bad_redirect_uri
+ | _, Some "cant_archive_general" -> `Cant_archive_general
+ | _, Some "cant_invite" -> `Cant_invite
+ | _, Some "cant_invite_self" -> `Cant_invite_self
+ | _, Some "cant_delete_file" -> `Cant_delete_file
+ | _, Some "cant_delete_message" -> `Cant_delete_message
+ | _, Some "cant_kick_from_general" -> `Cant_kick_from_general
+ | _, Some "cant_kick_from_last_channel" -> `Cant_kick_from_last_channel
+ | _, Some "cant_kick_self" -> `Cant_kick_self
+ | _, Some "cant_leave_general" -> `Cant_leave_general
+ | _, Some "cant_leave_last_channel" -> `Cant_leave_last_channel
+ | _, Some "cant_update_message" -> `Cant_update_message
+ | _, Some "channel_not_found" -> `Channel_not_found
+ | _, Some "edit_window_closed" -> `Edit_window_closed
+ | _, Some "file_deleted" -> `File_deleted
+ | _, Some "file_not_found" -> `File_not_found
+ | _, Some "invalid_auth" -> `Invalid_auth
+ | _, Some "invalid_client_id" -> `Invalid_client_id
+ | _, Some "invalid_code" -> `Invalid_code
+ | _, Some "invalid_name" -> `Invalid_name
+ | _, Some "invalid_presence" -> `Invalid_presence
+ | _, Some "invalid_ts_latest" -> `Invalid_ts_latest
+ | _, Some "invalid_ts_oldest" -> `Invalid_ts_oldest
+ | _, Some "is_archived" -> `Is_archived
+ | _, Some "last_member" -> `Last_member
+ | _, Some "last_ra_channel" -> `Last_restricted_channel
+ | _, Some "message_not_found" -> `Message_not_found
+ (* not supposed to happen *)
+ | _, Some "msg_too_long" -> `Msg_too_long
+ | _, Some "too_many_attachments" -> `Too_many_attachments
+ | _, Some "name_taken" -> `Name_taken
+ (* can't really happen *)
+ | _, Some "no_channel" -> `No_channel
+ (* can't really happen either *)
+ | _, Some "no_text" -> `No_text
+ | _, Some "not_archived" -> `Not_archived
+ | _, Some "not_authed" -> `Not_authed
+ | _, Some "not_authorized" -> `Not_authorized
+ | _, Some "not_in_channel" -> `Not_in_channel
+ | _, Some "paid_only" -> `Paid_only
+ | _, Some "rate_limited" -> `Rate_limited
+ | _, Some "restricted_action" -> `Restricted_action
+ | _, Some "too_long" -> `Too_long
+ | _, Some "unknown_type" -> `Unknown_type
+ | _, Some "user_does_not_own_channel" -> `User_does_not_own_channel
+ | _, Some "user_is_bot" -> `User_is_bot
+ | _, Some "user_is_restricted" -> `User_is_restricted
+ (* lolwat, I'm not making this up *)
+ | _, Some "user_is_ultra_restricted" -> `User_is_ultra_restricted
+ | _, Some "user_not_found" -> `User_not_found
+ | _, Some "user_not_visible" -> `User_not_visible
+ (* when the API changes and introduces new, yet unhandled error types *)
+ | _, Some err -> `Unhandled_error err
+ | _ -> `Unknown_error)
(* filter out "ok" and "error" keys *)
let filter_useless = function
- | `Json_response `Assoc items -> `Json_response (
- `Assoc (List.filter (fun (k, _) -> k <> "ok" && k <> "error") items))
+ | `Json_response (`Assoc items) ->
+ `Json_response
+ (`Assoc (List.filter (fun (k, _) -> k <> "ok" && k <> "error") items))
| otherwise -> otherwise
let process request =
- request
- >|= snd
- >>= Cohttp_body.to_string
- >|= Yojson.Safe.from_string
- >|= validate
- >|= filter_useless
+ request >|= snd >>= Cohttp_body.to_string >|= Yojson.Safe.from_string
+ >|= validate >|= filter_useless
let auth_header token =
Cohttp.Header.init_with "Authorization" ("Bearer " ^ token)
let endpoint base_url request =
let url = Uri.of_string (base_url ^ request.method') in
- List.fold_left (Uri.add_query_param') url request.arguments
+ List.fold_left Uri.add_query_param' url request.arguments
-let unauthed_query ?(base_url=default_base_url) request =
- endpoint base_url request
- |> Cohttp_unix.Client.get
- |> process
+let unauthed_query ?(base_url = default_base_url) request =
+ endpoint base_url request |> Cohttp_unix.Client.get |> process
let query session request =
endpoint session.base_url request
@@ -742,64 +609,53 @@ let query_post session body request =
|> process
let identity x = x
-
-let maybe fn = function
- | Some v -> Some (fn v)
- | None -> None
+let maybe fn = function Some v -> Some (fn v) | None -> None
(* nonpublic types for conversion in list types *)
-type conversations_list_obj = {
- channels: conversation_obj list
-} [@@deriving of_yojson { strict = false }]
-
-type users_list_obj = {
- members: user_obj list
-} [@@deriving of_yojson { strict = false }]
+type conversations_list_obj = { channels : conversation_obj list }
+[@@deriving of_yojson { strict = false }]
-type groups_list_obj = {
- groups: group_obj list;
-} [@@deriving of_yojson]
+type users_list_obj = { members : user_obj list }
+[@@deriving of_yojson { strict = false }]
-type im_list_obj = {
- ims: im_obj list;
-} [@@deriving of_yojson]
+type groups_list_obj = { groups : group_obj list } [@@deriving of_yojson]
+type im_list_obj = { ims : im_obj list } [@@deriving of_yojson]
let conversations_list ?exclude_archived session =
api_request "conversations.list"
- |> optionally_add "exclude_archived" @@ maybe string_of_bool @@ exclude_archived
- |> query session
- >|= function
- | `Json_response d ->
- (match d |> conversations_list_obj_of_yojson with
- | Ok x -> `Success x.channels
- | Error e -> `ParseFailure e)
- | #parsed_auth_error as res -> res
- | _ -> `Unknown_error
+ |> optionally_add "exclude_archived"
+ @@ maybe string_of_bool @@ exclude_archived
+ |> query session
+ >|= function
+ | `Json_response d -> (
+ match d |> conversations_list_obj_of_yojson with
+ | Ok x -> `Success x.channels
+ | Error e -> `ParseFailure e)
+ | #parsed_auth_error as res -> res
+ | _ -> `Unknown_error
let users_list session =
- api_request "users.list"
- |> query session
- >|= function
- | `Json_response d ->
- (match d |> users_list_obj_of_yojson with
- | Ok x -> `Success x.members
- | Error x -> `ParseFailure x)
- | #parsed_auth_error as res -> res
- | _ -> `Unknown_error
+ api_request "users.list" |> query session >|= function
+ | `Json_response d -> (
+ match d |> users_list_obj_of_yojson with
+ | Ok x -> `Success x.members
+ | Error x -> `ParseFailure x)
+ | #parsed_auth_error as res -> res
+ | _ -> `Unknown_error
let groups_list ?exclude_archived session =
api_request "groups.list"
- |> optionally_add "exclude_archived" @@ maybe string_of_bool exclude_archived
- |> query session
- >|= function
- | `Json_response d ->
- (match d |> groups_list_obj_of_yojson with
- | Ok x -> `Success x.groups
- | Error x -> `ParseFailure x)
- | #parsed_auth_error as res -> res
- | _ -> `Unknown_error
-
-type 'a listfn = session -> [`Success of 'a list | parsed_auth_error] Lwt.t
+ |> optionally_add "exclude_archived" @@ maybe string_of_bool exclude_archived
+ |> query session
+ >|= function
+ | `Json_response d -> (
+ match d |> groups_list_obj_of_yojson with
+ | Ok x -> `Success x.groups
+ | Error x -> `ParseFailure x)
+ | #parsed_auth_error as res -> res
+ | _ -> `Unknown_error
+
+type 'a listfn = session -> [ `Success of 'a list | parsed_auth_error ] Lwt.t
(* look up the id of query from results provided by the listfn *)
let lookupk session (listfn : 'a listfn) filterfn k =
@@ -810,34 +666,36 @@ let lookupk session (listfn : 'a listfn) filterfn k =
let id_of_channel session = function
| ChannelId id -> Lwt.return @@ `Found id
- | ChannelName name ->
- lookupk session conversations_list (fun (x:conversation_obj) -> x.name = name || x.name_normalized = name) @@ function
- | [] -> `Channel_not_found
- | [{id = s; _}] -> `Found s
- | _::_::_ -> failwith "Too many results from channel id lookup."
+ | ChannelName name -> (
+ lookupk session conversations_list (fun (x : conversation_obj) ->
+ x.name = name || x.name_normalized = name)
+ @@ function
+ | [] -> `Channel_not_found
+ | [ { id = s; _ } ] -> `Found s
+ | _ :: _ :: _ -> failwith "Too many results from channel id lookup.")
(* like id_of_channel but does not resolve names to ids *)
-let string_of_channel = function
- | ChannelId id -> id
- | ChannelName name -> name
+let string_of_channel = function ChannelId id -> id | ChannelName name -> name
let id_of_user session = function
| UserId id -> Lwt.return @@ `Found id
- | UserName name ->
- lookupk session users_list (fun (x:user_obj) -> x.name = name) @@ function
- | [] -> `User_not_found
- | [{id = UserId s; _}] -> `Found s
- | [_] -> failwith "Bad result from user id lookup."
- | _::_::_ -> failwith "Too many results from user id lookup."
+ | UserName name -> (
+ lookupk session users_list (fun (x : user_obj) -> x.name = name)
+ @@ function
+ | [] -> `User_not_found
+ | [ { id = UserId s; _ } ] -> `Found s
+ | [ _ ] -> failwith "Bad result from user id lookup."
+ | _ :: _ :: _ -> failwith "Too many results from user id lookup.")
let id_of_group session = function
| GroupId id -> Lwt.return @@ `Found id
- | GroupName name ->
- lookupk session groups_list (fun (x:group_obj) -> x.name = name) @@ function
- | [] -> `Channel_not_found
- | [{id = GroupId s; _}] -> `Found s
- | [_] -> failwith "Bad result from group id lookup."
- | _::_::_ -> failwith "Too many results from group id lookup."
+ | GroupName name -> (
+ lookupk session groups_list (fun (x : group_obj) -> x.name = name)
+ @@ function
+ | [] -> `Channel_not_found
+ | [ { id = GroupId s; _ } ] -> `Found s
+ | [ _ ] -> failwith "Bad result from group id lookup."
+ | _ :: _ :: _ -> failwith "Too many results from group id lookup.")
let id_of_chat session = function
| Channel c -> id_of_channel session c
@@ -849,27 +707,13 @@ let name_of_group = function
| GroupId _ -> failwith "Need to specify a name"
| GroupName name -> name
-let string_of_bool = function
- | true -> "1"
- | false -> "0"
-
-let string_of_criterion = function
- | Score -> "score"
- | Timestamp -> "timestamp"
-
-let string_of_direction = function
- | Ascending -> "asc"
- | Descending -> "desc"
-
-let string_of_presence = function
- | Auto -> "auto"
- | Away -> "away"
+let string_of_bool = function true -> "1" | false -> "0"
+let string_of_criterion = function Score -> "score" | Timestamp -> "timestamp"
+let string_of_direction = function Ascending -> "asc" | Descending -> "desc"
+let string_of_presence = function Auto -> "auto" | Away -> "away"
(* Slacko API helper methods *)
-let start_session ?(base_url=default_base_url) token = {
- base_url;
- token;
-}
+let start_session ?(base_url = default_base_url) token = { base_url; token }
let token_of_string token = start_session token
let message_of_string = identity
@@ -877,42 +721,36 @@ let message_of_string = identity
let utf8_codepoints text =
(* convert string to int list *)
let explode s =
- let rec exp i l =
- if i < 0 then l else exp (i - 1) (Char.code s.[i] :: l) in
- exp (String.length s - 1) [] in
+ let rec exp i l = if i < 0 then l else exp (i - 1) (Char.code s.[i] :: l) in
+ exp (String.length s - 1) []
+ in
(*
* http://www.daemonology.net/blog/2008-06-05-faster-utf8-strlen.html
* http://porg.es/blog/counting-characters-in-utf-8-strings-is-faster
*)
let rec codepoints = function
| [] -> 0
- | x::xs when x < 0x7F -> 1 + codepoints xs
- | x::_::xs when x >= 0xC0 && x <= 0xDF -> 1 + codepoints xs
- | x::_::_::xs when x >= 0xE0 && x <= 0xEF -> 1 + codepoints xs
- | x::_::_::_::xs when x >= 0xF0 && x <= 0xFF -> 1 + codepoints xs
+ | x :: xs when x < 0x7F -> 1 + codepoints xs
+ | x :: _ :: xs when x >= 0xC0 && x <= 0xDF -> 1 + codepoints xs
+ | x :: _ :: _ :: xs when x >= 0xE0 && x <= 0xEF -> 1 + codepoints xs
+ | x :: _ :: _ :: _ :: xs when x >= 0xF0 && x <= 0xFF -> 1 + codepoints xs
(* you are bad and should feel bad *)
- | x::_ -> failwith @@ Printf.sprintf "Invalid UTF-8 byte: 0x%X" x in
+ | x :: _ -> failwith @@ Printf.sprintf "Invalid UTF-8 byte: 0x%X" x
+ in
codepoints @@ explode text
-let topic_of_string text = if utf8_codepoints text <= 250 then Some text else None
+let topic_of_string text =
+ if utf8_codepoints text <= 250 then Some text else None
let topic_of_string_exn text =
- match topic_of_string text with
- | Some t -> t
- | None -> failwith "Too long"
-
-let channel_of_string s =
- if s.[0] = 'C' then ChannelId s else ChannelName s
+ match topic_of_string text with Some t -> t | None -> failwith "Too long"
-let user_of_string s =
- if s.[0] = 'U' then UserId s else UserName s
-
-let group_of_string s =
- if s.[0] = 'G' then GroupId s else GroupName s
+let channel_of_string s = if s.[0] = 'C' then ChannelId s else ChannelName s
+let user_of_string s = if s.[0] = 'U' then UserId s else UserName s
+let group_of_string s = if s.[0] = 'G' then GroupId s else GroupName s
(* TODO Create a im if im does not exist? *)
-let im_of_string s =
- if s.[0] = 'D' then s else failwith "Not an IM channel"
+let im_of_string s = if s.[0] = 'D' then s else failwith "Not an IM channel"
let translate_parsing_error = function
| Error a -> `ParseFailure a
@@ -920,110 +758,100 @@ let translate_parsing_error = function
(* Slack API begins here *)
-let api_test ?(base_url=default_base_url) ?foo ?error () =
- api_request "api.test"
- |> optionally_add "foo" foo
- |> optionally_add "error" error
- |> unauthed_query ~base_url
- >|= function
- | `Json_response x -> `Success x
- | #api_error as res -> res
- | _ -> `Unknown_error
+let api_test ?(base_url = default_base_url) ?foo ?error () =
+ api_request "api.test" |> optionally_add "foo" foo
+ |> optionally_add "error" error
+ |> unauthed_query ~base_url
+ >|= function
+ | `Json_response x -> `Success x
+ | #api_error as res -> res
+ | _ -> `Unknown_error
let auth_test session =
- api_request "auth.test"
- |> query session
- >|= function
- | `Json_response d -> d |> authed_obj_of_yojson |> translate_parsing_error
- | #parsed_auth_error as res -> res
- | _ -> `Unknown_error
+ api_request "auth.test" |> query session >|= function
+ | `Json_response d -> d |> authed_obj_of_yojson |> translate_parsing_error
+ | #parsed_auth_error as res -> res
+ | _ -> `Unknown_error
(* Operator for unwrapping channel_ids *)
-let (|->) m f =
+let ( |-> ) m f =
let* m = m in
match m with
- | `Channel_not_found
- | #parsed_auth_error as e -> Lwt.return e
+ | (`Channel_not_found | #parsed_auth_error) as e -> Lwt.return e
| `User_not_found -> Lwt.return `Unknown_error
| `Found v -> f v
(* Operator for unwrapping user_ids *)
-let (|+>) m f =
+let ( |+> ) m f =
let* m = m in
match m with
| `Channel_not_found -> Lwt.return `Unknown_error
- | `User_not_found
- | #parsed_auth_error as e -> Lwt.return e
+ | (`User_not_found | #parsed_auth_error) as e -> Lwt.return e
| `Found v -> f v
let channels_archive session channel =
id_of_channel session channel |-> fun channel_id ->
- api_request "channels.archive"
- |> definitely_add "channel" channel_id
- |> query session
- >|= function
- | `Json_response (`Assoc []) -> `Success
- | #parsed_auth_error
+ api_request "channels.archive"
+ |> definitely_add "channel" channel_id
+ |> query session
+ >|= function
+ | `Json_response (`Assoc []) -> `Success
+ | ( #parsed_auth_error
| #channel_error
| #bot_error
| #already_archived_error
- | `Cant_archive_general
- | `Last_restricted_channel
+ | `Cant_archive_general | `Last_restricted_channel
| #restriction_error
- | `User_is_restricted as res -> res
- | _ -> `Unknown_error
+ | `User_is_restricted ) as res ->
+ res
+ | _ -> `Unknown_error
let channels_create session name =
- api_request "channels.create"
- |> definitely_add "name" name
- |> query session
- >|= function
- | `Json_response (`Assoc [("channel", d)]) ->
- d |> channel_obj_of_yojson |> translate_parsing_error
- | #parsed_auth_error
- | #bot_error
- | #name_error
- | `User_is_restricted as res -> res
- | _ -> `Unknown_error
-
-let channels_history session
- ?latest ?oldest ?count ?inclusive channel =
+ api_request "channels.create" |> definitely_add "name" name |> query session
+ >|= function
+ | `Json_response (`Assoc [ ("channel", d) ]) ->
+ d |> channel_obj_of_yojson |> translate_parsing_error
+ | (#parsed_auth_error | #bot_error | #name_error | `User_is_restricted) as res
+ ->
+ res
+ | _ -> `Unknown_error
+
+let channels_history session ?latest ?oldest ?count ?inclusive channel =
id_of_channel session channel |-> fun channel_id ->
- api_request "channels.history"
- |> definitely_add "channel" channel_id
- |> optionally_add "latest" @@ maybe Timestamp.to_string latest
- |> optionally_add "oldest" @@ maybe Timestamp.to_string oldest
- |> optionally_add "count" @@ maybe string_of_int count
- |> optionally_add "inclusive" @@ maybe string_of_bool inclusive
- |> query session
- >|= function
- | `Json_response d -> d |> history_obj_of_yojson |> translate_parsing_error
- | #history_result as res -> res
- | _ -> `Unknown_error
+ api_request "channels.history"
+ |> definitely_add "channel" channel_id
+ |> optionally_add "latest" @@ maybe Timestamp.to_string latest
+ |> optionally_add "oldest" @@ maybe Timestamp.to_string oldest
+ |> optionally_add "count" @@ maybe string_of_int count
+ |> optionally_add "inclusive" @@ maybe string_of_bool inclusive
+ |> query session
+ >|= function
+ | `Json_response d -> d |> history_obj_of_yojson |> translate_parsing_error
+ | #history_result as res -> res
+ | _ -> `Unknown_error
let channels_info session channel =
id_of_channel session channel |-> fun channel_id ->
- api_request "channels.info"
- |> definitely_add "channel" channel_id
- |> query session
- >|= function
- | `Json_response (`Assoc [("channel", d)]) ->
- d |> channel_obj_of_yojson |> translate_parsing_error
- | #parsed_auth_error
- | #channel_error as res -> res
- | _ -> `Unknown_error
+ api_request "channels.info"
+ |> definitely_add "channel" channel_id
+ |> query session
+ >|= function
+ | `Json_response (`Assoc [ ("channel", d) ]) ->
+ d |> channel_obj_of_yojson |> translate_parsing_error
+ | (#parsed_auth_error | #channel_error) as res -> res
+ | _ -> `Unknown_error
let channels_invite session channel user =
id_of_channel session channel |-> fun channel_id ->
id_of_user session user |+> fun user_id ->
- api_request "channels.invite"
- |> definitely_add "channel" channel_id
- |> definitely_add "user" user_id
- |> query session
- >|= function
- | `Json_response (`Assoc [("channel", d)]) ->
- d |> channel_obj_of_yojson |> translate_parsing_error
- | #parsed_auth_error
+ api_request "channels.invite"
+ |> definitely_add "channel" channel_id
+ |> definitely_add "user" user_id
+ |> query session
+ >|= function
+ | `Json_response (`Assoc [ ("channel", d) ]) ->
+ d |> channel_obj_of_yojson |> translate_parsing_error
+ | ( #parsed_auth_error
| #channel_error
| #user_error
| #bot_error
@@ -1031,577 +859,551 @@ let channels_invite session channel user =
| #not_in_channel_error
| #already_in_channel_error
| #archive_error
- | `User_is_ultra_restricted as res -> res
- | _ -> `Unknown_error
+ | `User_is_ultra_restricted ) as res ->
+ res
+ | _ -> `Unknown_error
let channels_join session name =
api_request "channels.join"
- |> definitely_add "name" @@ string_of_channel name
- |> query session
- >|= function
- | `Json_response (`Assoc [("channel", d)]) ->
- d |> channel_obj_of_yojson |> translate_parsing_error
- | #parsed_auth_error
+ |> definitely_add "name" @@ string_of_channel name
+ |> query session
+ >|= function
+ | `Json_response (`Assoc [ ("channel", d) ]) ->
+ d |> channel_obj_of_yojson |> translate_parsing_error
+ | ( #parsed_auth_error
| #channel_error
| #name_error
| #archive_error
| #bot_error
- | `User_is_restricted as res -> res
- | _ -> `Unknown_error
+ | `User_is_restricted ) as res ->
+ res
+ | _ -> `Unknown_error
let channels_kick session channel user =
id_of_channel session channel |-> fun channel_id ->
id_of_user session user |+> fun user_id ->
- api_request "channels.kick"
- |> definitely_add "channel" channel_id
- |> definitely_add "user" user_id
- |> query session
- >|= function
- | `Json_response (`Assoc []) -> `Success
- | #parsed_auth_error
+ api_request "channels.kick"
+ |> definitely_add "channel" channel_id
+ |> definitely_add "user" user_id
+ |> query session
+ >|= function
+ | `Json_response (`Assoc []) -> `Success
+ | ( #parsed_auth_error
| #channel_error
| #user_error
| #bot_error
| #channel_kick_error
| #not_in_channel_error
| #restriction_error
- | `User_is_restricted as res -> res
- | _ -> `Unknown_error
+ | `User_is_restricted ) as res ->
+ res
+ | _ -> `Unknown_error
let channels_leave session channel =
id_of_channel session channel |-> fun channel_id ->
api_request "channels.leave"
- |> definitely_add "channel" channel_id
- |> query session
- >|= function
- | `Json_response d ->
+ |> definitely_add "channel" channel_id
+ |> query session
+ >|= function
+ | `Json_response d ->
d |> channel_leave_obj_of_yojson |> translate_parsing_error
- | #parsed_auth_error
+ | ( #parsed_auth_error
| #channel_error
| #bot_error
| #archive_error
| #leave_general_error
- | `User_is_restricted as res -> res
- | _ -> `Unknown_error
+ | `User_is_restricted ) as res ->
+ res
+ | _ -> `Unknown_error
let channels_mark session channel ts =
id_of_channel session channel |-> fun channel_id ->
api_request "channels.mark"
- |> definitely_add "channel" channel_id
- |> definitely_add "ts" @@ Timestamp.to_string ts
- |> query session
- >|= function
- | `Json_response (`Assoc []) -> `Success
- | #parsed_auth_error
+ |> definitely_add "channel" channel_id
+ |> definitely_add "ts" @@ Timestamp.to_string ts
+ |> query session
+ >|= function
+ | `Json_response (`Assoc []) -> `Success
+ | ( #parsed_auth_error
| #channel_error
| #archive_error
- | #not_in_channel_error as res -> res
- | _ -> `Unknown_error
+ | #not_in_channel_error ) as res ->
+ res
+ | _ -> `Unknown_error
let channels_rename session channel name =
id_of_channel session channel |-> fun channel_id ->
api_request "channels.rename"
- |> definitely_add "channel" channel_id
- |> definitely_add "name" name
- |> query session
- >|= function
- | `Json_response (`Assoc [("channel", d)]) ->
- d |> channel_rename_obj_of_yojson |> translate_parsing_error
- | #parsed_auth_error
+ |> definitely_add "channel" channel_id
+ |> definitely_add "name" name |> query session
+ >|= function
+ | `Json_response (`Assoc [ ("channel", d) ]) ->
+ d |> channel_rename_obj_of_yojson |> translate_parsing_error
+ | ( #parsed_auth_error
| #channel_error
| #bot_error
| #not_in_channel_error
| #name_error
| #invalid_name_error
- | `Not_authorized
- | `User_is_restricted as res -> res
- | _ -> `Unknown_error
+ | `Not_authorized | `User_is_restricted ) as res ->
+ res
+ | _ -> `Unknown_error
let channels_set_purpose session channel purpose =
id_of_channel session channel |-> fun channel_id ->
api_request "channels.setPurpose"
- |> definitely_add "channel" channel_id
- |> definitely_add "purpose" purpose
- |> query session
- >|= function
- | `Json_response (`Assoc [("purpose", `String d)]) ->
- `Success d
- | #topic_result as res -> res
- | _ -> `Unknown_error
+ |> definitely_add "channel" channel_id
+ |> definitely_add "purpose" purpose
+ |> query session
+ >|= function
+ | `Json_response (`Assoc [ ("purpose", `String d) ]) -> `Success d
+ | #topic_result as res -> res
+ | _ -> `Unknown_error
let channels_set_topic session channel topic =
id_of_channel session channel |-> fun channel_id ->
api_request "channels.setTopic"
- |> definitely_add "channel" channel_id
- |> definitely_add "topic" topic
- |> query session
- >|= function
- | `Json_response (`Assoc [("topic", `String d)]) ->
- `Success d
- | #topic_result as res -> res
- | _ -> `Unknown_error
+ |> definitely_add "channel" channel_id
+ |> definitely_add "topic" topic
+ |> query session
+ >|= function
+ | `Json_response (`Assoc [ ("topic", `String d) ]) -> `Success d
+ | #topic_result as res -> res
+ | _ -> `Unknown_error
let channels_unarchive session channel =
id_of_channel session channel |-> fun channel_id ->
api_request "channels.unarchive"
- |> definitely_add "channel" channel_id
- |> query session
- >|= function
- | `Json_response (`Assoc []) -> `Success
- | #parsed_auth_error
+ |> definitely_add "channel" channel_id
+ |> query session
+ >|= function
+ | `Json_response (`Assoc []) -> `Success
+ | ( #parsed_auth_error
| #channel_error
| #bot_error
- | `Not_archived
- | `User_is_restricted as res -> res
- | _ -> `Unknown_error
+ | `Not_archived | `User_is_restricted ) as res ->
+ res
+ | _ -> `Unknown_error
let chat_delete session ts chat =
id_of_chat session chat |-> fun chat_id ->
api_request "chat.delete"
- |> definitely_add "channel" chat_id
- |> definitely_add "ts" @@ Timestamp.to_string ts
- |> query session
- >|= function
- | `Json_response d -> d |> chat_obj_of_yojson |> translate_parsing_error
- | #parsed_auth_error
- | #channel_error
- | #message_error as res -> res
- | _ -> `Unknown_error
+ |> definitely_add "channel" chat_id
+ |> definitely_add "ts" @@ Timestamp.to_string ts
+ |> query session
+ >|= function
+ | `Json_response d -> d |> chat_obj_of_yojson |> translate_parsing_error
+ | (#parsed_auth_error | #channel_error | #message_error) as res -> res
+ | _ -> `Unknown_error
let jsonify_attachments attachments =
`List (List.map (fun a -> attachment_obj_to_yojson a) attachments)
|> Yojson.Safe.to_string
-let chat_post_message session chat
- ?as_user ?link_names ?mrkdwn
- ?reply_broadcast ?thread_ts ?unfurl_links ?unfurl_media
- ?username ?parse ?icon_url ?icon_emoji ?(attachments=[]) text =
+let chat_post_message session chat ?as_user ?link_names ?mrkdwn ?reply_broadcast
+ ?thread_ts ?unfurl_links ?unfurl_media ?username ?parse ?icon_url
+ ?icon_emoji ?(attachments = []) text =
id_of_chat session chat |-> fun chat_id ->
api_request "chat.postMessage"
- |> definitely_add "channel" chat_id
- |> definitely_add "text" text
- |> optionally_add "username" username
- |> optionally_add "parse" parse
- |> optionally_add "icon_url" icon_url
- |> optionally_add "icon_emoji" icon_emoji
- |> definitely_add "attachments" @@ jsonify_attachments attachments
- |> optionally_add "as_user" @@ maybe string_of_bool as_user
- |> optionally_add "link_names" @@ maybe string_of_bool link_names
- |> optionally_add "mrkdwn" @@ maybe string_of_bool mrkdwn
- |> optionally_add "reply_broadcast" @@ maybe string_of_bool reply_broadcast
- |> optionally_add "thread_ts" @@ maybe Timestamp.to_string thread_ts
- |> optionally_add "unfurl_links" @@ maybe string_of_bool unfurl_links
- |> optionally_add "unfurl_media" @@ maybe string_of_bool unfurl_media
- |> query session
- >|= function
- | `Json_response d ->
- d |> chat_obj_of_yojson |> translate_parsing_error
- | #parsed_auth_error
+ |> definitely_add "channel" chat_id
+ |> definitely_add "text" text
+ |> optionally_add "username" username
+ |> optionally_add "parse" parse
+ |> optionally_add "icon_url" icon_url
+ |> optionally_add "icon_emoji" icon_emoji
+ |> definitely_add "attachments" @@ jsonify_attachments attachments
+ |> optionally_add "as_user" @@ maybe string_of_bool as_user
+ |> optionally_add "link_names" @@ maybe string_of_bool link_names
+ |> optionally_add "mrkdwn" @@ maybe string_of_bool mrkdwn
+ |> optionally_add "reply_broadcast" @@ maybe string_of_bool reply_broadcast
+ |> optionally_add "thread_ts" @@ maybe Timestamp.to_string thread_ts
+ |> optionally_add "unfurl_links" @@ maybe string_of_bool unfurl_links
+ |> optionally_add "unfurl_media" @@ maybe string_of_bool unfurl_media
+ |> query session
+ >|= function
+ | `Json_response d -> d |> chat_obj_of_yojson |> translate_parsing_error
+ | ( #parsed_auth_error
| #channel_error
| #bot_error
| #archive_error
| #message_length_error
| #attachments_error
- | #rate_error as res -> res
- | _ -> `Unknown_error
+ | #rate_error ) as res ->
+ res
+ | _ -> `Unknown_error
let chat_update session ts chat ?as_user ?attachments ?link_names ?parse text =
id_of_chat session chat |-> fun chat_id ->
api_request "chat.update"
- |> definitely_add "channel" chat_id
- |> definitely_add "ts" @@ Timestamp.to_string ts
- |> definitely_add "text" text
- |> optionally_add "as_user" @@ maybe string_of_bool as_user
- |> optionally_add "attachments" @@ maybe jsonify_attachments attachments
- |> optionally_add "link_names" @@ maybe string_of_bool link_names
- |> optionally_add "parse" parse
- |> query session
- >|= function
- | `Json_response d ->
- d |> chat_obj_of_yojson |> translate_parsing_error
- | #parsed_auth_error
+ |> definitely_add "channel" chat_id
+ |> definitely_add "ts" @@ Timestamp.to_string ts
+ |> definitely_add "text" text
+ |> optionally_add "as_user" @@ maybe string_of_bool as_user
+ |> optionally_add "attachments" @@ maybe jsonify_attachments attachments
+ |> optionally_add "link_names" @@ maybe string_of_bool link_names
+ |> optionally_add "parse" parse
+ |> query session
+ >|= function
+ | `Json_response d -> d |> chat_obj_of_yojson |> translate_parsing_error
+ | ( #parsed_auth_error
| #channel_error
| #message_update_error
| #message_length_error
- | #attachments_error as res -> res
- | _ -> `Unknown_error
+ | #attachments_error ) as res ->
+ res
+ | _ -> `Unknown_error
let emoji_list session =
- api_request "emoji.list"
- |> query session
- >|= function
- | `Json_response d ->
- (match d |> emoji_list_obj_of_yojson with
+ api_request "emoji.list" |> query session >|= function
+ | `Json_response d -> (
+ match d |> emoji_list_obj_of_yojson with
| Ok x -> `Success x.emoji
| Error x -> `ParseFailure x)
- | #parsed_auth_error as res -> res
- | _ -> `Unknown_error
+ | #parsed_auth_error as res -> res
+ | _ -> `Unknown_error
let files_delete session file =
- api_request "files.delete"
- |> definitely_add "file" file
- |> query session
- >|= function
- | `Json_response (`Assoc []) -> `Success
- | #parsed_auth_error
- | #bot_error
- | `Cant_delete_file
- | #file_error as res -> res
- | _ -> `Unknown_error
+ api_request "files.delete" |> definitely_add "file" file |> query session
+ >|= function
+ | `Json_response (`Assoc []) -> `Success
+ | (#parsed_auth_error | #bot_error | `Cant_delete_file | #file_error) as res
+ ->
+ res
+ | _ -> `Unknown_error
let files_info session ?count ?page file =
- api_request "files.info"
- |> definitely_add "file" file
- |> optionally_add "count" @@ maybe string_of_int count
- |> optionally_add "page" @@ maybe string_of_int page
- |> query session
- >|= function
- | `Json_response d ->
- d |> files_info_obj_of_yojson |> translate_parsing_error
- | #parsed_auth_error
- | #bot_error
- | #file_error as res -> res
- | _ -> `Unknown_error
+ api_request "files.info" |> definitely_add "file" file
+ |> optionally_add "count" @@ maybe string_of_int count
+ |> optionally_add "page" @@ maybe string_of_int page
+ |> query session
+ >|= function
+ | `Json_response d -> d |> files_info_obj_of_yojson |> translate_parsing_error
+ | (#parsed_auth_error | #bot_error | #file_error) as res -> res
+ | _ -> `Unknown_error
let maybe_with_user session user f =
match user with
- | Some u -> id_of_user session u >>= (function
- | `Found id -> f @@ Some id
- | _ -> Lwt.return `User_not_found)
- | None -> f None
+ | Some u -> (
+ id_of_user session u >>= function
+ | `Found id -> f @@ Some id
+ | _ -> Lwt.return `User_not_found)
+ | None -> f None
let files_list ?user ?ts_from ?ts_to ?types ?count ?page session =
maybe_with_user session user @@ fun user_id ->
api_request "files.list"
- |> optionally_add "user" user_id
- |> optionally_add "ts_from" @@ maybe Timestamp.to_string ts_from
- |> optionally_add "ts_to" @@ maybe Timestamp.to_string ts_to
- |> optionally_add "types" types
- |> optionally_add "count" @@ maybe string_of_int count
- |> optionally_add "page" @@ maybe string_of_int page
- |> query session
- >|= function
- | `Json_response d ->
- d |> files_list_obj_of_yojson |> translate_parsing_error
- | #parsed_auth_error
- | #user_error
- | #bot_error
- | #unknown_type_error as res -> res
- | _ -> `Unknown_error
-
-let files_upload session
- ?filetype ?filename ?title ?initial_comment ?channels content =
+ |> optionally_add "user" user_id
+ |> optionally_add "ts_from" @@ maybe Timestamp.to_string ts_from
+ |> optionally_add "ts_to" @@ maybe Timestamp.to_string ts_to
+ |> optionally_add "types" types
+ |> optionally_add "count" @@ maybe string_of_int count
+ |> optionally_add "page" @@ maybe string_of_int page
+ |> query session
+ >|= function
+ | `Json_response d -> d |> files_list_obj_of_yojson |> translate_parsing_error
+ | (#parsed_auth_error | #user_error | #bot_error | #unknown_type_error) as res
+ ->
+ res
+ | _ -> `Unknown_error
+
+let files_upload session ?filetype ?filename ?title ?initial_comment ?channels
+ content =
api_request "files.upload"
- |> optionally_add "filetype" filetype
- |> optionally_add "filename" filename
- |> optionally_add "title" title
- |> optionally_add "initial_comment" initial_comment
- |> optionally_add "channels" channels
- |> query_post session content
- >|= function
- | `Json_response `Assoc [("file", d)] ->
- d |> file_obj_of_yojson |> translate_parsing_error
- | #parsed_auth_error
- | #bot_error as res -> res
- | _ -> `Unknown_error
+ |> optionally_add "filetype" filetype
+ |> optionally_add "filename" filename
+ |> optionally_add "title" title
+ |> optionally_add "initial_comment" initial_comment
+ |> optionally_add "channels" channels
+ |> query_post session content
+ >|= function
+ | `Json_response (`Assoc [ ("file", d) ]) ->
+ d |> file_obj_of_yojson |> translate_parsing_error
+ | (#parsed_auth_error | #bot_error) as res -> res
+ | _ -> `Unknown_error
let groups_archive session group =
id_of_group session group |-> fun group_id ->
api_request "groups.archive"
- |> definitely_add "channel" group_id
- |> query session
- >|= function
- | `Json_response (`Assoc []) -> `Success
- | #parsed_auth_error
+ |> definitely_add "channel" group_id
+ |> query session
+ >|= function
+ | `Json_response (`Assoc []) -> `Success
+ | ( #parsed_auth_error
| #channel_error
| #bot_error
| #already_archived_error
- | `Group_contains_others
- | `Last_restricted_channel
+ | `Group_contains_others | `Last_restricted_channel
| #restriction_error
- | `User_is_ultra_restricted as res -> res
- | _ -> `Unknown_error
+ | `User_is_ultra_restricted ) as res ->
+ res
+ | _ -> `Unknown_error
let groups_close session group =
id_of_group session group |-> fun group_id ->
api_request "groups.close"
- |> definitely_add "channel" group_id
- |> query session
- >|= function
- | `Json_response d ->
- d |> chat_close_obj_of_yojson |> translate_parsing_error
- | #parsed_auth_error
- | #channel_error as res -> res
- | _ -> `Unknown_error
+ |> definitely_add "channel" group_id
+ |> query session
+ >|= function
+ | `Json_response d -> d |> chat_close_obj_of_yojson |> translate_parsing_error
+ | (#parsed_auth_error | #channel_error) as res -> res
+ | _ -> `Unknown_error
let groups_create session name =
api_request "groups.create"
- |> definitely_add "name" @@ name_of_group name
- |> query session
- >|= function
- | `Json_response (`Assoc [("group", d)]) ->
+ |> definitely_add "name" @@ name_of_group name
+ |> query session
+ >|= function
+ | `Json_response (`Assoc [ ("group", d) ]) ->
d |> group_obj_of_yojson |> translate_parsing_error
- | #parsed_auth_error
+ | ( #parsed_auth_error
| #bot_error
| #name_error
| #restriction_error
- | `User_is_ultra_restricted as res -> res
- | _ -> `Unknown_error
+ | `User_is_ultra_restricted ) as res ->
+ res
+ | _ -> `Unknown_error
let groups_create_child session group =
id_of_group session group |-> fun group_id ->
api_request "groups.createChild"
- |> definitely_add "channel" group_id
- |> query session
- >|= function
- | `Json_response (`Assoc [("group", d)]) ->
+ |> definitely_add "channel" group_id
+ |> query session
+ >|= function
+ | `Json_response (`Assoc [ ("group", d) ]) ->
d |> group_obj_of_yojson |> translate_parsing_error
- | #parsed_auth_error
+ | ( #parsed_auth_error
| #channel_error
| #bot_error
| #already_archived_error
| #restriction_error
- | `User_is_ultra_restricted as res -> res
- | _ -> `Unknown_error
+ | `User_is_ultra_restricted ) as res ->
+ res
+ | _ -> `Unknown_error
let groups_history session ?latest ?oldest ?count ?inclusive group =
id_of_group session group |-> fun group_id ->
api_request "groups.history"
- |> definitely_add "channel" group_id
- |> optionally_add "latest" @@ maybe Timestamp.to_string latest
- |> optionally_add "oldest" @@ maybe Timestamp.to_string oldest
- |> optionally_add "count" @@ maybe string_of_int count
- |> optionally_add "inclusive" @@ maybe string_of_bool inclusive
- |> query session
- >|= function
- | `Json_response d -> d |> history_obj_of_yojson |> translate_parsing_error
- | #history_result as res -> res
- | _ -> `Unknown_error
+ |> definitely_add "channel" group_id
+ |> optionally_add "latest" @@ maybe Timestamp.to_string latest
+ |> optionally_add "oldest" @@ maybe Timestamp.to_string oldest
+ |> optionally_add "count" @@ maybe string_of_int count
+ |> optionally_add "inclusive" @@ maybe string_of_bool inclusive
+ |> query session
+ >|= function
+ | `Json_response d -> d |> history_obj_of_yojson |> translate_parsing_error
+ | #history_result as res -> res
+ | _ -> `Unknown_error
let groups_invite session group user =
id_of_group session group |-> fun group_id ->
id_of_user session user |+> fun user_id ->
api_request "groups.invite"
- |> definitely_add "channel" group_id
- |> definitely_add "user" user_id
- |> query session
- >|= function
- | `Json_response d ->
+ |> definitely_add "channel" group_id
+ |> definitely_add "user" user_id
+ |> query session
+ >|= function
+ | `Json_response d ->
d |> groups_invite_obj_of_yojson |> translate_parsing_error
- | #parsed_auth_error
+ | ( #parsed_auth_error
| #channel_error
| #user_error
| #bot_error
| #invite_error
| #archive_error
- | `User_is_ultra_restricted as res -> res
- | _ -> `Unknown_error
+ | `User_is_ultra_restricted ) as res ->
+ res
+ | _ -> `Unknown_error
let groups_kick session group user =
id_of_group session group |-> fun group_id ->
id_of_user session user |+> fun user_id ->
api_request "groups.kick"
- |> definitely_add "channel" group_id
- |> definitely_add "user" user_id
- |> query session
- >|= function
- | `Json_response (`Assoc []) -> `Success
- | #parsed_auth_error
+ |> definitely_add "channel" group_id
+ |> definitely_add "user" user_id
+ |> query session
+ >|= function
+ | `Json_response (`Assoc []) -> `Success
+ | ( #parsed_auth_error
| #channel_error
| #user_error
| #bot_error
| #kick_error
| #not_in_group_error
| #restriction_error
- | `User_is_restricted as res -> res
- | _ -> `Unknown_error
+ | `User_is_restricted ) as res ->
+ res
+ | _ -> `Unknown_error
let groups_leave session group =
id_of_group session group |-> fun group_id ->
api_request "groups.leave"
- |> definitely_add "channel" group_id
- |> query session
- >|= function
- | `Json_response (`Assoc []) -> `Success
- | #parsed_auth_error
+ |> definitely_add "channel" group_id
+ |> query session
+ >|= function
+ | `Json_response (`Assoc []) -> `Success
+ | ( #parsed_auth_error
| #channel_error
| #bot_error
| #archive_error
| #leave_last_channel_error
| #last_member_error
- | `User_is_ultra_restricted as res -> res
- | _ -> `Unknown_error
+ | `User_is_ultra_restricted ) as res ->
+ res
+ | _ -> `Unknown_error
let groups_mark session group ts =
id_of_group session group |-> fun group_id ->
api_request "groups.mark"
- |> definitely_add "channel" group_id
- |> definitely_add "ts" @@ Timestamp.to_string ts
- |> query session
- >|= function
- | `Json_response (`Assoc []) -> `Success
- | #parsed_auth_error
+ |> definitely_add "channel" group_id
+ |> definitely_add "ts" @@ Timestamp.to_string ts
+ |> query session
+ >|= function
+ | `Json_response (`Assoc []) -> `Success
+ | ( #parsed_auth_error
| #channel_error
| #archive_error
- | #not_in_channel_error as res -> res
- | _ -> `Unknown_error
+ | #not_in_channel_error ) as res ->
+ res
+ | _ -> `Unknown_error
let groups_open session group =
id_of_group session group |-> fun group_id ->
api_request "groups.open"
- |> definitely_add "channel" group_id
- |> query session
- >|= function
- | `Json_response d ->
+ |> definitely_add "channel" group_id
+ |> query session
+ >|= function
+ | `Json_response d ->
d |> groups_open_obj_of_yojson |> translate_parsing_error
- | #parsed_auth_error
- | #channel_error as res -> res
- | _ -> `Unknown_error
+ | (#parsed_auth_error | #channel_error) as res -> res
+ | _ -> `Unknown_error
let groups_rename session group name =
id_of_group session group |-> fun group_id ->
api_request "groups.rename"
- |> definitely_add "channel" group_id
- |> definitely_add "name" name
- |> query session
- >|= function
- | `Json_response (`Assoc [("channel", d)]) ->
+ |> definitely_add "channel" group_id
+ |> definitely_add "name" name |> query session
+ >|= function
+ | `Json_response (`Assoc [ ("channel", d) ]) ->
d |> groups_rename_obj_of_yojson |> translate_parsing_error
- | #parsed_auth_error
+ | ( #parsed_auth_error
| #channel_error
| #bot_error
| #name_error
| #invalid_name_error
- | `User_is_restricted as res -> res
- | _ -> `Unknown_error
+ | `User_is_restricted ) as res ->
+ res
+ | _ -> `Unknown_error
let groups_set_purpose session group purpose =
id_of_group session group |-> fun group_id ->
api_request "groups.setPurpose"
- |> definitely_add "channel" group_id
- |> definitely_add "purpose" purpose
- |> query session
- >|= function
- | `Json_response (`Assoc [("purpose", `String d)]) ->
- `Success d
- | #topic_result as res -> res
- | _ -> `Unknown_error
+ |> definitely_add "channel" group_id
+ |> definitely_add "purpose" purpose
+ |> query session
+ >|= function
+ | `Json_response (`Assoc [ ("purpose", `String d) ]) -> `Success d
+ | #topic_result as res -> res
+ | _ -> `Unknown_error
let groups_set_topic session group topic =
id_of_group session group |-> fun group_id ->
api_request "groups.setTopic"
- |> definitely_add "channel" group_id
- |> definitely_add "topic" topic
- |> query session
- >|= function
- | `Json_response (`Assoc [("topic", `String d)]) ->
- `Success d
- | #topic_result as res -> res
- | _ -> `Unknown_error
+ |> definitely_add "channel" group_id
+ |> definitely_add "topic" topic
+ |> query session
+ >|= function
+ | `Json_response (`Assoc [ ("topic", `String d) ]) -> `Success d
+ | #topic_result as res -> res
+ | _ -> `Unknown_error
let groups_unarchive session group =
id_of_group session group |-> fun group_id ->
api_request "groups.unarchive"
- |> definitely_add "channel" group_id
- |> query session
- >|= function
- | `Json_response (`Assoc []) -> `Success
- | #parsed_auth_error
+ |> definitely_add "channel" group_id
+ |> query session
+ >|= function
+ | `Json_response (`Assoc []) -> `Success
+ | ( #parsed_auth_error
| #channel_error
| #bot_error
- | `Not_archived
- | `User_is_restricted as res -> res
- | _ -> `Unknown_error
+ | `Not_archived | `User_is_restricted ) as res ->
+ res
+ | _ -> `Unknown_error
let im_close session channel =
- api_request "im.close"
- |> definitely_add "channel" channel
- |> query session
- >|= function
- | `Json_response d ->
- d |> chat_close_obj_of_yojson |> translate_parsing_error
- | #parsed_auth_error
- | #channel_error
- | `User_does_not_own_channel as res -> res
- | _ -> `Unknown_error
+ api_request "im.close" |> definitely_add "channel" channel |> query session
+ >|= function
+ | `Json_response d -> d |> chat_close_obj_of_yojson |> translate_parsing_error
+ | (#parsed_auth_error | #channel_error | `User_does_not_own_channel) as res ->
+ res
+ | _ -> `Unknown_error
let im_history session ?latest ?oldest ?count ?inclusive channel =
api_request "im.history"
- |> definitely_add "channel" channel
- |> optionally_add "latest" @@ maybe Timestamp.to_string latest
- |> optionally_add "oldest" @@ maybe Timestamp.to_string oldest
- |> optionally_add "count" @@ maybe string_of_int count
- |> optionally_add "inclusive" @@ maybe string_of_bool inclusive
- |> query session
- >|= function
- | `Json_response d -> d |> history_obj_of_yojson |> translate_parsing_error
- | #history_result as res -> res
- | _ -> `Unknown_error
+ |> definitely_add "channel" channel
+ |> optionally_add "latest" @@ maybe Timestamp.to_string latest
+ |> optionally_add "oldest" @@ maybe Timestamp.to_string oldest
+ |> optionally_add "count" @@ maybe string_of_int count
+ |> optionally_add "inclusive" @@ maybe string_of_bool inclusive
+ |> query session
+ >|= function
+ | `Json_response d -> d |> history_obj_of_yojson |> translate_parsing_error
+ | #history_result as res -> res
+ | _ -> `Unknown_error
let im_list session =
- api_request "im.list"
- |> query session
- >|= function
- | `Json_response d ->
- (match d |> im_list_obj_of_yojson with
- | Ok x -> `Success x.ims
- | Error x -> `ParseFailure x)
- | #parsed_auth_error as res -> res
- | _ -> `Unknown_error
+ api_request "im.list" |> query session >|= function
+ | `Json_response d -> (
+ match d |> im_list_obj_of_yojson with
+ | Ok x -> `Success x.ims
+ | Error x -> `ParseFailure x)
+ | #parsed_auth_error as res -> res
+ | _ -> `Unknown_error
let im_mark session channel ts =
api_request "im.mark"
- |> definitely_add "channel" channel
- |> definitely_add "ts" @@ Timestamp.to_string ts
- |> query session
- >|= function
- | `Json_response (`Assoc []) -> `Success
- | #parsed_auth_error
- | #channel_error
- | #not_in_channel_error as res -> res
- | _ -> `Unknown_error
+ |> definitely_add "channel" channel
+ |> definitely_add "ts" @@ Timestamp.to_string ts
+ |> query session
+ >|= function
+ | `Json_response (`Assoc []) -> `Success
+ | (#parsed_auth_error | #channel_error | #not_in_channel_error) as res -> res
+ | _ -> `Unknown_error
let im_open session user =
id_of_user session user |+> fun user_id ->
- api_request "im.open"
- |> definitely_add "user" user_id
- |> query session
- >|= function
- | `Json_response d ->
- d |> im_open_obj_of_yojson |> translate_parsing_error
- | #parsed_auth_error
- | #user_error
- | #user_visibility_error as res -> res
- | _ -> `Unknown_error
-
-let oauth_access ?(base_url=default_base_url) client_id client_secret ?redirect_url code =
+ api_request "im.open" |> definitely_add "user" user_id |> query session
+ >|= function
+ | `Json_response d -> d |> im_open_obj_of_yojson |> translate_parsing_error
+ | (#parsed_auth_error | #user_error | #user_visibility_error) as res -> res
+ | _ -> `Unknown_error
+
+let oauth_access ?(base_url = default_base_url) client_id client_secret
+ ?redirect_url code =
api_request "oauth.access"
- |> definitely_add "client_id" client_id
- |> definitely_add "client_secret" client_secret
- |> definitely_add "code" code
- |> optionally_add "redirect_url" redirect_url
- |> unauthed_query ~base_url
- >|= function
- | `Json_response d ->
- d |> oauth_obj_of_yojson |> translate_parsing_error
- | #oauth_error as res -> res
- | _ -> `Unknown_error
+ |> definitely_add "client_id" client_id
+ |> definitely_add "client_secret" client_secret
+ |> definitely_add "code" code
+ |> optionally_add "redirect_url" redirect_url
+ |> unauthed_query ~base_url
+ >|= function
+ | `Json_response d -> d |> oauth_obj_of_yojson |> translate_parsing_error
+ | #oauth_error as res -> res
+ | _ -> `Unknown_error
let search method' session ?sort ?sort_dir ?highlight ?count ?page query_ =
api_request method'
- |> definitely_add "query" @@ query_
- |> optionally_add "sort" @@ maybe string_of_criterion sort
- |> optionally_add "sort_dir" @@ maybe string_of_direction sort_dir
- |> optionally_add "highlight" @@ maybe string_of_bool highlight
- |> optionally_add "count" @@ maybe string_of_int count
- |> optionally_add "page" @@ maybe string_of_int page
- |> query session
- >|= function
- | `Json_response d ->
- d |> search_obj_of_yojson |> translate_parsing_error
- | #parsed_auth_error
- | #bot_error as res -> res
- | _ -> `Unknown_error
+ |> definitely_add "query" @@ query_
+ |> optionally_add "sort" @@ maybe string_of_criterion sort
+ |> optionally_add "sort_dir" @@ maybe string_of_direction sort_dir
+ |> optionally_add "highlight" @@ maybe string_of_bool highlight
+ |> optionally_add "count" @@ maybe string_of_int count
+ |> optionally_add "page" @@ maybe string_of_int page
+ |> query session
+ >|= function
+ | `Json_response d -> d |> search_obj_of_yojson |> translate_parsing_error
+ | (#parsed_auth_error | #bot_error) as res -> res
+ | _ -> `Unknown_error
let search_all = search "search.all"
let search_files = search "search.files"
@@ -1610,84 +1412,67 @@ let search_messages = search "search.messages"
let stars_list ?user ?count ?page session =
maybe_with_user session user @@ fun user_id ->
api_request "stars.list"
- |> optionally_add "user" user_id
- |> optionally_add "count" @@ maybe string_of_int count
- |> optionally_add "page" @@ maybe string_of_int page
- |> query session
- >|= function
- | `Json_response d ->
- d |> stars_list_obj_of_yojson |> translate_parsing_error
- | #parsed_auth_error
- | #bot_error
- | #user_error as res -> res
- | _ -> `Unknown_error
+ |> optionally_add "user" user_id
+ |> optionally_add "count" @@ maybe string_of_int count
+ |> optionally_add "page" @@ maybe string_of_int page
+ |> query session
+ >|= function
+ | `Json_response d -> d |> stars_list_obj_of_yojson |> translate_parsing_error
+ | (#parsed_auth_error | #bot_error | #user_error) as res -> res
+ | _ -> `Unknown_error
let team_access_logs ?count ?page session =
api_request "team.accessLogs"
- |> optionally_add "count" @@ maybe string_of_int count
- |> optionally_add "page" @@ maybe string_of_int page
- |> query session
- >|= function
- | `Json_response d ->
+ |> optionally_add "count" @@ maybe string_of_int count
+ |> optionally_add "page" @@ maybe string_of_int page
+ |> query session
+ >|= function
+ | `Json_response d ->
d |> team_access_log_obj_of_yojson |> translate_parsing_error
- | #parsed_auth_error
- | `Paid_only
- | #bot_error as res -> res
- | _ -> `Unknown_error
+ | (#parsed_auth_error | `Paid_only | #bot_error) as res -> res
+ | _ -> `Unknown_error
let team_info session =
- api_request "team.info"
- |> query session
- >|= function
- | `Json_response d ->
- d |> team_obj_of_yojson |> translate_parsing_error
- | #parsed_auth_error
- | #bot_error as res -> res
- | _ -> `Unknown_error
+ api_request "team.info" |> query session >|= function
+ | `Json_response d -> d |> team_obj_of_yojson |> translate_parsing_error
+ | (#parsed_auth_error | #bot_error) as res -> res
+ | _ -> `Unknown_error
let users_get_presence session user =
id_of_user session user |+> fun user_id ->
api_request "users.getPresence"
- |> definitely_add "user" user_id
- |> query session
- >|= function
- (* TODO parse more out of this *)
- | `Json_response (`Assoc [("presence", `String d)]) -> (match d with
+ |> definitely_add "user" user_id
+ |> query session
+ >|= function
+ (* TODO parse more out of this *)
+ | `Json_response (`Assoc [ ("presence", `String d) ]) -> (
+ match d with
| "active" -> `Success Auto
| "away" -> `Success Away
| _ -> `ParseFailure "Invalid presence")
- | #parsed_auth_error as res -> res
- | _ -> `Unknown_error
+ | #parsed_auth_error as res -> res
+ | _ -> `Unknown_error
let users_info session user =
- id_of_user session user
- |+> fun user_id ->
- api_request "users.info"
- |> definitely_add "user" user_id
- |> query session
- >|= function
- | `Json_response (`Assoc [("user", d)]) ->
- d |> user_obj_of_yojson |> translate_parsing_error
- | #parsed_auth_error
- | #user_error
- | #user_visibility_error as res -> res
- | _ -> `Unknown_error
+ id_of_user session user |+> fun user_id ->
+ api_request "users.info" |> definitely_add "user" user_id |> query session
+ >|= function
+ | `Json_response (`Assoc [ ("user", d) ]) ->
+ d |> user_obj_of_yojson |> translate_parsing_error
+ | (#parsed_auth_error | #user_error | #user_visibility_error) as res -> res
+ | _ -> `Unknown_error
let users_set_active session =
- api_request "users.setActive"
- |> query session
- >|= function
- | `Json_response (`Assoc []) -> `Success
- | #bot_error
- | #parsed_auth_error as res -> res
- | _ -> `Unknown_error
+ api_request "users.setActive" |> query session >|= function
+ | `Json_response (`Assoc []) -> `Success
+ | (#bot_error | #parsed_auth_error) as res -> res
+ | _ -> `Unknown_error
let users_set_presence session presence =
api_request "users.setPresence"
- |> definitely_add "presence" @@ string_of_presence presence
- |> query session
- >|= function
- | `Json_response (`Assoc []) -> `Success
- | #parsed_auth_error
- | #presence_error as res -> res
- | _ -> `Unknown_error
+ |> definitely_add "presence" @@ string_of_presence presence
+ |> query session
+ >|= function
+ | `Json_response (`Assoc []) -> `Success
+ | (#parsed_auth_error | #presence_error) as res -> res
+ | _ -> `Unknown_error
diff --git a/src/lib/timestamp.ml b/src/lib/timestamp.ml
index 2c60b13..9d439cf 100644
--- a/src/lib/timestamp.ml
+++ b/src/lib/timestamp.ml
@@ -20,12 +20,17 @@
let int64_pow b n =
let rec loop b n acc =
- if n = 0 then acc else
- loop Int64.(mul b b) (n lsr 1)
- (if n land 1 = 0 then acc else Int64.(mul b acc)) in
+ if n = 0 then acc
+ else
+ loop
+ Int64.(mul b b)
+ (n lsr 1)
+ (if n land 1 = 0 then acc else Int64.(mul b acc))
+ in
loop b n 1L
type t = Ptime.t
+
let pp = Ptime.pp_human ~frac_s:6 ()
let of_string x =
@@ -33,20 +38,20 @@ let of_string x =
let sec = Int64.of_string intlit in
let d = Int64.div sec 86_400L in
let ps = Int64.(mul (rem sec 86_400L) 1_000_000_000_000L) in
- (Int64.to_int d, ps) in
+ (Int64.to_int d, ps)
+ in
match
match String.split_on_char '.' x with
- | [_] ->
- Ptime.Span.of_d_ps (d_ps_of_intlit x)
- | [sec_lit; subsec_lit] ->
- let (d, ps_int) = d_ps_of_intlit sec_lit in
- let ps_frac =
- if String.length subsec_lit <= 12 then
- let scale = int64_pow 10L (12 - String.length subsec_lit) in
- Int64.mul scale (Int64.of_string subsec_lit)
- else
- Int64.of_string (String.sub subsec_lit 0 12) in
- Ptime.Span.of_d_ps (d, Int64.add ps_int ps_frac)
+ | [ _ ] -> Ptime.Span.of_d_ps (d_ps_of_intlit x)
+ | [ sec_lit; subsec_lit ] ->
+ let d, ps_int = d_ps_of_intlit sec_lit in
+ let ps_frac =
+ if String.length subsec_lit <= 12 then
+ let scale = int64_pow 10L (12 - String.length subsec_lit) in
+ Int64.mul scale (Int64.of_string subsec_lit)
+ else Int64.of_string (String.sub subsec_lit 0 12)
+ in
+ Ptime.Span.of_d_ps (d, Int64.add ps_int ps_frac)
| _ -> None
with
| exception Failure _ -> None
diff --git a/src/lib/timestamp.mli b/src/lib/timestamp.mli
index 583a55c..2ddc1ea 100644
--- a/src/lib/timestamp.mli
+++ b/src/lib/timestamp.mli
@@ -21,9 +21,6 @@
type t = Ptime.t
val to_string : t -> string
-
val of_yojson : Yojson.Safe.t -> (t, string) result
-
val to_yojson : t -> Yojson.Safe.t
-
val pp : Format.formatter -> t -> unit
diff --git a/test/abbrtypes.ml b/test/abbrtypes.ml
index 42c46ef..798f6a0 100644
--- a/test/abbrtypes.ml
+++ b/test/abbrtypes.ml
@@ -4,354 +4,353 @@
skip the problematic fields. *)
(* Wrap Yojson.Safe.t so we don't have to keep providing printers for it. *)
-type json = Yojson.Safe.t
-[@@deriving yojson]
+type json = Yojson.Safe.t [@@deriving yojson]
+
let pp_json fmt json = Format.pp_print_string fmt (Yojson.Safe.to_string json)
type abbr_authed_obj = {
- url: string;
- team: string;
- user: string;
- team_id: string;
- (* user_id: user; *)
-} [@@deriving make, show, yojson { strict = false }]
-
-let abbr_authed_obj (authed : Slacko.authed_obj) = {
- url = authed.Slacko.url;
- team = authed.Slacko.team;
- user = authed.Slacko.user;
- team_id = authed.Slacko.team_id;
+ url : string;
+ team : string;
+ user : string;
+ team_id : string; (* user_id: user; *)
}
+[@@deriving make, show, yojson { strict = false }]
+
+let abbr_authed_obj (authed : Slacko.authed_obj) =
+ {
+ url = authed.Slacko.url;
+ team = authed.Slacko.team;
+ user = authed.Slacko.user;
+ team_id = authed.Slacko.team_id;
+ }
type abbr_topic_obj = {
- value: string;
+ value : string;
(* creator: user; *)
- last_set: Timestamp.t;
-} [@@deriving show, yojson { strict = false }]
-
-let abbr_topic_obj (topic : Slacko.topic_obj) = {
- value = topic.Slacko.value;
- last_set = topic.Slacko.last_set;
+ last_set : Timestamp.t;
}
+[@@deriving show, yojson { strict = false }]
+
+let abbr_topic_obj (topic : Slacko.topic_obj) =
+ { value = topic.Slacko.value; last_set = topic.Slacko.last_set }
type abbr_channel_obj = {
(* id: channel; *)
- name: string;
- is_channel: bool;
- created: Timestamp.t;
+ name : string;
+ is_channel : bool;
+ created : Timestamp.t;
(* creator: user; *)
- is_archived: bool;
- is_general: bool;
- is_member: bool;
+ is_archived : bool;
+ is_general : bool;
+ is_member : bool;
(* members: user list; *)
- topic: abbr_topic_obj;
- purpose: abbr_topic_obj;
- last_read: Timestamp.t option [@default None];
- latest: json option [@default None];
- unread_count: int option [@default None];
- unread_count_display: int option [@default None];
- num_members: int option [@default None];
-} [@@deriving show, yojson { strict = false }]
-
-let abbr_channel_obj (chan : Slacko.channel_obj) = {
- name = chan.Slacko.name;
- is_channel = chan.Slacko.is_channel;
- created = chan.Slacko.created;
- is_archived = chan.Slacko.is_archived;
- is_general = chan.Slacko.is_general;
- is_member = chan.Slacko.is_member;
- topic = abbr_topic_obj chan.Slacko.topic;
- purpose = abbr_topic_obj chan.Slacko.purpose;
- last_read = chan.Slacko.last_read;
- latest = chan.Slacko.latest;
- unread_count = chan.Slacko.unread_count;
- unread_count_display = chan.Slacko.unread_count_display;
- num_members = chan.Slacko.num_members;
+ topic : abbr_topic_obj;
+ purpose : abbr_topic_obj;
+ last_read : Timestamp.t option; [@default None]
+ latest : json option; [@default None]
+ unread_count : int option; [@default None]
+ unread_count_display : int option; [@default None]
+ num_members : int option; [@default None]
}
-
-type abbr_channel_obj_list = abbr_channel_obj list
-[@@deriving show, yojson]
+[@@deriving show, yojson { strict = false }]
+
+let abbr_channel_obj (chan : Slacko.channel_obj) =
+ {
+ name = chan.Slacko.name;
+ is_channel = chan.Slacko.is_channel;
+ created = chan.Slacko.created;
+ is_archived = chan.Slacko.is_archived;
+ is_general = chan.Slacko.is_general;
+ is_member = chan.Slacko.is_member;
+ topic = abbr_topic_obj chan.Slacko.topic;
+ purpose = abbr_topic_obj chan.Slacko.purpose;
+ last_read = chan.Slacko.last_read;
+ latest = chan.Slacko.latest;
+ unread_count = chan.Slacko.unread_count;
+ unread_count_display = chan.Slacko.unread_count_display;
+ num_members = chan.Slacko.num_members;
+ }
+
+type abbr_channel_obj_list = abbr_channel_obj list [@@deriving show, yojson]
type abbr_conversation_obj = {
(* id: conversation; *)
- name: string;
- is_channel: bool;
- created: Timestamp.t;
+ name : string;
+ is_channel : bool;
+ created : Timestamp.t;
(* creator: user; *)
- is_archived: bool;
- is_general: bool;
- is_member: bool;
+ is_archived : bool;
+ is_general : bool;
+ is_member : bool;
(* members: user list; *)
- topic: abbr_topic_obj;
- purpose: abbr_topic_obj;
- last_read: Timestamp.t option [@default None];
+ topic : abbr_topic_obj;
+ purpose : abbr_topic_obj;
+ last_read : Timestamp.t option; [@default None]
(* latest: json option [@default None]; *)
- unread_count: int option [@default None];
- unread_count_display: int option [@default None];
- num_members: int option [@default None];
-} [@@deriving show, yojson { strict = false }]
-
-let abbr_conversation_obj (conversation : Slacko.conversation_obj) = {
- name = conversation.Slacko.name;
- is_channel = conversation.Slacko.is_channel;
- created = conversation.Slacko.created;
- is_archived = conversation.Slacko.is_archived;
- is_general = conversation.Slacko.is_general;
- is_member = conversation.Slacko.is_member;
- topic = abbr_topic_obj conversation.Slacko.topic;
- purpose = abbr_topic_obj conversation.Slacko.purpose;
- last_read = conversation.Slacko.last_read;
- unread_count = conversation.Slacko.unread_count;
- unread_count_display = conversation.Slacko.unread_count_display;
- num_members = conversation.Slacko.num_members;
+ unread_count : int option; [@default None]
+ unread_count_display : int option; [@default None]
+ num_members : int option; [@default None]
}
-
-type abbr_conversation_obj_list = abbr_conversation_obj list
-[@@deriving show]
-
-type abbr_conversation_list_obj = {
- channels: abbr_conversation_obj list
-} [@@deriving show, yojson { strict = false }]
+[@@deriving show, yojson { strict = false }]
+
+let abbr_conversation_obj (conversation : Slacko.conversation_obj) =
+ {
+ name = conversation.Slacko.name;
+ is_channel = conversation.Slacko.is_channel;
+ created = conversation.Slacko.created;
+ is_archived = conversation.Slacko.is_archived;
+ is_general = conversation.Slacko.is_general;
+ is_member = conversation.Slacko.is_member;
+ topic = abbr_topic_obj conversation.Slacko.topic;
+ purpose = abbr_topic_obj conversation.Slacko.purpose;
+ last_read = conversation.Slacko.last_read;
+ unread_count = conversation.Slacko.unread_count;
+ unread_count_display = conversation.Slacko.unread_count_display;
+ num_members = conversation.Slacko.num_members;
+ }
+
+type abbr_conversation_obj_list = abbr_conversation_obj list [@@deriving show]
+
+type abbr_conversation_list_obj = { channels : abbr_conversation_obj list }
+[@@deriving show, yojson { strict = false }]
let abbr_conversation_obj_list_of_yojson json =
match abbr_conversation_list_obj_of_yojson json with
| Ok obj -> Ok obj.channels
- | (Error _) as err -> err
+ | Error _ as err -> err
type abbr_message_obj = {
- type': string [@key "type"];
- ts: Timestamp.t;
+ type' : string; [@key "type"]
+ ts : Timestamp.t;
(* user: user; *)
- text: string option;
- is_starred: bool option [@default None];
-} [@@deriving show, yojson { strict = false }]
-
-let abbr_message_obj (message : Slacko.message_obj) = {
- type' = message.Slacko.type';
- ts = message.Slacko.ts;
- text = message.Slacko.text;
- is_starred = message.Slacko.is_starred;
+ text : string option;
+ is_starred : bool option; [@default None]
}
+[@@deriving show, yojson { strict = false }]
+
+let abbr_message_obj (message : Slacko.message_obj) =
+ {
+ type' = message.Slacko.type';
+ ts = message.Slacko.ts;
+ text = message.Slacko.text;
+ is_starred = message.Slacko.is_starred;
+ }
type abbr_history_obj = {
- latest: Timestamp.t option [@default None];
- messages: abbr_message_obj list;
- has_more: bool;
-} [@@deriving show, yojson { strict = false }]
-
-let abbr_history_obj (history : Slacko.history_obj) = {
- latest = history.Slacko.latest;
- messages = List.map abbr_message_obj history.Slacko.messages;
- has_more = history.Slacko.has_more;
+ latest : Timestamp.t option; [@default None]
+ messages : abbr_message_obj list;
+ has_more : bool;
}
+[@@deriving show, yojson { strict = false }]
+
+let abbr_history_obj (history : Slacko.history_obj) =
+ {
+ latest = history.Slacko.latest;
+ messages = List.map abbr_message_obj history.Slacko.messages;
+ has_more = history.Slacko.has_more;
+ }
type abbr_user_obj = {
(* id: user; *)
- name: string;
- deleted: bool;
- color: string option [@default None];
- real_name: string option [@default None];
- tz: string option [@default None];
- tz_label: string option [@default None];
- tz_offset: int [@default 0];
- profile: json;
- is_admin: bool [@default false];
- is_owner: bool [@default false];
- is_primary_owner: bool [@default false];
- is_restricted: bool [@default false];
- is_ultra_restricted: bool [@default false];
- is_bot: bool;
- has_files: bool [@default false];
-} [@@deriving show, yojson { strict = false } ]
-
-let abbr_user_obj (user : Slacko.user_obj) = {
- name = user.Slacko.name;
- deleted = user.Slacko.deleted;
- color = user.Slacko.color;
- real_name = user.Slacko.real_name;
- tz = user.Slacko.tz;
- tz_label = user.Slacko.tz_label;
- tz_offset = user.Slacko.tz_offset;
- profile = user.Slacko.profile;
- is_admin = user.Slacko.is_admin;
- is_owner = user.Slacko.is_owner;
- is_primary_owner = user.Slacko.is_primary_owner;
- is_restricted = user.Slacko.is_restricted;
- is_ultra_restricted = user.Slacko.is_ultra_restricted;
- is_bot = user.Slacko.is_bot;
- has_files = user.Slacko.has_files;
+ name : string;
+ deleted : bool;
+ color : string option; [@default None]
+ real_name : string option; [@default None]
+ tz : string option; [@default None]
+ tz_label : string option; [@default None]
+ tz_offset : int; [@default 0]
+ profile : json;
+ is_admin : bool; [@default false]
+ is_owner : bool; [@default false]
+ is_primary_owner : bool; [@default false]
+ is_restricted : bool; [@default false]
+ is_ultra_restricted : bool; [@default false]
+ is_bot : bool;
+ has_files : bool; [@default false]
}
-
-type abbr_users_list_obj = {
- members: abbr_user_obj list
-} [@@deriving of_yojson { strict = false }]
-
-type abbr_user_obj_list = abbr_user_obj list
-[@@deriving show]
+[@@deriving show, yojson { strict = false }]
+
+let abbr_user_obj (user : Slacko.user_obj) =
+ {
+ name = user.Slacko.name;
+ deleted = user.Slacko.deleted;
+ color = user.Slacko.color;
+ real_name = user.Slacko.real_name;
+ tz = user.Slacko.tz;
+ tz_label = user.Slacko.tz_label;
+ tz_offset = user.Slacko.tz_offset;
+ profile = user.Slacko.profile;
+ is_admin = user.Slacko.is_admin;
+ is_owner = user.Slacko.is_owner;
+ is_primary_owner = user.Slacko.is_primary_owner;
+ is_restricted = user.Slacko.is_restricted;
+ is_ultra_restricted = user.Slacko.is_ultra_restricted;
+ is_bot = user.Slacko.is_bot;
+ has_files = user.Slacko.has_files;
+ }
+
+type abbr_users_list_obj = { members : abbr_user_obj list }
+[@@deriving of_yojson { strict = false }]
+
+type abbr_user_obj_list = abbr_user_obj list [@@deriving show]
let abbr_user_obj_list_of_yojson json =
match abbr_users_list_obj_of_yojson json with
| Ok obj -> Ok obj.members
- | (Error _) as err -> err
-
+ | Error _ as err -> err
type abbr_file_obj = {
(* TODO file id type *)
- id: string;
- created: Timestamp.t;
+ id : string;
+ created : Timestamp.t;
(* deprecated *)
- timestamp: Timestamp.t;
-
- name: string option [@default None];
- title: string;
- mimetype: string;
- pretty_type: string;
- (* user: user; *)
-
- mode: string;
- editable: bool;
- is_external: bool;
- external_type: string;
-
- size: int;
-
+ timestamp : Timestamp.t;
+ name : string option; [@default None]
+ title : string;
+ mimetype : string;
+ pretty_type : string; (* user: user; *)
+ mode : string;
+ editable : bool;
+ is_external : bool;
+ external_type : string;
+ size : int;
(* These two are deprecated and appear to be gone. *)
(* url: string; *)
(* url_download: string; *)
- url_private: string;
- url_private_download: string;
-
- thumb_64: string option [@default None];
- thunb_80: string option [@default None];
- thumb_360: string option [@default None];
- thumb_360_gif: string option [@default None];
- thumb_360_w: int option [@default None];
- thumb_360_h: int option [@default None];
-
- permalink: string;
- edit_link: string option [@default None];
- preview: string option [@default None];
- preview_highlight: string option [@default None];
- lines: int option [@default None];
- lines_more: int option [@default None];
-
- is_public: bool;
+ url_private : string;
+ url_private_download : string;
+ thumb_64 : string option; [@default None]
+ thunb_80 : string option; [@default None]
+ thumb_360 : string option; [@default None]
+ thumb_360_gif : string option; [@default None]
+ thumb_360_w : int option; [@default None]
+ thumb_360_h : int option; [@default None]
+ permalink : string;
+ edit_link : string option; [@default None]
+ preview : string option; [@default None]
+ preview_highlight : string option; [@default None]
+ lines : int option; [@default None]
+ lines_more : int option; [@default None]
+ is_public : bool;
(*public_url_shared: ???;*)
(* channels: channel list; *)
(* groups: group list; *)
(* ims: conversation list; *)
- initial_comment: json option [@default None];
- num_stars: int option [@default None];
-} [@@deriving show, yojson { strict = false }]
-
-let abbr_file_obj (file : Slacko.file_obj) = {
- id = file.Slacko.id;
- created = file.Slacko.created;
- timestamp = file.Slacko.timestamp;
- name = file.Slacko.name;
- title = file.Slacko.title;
- mimetype = file.Slacko.mimetype;
- pretty_type = file.Slacko.pretty_type;
- mode = file.Slacko.mode;
- editable = file.Slacko.editable;
- is_external = file.Slacko.is_external;
- external_type = file.Slacko.external_type;
- size = file.Slacko.size;
- url_private = file.Slacko.url_private;
- url_private_download = file.Slacko.url_private_download;
- thumb_64 = file.Slacko.thumb_64;
- thunb_80 = file.Slacko.thunb_80;
- thumb_360 = file.Slacko.thumb_360;
- thumb_360_gif = file.Slacko.thumb_360_gif;
- thumb_360_w = file.Slacko.thumb_360_w;
- thumb_360_h = file.Slacko.thumb_360_h;
- permalink = file.Slacko.permalink;
- edit_link = file.Slacko.edit_link;
- preview = file.Slacko.preview;
- preview_highlight = file.Slacko.preview_highlight;
- lines = file.Slacko.lines;
- lines_more = file.Slacko.lines_more;
- is_public = file.Slacko.is_public;
- initial_comment = file.Slacko.initial_comment;
- num_stars = file.Slacko.num_stars;
-}
-
-type abbr_paging_obj = {
- count: int;
- total: int;
- page: int;
- pages: int;
-} [@@deriving show, yojson { strict = false }]
-
-let abbr_paging_obj (paging : Slacko.paging_obj) = {
- count = paging.Slacko.count;
- total = paging.Slacko.total;
- page = paging.Slacko.page;
- pages = paging.Slacko.pages;
+ initial_comment : json option; [@default None]
+ num_stars : int option; [@default None]
}
+[@@deriving show, yojson { strict = false }]
+
+let abbr_file_obj (file : Slacko.file_obj) =
+ {
+ id = file.Slacko.id;
+ created = file.Slacko.created;
+ timestamp = file.Slacko.timestamp;
+ name = file.Slacko.name;
+ title = file.Slacko.title;
+ mimetype = file.Slacko.mimetype;
+ pretty_type = file.Slacko.pretty_type;
+ mode = file.Slacko.mode;
+ editable = file.Slacko.editable;
+ is_external = file.Slacko.is_external;
+ external_type = file.Slacko.external_type;
+ size = file.Slacko.size;
+ url_private = file.Slacko.url_private;
+ url_private_download = file.Slacko.url_private_download;
+ thumb_64 = file.Slacko.thumb_64;
+ thunb_80 = file.Slacko.thunb_80;
+ thumb_360 = file.Slacko.thumb_360;
+ thumb_360_gif = file.Slacko.thumb_360_gif;
+ thumb_360_w = file.Slacko.thumb_360_w;
+ thumb_360_h = file.Slacko.thumb_360_h;
+ permalink = file.Slacko.permalink;
+ edit_link = file.Slacko.edit_link;
+ preview = file.Slacko.preview;
+ preview_highlight = file.Slacko.preview_highlight;
+ lines = file.Slacko.lines;
+ lines_more = file.Slacko.lines_more;
+ is_public = file.Slacko.is_public;
+ initial_comment = file.Slacko.initial_comment;
+ num_stars = file.Slacko.num_stars;
+ }
+
+type abbr_paging_obj = { count : int; total : int; page : int; pages : int }
+[@@deriving show, yojson { strict = false }]
+
+let abbr_paging_obj (paging : Slacko.paging_obj) =
+ {
+ count = paging.Slacko.count;
+ total = paging.Slacko.total;
+ page = paging.Slacko.page;
+ pages = paging.Slacko.pages;
+ }
type abbr_files_list_obj = {
- files: abbr_file_obj list;
- paging: abbr_paging_obj;
-} [@@deriving show, yojson { strict = false }]
-
-let abbr_files_list_obj (files : Slacko.files_list_obj) = {
- files = List.map abbr_file_obj files.Slacko.files;
- paging = abbr_paging_obj files.Slacko.paging;
+ files : abbr_file_obj list;
+ paging : abbr_paging_obj;
}
+[@@deriving show, yojson { strict = false }]
+
+let abbr_files_list_obj (files : Slacko.files_list_obj) =
+ {
+ files = List.map abbr_file_obj files.Slacko.files;
+ paging = abbr_paging_obj files.Slacko.paging;
+ }
type abbr_group_obj = {
(* id: group; *)
- name: string;
- is_group: bool;
- created: Timestamp.t;
+ name : string;
+ is_group : bool;
+ created : Timestamp.t;
(* creator: user; *)
- is_archived: bool;
+ is_archived : bool;
(* members: user list; *)
- topic: abbr_topic_obj;
- purpose: abbr_topic_obj;
- is_open: bool option [@default None];
- last_read: Timestamp.t option [@default None];
- unread_count: int option [@default None];
- unread_count_display: int option [@default None];
- latest: json option [@default None];
-} [@@deriving show, yojson { strict = false }]
-
-let abbr_group_obj (group : Slacko.group_obj) = {
- name = group.Slacko.name;
- is_group = group.Slacko.is_group;
- created = group.Slacko.created;
- is_archived = group.Slacko.is_archived;
- topic = abbr_topic_obj group.Slacko.topic;
- purpose = abbr_topic_obj group.Slacko.purpose;
- is_open = group.Slacko.is_open;
- last_read = group.Slacko.last_read;
- unread_count = group.Slacko.unread_count;
- unread_count_display = group.Slacko.unread_count_display;
- latest = group.Slacko.latest;
+ topic : abbr_topic_obj;
+ purpose : abbr_topic_obj;
+ is_open : bool option; [@default None]
+ last_read : Timestamp.t option; [@default None]
+ unread_count : int option; [@default None]
+ unread_count_display : int option; [@default None]
+ latest : json option; [@default None]
}
-
-type abbr_group_obj_list = abbr_group_obj list
-[@@deriving show, yojson]
+[@@deriving show, yojson { strict = false }]
+
+let abbr_group_obj (group : Slacko.group_obj) =
+ {
+ name = group.Slacko.name;
+ is_group = group.Slacko.is_group;
+ created = group.Slacko.created;
+ is_archived = group.Slacko.is_archived;
+ topic = abbr_topic_obj group.Slacko.topic;
+ purpose = abbr_topic_obj group.Slacko.purpose;
+ is_open = group.Slacko.is_open;
+ last_read = group.Slacko.last_read;
+ unread_count = group.Slacko.unread_count;
+ unread_count_display = group.Slacko.unread_count_display;
+ latest = group.Slacko.latest;
+ }
+
+type abbr_group_obj_list = abbr_group_obj list [@@deriving show, yojson]
type abbr_im_obj = {
- id: string;
- is_im: bool;
+ id : string;
+ is_im : bool;
(* user: user; *)
- created: Timestamp.t;
- is_user_deleted: bool;
- unread_count: int option [@default None];
- unread_count_display: int option [@default None];
-} [@@deriving show, yojson { strict = false }]
-
-let abbr_im_obj (im : Slacko.im_obj) = {
- id = im.Slacko.id;
- is_im = im.Slacko.is_im;
- created = im.Slacko.created;
- is_user_deleted = im.Slacko.is_user_deleted;
- unread_count = im.Slacko.unread_count;
- unread_count_display = im.Slacko.unread_count_display;
+ created : Timestamp.t;
+ is_user_deleted : bool;
+ unread_count : int option; [@default None]
+ unread_count_display : int option; [@default None]
}
-
-type abbr_im_obj_list = abbr_im_obj list
-[@@deriving show, yojson]
+[@@deriving show, yojson { strict = false }]
+
+let abbr_im_obj (im : Slacko.im_obj) =
+ {
+ id = im.Slacko.id;
+ is_im = im.Slacko.is_im;
+ created = im.Slacko.created;
+ is_user_deleted = im.Slacko.is_user_deleted;
+ unread_count = im.Slacko.unread_count;
+ unread_count_display = im.Slacko.unread_count_display;
+ }
+
+type abbr_im_obj_list = abbr_im_obj list [@@deriving show, yojson]
diff --git a/test/dune b/test/dune
index d346aec..6ff6157 100644
--- a/test/dune
+++ b/test/dune
@@ -1,15 +1,20 @@
(rule
- (targets timestamp.ml)
- (deps ../src/lib/timestamp.ml)
- (action (copy %{deps} %{targets})))
+ (targets timestamp.ml)
+ (deps ../src/lib/timestamp.ml)
+ (action
+ (copy %{deps} %{targets})))
(executable
- (name test_slacko)
- (libraries slacko ounit2)
- (preprocess (pps ppx_deriving_yojson ppx_deriving.std)))
+ (name test_slacko)
+ (libraries slacko ounit2)
+ (preprocess
+ (pps ppx_deriving_yojson ppx_deriving.std)))
(rule
- (alias runtest)
- (deps (:test (file test_slacko.exe))
- (glob_files *.json))
- (action (run %{test} -runner sequential)))
+ (alias runtest)
+ (deps
+ (:test
+ (file test_slacko.exe))
+ (glob_files *.json))
+ (action
+ (run %{test} -runner sequential)))
diff --git a/test/fake_slack.ml b/test/fake_slack.ml
index d48d952..12fa192 100644
--- a/test/fake_slack.ml
+++ b/test/fake_slack.ml
@@ -14,10 +14,9 @@ let ch_random = "C3TTWNCTA"
let ch_archivable = "C3XTJPLFL"
let ch_archived = "C3XTHDCTC"
let gr_seekrit = "G536YKXPE"
+
(* slacko doesn't have a lookup function for us, so we just use it directly. *)
let im_slackbot = "D3UMJU8VA"
-
-
let channels_json = Yojson.Safe.from_file "channels.json"
let conversations_json = Yojson.Safe.from_file "conversations.json"
let new_channel_json = Yojson.Safe.from_file "new_channel.json"
@@ -34,16 +33,11 @@ let json_fields = function
| `Assoc fields -> fields
| _ -> failwith "Can't parse test json."
-
let reply_json ok fields =
- let body =
- `Assoc (("ok", `Bool ok) :: fields)
- |> Yojson.Safe.to_string
- in
+ let body = `Assoc (("ok", `Bool ok) :: fields) |> Yojson.Safe.to_string in
Server.respond_string ~status:`OK ~body ()
let reply_ok fields = reply_json true fields
-
let reply_err err fields = reply_json false (("error", `String err) :: fields)
let get_token_opt req =
@@ -52,16 +46,13 @@ let get_token_opt req =
match header with
| Some x ->
let hlen = String.length "Bearer " in
- Some (String.sub x hlen @@ String.length x - hlen)
+ Some (String.sub x hlen @@ (String.length x - hlen))
| _ -> None
-let get_arg_opt arg req =
- Uri.get_query_param (Request.uri req) arg
+let get_arg_opt arg req = Uri.get_query_param (Request.uri req) arg
let get_arg_default arg default req =
- match get_arg_opt arg req with
- | Some x -> x
- | None -> default
+ match get_arg_opt arg req with Some x -> x | None -> default
let get_arg arg req =
match get_arg_opt arg req with
@@ -77,21 +68,21 @@ let check_auth f req body =
let bad_path req _body =
let path = req |> Request.uri |> Uri.path in
- reply_err "unknown_method" ["req_method", `String path]
+ reply_err "unknown_method" [ ("req_method", `String path) ]
let api_test req _body =
let args = req |> Request.uri |> Uri.query in
- let field_of_arg (k, v) = k, `String (List.hd v) in
- let fields = match args with
+ let field_of_arg (k, v) = (k, `String (List.hd v)) in
+ let fields =
+ match args with
| [] -> []
- | args -> ["args", `Assoc (List.map field_of_arg args)]
+ | args -> [ ("args", `Assoc (List.map field_of_arg args)) ]
in
match Uri.get_query_param (Request.uri req) "error" with
| None -> reply_ok fields
| Some err -> reply_err err fields
-let auth_test _req _body =
- reply_ok (json_fields authed_json)
+let auth_test _req _body = reply_ok (json_fields authed_json)
let channels_archive req _body =
match get_arg "channel" req with
@@ -103,7 +94,7 @@ let channels_archive req _body =
let channels_create req _body =
match get_arg "name" req with
| "general" | "random" -> reply_err "name_taken" []
- | "new_channel" | _ -> reply_ok ["channel", new_channel_json]
+ | "new_channel" | _ -> reply_ok [ ("channel", new_channel_json) ]
let channels_history req _body =
(* TODO: Check various filtering params. *)
@@ -113,7 +104,7 @@ let channels_history req _body =
let channels_list _req _body =
(* TODO: Check exclude_archived param. *)
- reply_ok ["channels", channels_json]
+ reply_ok [ ("channels", channels_json) ]
let files_list _req _body =
(* TODO: Check various filtering params. *)
@@ -121,7 +112,7 @@ let files_list _req _body =
let groups_list _req _body =
(* TODO: Check exclude_archived param. *)
- reply_ok ["groups", groups_json]
+ reply_ok [ ("groups", groups_json) ]
let groups_history req _body =
(* TODO: Check various filtering params. *)
@@ -129,8 +120,7 @@ let groups_history req _body =
| gr when gr = gr_seekrit -> reply_ok (json_fields seekrit_history_json)
| _ -> reply_err "channel_not_found" []
-let im_list _req _body =
- reply_ok ["ims", ims_json]
+let im_list _req _body = reply_ok [ ("ims", ims_json) ]
let im_history req _body =
(* TODO: Check various filtering params. *)
@@ -142,14 +132,14 @@ let users_list _req _body =
(* TODO: Check presence param. *)
reply_ok (json_fields users_json)
-let conversations_list _req _body =
- reply_ok (json_fields conversations_json)
+let conversations_list _req _body = reply_ok (json_fields conversations_json)
(* Dispatcher, etc. *)
-let server ?(port=7357) ~stop () =
+let server ?(port = 7357) ~stop () =
let callback _conn req body =
- let handler = match req |> Request.uri |> Uri.path with
+ let handler =
+ match req |> Request.uri |> Uri.path with
| "/api/api.test" -> api_test
| "/api/auth.test" -> check_auth auth_test
| "/api/channels.archive" -> check_auth channels_archive
diff --git a/test/files.json b/test/files.json
index ff6d1d4..c534a76 100644
--- a/test/files.json
+++ b/test/files.json
@@ -1,134 +1,134 @@
{
- "files": [
- {
- "channels": [],
- "comments_count": 0,
- "created": 1484993283,
- "display_as_bot": false,
- "editable": true,
- "external_type": "",
- "filetype": "space",
- "groups": [],
- "id": "F3UMJU94L",
- "ims": [],
- "is_external": false,
- "is_public": true,
- "mimetype": "text/plain",
- "mode": "space",
- "name": "Welcome_to_Slack",
- "permalink": "https://slackobot.slack.com/files/slackbot/F3UMJU94L/welcome_to_slack",
- "permalink_public": "https://slack-files.com/T3UMV2E2H-F3UMJU94L-37beaf2b00",
- "pretty_type": "Post",
- "preview": "Slack is here to help make your working life simpler, more pleasant, and more productive.
- Communicate transparently and instantly with your team members in channels, or privately in direct messages (DMs).
- Share and comment on files to get or give feedback on your projects.
- Receive notifications when a team member mentions your name in a channel, file comment, or DM.
- We keep track of which messages you've read and sync that information from the desktop to mobile and back again.
",
- "public_url_shared": false,
- "size": 1887,
- "state": "locked",
- "timestamp": 1484993283,
- "title": "Welcome to Slack!",
- "updated": 1484993283,
- "url_private": "https://files.slack.com/files-pri/T3UMV2E2H-F3UMJU94L/welcome_to_slack",
- "url_private_download": "https://files.slack.com/files-pri/T3UMV2E2H-F3UMJU94L/download/welcome_to_slack",
- "user": "USLACKBOT",
- "username": ""
- },
- {
- "channels": [],
- "comments_count": 0,
- "created": 1484993283,
- "display_as_bot": false,
- "editable": true,
- "external_type": "",
- "filetype": "space",
- "groups": [],
- "id": "F3TTWND40",
- "ims": [],
- "is_external": false,
- "is_public": true,
- "mimetype": "text/plain",
- "mode": "space",
- "name": "Channels_Keep_Your_Conversations_Organized",
- "permalink": "https://slackobot.slack.com/files/slackbot/F3TTWND40/channels_keep_your_conversations_organized",
- "permalink_public": "https://slack-files.com/T3UMV2E2H-F3TTWND40-e6670a0e44",
- "pretty_type": "Post",
- "preview": "Slack lets you join and create channels to keep your conversations organized and focused. Create channels for your functional teams, large projects, and topics of interest.
Find existing channels to join by clicking the more channels link below, or \"your channels\" above, your open channels. Or create a new one from those same menus (hint: you can also do the same thing by typing \"/open #name\" into the chat input).
When you join a channel, the entire message history is available to you. You can see who else is in that channel by clicking the members tab in the upper right corner of the message pane.
Remove a channel from your open channel list by typing /close in the chat input or from the channel's drop-down list. If you re-open the channel later, all the content will still be there, including messages exchanged when you didn't have the channel open.
You can view content from all your team's channels without joining the channel in the Message Archives. And when you search in Slack, the results show content from all channels, even if you are not in that one.
",
- "public_url_shared": false,
- "size": 1445,
- "state": "locked",
- "timestamp": 1484993283,
- "title": "Channels Keep Your Conversations Organized",
- "updated": 1484993283,
- "url_private": "https://files.slack.com/files-pri/T3UMV2E2H-F3TTWND40/channels_keep_your_conversations_organized",
- "url_private_download": "https://files.slack.com/files-pri/T3UMV2E2H-F3TTWND40/download/channels_keep_your_conversations_organized",
- "user": "USLACKBOT",
- "username": ""
- },
- {
- "channels": [],
- "comments_count": 0,
- "created": 1484993283,
- "display_as_bot": false,
- "editable": true,
- "external_type": "",
- "filetype": "space",
- "groups": [],
- "id": "F3V9V05SS",
- "ims": [],
- "is_external": false,
- "is_public": true,
- "mimetype": "text/plain",
- "mode": "space",
- "name": "Getting_Started_with_Posts",
- "permalink": "https://slackobot.slack.com/files/slackbot/F3V9V05SS/getting_started_with_posts",
- "permalink_public": "https://slack-files.com/T3UMV2E2H-F3V9V05SS-342113c685",
- "pretty_type": "Post",
- "preview": "Hi! Welcome to Posts, Slack's built-in document editor. Posts are a great way to share long-form content — like project plans, or documentation — directly in Slack. So how does one use Posts? Well, let's get right to it:
Creating a new Post
You can create a new Post from the + button in the Slack message input.
Formatting text
Text formatting in Posts was designed for simplicity, with just the right formatting options to help you get your thoughts organized.
",
- "public_url_shared": false,
- "size": 3294,
- "state": "locked",
- "timestamp": 1484993283,
- "title": "Getting Started with Posts",
- "updated": 1484993283,
- "url_private": "https://files.slack.com/files-pri/T3UMV2E2H-F3V9V05SS/getting_started_with_posts",
- "url_private_download": "https://files.slack.com/files-pri/T3UMV2E2H-F3V9V05SS/download/getting_started_with_posts",
- "user": "USLACKBOT",
- "username": ""
- },
- {
- "channels": [],
- "comments_count": 0,
- "created": 1484993283,
- "display_as_bot": false,
- "editable": true,
- "external_type": "",
- "filetype": "space",
- "groups": [],
- "id": "F3UMJU96G",
- "ims": [],
- "is_external": false,
- "is_public": true,
- "mimetype": "text/plain",
- "mode": "space",
- "name": "Uploading_Your_Files_Into_Slack",
- "permalink": "https://slackobot.slack.com/files/slackbot/F3UMJU96G/uploading_your_files_into_slack",
- "permalink_public": "https://slack-files.com/T3UMV2E2H-F3UMJU96G-3d27c638d7",
- "pretty_type": "Post",
- "preview": "Slack lets you add your files into a channel to get feedback from your team. Anyone who can see the document can add comments, and all those comments stay with the file. You can add your files into additional channels with the share command, and all comments and changes will flow back to those channels.
Just drag and drop the file into the Slack web app or click + File to the left of the chat input. You will be prompted to add a title, select a channel or individual, and will also have an option to make the file private for your eyes only. You can also add files from the mobile app using the + button in the Files tab.
Sharing a file with an individual in a direct message won't make that file public if it wasn't already; you can share private files on an individual basis and otherwise keep them private.
All the text in your file is indexed and searchable. Even PDFs.
",
- "public_url_shared": false,
- "size": 1141,
- "state": "locked",
- "timestamp": 1484993283,
- "title": "Uploading Your Files Into Slack",
- "updated": 1484993283,
- "url_private": "https://files.slack.com/files-pri/T3UMV2E2H-F3UMJU96G/uploading_your_files_into_slack",
- "url_private_download": "https://files.slack.com/files-pri/T3UMV2E2H-F3UMJU96G/download/uploading_your_files_into_slack",
- "user": "USLACKBOT",
- "username": ""
- }
- ],
- "paging": {
- "count": 100,
- "page": 1,
- "pages": 1,
- "total": 4
+ "files": [
+ {
+ "channels": [],
+ "comments_count": 0,
+ "created": 1484993283,
+ "display_as_bot": false,
+ "editable": true,
+ "external_type": "",
+ "filetype": "space",
+ "groups": [],
+ "id": "F3UMJU94L",
+ "ims": [],
+ "is_external": false,
+ "is_public": true,
+ "mimetype": "text/plain",
+ "mode": "space",
+ "name": "Welcome_to_Slack",
+ "permalink": "https://slackobot.slack.com/files/slackbot/F3UMJU94L/welcome_to_slack",
+ "permalink_public": "https://slack-files.com/T3UMV2E2H-F3UMJU94L-37beaf2b00",
+ "pretty_type": "Post",
+ "preview": "Slack is here to help make your working life simpler, more pleasant, and more productive.
- Communicate transparently and instantly with your team members in channels, or privately in direct messages (DMs).
- Share and comment on files to get or give feedback on your projects.
- Receive notifications when a team member mentions your name in a channel, file comment, or DM.
- We keep track of which messages you've read and sync that information from the desktop to mobile and back again.
",
+ "public_url_shared": false,
+ "size": 1887,
+ "state": "locked",
+ "timestamp": 1484993283,
+ "title": "Welcome to Slack!",
+ "updated": 1484993283,
+ "url_private": "https://files.slack.com/files-pri/T3UMV2E2H-F3UMJU94L/welcome_to_slack",
+ "url_private_download": "https://files.slack.com/files-pri/T3UMV2E2H-F3UMJU94L/download/welcome_to_slack",
+ "user": "USLACKBOT",
+ "username": ""
+ },
+ {
+ "channels": [],
+ "comments_count": 0,
+ "created": 1484993283,
+ "display_as_bot": false,
+ "editable": true,
+ "external_type": "",
+ "filetype": "space",
+ "groups": [],
+ "id": "F3TTWND40",
+ "ims": [],
+ "is_external": false,
+ "is_public": true,
+ "mimetype": "text/plain",
+ "mode": "space",
+ "name": "Channels_Keep_Your_Conversations_Organized",
+ "permalink": "https://slackobot.slack.com/files/slackbot/F3TTWND40/channels_keep_your_conversations_organized",
+ "permalink_public": "https://slack-files.com/T3UMV2E2H-F3TTWND40-e6670a0e44",
+ "pretty_type": "Post",
+ "preview": "Slack lets you join and create channels to keep your conversations organized and focused. Create channels for your functional teams, large projects, and topics of interest.
Find existing channels to join by clicking the more channels link below, or \"your channels\" above, your open channels. Or create a new one from those same menus (hint: you can also do the same thing by typing \"/open #name\" into the chat input).
When you join a channel, the entire message history is available to you. You can see who else is in that channel by clicking the members tab in the upper right corner of the message pane.
Remove a channel from your open channel list by typing /close in the chat input or from the channel's drop-down list. If you re-open the channel later, all the content will still be there, including messages exchanged when you didn't have the channel open.
You can view content from all your team's channels without joining the channel in the Message Archives. And when you search in Slack, the results show content from all channels, even if you are not in that one.
",
+ "public_url_shared": false,
+ "size": 1445,
+ "state": "locked",
+ "timestamp": 1484993283,
+ "title": "Channels Keep Your Conversations Organized",
+ "updated": 1484993283,
+ "url_private": "https://files.slack.com/files-pri/T3UMV2E2H-F3TTWND40/channels_keep_your_conversations_organized",
+ "url_private_download": "https://files.slack.com/files-pri/T3UMV2E2H-F3TTWND40/download/channels_keep_your_conversations_organized",
+ "user": "USLACKBOT",
+ "username": ""
+ },
+ {
+ "channels": [],
+ "comments_count": 0,
+ "created": 1484993283,
+ "display_as_bot": false,
+ "editable": true,
+ "external_type": "",
+ "filetype": "space",
+ "groups": [],
+ "id": "F3V9V05SS",
+ "ims": [],
+ "is_external": false,
+ "is_public": true,
+ "mimetype": "text/plain",
+ "mode": "space",
+ "name": "Getting_Started_with_Posts",
+ "permalink": "https://slackobot.slack.com/files/slackbot/F3V9V05SS/getting_started_with_posts",
+ "permalink_public": "https://slack-files.com/T3UMV2E2H-F3V9V05SS-342113c685",
+ "pretty_type": "Post",
+ "preview": "Hi! Welcome to Posts, Slack's built-in document editor. Posts are a great way to share long-form content — like project plans, or documentation — directly in Slack. So how does one use Posts? Well, let's get right to it:
Creating a new Post
You can create a new Post from the + button in the Slack message input.
Formatting text
Text formatting in Posts was designed for simplicity, with just the right formatting options to help you get your thoughts organized.
",
+ "public_url_shared": false,
+ "size": 3294,
+ "state": "locked",
+ "timestamp": 1484993283,
+ "title": "Getting Started with Posts",
+ "updated": 1484993283,
+ "url_private": "https://files.slack.com/files-pri/T3UMV2E2H-F3V9V05SS/getting_started_with_posts",
+ "url_private_download": "https://files.slack.com/files-pri/T3UMV2E2H-F3V9V05SS/download/getting_started_with_posts",
+ "user": "USLACKBOT",
+ "username": ""
+ },
+ {
+ "channels": [],
+ "comments_count": 0,
+ "created": 1484993283,
+ "display_as_bot": false,
+ "editable": true,
+ "external_type": "",
+ "filetype": "space",
+ "groups": [],
+ "id": "F3UMJU96G",
+ "ims": [],
+ "is_external": false,
+ "is_public": true,
+ "mimetype": "text/plain",
+ "mode": "space",
+ "name": "Uploading_Your_Files_Into_Slack",
+ "permalink": "https://slackobot.slack.com/files/slackbot/F3UMJU96G/uploading_your_files_into_slack",
+ "permalink_public": "https://slack-files.com/T3UMV2E2H-F3UMJU96G-3d27c638d7",
+ "pretty_type": "Post",
+ "preview": "Slack lets you add your files into a channel to get feedback from your team. Anyone who can see the document can add comments, and all those comments stay with the file. You can add your files into additional channels with the share command, and all comments and changes will flow back to those channels.
Just drag and drop the file into the Slack web app or click + File to the left of the chat input. You will be prompted to add a title, select a channel or individual, and will also have an option to make the file private for your eyes only. You can also add files from the mobile app using the + button in the Files tab.
Sharing a file with an individual in a direct message won't make that file public if it wasn't already; you can share private files on an individual basis and otherwise keep them private.
All the text in your file is indexed and searchable. Even PDFs.
",
+ "public_url_shared": false,
+ "size": 1141,
+ "state": "locked",
+ "timestamp": 1484993283,
+ "title": "Uploading Your Files Into Slack",
+ "updated": 1484993283,
+ "url_private": "https://files.slack.com/files-pri/T3UMV2E2H-F3UMJU96G/uploading_your_files_into_slack",
+ "url_private_download": "https://files.slack.com/files-pri/T3UMV2E2H-F3UMJU96G/download/uploading_your_files_into_slack",
+ "user": "USLACKBOT",
+ "username": ""
}
+ ],
+ "paging": {
+ "count": 100,
+ "page": 1,
+ "pages": 1,
+ "total": 4
+ }
}
diff --git a/test/groups.json b/test/groups.json
index ef854af..ba30f17 100644
--- a/test/groups.json
+++ b/test/groups.json
@@ -1,25 +1,25 @@
[
- {
- "created": 1492937682,
- "creator": "U3UMJU868",
- "id": "G536YKXPE",
- "is_archived": false,
- "is_group": true,
- "is_mpim": false,
- "members": [
- "U3UMJU868"
- ],
- "name": "seekrit",
- "name_normalized": "seekrit",
- "purpose": {
- "creator": "U3UMJU868",
- "last_set": 1492937683,
- "value": "Secret place for secretly secreting secrets"
- },
- "topic": {
- "creator": "",
- "last_set": 0,
- "value": ""
- }
+ {
+ "created": 1492937682,
+ "creator": "U3UMJU868",
+ "id": "G536YKXPE",
+ "is_archived": false,
+ "is_group": true,
+ "is_mpim": false,
+ "members": [
+ "U3UMJU868"
+ ],
+ "name": "seekrit",
+ "name_normalized": "seekrit",
+ "purpose": {
+ "creator": "U3UMJU868",
+ "last_set": 1492937683,
+ "value": "Secret place for secretly secreting secrets"
+ },
+ "topic": {
+ "creator": "",
+ "last_set": 0,
+ "value": ""
}
+ }
]
diff --git a/test/ims.json b/test/ims.json
index bb1122a..e05ca8a 100644
--- a/test/ims.json
+++ b/test/ims.json
@@ -1,18 +1,18 @@
[
- {
- "created": 1484993283,
- "id": "D3UMJU8VA",
- "is_im": true,
- "is_org_shared": false,
- "is_user_deleted": false,
- "user": "USLACKBOT"
- },
- {
- "created": 1484993283,
- "id": "D3TUQB1PB",
- "is_im": true,
- "is_org_shared": false,
- "is_user_deleted": false,
- "user": "U3UMJU868"
- }
+ {
+ "created": 1484993283,
+ "id": "D3UMJU8VA",
+ "is_im": true,
+ "is_org_shared": false,
+ "is_user_deleted": false,
+ "user": "USLACKBOT"
+ },
+ {
+ "created": 1484993283,
+ "id": "D3TUQB1PB",
+ "is_im": true,
+ "is_org_shared": false,
+ "is_user_deleted": false,
+ "user": "U3UMJU868"
+ }
]
diff --git a/test/random_history.json b/test/random_history.json
index ffa5447..2071c01 100644
--- a/test/random_history.json
+++ b/test/random_history.json
@@ -1,31 +1,31 @@
{
- "has_more": false,
- "messages": [
- {
- "subtype": "me_message",
- "text": "thinks you are.",
- "ts": "1492867855.021331",
- "type": "message",
- "user": "U3UMJU868"
- },
- {
- "text": "I am not a slackobot. Are you?",
- "ts": "1492867843.020464",
- "type": "message",
- "user": "U3UMJU868"
- },
- {
- "text": "hello",
- "ts": "1492867142.979902",
- "type": "message",
- "user": "U3UMJU868"
- },
- {
- "subtype": "channel_join",
- "text": "<@U3UMJU868|jerith> has joined the channel",
- "ts": "1484993283.000002",
- "type": "message",
- "user": "U3UMJU868"
- }
- ]
+ "has_more": false,
+ "messages": [
+ {
+ "subtype": "me_message",
+ "text": "thinks you are.",
+ "ts": "1492867855.021331",
+ "type": "message",
+ "user": "U3UMJU868"
+ },
+ {
+ "text": "I am not a slackobot. Are you?",
+ "ts": "1492867843.020464",
+ "type": "message",
+ "user": "U3UMJU868"
+ },
+ {
+ "text": "hello",
+ "ts": "1492867142.979902",
+ "type": "message",
+ "user": "U3UMJU868"
+ },
+ {
+ "subtype": "channel_join",
+ "text": "<@U3UMJU868|jerith> has joined the channel",
+ "ts": "1484993283.000002",
+ "type": "message",
+ "user": "U3UMJU868"
+ }
+ ]
}
diff --git a/test/seekrit_history.json b/test/seekrit_history.json
index db3854d..c4a8e80 100644
--- a/test/seekrit_history.json
+++ b/test/seekrit_history.json
@@ -1,45 +1,45 @@
{
- "has_more": false,
- "messages": [
- {
- "text": "Want an X.509 private key?",
- "ts": "1492937859.690158",
- "type": "message",
- "user": "U3UMJU868"
- },
- {
- "subtype": "me_message",
- "text": "lurks in a shadow.",
- "ts": "1492937718.682784",
- "type": "message",
- "user": "U3UMJU868"
- },
- {
- "text": "Hey you, pssst.",
- "ts": "1492937707.682226",
- "type": "message",
- "user": "U3UMJU868"
- },
- {
- "text": "Pssssst.",
- "ts": "1492937698.681778",
- "type": "message",
- "user": "U3UMJU868"
- },
- {
- "purpose": "Secret place for secretly secreting secrets",
- "subtype": "group_purpose",
- "text": "<@U3UMJU868|jerith> set the channel's purpose: Secret place for secretly secreting secrets",
- "ts": "1492937683.680879",
- "type": "message",
- "user": "U3UMJU868"
- },
- {
- "subtype": "group_join",
- "text": "<@U3UMJU868|jerith> has joined the group",
- "ts": "1492937682.680791",
- "type": "message",
- "user": "U3UMJU868"
- }
- ]
+ "has_more": false,
+ "messages": [
+ {
+ "text": "Want an X.509 private key?",
+ "ts": "1492937859.690158",
+ "type": "message",
+ "user": "U3UMJU868"
+ },
+ {
+ "subtype": "me_message",
+ "text": "lurks in a shadow.",
+ "ts": "1492937718.682784",
+ "type": "message",
+ "user": "U3UMJU868"
+ },
+ {
+ "text": "Hey you, pssst.",
+ "ts": "1492937707.682226",
+ "type": "message",
+ "user": "U3UMJU868"
+ },
+ {
+ "text": "Pssssst.",
+ "ts": "1492937698.681778",
+ "type": "message",
+ "user": "U3UMJU868"
+ },
+ {
+ "purpose": "Secret place for secretly secreting secrets",
+ "subtype": "group_purpose",
+ "text": "<@U3UMJU868|jerith> set the channel's purpose: Secret place for secretly secreting secrets",
+ "ts": "1492937683.680879",
+ "type": "message",
+ "user": "U3UMJU868"
+ },
+ {
+ "subtype": "group_join",
+ "text": "<@U3UMJU868|jerith> has joined the group",
+ "ts": "1492937682.680791",
+ "type": "message",
+ "user": "U3UMJU868"
+ }
+ ]
}
diff --git a/test/slackbot_history.json b/test/slackbot_history.json
index 281fedc..2201ed0 100644
--- a/test/slackbot_history.json
+++ b/test/slackbot_history.json
@@ -1,11 +1,11 @@
{
- "has_more": false,
- "messages": [
- {
- "text": "If you have any questions about *how to use Slack*, please ask me! I’ll do my best to help.",
- "ts": "1484993303.000002",
- "type": "message",
- "user": "USLACKBOT"
- }
- ]
+ "has_more": false,
+ "messages": [
+ {
+ "text": "If you have any questions about *how to use Slack*, please ask me! I’ll do my best to help.",
+ "ts": "1484993303.000002",
+ "type": "message",
+ "user": "USLACKBOT"
+ }
+ ]
}
diff --git a/test/test_slacko.ml b/test/test_slacko.ml
index 58d0854..2a7995d 100644
--- a/test/test_slacko.ml
+++ b/test/test_slacko.ml
@@ -1,10 +1,8 @@
open Lwt
open OUnit2
-
open Slounit
open Abbrtypes
-
let token =
try Sys.getenv "SLACKO_TEST_TOKEN" with Not_found -> Fake_slack.valid_token
@@ -12,18 +10,19 @@ let badtoken = "badtoken"
(* If we have a non-default token, assume we want to talk to real slack. If
not, use our local fake instead. *)
-let base_url = match token with
+let base_url =
+ match token with
| t when t = Fake_slack.valid_token -> Some "http://127.0.0.1:7357/api/"
- | _ ->
- print_endline ("NOTE: Because an API token has been provided, " ^
- "tests will run against the real slack API.");
- try
- (* We may want to talk to a proxy or a different fake slack. *)
- let base_url = Sys.getenv "SLACKO_TEST_BASE_URL" in
- print_endline @@ "NOTE: Overriding slack base URL to " ^ base_url;
- Some base_url;
- with Not_found -> None
-
+ | _ -> (
+ print_endline
+ ("NOTE: Because an API token has been provided, "
+ ^ "tests will run against the real slack API.");
+ try
+ (* We may want to talk to a proxy or a different fake slack. *)
+ let base_url = Sys.getenv "SLACKO_TEST_BASE_URL" in
+ print_endline @@ "NOTE: Overriding slack base URL to " ^ base_url;
+ Some base_url
+ with Not_found -> None)
let abbr_json abbr_of_yojson json =
match abbr_of_yojson json with
@@ -34,19 +33,16 @@ let get_success = function
| `Success obj -> obj
| _ -> assert_failure "Unexpected failure."
-
(* api_test *)
let test_api_test_nodata _tctx =
Slacko.api_test ?base_url () >|= get_success >|= fun json ->
- assert_equal ~printer:Yojson.Safe.to_string
- (`Assoc [])
- json
+ assert_equal ~printer:Yojson.Safe.to_string (`Assoc []) json
let test_api_test_foo _tctx =
Slacko.api_test ?base_url ~foo:"hello" () >|= get_success >|= fun json ->
assert_equal ~printer:Yojson.Safe.to_string
- (`Assoc ["args", `Assoc ["foo", `String "hello"]])
+ (`Assoc [ ("args", `Assoc [ ("foo", `String "hello") ]) ])
json
let test_api_test_err _tctx =
@@ -57,32 +53,34 @@ let test_api_test_err_foo _tctx =
Slacko.api_test ?base_url ~foo:"goodbye" ~error:"badthing" () >|= fun resp ->
assert_equal (`Unhandled_error "badthing") resp
-let api_test_tests = fake_slack_tests "api_test" [
- "test_nodata", test_api_test_nodata;
- "test_foo", test_api_test_foo;
- "test_err", test_api_test_err;
- "test_err_foo", test_api_test_err_foo;
-]
+let api_test_tests =
+ fake_slack_tests "api_test"
+ [
+ ("test_nodata", test_api_test_nodata);
+ ("test_foo", test_api_test_foo);
+ ("test_err", test_api_test_err);
+ ("test_err_foo", test_api_test_err_foo);
+ ]
(* auth_test *)
let test_auth_test_valid _tctx =
let session = Slacko.start_session ?base_url token in
- Slacko.auth_test session >|= get_success >|=
- abbr_authed_obj >|= fun authed ->
+ Slacko.auth_test session >|= get_success >|= abbr_authed_obj >|= fun authed ->
assert_equal ~printer:show_abbr_authed_obj
(abbr_json abbr_authed_obj_of_yojson Fake_slack.authed_json)
authed
let test_auth_test_invalid _tctx =
let session = Slacko.start_session ?base_url badtoken in
- Slacko.auth_test session >|= fun resp ->
- assert_equal `Invalid_auth resp
+ Slacko.auth_test session >|= fun resp -> assert_equal `Invalid_auth resp
-let auth_test_tests = fake_slack_tests "test_auth" [
- "test_valid", test_auth_test_valid;
- "test_invalid", test_auth_test_invalid;
-]
+let auth_test_tests =
+ fake_slack_tests "test_auth"
+ [
+ ("test_valid", test_auth_test_valid);
+ ("test_invalid", test_auth_test_invalid);
+ ]
(* channels_archive *)
@@ -116,13 +114,15 @@ let test_channels_archive_general _tctx =
Slacko.channels_archive session general >|= fun resp ->
assert_equal `Cant_archive_general resp
-let channels_archive_tests = fake_slack_tests "channels_archive" [
- "test_bad_auth", test_channels_archive_bad_auth;
- "test_existing", test_channels_archive_existing;
- "test_missing", test_channels_archive_missing;
- "test_archived", test_channels_archive_archived;
- "test_general", test_channels_archive_general;
-]
+let channels_archive_tests =
+ fake_slack_tests "channels_archive"
+ [
+ ("test_bad_auth", test_channels_archive_bad_auth);
+ ("test_existing", test_channels_archive_existing);
+ ("test_missing", test_channels_archive_missing);
+ ("test_archived", test_channels_archive_archived);
+ ("test_general", test_channels_archive_general);
+ ]
(* channels_create *)
@@ -133,8 +133,9 @@ let test_channels_create_bad_auth _tctx =
let test_channels_create_new _tctx =
let session = Slacko.start_session ?base_url token in
- Slacko.channels_create session "new_channel" >|= get_success >|=
- abbr_channel_obj >|= fun channel ->
+ Slacko.channels_create session "new_channel"
+ >|= get_success >|= abbr_channel_obj
+ >|= fun channel ->
assert_equal ~printer:show_abbr_channel_obj
(abbr_json abbr_channel_obj_of_yojson Fake_slack.new_channel_json)
channel
@@ -144,11 +145,13 @@ let test_channels_create_existing _tctx =
Slacko.channels_create session "general" >|= fun resp ->
assert_equal `Name_taken resp
-let channels_create_tests = fake_slack_tests "channels_create" [
- "test_bad_auth", test_channels_create_bad_auth;
- "test_new", test_channels_create_new;
- "test_existing", test_channels_create_existing;
-]
+let channels_create_tests =
+ fake_slack_tests "channels_create"
+ [
+ ("test_bad_auth", test_channels_create_bad_auth);
+ ("test_new", test_channels_create_new);
+ ("test_existing", test_channels_create_existing);
+ ]
(* channels_history *)
@@ -166,10 +169,12 @@ let test_channels_history_no_params _tctx =
(abbr_json abbr_history_obj_of_yojson Fake_slack.random_history_json)
(abbr_history_obj history)
-let channels_history_tests = fake_slack_tests "channels_history" [
- "test_bad_auth", test_channels_history_bad_auth;
- "test_no_params", test_channels_history_no_params;
-]
+let channels_history_tests =
+ fake_slack_tests "channels_history"
+ [
+ ("test_bad_auth", test_channels_history_bad_auth);
+ ("test_no_params", test_channels_history_no_params);
+ ]
(* channels_info *)
(* channels_invite *)
@@ -191,13 +196,16 @@ let test_conversations_list _tctx =
>|= List.map abbr_conversation_obj
>|= fun conversations ->
assert_equal ~printer:show_abbr_conversation_obj_list
- (abbr_json abbr_conversation_obj_list_of_yojson Fake_slack.conversations_json)
+ (abbr_json abbr_conversation_obj_list_of_yojson
+ Fake_slack.conversations_json)
conversations
-let conversations_list_tests = fake_slack_tests "conversations_list" [
- "test_bad_auth", test_conversations_list_bad_auth;
- "test", test_conversations_list;
-]
+let conversations_list_tests =
+ fake_slack_tests "conversations_list"
+ [
+ ("test_bad_auth", test_conversations_list_bad_auth);
+ ("test", test_conversations_list);
+ ]
(* channels_mark *)
(* channels_rename *)
@@ -215,21 +223,19 @@ let conversations_list_tests = fake_slack_tests "conversations_list" [
let test_files_list_bad_auth _tctx =
let session = Slacko.start_session ?base_url badtoken in
- Slacko.files_list session >|= fun resp ->
- assert_equal `Invalid_auth resp
+ Slacko.files_list session >|= fun resp -> assert_equal `Invalid_auth resp
let test_files_list _tctx =
let session = Slacko.start_session ?base_url token in
- Slacko.files_list session >|= get_success >|=
- abbr_files_list_obj >|= fun files ->
+ Slacko.files_list session >|= get_success >|= abbr_files_list_obj
+ >|= fun files ->
assert_equal ~printer:show_abbr_files_list_obj
(abbr_json abbr_files_list_obj_of_yojson Fake_slack.files_json)
files
-let files_list_tests = fake_slack_tests "files_list" [
- "test_bad_auth", test_files_list_bad_auth;
- "test", test_files_list;
-]
+let files_list_tests =
+ fake_slack_tests "files_list"
+ [ ("test_bad_auth", test_files_list_bad_auth); ("test", test_files_list) ]
(* files_upload *)
(* groups_archive *)
@@ -253,10 +259,12 @@ let test_groups_history_no_params _tctx =
(abbr_json abbr_history_obj_of_yojson Fake_slack.seekrit_history_json)
(abbr_history_obj history)
-let groups_history_tests = fake_slack_tests "groups_history" [
- "test_bad_auth", test_groups_history_bad_auth;
- "test_no_params", test_groups_history_no_params;
-]
+let groups_history_tests =
+ fake_slack_tests "groups_history"
+ [
+ ("test_bad_auth", test_groups_history_bad_auth);
+ ("test_no_params", test_groups_history_no_params);
+ ]
(* groups_invite *)
(* groups_kick *)
@@ -266,21 +274,19 @@ let groups_history_tests = fake_slack_tests "groups_history" [
let test_groups_list_bad_auth _tctx =
let session = Slacko.start_session ?base_url badtoken in
- Slacko.groups_list session >|= fun resp ->
- assert_equal `Invalid_auth resp
+ Slacko.groups_list session >|= fun resp -> assert_equal `Invalid_auth resp
let test_groups_list _tctx =
let session = Slacko.start_session ?base_url token in
- Slacko.groups_list session >|= get_success >|=
- List.map abbr_group_obj >|= fun groups ->
+ Slacko.groups_list session >|= get_success >|= List.map abbr_group_obj
+ >|= fun groups ->
assert_equal ~printer:show_abbr_group_obj_list
(abbr_json abbr_group_obj_list_of_yojson Fake_slack.groups_json)
groups
-let groups_list_tests = fake_slack_tests "groups_list" [
- "test_bad_auth", test_groups_list_bad_auth;
- "test", test_groups_list;
-]
+let groups_list_tests =
+ fake_slack_tests "groups_list"
+ [ ("test_bad_auth", test_groups_list_bad_auth); ("test", test_groups_list) ]
(* groups_mark *)
(* groups_open *)
@@ -306,30 +312,29 @@ let test_im_history_no_params _tctx =
(abbr_json abbr_history_obj_of_yojson Fake_slack.slackbot_history_json)
(abbr_history_obj history)
-let im_history_tests = fake_slack_tests "im_history" [
- "test_bad_auth", test_im_history_bad_auth;
- "test_no_params", test_im_history_no_params;
-]
+let im_history_tests =
+ fake_slack_tests "im_history"
+ [
+ ("test_bad_auth", test_im_history_bad_auth);
+ ("test_no_params", test_im_history_no_params);
+ ]
(* im_list *)
let test_im_list_bad_auth _tctx =
let session = Slacko.start_session ?base_url badtoken in
- Slacko.im_list session >|= fun resp ->
- assert_equal `Invalid_auth resp
+ Slacko.im_list session >|= fun resp -> assert_equal `Invalid_auth resp
let test_im_list _tctx =
let session = Slacko.start_session ?base_url token in
- Slacko.im_list session >|= get_success >|=
- List.map abbr_im_obj >|= fun ims ->
+ Slacko.im_list session >|= get_success >|= List.map abbr_im_obj >|= fun ims ->
assert_equal ~printer:show_abbr_im_obj_list
(abbr_json abbr_im_obj_list_of_yojson Fake_slack.ims_json)
ims
-let im_list_tests = fake_slack_tests "im_list" [
- "test_bad_auth", test_im_list_bad_auth;
- "test", test_im_list;
-]
+let im_list_tests =
+ fake_slack_tests "im_list"
+ [ ("test_bad_auth", test_im_list_bad_auth); ("test", test_im_list) ]
(* im_mark *)
(* im_open *)
@@ -347,85 +352,84 @@ let im_list_tests = fake_slack_tests "im_list" [
let test_users_list_bad_auth _tctx =
let session = Slacko.start_session ?base_url badtoken in
- Slacko.users_list session >|= fun resp ->
- assert_equal `Invalid_auth resp
+ Slacko.users_list session >|= fun resp -> assert_equal `Invalid_auth resp
let test_users_list _tctx =
let session = Slacko.start_session ?base_url token in
- Slacko.users_list session >|= get_success >|=
- List.map abbr_user_obj >|= fun users ->
+ Slacko.users_list session >|= get_success >|= List.map abbr_user_obj
+ >|= fun users ->
assert_equal ~printer:show_abbr_user_obj_list
(abbr_json abbr_user_obj_list_of_yojson Fake_slack.users_json)
users
-let users_list_tests = fake_slack_tests "users_list" [
- "test_bad_auth", test_users_list_bad_auth;
- "test", test_users_list;
-]
+let users_list_tests =
+ fake_slack_tests "users_list"
+ [ ("test_bad_auth", test_users_list_bad_auth); ("test", test_users_list) ]
(* users_set_active *)
(* users_set_presence *)
(* Gotta run them all! *)
-let suite = "tests" >::: [
- api_test_tests;
- auth_test_tests;
- channels_archive_tests;
- channels_create_tests;
- channels_history_tests;
- (* channels_info_tests; *)
- (* channels_invite_tests; *)
- (* channels_join_tests; *)
- (* channels_kick_tests; *)
- (* channels_leave_tests; *)
- conversations_list_tests;
- (* channels_mark_tests; *)
- (* channels_rename_tests; *)
- (* channels_set_purpose_tests; *)
- (* channels_set_topic_tests; *)
- (* channels_unarchive_tests; *)
- (* chat_delete_tests; *)
- (* chat_post_message_tests; *)
- (* chat_update_tests; *)
- (* emoji_list_tests; *)
- (* files_delete_tests; *)
- (* files_info_tests; *)
- files_list_tests;
- (* files_upload_tests; *)
- (* groups_archive_tests; *)
- (* groups_close_tests; *)
- (* groups_create_tests; *)
- (* groups_create_child_tests; *)
- groups_history_tests;
- (* groups_invite_tests; *)
- (* groups_kick_tests; *)
- (* groups_leave_tests; *)
- groups_list_tests;
- (* groups_mark_tests; *)
- (* groups_open_tests; *)
- (* groups_rename_tests; *)
- (* groups_set_purpose_tests; *)
- (* groups_set_topic_tests; *)
- (* groups_unarchive_tests; *)
- (* im_close_tests; *)
- im_history_tests;
- im_list_tests;
- (* im_mark_tests; *)
- (* im_open_tests; *)
- (* oauth_access_tests; *)
- (* search_all_tests; *)
- (* search_files_tests; *)
- (* search_messages_tests; *)
- (* stars_list_tests; *)
- (* team_access_logs_tests; *)
- (* team_info_tests; *)
- (* users_get_presence_tests; *)
- (* users_info_tests; *)
- users_list_tests;
- (* users_set_active_tests; *)
- (* users_set_presence_tests; *)
- ]
-
+let suite =
+ "tests"
+ >::: [
+ api_test_tests;
+ auth_test_tests;
+ channels_archive_tests;
+ channels_create_tests;
+ channels_history_tests;
+ (* channels_info_tests; *)
+ (* channels_invite_tests; *)
+ (* channels_join_tests; *)
+ (* channels_kick_tests; *)
+ (* channels_leave_tests; *)
+ conversations_list_tests;
+ (* channels_mark_tests; *)
+ (* channels_rename_tests; *)
+ (* channels_set_purpose_tests; *)
+ (* channels_set_topic_tests; *)
+ (* channels_unarchive_tests; *)
+ (* chat_delete_tests; *)
+ (* chat_post_message_tests; *)
+ (* chat_update_tests; *)
+ (* emoji_list_tests; *)
+ (* files_delete_tests; *)
+ (* files_info_tests; *)
+ files_list_tests;
+ (* files_upload_tests; *)
+ (* groups_archive_tests; *)
+ (* groups_close_tests; *)
+ (* groups_create_tests; *)
+ (* groups_create_child_tests; *)
+ groups_history_tests;
+ (* groups_invite_tests; *)
+ (* groups_kick_tests; *)
+ (* groups_leave_tests; *)
+ groups_list_tests;
+ (* groups_mark_tests; *)
+ (* groups_open_tests; *)
+ (* groups_rename_tests; *)
+ (* groups_set_purpose_tests; *)
+ (* groups_set_topic_tests; *)
+ (* groups_unarchive_tests; *)
+ (* im_close_tests; *)
+ im_history_tests;
+ im_list_tests;
+ (* im_mark_tests; *)
+ (* im_open_tests; *)
+ (* oauth_access_tests; *)
+ (* search_all_tests; *)
+ (* search_files_tests; *)
+ (* search_messages_tests; *)
+ (* stars_list_tests; *)
+ (* team_access_logs_tests; *)
+ (* team_info_tests; *)
+ (* users_get_presence_tests; *)
+ (* users_info_tests; *)
+ users_list_tests;
+ (* users_set_active_tests; *)
+ (* users_set_presence_tests; *)
+ ]
let () = run_test_tt_main suite
diff --git a/test/users.json b/test/users.json
index a53272d..da2dd8b 100644
--- a/test/users.json
+++ b/test/users.json
@@ -1,73 +1,73 @@
{
- "cache_ts": 1492880206,
- "members": [
- {
- "color": "9f69e7",
- "deleted": false,
- "has_2fa": false,
- "id": "U3UMJU868",
- "is_admin": true,
- "is_bot": false,
- "is_owner": true,
- "is_primary_owner": true,
- "is_restricted": false,
- "is_ultra_restricted": false,
- "name": "jerith",
- "profile": {
- "avatar_hash": "gb7842ee0df3",
- "email": "firxen@gmail.com",
- "first_name": "Jeremy",
- "image_192": "https://secure.gravatar.com/avatar/b7842ee0df3b024a6cad55bbe09c0d08.jpg?s=192&d=https%3A%2F%2Fa.slack-edge.com%2F7fa9%2Fimg%2Favatars%2Fava_0011-192.png",
- "image_24": "https://secure.gravatar.com/avatar/b7842ee0df3b024a6cad55bbe09c0d08.jpg?s=24&d=https%3A%2F%2Fa.slack-edge.com%2F66f9%2Fimg%2Favatars%2Fava_0011-24.png",
- "image_32": "https://secure.gravatar.com/avatar/b7842ee0df3b024a6cad55bbe09c0d08.jpg?s=32&d=https%3A%2F%2Fa.slack-edge.com%2F66f9%2Fimg%2Favatars%2Fava_0011-32.png",
- "image_48": "https://secure.gravatar.com/avatar/b7842ee0df3b024a6cad55bbe09c0d08.jpg?s=48&d=https%3A%2F%2Fa.slack-edge.com%2F66f9%2Fimg%2Favatars%2Fava_0011-48.png",
- "image_512": "https://secure.gravatar.com/avatar/b7842ee0df3b024a6cad55bbe09c0d08.jpg?s=512&d=https%3A%2F%2Fa.slack-edge.com%2F7fa9%2Fimg%2Favatars%2Fava_0011-512.png",
- "image_72": "https://secure.gravatar.com/avatar/b7842ee0df3b024a6cad55bbe09c0d08.jpg?s=72&d=https%3A%2F%2Fa.slack-edge.com%2F3654%2Fimg%2Favatars%2Fava_0011-72.png",
- "last_name": "Thurgood",
- "real_name": "Jeremy Thurgood",
- "real_name_normalized": "Jeremy Thurgood"
- },
- "real_name": "Jeremy Thurgood",
- "status": null,
- "team_id": "T3UMV2E2H",
- "tz": "Africa/Harare",
- "tz_label": "Central Africa Time",
- "tz_offset": 7200,
- "updated": 1484993283
- },
- {
- "color": "757575",
- "deleted": false,
- "id": "USLACKBOT",
- "is_admin": false,
- "is_bot": false,
- "is_owner": false,
- "is_primary_owner": false,
- "is_restricted": false,
- "is_ultra_restricted": false,
- "name": "slackbot",
- "profile": {
- "always_active": true,
- "avatar_hash": "sv1444671949",
- "fields": null,
- "first_name": "slackbot",
- "image_192": "https://a.slack-edge.com/66f9/img/slackbot_192.png",
- "image_24": "https://a.slack-edge.com/0180/img/slackbot_24.png",
- "image_32": "https://a.slack-edge.com/2fac/plugins/slackbot/assets/service_32.png",
- "image_48": "https://a.slack-edge.com/2fac/plugins/slackbot/assets/service_48.png",
- "image_512": "https://a.slack-edge.com/1801/img/slackbot_512.png",
- "image_72": "https://a.slack-edge.com/0180/img/slackbot_72.png",
- "last_name": "",
- "real_name": "slackbot",
- "real_name_normalized": "slackbot"
- },
- "real_name": "slackbot",
- "status": null,
- "team_id": "T3UMV2E2H",
- "tz": null,
- "tz_label": "Pacific Daylight Time",
- "tz_offset": -25200,
- "updated": 0
- }
- ]
+ "cache_ts": 1492880206,
+ "members": [
+ {
+ "color": "9f69e7",
+ "deleted": false,
+ "has_2fa": false,
+ "id": "U3UMJU868",
+ "is_admin": true,
+ "is_bot": false,
+ "is_owner": true,
+ "is_primary_owner": true,
+ "is_restricted": false,
+ "is_ultra_restricted": false,
+ "name": "jerith",
+ "profile": {
+ "avatar_hash": "gb7842ee0df3",
+ "email": "firxen@gmail.com",
+ "first_name": "Jeremy",
+ "image_192": "https://secure.gravatar.com/avatar/b7842ee0df3b024a6cad55bbe09c0d08.jpg?s=192&d=https%3A%2F%2Fa.slack-edge.com%2F7fa9%2Fimg%2Favatars%2Fava_0011-192.png",
+ "image_24": "https://secure.gravatar.com/avatar/b7842ee0df3b024a6cad55bbe09c0d08.jpg?s=24&d=https%3A%2F%2Fa.slack-edge.com%2F66f9%2Fimg%2Favatars%2Fava_0011-24.png",
+ "image_32": "https://secure.gravatar.com/avatar/b7842ee0df3b024a6cad55bbe09c0d08.jpg?s=32&d=https%3A%2F%2Fa.slack-edge.com%2F66f9%2Fimg%2Favatars%2Fava_0011-32.png",
+ "image_48": "https://secure.gravatar.com/avatar/b7842ee0df3b024a6cad55bbe09c0d08.jpg?s=48&d=https%3A%2F%2Fa.slack-edge.com%2F66f9%2Fimg%2Favatars%2Fava_0011-48.png",
+ "image_512": "https://secure.gravatar.com/avatar/b7842ee0df3b024a6cad55bbe09c0d08.jpg?s=512&d=https%3A%2F%2Fa.slack-edge.com%2F7fa9%2Fimg%2Favatars%2Fava_0011-512.png",
+ "image_72": "https://secure.gravatar.com/avatar/b7842ee0df3b024a6cad55bbe09c0d08.jpg?s=72&d=https%3A%2F%2Fa.slack-edge.com%2F3654%2Fimg%2Favatars%2Fava_0011-72.png",
+ "last_name": "Thurgood",
+ "real_name": "Jeremy Thurgood",
+ "real_name_normalized": "Jeremy Thurgood"
+ },
+ "real_name": "Jeremy Thurgood",
+ "status": null,
+ "team_id": "T3UMV2E2H",
+ "tz": "Africa/Harare",
+ "tz_label": "Central Africa Time",
+ "tz_offset": 7200,
+ "updated": 1484993283
+ },
+ {
+ "color": "757575",
+ "deleted": false,
+ "id": "USLACKBOT",
+ "is_admin": false,
+ "is_bot": false,
+ "is_owner": false,
+ "is_primary_owner": false,
+ "is_restricted": false,
+ "is_ultra_restricted": false,
+ "name": "slackbot",
+ "profile": {
+ "always_active": true,
+ "avatar_hash": "sv1444671949",
+ "fields": null,
+ "first_name": "slackbot",
+ "image_192": "https://a.slack-edge.com/66f9/img/slackbot_192.png",
+ "image_24": "https://a.slack-edge.com/0180/img/slackbot_24.png",
+ "image_32": "https://a.slack-edge.com/2fac/plugins/slackbot/assets/service_32.png",
+ "image_48": "https://a.slack-edge.com/2fac/plugins/slackbot/assets/service_48.png",
+ "image_512": "https://a.slack-edge.com/1801/img/slackbot_512.png",
+ "image_72": "https://a.slack-edge.com/0180/img/slackbot_72.png",
+ "last_name": "",
+ "real_name": "slackbot",
+ "real_name_normalized": "slackbot"
+ },
+ "real_name": "slackbot",
+ "status": null,
+ "team_id": "T3UMV2E2H",
+ "tz": null,
+ "tz_label": "Pacific Daylight Time",
+ "tz_offset": -25200,
+ "updated": 0
+ }
+ ]
}