-
Couldn't load subscription status.
- Fork 2
Adding the v2/Teams API #6
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
ed6fe8f
9f5b77b
87f8250
d702cfc
5904ba4
d5217b0
d7adf45
9d73613
1a57640
5e48131
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,157 @@ | ||||||||||||||||||||
| import type { | ||||||||||||||||||||
| TeamsResultPage, TeamFields, TeamsIncluded, Team, | ||||||||||||||||||||
| TeamMembership, TeamLink, TeamPermissionSetting | ||||||||||||||||||||
| } from "./lib/identity.ts"; | ||||||||||||||||||||
|
|
||||||||||||||||||||
| type TODO = unknown; | ||||||||||||||||||||
|
|
||||||||||||||||||||
| // Common API client contract | ||||||||||||||||||||
| interface ApiClient { | ||||||||||||||||||||
| fetchJson(opts: { | ||||||||||||||||||||
| method: "GET" | "POST" | "DELETE"; | ||||||||||||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It looks like this is the first DELETE call in this project, and so the new method needs to be also added to Line 40 in 657811e
|
||||||||||||||||||||
| path: string; | ||||||||||||||||||||
| query?: URLSearchParams; | ||||||||||||||||||||
| body?: unknown; | ||||||||||||||||||||
| }): Promise<unknown>; | ||||||||||||||||||||
| } | ||||||||||||||||||||
|
|
||||||||||||||||||||
| export default class DatadogTeamsApi { | ||||||||||||||||||||
| #api: ApiClient; | ||||||||||||||||||||
| constructor(api: ApiClient) { | ||||||||||||||||||||
| this.#api = api; | ||||||||||||||||||||
| } | ||||||||||||||||||||
|
|
||||||||||||||||||||
| /** | ||||||||||||||||||||
| * Get the list of all users in the organization. | ||||||||||||||||||||
| * This list includes all users even if they are deactivated or unverified. | ||||||||||||||||||||
| */ | ||||||||||||||||||||
| async listTeams(opts: { | ||||||||||||||||||||
| page?: number; | ||||||||||||||||||||
| per_page?: number; | ||||||||||||||||||||
| sort?: { | ||||||||||||||||||||
| field: "name" | "user_count"; | ||||||||||||||||||||
| order?: "asc" | "desc"; | ||||||||||||||||||||
| }; | ||||||||||||||||||||
| filterKeyword?: string; | ||||||||||||||||||||
| filterMe?: boolean; | ||||||||||||||||||||
| fieldsTeam?: Array<TeamFields>; | ||||||||||||||||||||
| } = {}): Promise<TeamsResultPage<Team> & TeamsIncluded> { | ||||||||||||||||||||
| const qs = new URLSearchParams(); | ||||||||||||||||||||
| if (opts.page != null) qs.set("page[number]", `${opts.page}`); | ||||||||||||||||||||
| if (opts.per_page != null) qs.set("page[size]", `${opts.per_page}`); | ||||||||||||||||||||
| if (opts.sort != null) qs.set("sort", | ||||||||||||||||||||
| `${opts.sort.order == 'desc' ? '-' : ''}${opts.sort.field}`); | ||||||||||||||||||||
| if (opts.filterKeyword != null) qs.set("filter[keyword]", `${opts.filterKeyword}`); | ||||||||||||||||||||
| if (opts.filterMe != null) qs.set("filter[me]", `${opts.filterMe}`); | ||||||||||||||||||||
| if (opts.fieldsTeam) qs.set("fields[team]", opts.fieldsTeam.join(',')); | ||||||||||||||||||||
|
|
||||||||||||||||||||
| const json = await this.#api.fetchJson({ | ||||||||||||||||||||
| path: `/api/v2/team`, | ||||||||||||||||||||
| method: "GET", | ||||||||||||||||||||
| query: qs, | ||||||||||||||||||||
| }); | ||||||||||||||||||||
| return json as TeamsResultPage<Team> & TeamsIncluded; | ||||||||||||||||||||
| } | ||||||||||||||||||||
|
|
||||||||||||||||||||
| /** Get a team in the organization specified by the team’s team_id. */ | ||||||||||||||||||||
| async getTeam(teamId: string): Promise<{data: Team}> { | ||||||||||||||||||||
| const json = await this.#api.fetchJson({ | ||||||||||||||||||||
| method: "GET", | ||||||||||||||||||||
| path: `/api/v2/team/${encodeURIComponent(teamId)}`, | ||||||||||||||||||||
| }); | ||||||||||||||||||||
| return json as {data: Team}; | ||||||||||||||||||||
| } | ||||||||||||||||||||
|
|
||||||||||||||||||||
| /** Get a list of members for a team */ | ||||||||||||||||||||
| async getTeamMemberships(teamId: string): Promise<TeamsResultPage<TeamMembership>> { | ||||||||||||||||||||
| const json = await this.#api.fetchJson({ | ||||||||||||||||||||
| method: "GET", | ||||||||||||||||||||
| path: `/api/v2/team/${encodeURIComponent(teamId)}/memberships`, | ||||||||||||||||||||
| }); | ||||||||||||||||||||
| return json as TeamsResultPage<TeamMembership>; | ||||||||||||||||||||
| } | ||||||||||||||||||||
|
|
||||||||||||||||||||
| /** List the links for a team */ | ||||||||||||||||||||
| async listTeamLinks(teamId: string): Promise<Array<TeamLink>> { | ||||||||||||||||||||
| const json = await this.#api.fetchJson({ | ||||||||||||||||||||
| method: "GET", | ||||||||||||||||||||
| path: `/api/v2/team/${encodeURIComponent(teamId)}/links`, | ||||||||||||||||||||
| }); | ||||||||||||||||||||
| return json as Array<TeamLink>; | ||||||||||||||||||||
| } | ||||||||||||||||||||
|
|
||||||||||||||||||||
| /** Get a single link for a team */ | ||||||||||||||||||||
| async getTeamLink(teamId: string, linkId: string): Promise<TeamLink> { | ||||||||||||||||||||
| const json = await this.#api.fetchJson({ | ||||||||||||||||||||
| method: "GET", | ||||||||||||||||||||
| path: `/api/v2/team/${encodeURIComponent(teamId)}/links/${encodeURIComponent(linkId)}`, | ||||||||||||||||||||
| }); | ||||||||||||||||||||
| return json as TeamLink; | ||||||||||||||||||||
| } | ||||||||||||||||||||
|
|
||||||||||||||||||||
| /** Get teams' permission settings */ | ||||||||||||||||||||
| async getTeamPermissionSettings(teamId: string): Promise<Array<TeamPermissionSetting>> { | ||||||||||||||||||||
| const json = await this.#api.fetchJson({ | ||||||||||||||||||||
| method: "GET", | ||||||||||||||||||||
| path: `/api/v2/team/${encodeURIComponent(teamId)}/permission-settings`, | ||||||||||||||||||||
| }); | ||||||||||||||||||||
| return json as Array<TeamPermissionSetting>; | ||||||||||||||||||||
| } | ||||||||||||||||||||
|
|
||||||||||||||||||||
| /** Create a team */ | ||||||||||||||||||||
| async createTeam(name: string): Promise<string> { | ||||||||||||||||||||
| const words = [...name.toLowerCase().matchAll(/[a-z0-9]+/g)].map((x) => x[0]) | ||||||||||||||||||||
| const handle = words.join("-") | ||||||||||||||||||||
|
Comment on lines
+102
to
+104
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is slightly magic. Does this string manipulation follow a particular recommendation from datadog? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. oof. I'm afraid I leaked out some business logic from my script here 😅 refactoring in progress |
||||||||||||||||||||
| const json = await this.#api.fetchJson({ | ||||||||||||||||||||
| method: "POST", | ||||||||||||||||||||
| path: `/api/v2/team`, | ||||||||||||||||||||
| body: { | ||||||||||||||||||||
| data: { | ||||||||||||||||||||
| type: "team", | ||||||||||||||||||||
| attributes: { | ||||||||||||||||||||
| name: name, | ||||||||||||||||||||
| handle: handle | ||||||||||||||||||||
| }, | ||||||||||||||||||||
|
Comment on lines
+111
to
+114
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I see that there are additional possible attributes for this API, so perhaps we can accept a second optional parameter
Suggested change
|
||||||||||||||||||||
| relationships: {} | ||||||||||||||||||||
| } | ||||||||||||||||||||
| } | ||||||||||||||||||||
| }); | ||||||||||||||||||||
| return (json as { status: string }).status; | ||||||||||||||||||||
| } | ||||||||||||||||||||
|
|
||||||||||||||||||||
| /** Delete a team */ | ||||||||||||||||||||
| async deleteTeam(teamId: string): Promise<string> { | ||||||||||||||||||||
| const json = await this.#api.fetchJson({ | ||||||||||||||||||||
| method: "DELETE", | ||||||||||||||||||||
| path: `/api/v2/team/${encodeURIComponent(teamId)}`, | ||||||||||||||||||||
| }); | ||||||||||||||||||||
| return (json as { status: string }).status; | ||||||||||||||||||||
| } | ||||||||||||||||||||
|
|
||||||||||||||||||||
| /** Add a user to a team */ | ||||||||||||||||||||
| async addUserToTeam(teamId: string, userId: string): Promise<string> { | ||||||||||||||||||||
|
|
||||||||||||||||||||
| const json = await this.#api.fetchJson({ | ||||||||||||||||||||
| method: "POST", | ||||||||||||||||||||
| path: `/api/v2/team/${encodeURIComponent(teamId)}/memberships`, | ||||||||||||||||||||
| body: { | ||||||||||||||||||||
| data: { | ||||||||||||||||||||
| type: "team_memberships", | ||||||||||||||||||||
| id: teamId, | ||||||||||||||||||||
| attributes: { | ||||||||||||||||||||
| role: "admin" | ||||||||||||||||||||
| }, | ||||||||||||||||||||
| relationships: { | ||||||||||||||||||||
| user: { | ||||||||||||||||||||
| data: { | ||||||||||||||||||||
| type: "users", | ||||||||||||||||||||
| id: userId | ||||||||||||||||||||
| } | ||||||||||||||||||||
| } | ||||||||||||||||||||
| } | ||||||||||||||||||||
| } | ||||||||||||||||||||
| }, | ||||||||||||||||||||
| }); | ||||||||||||||||||||
| return (json as { status: string }).status; | ||||||||||||||||||||
| } | ||||||||||||||||||||
| } | ||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Did datadog really need to add another pagination structure within v2 😅 LGTM