Skip to content
This repository has been archived by the owner on Mar 10, 2024. It is now read-only.

Commit

Permalink
[skip ci] updates from NCA (#48)
Browse files Browse the repository at this point in the history
  • Loading branch information
borisno2 committed Mar 25, 2022
1 parent 96823af commit c136101
Show file tree
Hide file tree
Showing 20 changed files with 194 additions and 39 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/master_pantrydeploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,14 +34,14 @@ jobs:
username: ${{ secrets.AzureAppService_ContainerUsername_28d39508e5734f558fc68a409d6d0fac }}
password: ${{ secrets.AzureAppService_ContainerPassword_807a7babf8fc4bbab3814a0bd2d77375 }}

- name: Build and push container image to registry
- name: Build and push backend container image to registry
uses: docker/build-push-action@v2
with:
push: true
tags: collectivereg.azurecr.io/${{ secrets.AzureAppService_ContainerUsername_28d39508e5734f558fc68a409d6d0fac }}/pantry-backend:${{ github.sha }}
file: ./backend/Dockerfile

- name: Build and push container image to registry
- name: Build and push frontend container image to registry
uses: docker/build-push-action@v2
with:
push: true
Expand Down
5 changes: 2 additions & 3 deletions apps/user-portal/components/ManageStripeButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ export function ManageStripeButton() {
const router = useRouter();

const MANAGE_STRIPE_MUTATION = gql`
mutation MANAGE_STRIPE_MUTATION($userId: ID!, $returnUrl: String!) {
manageStripe(userId: $userId, returnUrl: $returnUrl)
mutation MANAGE_STRIPE_MUTATION($returnUrl: String!) {
manageStripe(returnUrl: $returnUrl)
}
`;

Expand All @@ -32,7 +32,6 @@ export function ManageStripeButton() {

const portalSession = await getPortalSession({
variables: {
userId: userSession.id,
returnUrl: `${window.location.origin}/profile`,
},
});
Expand Down
13 changes: 2 additions & 11 deletions apps/user-portal/components/SubscribeButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,8 @@ export function SubscribeButton({ ...props }) {

const { variation, subscription, club } = props;
const SUBSCRIPTION_MUTATION = gql`
mutation SUBSCRIPTION_MUTATION(
$variationId: ID!
$userId: ID!
$returnUrl: String!
) {
membershipSignup(
userId: $userId
returnUrl: $returnUrl
variationId: $variationId
)
mutation SUBSCRIPTION_MUTATION($variationId: ID!, $returnUrl: String!) {
membershipSignup(returnUrl: $returnUrl, variationId: $variationId)
}
`;

Expand Down Expand Up @@ -66,7 +58,6 @@ export function SubscribeButton({ ...props }) {
const session = await getStripeSession({
variables: {
variationId: variation.id,
userId: userSession.id,
returnUrl: `${window.location.origin}/${club}/${subscription}`,
},
});
Expand Down
17 changes: 13 additions & 4 deletions backend/access.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,16 @@ export const rules = {
return true;
}
// 2. If not, do they own this item?
return { user: { id: session?.itemId } };
return { user: { id: { equals: session?.itemId }} };
},
canManageSubscriptions({ session }: ListAccessArgs) {

// 1. Do they have the permission of canManageVariations
if (permissions.canManageProducts({ session })) {
return true;
}
// 2. If not, do they own this item?
return false;
},
canManageOrgs({ session }: ListAccessArgs) {
if (!isSignedIn({ session })) {
Expand All @@ -54,7 +63,7 @@ export const rules = {
return true;
}
// 2. If not, do they own this item?
return { user: { id: session?.itemId } };
return { user: { id: { equals: session?.itemId }} };
},
canManageOrderItems({ session }: ListAccessArgs) {
if (!isSignedIn({ session })) {
Expand All @@ -75,7 +84,7 @@ export const rules = {
return true; // They can read everything!
}
// They should only see available products (based on the status field)
return { status: 'AVAILABLE' };
return {status: {equals: 'active'} };
},
canManageUsers({ session }: ListAccessArgs) {
if (!isSignedIn({ session })) {
Expand All @@ -85,6 +94,6 @@ export const rules = {
return true;
}
// Otherwise they may only update themselves!
return { id: session?.itemId };
return { id: { equals: session?.itemId }};
},
};
6 changes: 4 additions & 2 deletions backend/keystone.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import { statelessSessions } from '@keystone-6/core/session';
import { createAuth } from '@opensaas/keystone-nextjs-auth';
import AzureB2C from '@opensaas/keystone-nextjs-auth/providers/azure-ad-b2c';
import { stripeHook } from './lib/stripe';
import { permissionsList } from './schemas/roleFields';

import express from 'express';
import url from 'url';

Expand All @@ -30,7 +32,7 @@ let sessionMaxAge = 60 * 60 * 24 * 30; // 30 days
const auth = createAuth({
listKey: 'User',
identityField: 'subjectId',
sessionData: `id name email memberships { id name status startDate renewalDate variation { id name subscription { id name }}}`,
sessionData: `id name email isAdmin role { ${permissionsList.join(' ')} } memberships { id name status startDate renewalDate variation { id name subscription { id name }}}`,
autoCreate: true,
userMap: { subjectId: 'id', email: 'email', name: 'name',},
accountMap: {},
Expand Down Expand Up @@ -58,7 +60,7 @@ export default auth.withAuth(
'postgres://postgres:mysecretpassword@localhost:55000',
},
ui: {
isAccessAllowed: (context) => !!context.session?.data,
isAccessAllowed: (context) => context.session?.data?.isAdmin,
},
lists,
extendGraphqlSchema,
Expand Down
21 changes: 15 additions & 6 deletions backend/lib/stripe.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ export async function stripeHook(req: Request, res: Response) {
const context = (req as any).context as KeystoneContext;
let data;
let eventType;
const sudo = context.sudo();
// Check if webhook signing is configured.
const webhookSecret =
process.env.STRIPE_WEBHOOK_SECRET || 'whsec_1234567890123456789012345678901234567890';
Expand All @@ -83,13 +84,12 @@ export async function stripeHook(req: Request, res: Response) {
} else {
// Webhook signing is recommended, but if the secret is not configured in `config.js`,
// retrieve the event data directly from the request body.

data = req.body.data;
eventType = req.body.type;
}
switch (eventType) {
case 'checkout.session.completed':
const membership = await context.query.Membership.findOne({
const membership = await sudo.query.Membership.findOne({
where: { signupSessionId: data.object.id },
query: graphql`
id
Expand All @@ -98,7 +98,12 @@ export async function stripeHook(req: Request, res: Response) {
}
`,
});
await context.query.Membership.updateOne({

if (!membership) {
console.log('⚠️ No membership found for checkout.session.completed');
return res.sendStatus(404);
}
await sudo.query.Membership.updateOne({
where: { id: membership.id },
data: {
status: 'PAID',
Expand All @@ -115,7 +120,7 @@ export async function stripeHook(req: Request, res: Response) {
// This approach helps you avoid hitting rate limits.
break;
case 'invoice.payment_failed':
const failedMembership = await context.query.Membership.findOne({
const failedMembership = await sudo.query.Membership.findOne({
where: { stripeSubscriptionId: data.object.subscription },
query: graphql`
id
Expand All @@ -124,7 +129,11 @@ export async function stripeHook(req: Request, res: Response) {
}
`,
});
await context.query.Membership.updateOne({
if (!failedMembership.id) {
console.log('⚠️ No membership found for invoice.payment_failed');
return res.sendStatus(404);
}
await sudo.query.Membership.updateOne({
where: { id: failedMembership.id },
data: {
status: 'FAILED',
Expand All @@ -138,6 +147,6 @@ export async function stripeHook(req: Request, res: Response) {
default:
// Unhandled event type
}

sudo.exitSudo;
res.sendStatus(200);
}
5 changes: 5 additions & 0 deletions backend/migrations/20220318084652_is_admin_flag/migration.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
-- AlterTable
ALTER TABLE "Role" ADD COLUMN "canManageProducts" BOOLEAN NOT NULL DEFAULT false;

-- AlterTable
ALTER TABLE "User" ADD COLUMN "isAdmin" BOOLEAN NOT NULL DEFAULT false;
5 changes: 5 additions & 0 deletions backend/migrations/20220321230524_add_status/migration.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
-- AlterTable
ALTER TABLE "Subscription" ADD COLUMN "status" TEXT DEFAULT E'active';

-- AlterTable
ALTER TABLE "Variation" ADD COLUMN "status" TEXT DEFAULT E'active';
4 changes: 2 additions & 2 deletions backend/mutations/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ const graphql = String.raw;
export const extendGraphqlSchema = graphQLSchemaExtension({
typeDefs: graphql`
type Mutation {
membershipSignup(variationId: ID!, userId: ID!, returnUrl: String!): JSON
membershipSignup(variationId: ID!, returnUrl: String!): JSON
customSignup(
email: String!
name: String!
Expand All @@ -22,7 +22,7 @@ export const extendGraphqlSchema = graphQLSchemaExtension({
createUser: Boolean
suburb: String
): JSON
stripeManage(userId: ID!, returnUrl: String!): JSON
stripeManage(returnUrl: String!): JSON
}
`,
resolvers: {
Expand Down
7 changes: 6 additions & 1 deletion backend/mutations/membershipSignup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,14 @@ const graphql = String.raw;

async function membershipSignup(
root: any,
{ variationId, userId, returnUrl }: Arguments,
{ variationId, returnUrl }: Arguments,
context: KeystoneContext
) {
const userId = context.session?.itemId;
if (!userId) {
console.log("No user signed in");
return {error: "No user signed in"};
};
// get the subscription from the id
const variation = await context.query.Variation.findOne({
where: { id: variationId },
Expand Down
7 changes: 6 additions & 1 deletion backend/mutations/stripeManage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,14 @@ const graphql = String.raw;

async function stripeManage(
root: any,
{ userId, returnUrl }: Arguments,
{ returnUrl }: Arguments,
context: KeystoneContext
) {
const userId = context.session?.itemId;
if (!userId) {
console.log("No user signed in");
return {error: "No user signed in"};
};
const user = await context.query.User.findOne({
where: { id: userId },
query: graphql`
Expand Down
Loading

0 comments on commit c136101

Please sign in to comment.