Skip to content
This repository has been archived by the owner on Apr 19, 2023. It is now read-only.

Commit

Permalink
✨ Update membership endpoints to org
Browse files Browse the repository at this point in the history
  • Loading branch information
AnandChowdhary committed Jul 31, 2019
1 parent 3a4d48c commit de55eda
Show file tree
Hide file tree
Showing 8 changed files with 337 additions and 112 deletions.
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "staart-manager",
"version": "1.0.112",
"version": "1.0.113",
"main": "index.js",
"repository": "[email protected]:AnandChowdhary/staart.git",
"author": "Anand Chowdhary <[email protected]>",
Expand Down Expand Up @@ -135,5 +135,5 @@
"setup"
],
"snyk": true,
"staart-version": "1.0.112"
"staart-version": "1.0.113"
}
4 changes: 0 additions & 4 deletions src/controllers/v1/membership.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import { Request, Response } from "express";
import { ErrorCode } from "../../interfaces/enum";
import {
getMembershipDetailsForUser,
inviteMemberToOrganization,
deleteMembershipForUser,
updateMembershipForUser
} from "../../rest/membership";
Expand All @@ -19,8 +17,6 @@ import {
import { authHandler, validator } from "../../helpers/middleware";
import asyncHandler from "express-async-handler";
import Joi from "@hapi/joi";
import { joiValidate } from "../../helpers/utils";
import i18n from "../../i18n";

@Controller("v1/memberships")
@ClassWrapper(asyncHandler)
Expand Down
78 changes: 76 additions & 2 deletions src/controllers/v1/organization.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,11 @@ import {
createWebhookForUser,
getOrganizationWebhookForUser,
updateWebhookForUser,
deleteWebhookForUser
deleteWebhookForUser,
inviteMemberToOrganization,
getOrganizationMembershipForUser,
deleteOrganizationMembershipForUser,
updateOrganizationMembershipForUser
} from "../../rest/organization";
import {
Get,
Expand All @@ -53,7 +57,6 @@ import { authHandler, validator } from "../../helpers/middleware";
import { MembershipRole } from "../../interfaces/enum";
import { CREATED } from "http-status-codes";
import asyncHandler from "express-async-handler";
import { inviteMemberToOrganization } from "../../rest/membership";
import {
joiValidate,
organizationUsernameToId,
Expand Down Expand Up @@ -519,6 +522,77 @@ export class OrganizationController {
res.status(CREATED).json({ invited: true });
}

@Get(":id/memberships/:membershipId")
async getMembership(req: Request, res: Response) {
const organizationId = await organizationUsernameToId(req.params.id);
const membershipId = req.params.membershipId;
joiValidate(
{
organizationId: Joi.number().required(),
membershipId: Joi.number().required()
},
{ organizationId, membershipId }
);
res.json(
await getOrganizationMembershipForUser(
localsToTokenOrKey(res),
organizationId,
membershipId
)
);
}

@Patch(":id/memberships/:membershipId")
@Middleware(
validator(
{
role: Joi.number()
.min(1)
.max(5)
},
"body"
)
)
async updateMembership(req: Request, res: Response) {
const organizationId = await organizationUsernameToId(req.params.id);
const membershipId = req.params.membershipId;
joiValidate(
{
organizationId: Joi.number().required(),
membershipId: Joi.number().required()
},
{ organizationId, membershipId }
);
res.json(
await updateOrganizationMembershipForUser(
localsToTokenOrKey(res),
organizationId,
membershipId,
req.body
)
);
}

@Delete(":id/memberships/:membershipId")
async deleteMembership(req: Request, res: Response) {
const organizationId = await organizationUsernameToId(req.params.id);
const membershipId = req.params.membershipId;
joiValidate(
{
organizationId: Joi.number().required(),
membershipId: Joi.number().required()
},
{ organizationId, membershipId }
);
res.json(
await deleteOrganizationMembershipForUser(
localsToTokenOrKey(res),
organizationId,
membershipId
)
);
}

@Get(":id/api-keys")
async getUserApiKeys(req: Request, res: Response) {
const id = await organizationUsernameToId(req.params.id);
Expand Down
36 changes: 0 additions & 36 deletions src/crud/membership.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,24 +65,6 @@ export const deleteMembership = async (id: number) => {
]);
};

/*
* Delete all memberships in an organization
*/
export const deleteAllOrganizationMemberships = async (
organizationId: number
) => {
const allMemberships = await getOrganizationMembers(organizationId);
for await (const membership of allMemberships) {
if (membership.id) {
deleteItemFromCache(CacheCategories.USER_MEMBERSHIPS, membership.userId);
}
}
return await query(
`DELETE FROM ${tableName("memberships")} WHERE organizationId = ?`,
[organizationId]
);
};

/*
* Delete all memberships for a user
*/
Expand Down Expand Up @@ -137,24 +119,6 @@ export const getOrganizationMembers = async (organizationId: number) => {
);
};

/*
* Get a detailed list of all members in an organization
*/
export const getOrganizationMemberDetails = async (
organizationId: number,
query?: KeyValue
) => {
const members: any = await getPaginatedData({
table: "memberships",
conditions: { organizationId },
...query
});
for await (const member of members.data) {
member.user = await getUser(member.userId);
}
return members;
};

export const getUserMemberships = async (user: User | number) => {
if (typeof user !== "number" && typeof user !== "string") {
if (user.id) user = user.id;
Expand Down
122 changes: 122 additions & 0 deletions src/crud/organization.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ import cryptoRandomString from "crypto-random-string";
import { apiKeyToken, invalidateToken } from "../helpers/jwt";
import { TOKEN_EXPIRY_API_KEY_MAX, JWT_ISSUER } from "../config";
import { InsertResult } from "../interfaces/mysql";
import { Membership } from "../interfaces/tables/memberships";
import { getUser } from "./user";

/*
* Create a new organization for a user
Expand Down Expand Up @@ -405,3 +407,123 @@ export const deleteWebhook = async (
[webhookId, organizationId]
);
};

/*
* Get a detailed list of all members in an organization
*/
export const getOrganizationMemberships = async (
organizationId: number,
query?: KeyValue
) => {
const members: any = await getPaginatedData({
table: "memberships",
conditions: { organizationId },
...query
});
for await (const member of members.data) {
member.user = await getUser(member.userId);
}
return members;
};

/*
* Get details about a specific organization membership
*/
export const getOrganizationMembership = async (
organizationId: number,
id: number
) => {
return (<Membership[]>(
await cachedQuery(
CacheCategories.MEMBERSHIP,
id,
`SELECT * FROM ${tableName(
"memberships"
)} WHERE id = ? AND organizationId = ? LIMIT 1`,
[id, organizationId]
)
))[0];
};

/*
* Get a detailed version of a membership
*/
export const getOrganizationMembershipDetailed = async (
organizationId: number,
id: number
) => {
const membership = (await getOrganizationMembership(
organizationId,
id
)) as any;
if (!membership || !membership.id)
throw new Error(ErrorCode.MEMBERSHIP_NOT_FOUND);
membership.organization = await getOrganization(membership.organizationId);
membership.user = await getUser(membership.userId);
return membership;
};

/*
* Update an organization membership for a user
*/
export const updateOrganizationMembership = async (
organizationId: number,
id: number,
membership: KeyValue
) => {
membership.updatedAt = new Date();
membership = removeReadOnlyValues(membership);
const membershipDetails = await getOrganizationMembership(organizationId, id);
if (membershipDetails.id)
deleteItemFromCache(
CacheCategories.USER_MEMBERSHIPS,
membershipDetails.userId
);
deleteItemFromCache(CacheCategories.MEMBERSHIP, id);
return await query(
`UPDATE ${tableName("memberships")} SET ${setValues(
membership
)} WHERE id = ? AND organizationId = ?`,
[...Object.values(membership), id, organizationId]
);
};

/*
* Delete an organization membership
*/
export const deleteOrganizationMembership = async (
organizationId: number,
id: number
) => {
const membershipDetails = await getOrganizationMembership(organizationId, id);
if (membershipDetails.id)
deleteItemFromCache(
CacheCategories.USER_MEMBERSHIPS,
membershipDetails.userId
);
deleteItemFromCache(CacheCategories.MEMBERSHIP, id);
return await query(
`DELETE FROM ${tableName(
"memberships"
)} WHERE id = ? AND organizationId = ?`,
[id, organizationId]
);
};

/*
* Delete all memberships in an organization
*/
export const deleteAllOrganizationMemberships = async (
organizationId: number
) => {
const allMemberships = await getOrganizationMemberships(organizationId);
for await (const membership of allMemberships.data) {
if (membership.id) {
deleteItemFromCache(CacheCategories.USER_MEMBERSHIPS, membership.userId);
}
}
return await query(
`DELETE FROM ${tableName("memberships")} WHERE organizationId = ?`,
[organizationId]
);
};
7 changes: 5 additions & 2 deletions src/interfaces/enum.ts
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,6 @@ export enum OrgScopes {
UPDATE_ORG_SUBSCRIPTIONS = "org:subscriptions:update",
CREATE_ORG_SUBSCRIPTIONS = "org:subscriptions:create",
READ_ORG_PLANS = "org:plans:read",
READ_ORG_MEMBERSHIPS = "org:memberships:read",
READ_ORG_API_KEYS = "org:api-key:read",
UPDATE_ORG_API_KEYS = "org:api-key:update",
DELETE_ORG_API_KEYS = "org:api-key:delete",
Expand All @@ -172,7 +171,11 @@ export enum OrgScopes {
READ_ORG_WEBHOOKS = "org:webhook:read",
UPDATE_ORG_WEBHOOKS = "org:webhook:update",
DELETE_ORG_WEBHOOKS = "org:webhook:delete",
CREATE_ORG_WEBHOOKS = "org:webhook:create"
CREATE_ORG_WEBHOOKS = "org:webhook:create",
READ_ORG_MEMBERSHIPS = "org:membership:read",
UPDATE_ORG_MEMBERSHIPS = "org:membership:update",
DELETE_ORG_MEMBERSHIPS = "org:membership:delete",
CREATE_ORG_MEMBERSHIPS = "org:membership:create"
}

export enum UserScopes {
Expand Down
Loading

0 comments on commit de55eda

Please sign in to comment.