mirror of
https://github.com/webstudio-is/webstudio.git
synced 2026-10-30 08:37:56 +09:00
## Description closes #3400 `+` on dev login its now possible to add any email like `{code}:hello@world.xx` to login as other user ## Steps for reproduction Login on main with `{code}:ice@yandex.ru` - See no plan <img width="213" alt="image" src="https://github.com/webstudio-is/webstudio/assets/5077042/65f79295-63b3-4d4f-b5d2-ed854f8462e3"> --- Login on main as usual - See user has plan <img width="265" alt="image" src="https://github.com/webstudio-is/webstudio/assets/5077042/db9e1c3e-a8d7-4cde-bbd5-1f39ce7442b8"> --- Login locally See user has plan <img width="231" alt="image" src="https://github.com/webstudio-is/webstudio/assets/5077042/c1187bce-2c7e-49f3-a3ac-bfa15560ccce"> ## Code Review - [ ] hi @kof, I need you to do - conceptual review (architecture, feature-correctness) - detailed review (read every line) - test it on preview ## Before requesting a review - [ ] made a self-review - [ ] added inline comments where things may be not obvious (the "why", not "what") ## Before merging - [ ] tested locally and on preview environment (preview dev login: 5de6) - [ ] updated [test cases](https://github.com/webstudio-is/webstudio/blob/main/apps/builder/docs/test-cases.md) document - [ ] added tests - [ ] if any new env variables are added, added them to `.env.example` and the `builder/env-check.js` if mandatory
96 lines
2.3 KiB
TypeScript
96 lines
2.3 KiB
TypeScript
import { prisma } from "@webstudio-is/prisma-client";
|
|
import type { AppContext } from "@webstudio-is/trpc-interface/index.server";
|
|
import env from "~/env/env.server";
|
|
|
|
export type UserPlanFeatures = NonNullable<AppContext["userPlanFeatures"]>;
|
|
|
|
export const getTokenPlanFeatures = async (token: string) => {
|
|
const projectOwnerIdByToken = await prisma.authorizationToken.findUnique({
|
|
where: {
|
|
token,
|
|
},
|
|
select: {
|
|
project: {
|
|
select: {
|
|
id: true,
|
|
userId: true,
|
|
},
|
|
},
|
|
},
|
|
});
|
|
|
|
if (projectOwnerIdByToken === null) {
|
|
throw new Error(`Project owner can't be found for token ${token}`);
|
|
}
|
|
|
|
const userId = projectOwnerIdByToken.project.userId;
|
|
if (userId === null) {
|
|
throw new Error(
|
|
`Project ${projectOwnerIdByToken.project.id} has null instead of userId`
|
|
);
|
|
}
|
|
|
|
return await getUserPlanFeatures(userId);
|
|
};
|
|
|
|
export const getUserPlanFeatures = async (
|
|
userId: string
|
|
): Promise<UserPlanFeatures> => {
|
|
const userProducts = await prisma.userProduct.findMany({
|
|
where: { userId },
|
|
select: {
|
|
customerId: true,
|
|
subscriptionId: true,
|
|
product: {
|
|
select: {
|
|
id: true,
|
|
name: true,
|
|
description: true,
|
|
features: true,
|
|
meta: true,
|
|
images: true,
|
|
},
|
|
},
|
|
},
|
|
});
|
|
|
|
// This is fast and dirty implementation
|
|
// @todo: implement this using products meta, custom table with aggregated transaction info
|
|
if (userProducts.length > 0) {
|
|
const hasSubscription = userProducts.some(
|
|
(log) => log.subscriptionId !== null
|
|
);
|
|
|
|
return {
|
|
allowShareAdminLinks: true,
|
|
allowDynamicData: true,
|
|
allowContactEmail: true,
|
|
maxDomainsAllowedPerUser: Number.MAX_SAFE_INTEGER,
|
|
hasSubscription,
|
|
hasProPlan: true,
|
|
planName: userProducts[0].product.name,
|
|
};
|
|
}
|
|
|
|
if (env.USER_PLAN === "pro") {
|
|
return {
|
|
allowShareAdminLinks: true,
|
|
allowDynamicData: true,
|
|
allowContactEmail: true,
|
|
maxDomainsAllowedPerUser: Number.MAX_SAFE_INTEGER,
|
|
hasSubscription: true,
|
|
hasProPlan: true,
|
|
planName: "env.USER_PLAN Pro",
|
|
};
|
|
}
|
|
|
|
return {
|
|
allowShareAdminLinks: false,
|
|
allowDynamicData: false,
|
|
allowContactEmail: false,
|
|
maxDomainsAllowedPerUser: 5,
|
|
hasSubscription: false,
|
|
hasProPlan: false,
|
|
};
|
|
};
|