Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ major version hasn't changed.
- `fiberplane-models`: Rename `OidLinkupLocation` to `SoftRedirect` (#224)
- `fiberplane-models`: New variants have been added to `PagerDutyReceiverWebhookError` (#226)
- `fiberplane-models`: Documentation now matches reality for PagerDuty and GitHub integrations (#227)
- `fiberplane-models`: New models added to communicate with the new version of Slack integration (#228)
- `fiberplane-api-client`: New endpoints (beta) for slack integration: `integrations_slack_install`, and
`integrations_slack_uninstall` (#228)

## [v1.0.0-beta.14] - 2024-03-07

Expand Down
21 changes: 21 additions & 0 deletions fiberplane-api-client/src/lib.rs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions fiberplane-models/src/integrations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ use strum_macros::{Display, EnumIter};
use thiserror::Error;
use typed_builder::TypedBuilder;

pub mod slack;

#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize, TypedBuilder)]
#[cfg_attr(
feature = "fp-bindgen",
Expand Down Expand Up @@ -42,6 +44,7 @@ pub struct PersonalIntegrationSummary {
#[serde(rename_all = "lowercase")]
pub enum PersonalIntegrationId {
GitHub,
Slack,
}

#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize, TypedBuilder)]
Expand Down
167 changes: 167 additions & 0 deletions fiberplane-models/src/integrations/slack.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
use crate::auth::AuthError;
use base64uuid::Base64Uuid;
#[cfg(feature = "fp-bindgen")]
use fp_bindgen::prelude::Serializable;
#[cfg(feature = "axum_06")]
use http_02::StatusCode;
#[cfg(feature = "axum_07")]
use http_1::StatusCode;
use serde::{Deserialize, Serialize};
use thiserror::Error;
use typed_builder::TypedBuilder;

/// Request to install the Slack integration and link
/// the user to a Slack user in a single workspace.
#[derive(Debug, Deserialize, Serialize, TypedBuilder)]
#[cfg_attr(
feature = "fp-bindgen",
derive(Serializable),
fp(rust_module = "fiberplane_models::integrations::slack")
)]
#[serde(rename_all = "camelCase")]
#[non_exhaustive]
pub struct SlackInstallRequest {
pub client_id: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub slack_team_id: Option<String>,
}

/// Internal communication model between the services.
#[derive(Debug, Deserialize, Serialize, TypedBuilder)]
#[cfg_attr(
feature = "fp-bindgen",
derive(Serializable),
fp(rust_module = "fiberplane_models::integrations::slack")
)]
#[serde(rename_all = "camelCase")]
#[non_exhaustive]
pub struct SlackOAuthStartRequest {
pub api_user_id: Base64Uuid,
pub api_access_token: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub slack_team_id: Option<String>,
}

#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq, Error)]
#[cfg_attr(
feature = "fp-bindgen",
derive(Serializable),
fp(rust_module = "fiberplane_models::integrations::slack")
)]
#[non_exhaustive]
#[serde(tag = "error", content = "details", rename_all = "snake_case")]
pub enum SlackInstallError {
// The String is meant to be the string representation
// of an api::service::ServiceError, as the token_create
// doesn’t use the new error types yet.
#[error("integration token creation: {0}")]
TokenCreation(String),

#[error("slack service: {0}")]
SlackService(String),

#[error("internal error")]
Internal,

/// Common auth errors.
#[error(transparent)]
Auth(AuthError),
}

impl SlackInstallError {
#[cfg(any(feature = "axum_06", feature = "axum_07"))]
fn status_code(&self) -> StatusCode {
match self {
SlackInstallError::TokenCreation(_) => StatusCode::INTERNAL_SERVER_ERROR,
SlackInstallError::SlackService(_) => StatusCode::INTERNAL_SERVER_ERROR,
SlackInstallError::Internal => StatusCode::INTERNAL_SERVER_ERROR,
SlackInstallError::Auth(err) => err.status_code(),
}
}
}

impl From<AuthError> for SlackInstallError {
fn from(value: AuthError) -> Self {
SlackInstallError::Auth(value)
}
}

#[cfg(feature = "axum_06")]
impl axum_06::response::IntoResponse for SlackInstallError {
fn into_response(self) -> axum_06::response::Response {
let body = serde_json::to_string(&self).expect("unable to serialize error body");
let status_code = self.status_code();

(status_code, body).into_response()
}
}

#[cfg(feature = "axum_07")]
impl axum_07::response::IntoResponse for SlackInstallError {
fn into_response(self) -> axum_07::response::Response {
let body = serde_json::to_string(&self).expect("unable to serialize error body");
let status_code = self.status_code();

(status_code, body).into_response()
}
}

#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq, Error)]
#[cfg_attr(
feature = "fp-bindgen",
derive(Serializable),
fp(rust_module = "fiberplane_models::integrations::slack")
)]
#[non_exhaustive]
#[serde(tag = "error", content = "details", rename_all = "snake_case")]
pub enum SlackUninstallError {
// The String is meant to be the string representation
// of an api::service::ServiceError, as the token_delete
// doesn’t use the new error types yet.
#[error("integration token deletion: {0}")]
TokenDeletion(String),

#[error("internal error")]
Internal,

/// Common auth errors.
#[error(transparent)]
Auth(AuthError),
}

impl SlackUninstallError {
#[cfg(any(feature = "axum_06", feature = "axum_07"))]
fn status_code(&self) -> StatusCode {
match self {
SlackUninstallError::TokenDeletion(_) => StatusCode::INTERNAL_SERVER_ERROR,
SlackUninstallError::Internal => StatusCode::INTERNAL_SERVER_ERROR,
SlackUninstallError::Auth(err) => err.status_code(),
}
}
}

impl From<AuthError> for SlackUninstallError {
fn from(value: AuthError) -> Self {
SlackUninstallError::Auth(value)
}
}

#[cfg(feature = "axum_06")]
impl axum_06::response::IntoResponse for SlackUninstallError {
fn into_response(self) -> axum_06::response::Response {
let body = serde_json::to_string(&self).expect("unable to serialize error body");
let status_code = self.status_code();

(status_code, body).into_response()
}
}

#[cfg(feature = "axum_07")]
impl axum_07::response::IntoResponse for SlackUninstallError {
fn into_response(self) -> axum_07::response::Response {
let body = serde_json::to_string(&self).expect("unable to serialize error body");
let status_code = self.status_code();

(status_code, body).into_response()
}
}
2 changes: 1 addition & 1 deletion fiberplane-openapi-rust-gen/src/routes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -595,7 +595,7 @@ fn generate_function_body_new_style(

write!(writer, ");")?;
} else {
write!(writer, " \"{endpoint};\"")?;
write!(writer, " \"{endpoint}\";")?;
}
writeln!(writer)?;

Expand Down
103 changes: 103 additions & 0 deletions schemas/openapi_v1.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2434,6 +2434,7 @@ components:
type: string
enum:
- "github"
- "slack"
status:
type: object
required:
Expand Down Expand Up @@ -2852,6 +2853,70 @@ components:
type: string
enum:
- "duplicate_resource"
slackInstallError:
oneOf:
- $ref: "#/components/schemas/internalServerError"
- $ref: "#/components/schemas/unauthorizedError"
- $ref: "#/components/schemas/unauthenticatedError"
- $ref: "#/components/schemas/slackServiceError"
- $ref: "#/components/schemas/tokenCreationError"
discriminator:
propertyName: error
mapping:
internal_server_error: "#/components/schemas/internalServerError"
unauthorized: "#/components/schemas/unauthorizedError"
unauthenticated: "#/components/schemas/unauthenticatedError"
slack_service: "#/components/schemas/slackServiceError"
token_creation: "#/components/schemas/tokenCreationError"
slackServiceError:
type: object
required:
- error
- details
properties:
error:
type: string
enum:
- "slack_service"
details:
type: string
tokenCreationError:
type: object
required:
- error
- details
properties:
error:
type: string
enum:
- "token_creation"
details:
type: string
slackUninstallError:
oneOf:
- $ref: "#/components/schemas/internalServerError"
- $ref: "#/components/schemas/unauthorizedError"
- $ref: "#/components/schemas/unauthenticatedError"
- $ref: "#/components/schemas/tokenDeletionError"
discriminator:
propertyName: error
mapping:
internal_server_error: "#/components/schemas/internalServerError"
unauthorized: "#/components/schemas/unauthorizedError"
unauthenticated: "#/components/schemas/unauthenticatedError"
token_deletion: "#/components/schemas/tokenDeletionError"
tokenDeletionError:
type: object
required:
- error
- details
properties:
error:
type: string
enum:
- "token_deletion"
details:
type: string
parameters:
sortDirection:
in: query
Expand Down Expand Up @@ -5554,3 +5619,41 @@ paths:
application/json:
schema:
$ref: "#/components/schemas/gitHubAppUninstallError"
/api/integrations/slack/install:
get:
operationId: integrations_slack_install
x-new-style: true
summary: Install Slack Integration for the current user
description: Install Slack Integration for the current user
tags:
- Integrations
responses:
"200":
description: OK
content:
application/json:
schema:
$ref: "#/components/schemas/softRedirect"
default:
description: Error
content:
application/json:
schema:
$ref: "#/components/schemas/slackInstallError"
/api/integrations/slack/uninstall:
get:
operationId: integrations_slack_uninstall
x-new-style: true
summary: Unlink Slack and Fiberplane accounts
description: Unlink Slack and Fiberplane accounts
tags:
- Integrations
responses:
"200":
description: OK
default:
description: Error
content:
application/json:
schema:
$ref: "#/components/schemas/slackUninstallError"
1 change: 1 addition & 0 deletions xtask/src/commands/generate_api_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ pub fn handle_generate_api_client_command() -> TaskResult {
"fiberplane_models::formatting::*".to_owned(),
"fiberplane_models::front_matter_schemas::*".to_owned(),
"fiberplane_models::integrations::*".to_owned(),
"fiberplane_models::integrations::slack::*".to_owned(),
"fiberplane_models::labels::*".to_owned(),
"fiberplane_models::names::*".to_owned(),
"fiberplane_models::notebooks::*".to_owned(),
Expand Down