-
Notifications
You must be signed in to change notification settings - Fork 348
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Initially disable Segment app webhooks (#1678)
- Loading branch information
1 parent
1f524da
commit b4196e7
Showing
19 changed files
with
404 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
--- | ||
"segment": patch | ||
--- | ||
|
||
After this change webhooks in Segment app will be by default disabled. After configuration is successfully set app will enable webhooks. |
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
mutation EnableWebhook($id: ID!) { | ||
webhookUpdate(id: $id, input: { isActive: true }) { | ||
errors { | ||
message | ||
code | ||
} | ||
} | ||
} |
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
query FetchAppWebhooks($id: ID!) { | ||
app(id: $id) { | ||
webhooks { | ||
id | ||
isActive | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
40 changes: 40 additions & 0 deletions
40
apps/segment/src/modules/configuration/webhooks-status/webhooks-status.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
import { Layout, SemanticChip, SkeletonLayout } from "@saleor/apps-ui"; | ||
import { Box, Text } from "@saleor/macaw-ui"; | ||
|
||
import { trpcClient } from "@/modules/trpc/trpc-client"; | ||
|
||
export const WebhookStatus = () => { | ||
const { data: config, isLoading } = trpcClient.configuration.getWebhookConfig.useQuery(); | ||
|
||
if (isLoading || !config) { | ||
return <SkeletonLayout.Section />; | ||
} | ||
|
||
return ( | ||
<Layout.AppSectionCard> | ||
<Box display={"flex"} gap={4} alignItems={"center"} justifyContent={"space-between"}> | ||
{config.areWebhooksActive ? ( | ||
<> | ||
<Text size={2} color="default2"> | ||
Webhooks are active. For more information about webhooks check Manage app button in | ||
header above. | ||
</Text> | ||
<SemanticChip marginLeft={"auto"} size="small" variant={"success"}> | ||
ACTIVE | ||
</SemanticChip> | ||
</> | ||
) : ( | ||
<> | ||
<Text size={2} color="default2"> | ||
Your webhooks were disabled. Most likely, your configuration is invalid. Check your | ||
credentials. | ||
</Text> | ||
<SemanticChip marginLeft={"auto"} size="small" variant={"error"}> | ||
DISABLED | ||
</SemanticChip> | ||
</> | ||
)} | ||
</Box> | ||
</Layout.AppSectionCard> | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
69 changes: 69 additions & 0 deletions
69
apps/segment/src/modules/webhooks/webhook-activity/webhook-activity-client.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
import { err, ok, Result } from "neverthrow"; | ||
import { Client } from "urql"; | ||
|
||
import { BaseError } from "@/errors"; | ||
import { EnableWebhookDocument, FetchAppWebhooksDocument } from "@/generated/graphql"; | ||
|
||
export interface IWebhooksActivityClient { | ||
fetchAppWebhooksInformation( | ||
id: string, | ||
): Promise<Result<{ id: string; isActive: boolean }[], unknown>>; | ||
enableSingleWebhook(id: string): Promise<Result<undefined, unknown>>; | ||
} | ||
|
||
export class WebhooksActivityClient implements IWebhooksActivityClient { | ||
private static FetchAppWebhooksError = BaseError.subclass("FetchAppWebhooksError"); | ||
|
||
constructor(private client: Pick<Client, "query" | "mutation">) {} | ||
|
||
async fetchAppWebhooksInformation(id: string) { | ||
const result = await this.client.query(FetchAppWebhooksDocument, { id }).toPromise(); | ||
|
||
if (result.error || !result.data) { | ||
return err( | ||
new WebhooksActivityClient.FetchAppWebhooksError("Error fetching app webhooks", { | ||
cause: result.error, | ||
}), | ||
); | ||
} | ||
|
||
if (!result.data?.app?.webhooks) { | ||
return err( | ||
new WebhooksActivityClient.FetchAppWebhooksError( | ||
"Couldnt find webhooks registered for app. Check if app is properly registered", | ||
), | ||
); | ||
} | ||
return ok(result.data.app.webhooks.map((w) => w)); | ||
} | ||
|
||
async enableSingleWebhook(id: string) { | ||
const result = await this.client | ||
.mutation(EnableWebhookDocument, { | ||
id, | ||
}) | ||
.toPromise(); | ||
|
||
if (result.error || !result.data) { | ||
return err( | ||
new WebhooksActivityClient.FetchAppWebhooksError("Error fetching app webhooks", { | ||
cause: result.error, | ||
}), | ||
); | ||
} | ||
|
||
const possibleErrors = result.data.webhookUpdate?.errors ?? []; | ||
|
||
if (possibleErrors.length > 0) { | ||
return err( | ||
new WebhooksActivityClient.FetchAppWebhooksError("Error enabling webhook", { | ||
errors: possibleErrors.map((error) => | ||
WebhooksActivityClient.FetchAppWebhooksError.normalize(error), | ||
), | ||
}), | ||
); | ||
} | ||
|
||
return ok(undefined); | ||
} | ||
} |
90 changes: 90 additions & 0 deletions
90
apps/segment/src/modules/webhooks/webhook-activity/webhook-activity-service.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
import { err, ok } from "neverthrow"; | ||
import { describe, expect, it, vi } from "vitest"; | ||
|
||
import { IWebhooksActivityClient } from "./webhook-activity-client"; | ||
import { WebhookActivityService } from "./webhook-activity-service"; | ||
|
||
describe("WebhookActivityService", () => { | ||
it("should enable app webhooks", async () => { | ||
const mockedClient: IWebhooksActivityClient = { | ||
enableSingleWebhook: vi.fn(() => Promise.resolve(ok(undefined))), | ||
fetchAppWebhooksInformation: vi.fn(() => | ||
Promise.resolve( | ||
ok([ | ||
{ id: "webhook-id-1", isActive: true }, | ||
{ id: "webhook-id-2", isActive: true }, | ||
]), | ||
), | ||
), | ||
}; | ||
|
||
const service = new WebhookActivityService("app-id", mockedClient); | ||
|
||
await service.enableAppWebhooks(); | ||
|
||
expect(mockedClient.fetchAppWebhooksInformation).toHaveBeenCalled(); | ||
expect(mockedClient.enableSingleWebhook).toHaveBeenCalledTimes(2); | ||
expect(mockedClient.enableSingleWebhook).toHaveBeenNthCalledWith(1, "webhook-id-1"); | ||
expect(mockedClient.enableSingleWebhook).toHaveBeenNthCalledWith(2, "webhook-id-2"); | ||
}); | ||
|
||
it("should get information if webhooks are active", async () => { | ||
const mockedClient: IWebhooksActivityClient = { | ||
enableSingleWebhook: vi.fn(() => Promise.resolve(ok(undefined))), | ||
fetchAppWebhooksInformation: vi.fn(() => | ||
Promise.resolve( | ||
ok([ | ||
{ id: "webhook-id-1", isActive: true }, | ||
{ id: "webhook-id-2", isActive: false }, | ||
]), | ||
), | ||
), | ||
}; | ||
|
||
const service = new WebhookActivityService("app-id", mockedClient); | ||
|
||
const response = await service.getWebhooksIsActive(); | ||
|
||
expect(response._unsafeUnwrap()).toStrictEqual([true, false]); | ||
}); | ||
|
||
it("should throw error when fetching webhooks information fails", async () => { | ||
const mockedClient: IWebhooksActivityClient = { | ||
enableSingleWebhook: vi.fn(), | ||
fetchAppWebhooksInformation: vi.fn(() => | ||
Promise.resolve(err("Error during fetching webhooks information")), | ||
), | ||
}; | ||
|
||
const service = new WebhookActivityService("app-id", mockedClient); | ||
|
||
const result = await service.enableAppWebhooks(); | ||
|
||
expect(result._unsafeUnwrapErr()).toBeInstanceOf( | ||
WebhookActivityService.WebhookActivityServiceWebhooksError, | ||
); | ||
|
||
expect(mockedClient.fetchAppWebhooksInformation).toHaveBeenCalled(); | ||
expect(mockedClient.enableSingleWebhook).not.toHaveBeenCalled(); | ||
}); | ||
|
||
it("should throw error when enabling app webhooks fails", async () => { | ||
const mockedClient: IWebhooksActivityClient = { | ||
enableSingleWebhook: vi.fn(() => Promise.resolve(err("Error during enabling webhooks"))), | ||
fetchAppWebhooksInformation: vi.fn(() => | ||
Promise.resolve(ok([{ id: "webhook-id", isActive: false }])), | ||
), | ||
}; | ||
|
||
const service = new WebhookActivityService("app-id", mockedClient); | ||
|
||
const result = await service.enableAppWebhooks(); | ||
|
||
expect(result._unsafeUnwrapErr()).toBeInstanceOf( | ||
WebhookActivityService.WebhookActivityServiceWebhooksError, | ||
); | ||
|
||
expect(mockedClient.fetchAppWebhooksInformation).toHaveBeenCalled(); | ||
expect(mockedClient.enableSingleWebhook).toHaveBeenCalled(); | ||
}); | ||
}); |
Oops, something went wrong.