/
team_management.R
236 lines (215 loc) · 7.32 KB
/
team_management.R
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
#' @title Team Management Functions
#' @description Manage teams that can be accessed
#' @param team character, team name
#' @param verbose logical, Print messages to console, Default: TRUE
#' @return NULL
#' @concept management
#' @rdname manage_team
#' @importFrom jsonlite validate
#' @export
activate_team <- function(team, verbose = TRUE) {
validate_team(team)
slack_setenv(team)
.slack$activeteam <- team
if (verbose) {
slack_setenv_msg(team)
}
}
#' @rdname manage_team
#' @param token character, a token returned from Slack
#' @export
add_team <- function(team, token) {
if(team %in% names(.slack$teams)){
.slack$teams[[team]] <- token
}else{
new_team <- list(token)
names(new_team) <- team
.slack$teams <- append(.slack$teams, new_team)
}
}
#' @rdname manage_team
#' @export
add_team_token <- function(team,
token,
verbose = TRUE) {
add_team(team = team,token = token)
.slack$file[[team]] <- ""
.slack$creds <- list(
api_token = token
)
if (verbose) {
message(sprintf(
"The following teams are loaded:\n %s",
paste0(get_teams(), collapse = ", ")
))
}
}
#' @title Interactive Team Management
#' @description Add a team interactively
#' @param scopes character, scopes to request. Must include "users:read",
#' "channels:read", "groups:read", "im:read", and "mpim:read" at minimum.
#' @details Launch a browser window to interactively grant slackteams permission
#' to act on your behalf on a Slack team.
#'
#' Two environment variables control this function:
#' \itemize{
#' \item{SLACK_CLIENT_ID: character, the client_id of a Slack app. If this
#' is not provided, the function will use the built-in R4DS Slack app.}
#' \item{SLACK_CLIENT_SECRET: character, the client_secret of a Slack app.
#' If this is not provided, the function will use the built-in R4DS Slack
#' app.}
#' }
#' @note This function does not currently work in an Rstudio Server setup. We
#' are exploring options to remedy this situation.
#' @return NULL
#' @concept management
#' @export
add_team_interactive <- function(scopes = load_scopes()) {
min_scopes <- c(
"users:read", "channels:read", "groups:read", "im:read", "mpim:read","team:read"
)
if (!all(min_scopes %in% scopes)) {
stop(
"At a minimum, scopes must include\n",
"users:read, channels:read, groups:read, im:read, and mpim:read"
)
}
slack_oauth_app <- httr::oauth_app(
appname = "slackteams",
key = Sys.getenv('SLACK_CLIENT_ID', unset = client_id),
secret = Sys.getenv('SLACK_CLIENT_SECRET', unset = client_secret)
)
full_token <- httr::oauth2.0_token(
endpoint = slack_oauth_endpoint,
app = slack_oauth_app,
query_authorize_extra = list(
user_scope = paste(
scopes,
collapse = ","
)
),
cache = FALSE,
use_oob = FALSE
)
if (full_token$credentials$ok) {
token <- full_token$credentials$authed_user$access_token
team <- full_token$credentials$team$name
message(sprintf('\nAdding %s to loaded teams ...',team))
add_team(team, token)
message(sprintf('\nActivating %s ...',team))
activate_team(team)
} else {
# I suspect httr might fail for us in this case, but it mirror the case that
# ISN'T handled in add_team_code, so I added the safety in case.
stop(
"Failed to authenticate. Slack returned: ",
full_token$credentials$error
)
}
}
#' @title Semi-Interactive Team Management
#' @description Add a team using a Slack response code.
#' @param code character, a code returned by the slack oauth2 v2 api.
#' @param redirect_uri character, the uri to which the user was redirected when
#' the code was generated.
#' @inheritParams activate_team
#' @details Launch a browser window to interactively grant slackteams permission
#' to act on your behalf on a Slack team.
#'
#' Two environment variables control this function:
#' \itemize{
#' \item{SLACK_CLIENT_ID: character, the client_id of a Slack app. If this
#' is not provided, the function will use the built-in R4DS Slack app.}
#' \item{SLACK_CLIENT_SECRET: character, the client_secret of a Slack app.
#' If this is not provided, the function will use the built-in R4DS Slack
#' app.}
#' }
#' @note This function does not currently work in an Rstudio Server setup. We
#' are exploring options to remedy this situation.
#' @return The token (invisibly)
#' @concept management
#' @export
add_team_code <- function(code,
redirect_uri = NULL,
verbose = TRUE) {
access_url <- paste0(
access_root,
"?code=", code,
query_piece(redirect_uri, "redirect_uri"),
query_piece(
Sys.getenv('SLACK_CLIENT_ID', unset = client_id), "client_id"
),
query_piece(
Sys.getenv('SLACK_CLIENT_SECRET', unset = client_secret), "client_secret"
)
)
response <- httr::GET(
access_url
)
httr::stop_for_status(response, "convert code to token")
full_token <- httr::content(response)
if (full_token$ok) {
token <- full_token$authed_user$access_token
team <- full_token$team$name
add_team_token(team, token, verbose)
invisible(token)
} else {
stop(
"Failed to validate code. Slack returned: ",
full_token$error
)
}
}
#' @rdname manage_team
#' @export
remove_team <- function(team) {
idx <- which(team %in% get_teams())
if (length(idx) > 0) {
.slack$teams <- .slack$teams[-idx]
}
}
slack_team_info <- function(team) {
.slack$users[[team]] <- clean_users(get_users_list())
.slack$channels[[team]] <- clean_channel(get_conversations_list(), team)
}
update_cache <- function() {
slack_team_info(get_active_team())
}
#' @title Slack Authorization URL
#' @description Generate an authorization URL to add a team manually. Useful,
#' for example, for authorizing a team in a Shiny app.
#' @param scopes character, scopes to request.
#' @param redirect_uri character, the uri to which the user should be directed
#' after authorization. If this is NULL (default), the user will be directed
#' to the default redirection set up in the Slack app.
#' @param team_code character, a team code to restrict the user to (in case they
#' have multiple Slack teams authorized in their browser).
#' @param state character, a code to send to your redirect_uri indicating a
#' state. It is recommended to use a non-human-readable format for this
#' string.
#' @return character, an authorization URL.
#' @details An environment variable controls this function:
#' \itemize{
#' \item{SLACK_CLIENT_ID: character, the client_id of a Slack app. If this
#' is not provided, the function will use the built-in R4DS Slack app.}
#' }
#' @export
#' @concept management
#' @examples
#' auth_url()
#' auth_url(redirect_uri = "http://127.0.0.1:4242")
#' auth_url(redirect_uri = "http://127.0.0.1:4242", team_code = "T6UC1DKJQ")
#' auth_url(state = "aabbCCddeeFF")
auth_url <- function(scopes = load_scopes(),
redirect_uri = NULL,
team_code = NULL,
state = NULL) {
paste0(
auth_root,
"?user_scope=", paste(scopes, collapse = ","),
"&client_id=", Sys.getenv('SLACK_CLIENT_ID', unset = client_id),
query_piece(redirect_uri, "redirect_uri"),
query_piece(team_code, "team"),
query_piece(state, "state")
)
}