prettier fixes #16
This commit is contained in:
@@ -1,6 +1,13 @@
|
||||
import { ACCOUNT_ACCESS } from '~~/prisma/account-access-enum';
|
||||
import prisma_client from '~~/prisma/prisma.client';
|
||||
import { accountWithMembers, AccountWithMembers, membershipWithAccount, MembershipWithAccount, membershipWithUser, MembershipWithUser } from './service.types';
|
||||
import {
|
||||
accountWithMembers,
|
||||
AccountWithMembers,
|
||||
membershipWithAccount,
|
||||
MembershipWithAccount,
|
||||
membershipWithUser,
|
||||
MembershipWithUser
|
||||
} from './service.types';
|
||||
import generator from 'generate-password-ts';
|
||||
import { UtilService } from './util.service';
|
||||
import { AccountLimitError } from './errors';
|
||||
@@ -9,52 +16,62 @@ const config = useRuntimeConfig();
|
||||
|
||||
export default class AccountService {
|
||||
async getAccountById(account_id: number): Promise<AccountWithMembers> {
|
||||
return prisma_client.account.findFirstOrThrow({
|
||||
return prisma_client.account.findFirstOrThrow({
|
||||
where: { id: account_id },
|
||||
...accountWithMembers
|
||||
});
|
||||
}
|
||||
|
||||
async getAccountByJoinPassword(join_password: string): Promise<AccountWithMembers> {
|
||||
return prisma_client.account.findFirstOrThrow({
|
||||
async getAccountByJoinPassword(
|
||||
join_password: string
|
||||
): Promise<AccountWithMembers> {
|
||||
return prisma_client.account.findFirstOrThrow({
|
||||
where: { join_password },
|
||||
...accountWithMembers
|
||||
});
|
||||
}
|
||||
|
||||
async getAccountMembers(account_id: number): Promise<MembershipWithUser[]> {
|
||||
return prisma_client.membership.findMany({
|
||||
return prisma_client.membership.findMany({
|
||||
where: { account_id },
|
||||
...membershipWithUser
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
async updateAccountStipeCustomerId (account_id: number, stripe_customer_id: string){
|
||||
async updateAccountStipeCustomerId(
|
||||
account_id: number,
|
||||
stripe_customer_id: string
|
||||
) {
|
||||
return await prisma_client.account.update({
|
||||
where: { id: account_id },
|
||||
data: {
|
||||
stripe_customer_id,
|
||||
stripe_customer_id
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
async updateStripeSubscriptionDetailsForAccount (stripe_customer_id: string, stripe_subscription_id: string, current_period_ends: Date, stripe_product_id: string){
|
||||
async updateStripeSubscriptionDetailsForAccount(
|
||||
stripe_customer_id: string,
|
||||
stripe_subscription_id: string,
|
||||
current_period_ends: Date,
|
||||
stripe_product_id: string
|
||||
) {
|
||||
const account = await prisma_client.account.findFirstOrThrow({
|
||||
where: {stripe_customer_id}
|
||||
where: { stripe_customer_id }
|
||||
});
|
||||
|
||||
const paid_plan = await prisma_client.plan.findFirstOrThrow({
|
||||
where: { stripe_product_id },
|
||||
const paid_plan = await prisma_client.plan.findFirstOrThrow({
|
||||
where: { stripe_product_id }
|
||||
});
|
||||
|
||||
if(paid_plan.id == account.plan_id){
|
||||
if (paid_plan.id == account.plan_id) {
|
||||
// only update sub and period info
|
||||
return await prisma_client.account.update({
|
||||
where: { id: account.id },
|
||||
data: {
|
||||
stripe_subscription_id,
|
||||
current_period_ends,
|
||||
ai_gen_count:0,
|
||||
ai_gen_count: 0
|
||||
}
|
||||
});
|
||||
} else {
|
||||
@@ -70,72 +87,82 @@ export default class AccountService {
|
||||
max_members: paid_plan.max_members,
|
||||
plan_name: paid_plan.name,
|
||||
ai_gen_max_pm: paid_plan.ai_gen_max_pm,
|
||||
ai_gen_count:0, // I did vacillate on this point ultimately easier to just reset, discussion here https://www.reddit.com/r/SaaS/comments/16e9bew/should_i_reset_usage_counts_on_plan_upgrade/
|
||||
ai_gen_count: 0 // I did vacillate on this point ultimately easier to just reset, discussion here https://www.reddit.com/r/SaaS/comments/16e9bew/should_i_reset_usage_counts_on_plan_upgrade/
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
async acceptPendingMembership(account_id: number, membership_id: number): Promise<MembershipWithAccount> {
|
||||
async acceptPendingMembership(
|
||||
account_id: number,
|
||||
membership_id: number
|
||||
): Promise<MembershipWithAccount> {
|
||||
const membership = prisma_client.membership.findFirstOrThrow({
|
||||
where: {
|
||||
id: membership_id
|
||||
}
|
||||
});
|
||||
|
||||
if((await membership).account_id != account_id){
|
||||
if ((await membership).account_id != account_id) {
|
||||
throw new Error(`Membership does not belong to current account`);
|
||||
}
|
||||
|
||||
return await prisma_client.membership.update({
|
||||
where: {
|
||||
id: membership_id,
|
||||
id: membership_id
|
||||
},
|
||||
data: {
|
||||
pending: false
|
||||
},
|
||||
...membershipWithAccount
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
async deleteMembership(account_id: number, membership_id: number): Promise<MembershipWithAccount> {
|
||||
async deleteMembership(
|
||||
account_id: number,
|
||||
membership_id: number
|
||||
): Promise<MembershipWithAccount> {
|
||||
const membership = prisma_client.membership.findFirstOrThrow({
|
||||
where: {
|
||||
id: membership_id
|
||||
}
|
||||
});
|
||||
|
||||
if((await membership).account_id != account_id){
|
||||
if ((await membership).account_id != account_id) {
|
||||
throw new Error(`Membership does not belong to current account`);
|
||||
}
|
||||
|
||||
return await prisma_client.membership.delete({
|
||||
where: {
|
||||
id: membership_id,
|
||||
id: membership_id
|
||||
},
|
||||
...membershipWithAccount
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
async joinUserToAccount(user_id: number, account_id: number, pending: boolean ): Promise<MembershipWithAccount> {
|
||||
async joinUserToAccount(
|
||||
user_id: number,
|
||||
account_id: number,
|
||||
pending: boolean
|
||||
): Promise<MembershipWithAccount> {
|
||||
const account = await prisma_client.account.findUnique({
|
||||
where: {
|
||||
id: account_id,
|
||||
},
|
||||
include:{
|
||||
members: true,
|
||||
}
|
||||
where: {
|
||||
id: account_id
|
||||
},
|
||||
include: {
|
||||
members: true
|
||||
}
|
||||
)
|
||||
});
|
||||
|
||||
if(account?.members && account?.members?.length >= account?.max_members){
|
||||
throw new Error(`Too Many Members, Account only permits ${account?.max_members} members.`);
|
||||
if (account?.members && account?.members?.length >= account?.max_members) {
|
||||
throw new Error(
|
||||
`Too Many Members, Account only permits ${account?.max_members} members.`
|
||||
);
|
||||
}
|
||||
|
||||
if(account?.members){
|
||||
for(const member of account.members){
|
||||
if(member.user_id === user_id){
|
||||
if (account?.members) {
|
||||
for (const member of account.members) {
|
||||
if (member.user_id === user_id) {
|
||||
throw new Error(`User is already a member`);
|
||||
}
|
||||
}
|
||||
@@ -154,21 +181,23 @@ export default class AccountService {
|
||||
|
||||
async changeAccountName(account_id: number, new_name: string) {
|
||||
return prisma_client.account.update({
|
||||
where: { id: account_id},
|
||||
where: { id: account_id },
|
||||
data: {
|
||||
name: new_name,
|
||||
name: new_name
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async changeAccountPlan(account_id: number, plan_id: number) {
|
||||
const plan = await prisma_client.plan.findFirstOrThrow({ where: {id: plan_id}});
|
||||
const plan = await prisma_client.plan.findFirstOrThrow({
|
||||
where: { id: plan_id }
|
||||
});
|
||||
return prisma_client.account.update({
|
||||
where: { id: account_id},
|
||||
where: { id: account_id },
|
||||
data: {
|
||||
plan_id: plan_id,
|
||||
features: plan.features,
|
||||
max_notes: plan.max_notes,
|
||||
max_notes: plan.max_notes
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -179,23 +208,26 @@ export default class AccountService {
|
||||
numbers: true
|
||||
});
|
||||
return prisma_client.account.update({
|
||||
where: { id: account_id},
|
||||
where: { id: account_id },
|
||||
data: { join_password }
|
||||
});
|
||||
}
|
||||
|
||||
// Claim ownership of an account.
|
||||
// Claim ownership of an account.
|
||||
// User must already be an ADMIN for the Account
|
||||
// Existing OWNER memberships are downgraded to ADMIN
|
||||
// In future, some sort of Billing/Stripe tie in here e.g. changing email details on the Account, not sure.
|
||||
async claimOwnershipOfAccount(user_id: number, account_id: number): Promise<MembershipWithUser[]> {
|
||||
async claimOwnershipOfAccount(
|
||||
user_id: number,
|
||||
account_id: number
|
||||
): Promise<MembershipWithUser[]> {
|
||||
const membership = await prisma_client.membership.findUniqueOrThrow({
|
||||
where: {
|
||||
user_id_account_id: {
|
||||
user_id: user_id,
|
||||
account_id: account_id,
|
||||
account_id: account_id
|
||||
}
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
if (membership.access === ACCOUNT_ACCESS.OWNER) {
|
||||
@@ -207,20 +239,20 @@ export default class AccountService {
|
||||
const existing_owner_memberships = await prisma_client.membership.findMany({
|
||||
where: {
|
||||
account_id: account_id,
|
||||
access: ACCOUNT_ACCESS.OWNER,
|
||||
},
|
||||
access: ACCOUNT_ACCESS.OWNER
|
||||
}
|
||||
});
|
||||
|
||||
for(const existing_owner_membership of existing_owner_memberships) {
|
||||
for (const existing_owner_membership of existing_owner_memberships) {
|
||||
await prisma_client.membership.update({
|
||||
where: {
|
||||
user_id_account_id: {
|
||||
user_id: existing_owner_membership.user_id,
|
||||
account_id: account_id,
|
||||
account_id: account_id
|
||||
}
|
||||
},
|
||||
data: {
|
||||
access: ACCOUNT_ACCESS.ADMIN, // Downgrade OWNER to ADMIN
|
||||
access: ACCOUNT_ACCESS.ADMIN // Downgrade OWNER to ADMIN
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -230,49 +262,57 @@ export default class AccountService {
|
||||
where: {
|
||||
user_id_account_id: {
|
||||
user_id: user_id,
|
||||
account_id: account_id,
|
||||
account_id: account_id
|
||||
}
|
||||
},
|
||||
data: {
|
||||
access: ACCOUNT_ACCESS.OWNER,
|
||||
},
|
||||
access: ACCOUNT_ACCESS.OWNER
|
||||
}
|
||||
});
|
||||
|
||||
// return the full membership list because 2 members have changed.
|
||||
return prisma_client.membership.findMany({
|
||||
return prisma_client.membership.findMany({
|
||||
where: { account_id },
|
||||
...membershipWithUser
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// Upgrade access of a membership. Cannot use this method to upgrade to or downgrade from OWNER access
|
||||
async changeUserAccessWithinAccount(user_id: number, account_id: number, access: ACCOUNT_ACCESS) {
|
||||
async changeUserAccessWithinAccount(
|
||||
user_id: number,
|
||||
account_id: number,
|
||||
access: ACCOUNT_ACCESS
|
||||
) {
|
||||
if (access === ACCOUNT_ACCESS.OWNER) {
|
||||
throw new Error('UNABLE TO UPDATE MEMBERSHIP: use claimOwnershipOfAccount method to change ownership');
|
||||
throw new Error(
|
||||
'UNABLE TO UPDATE MEMBERSHIP: use claimOwnershipOfAccount method to change ownership'
|
||||
);
|
||||
}
|
||||
|
||||
const membership = await prisma_client.membership.findUniqueOrThrow({
|
||||
where: {
|
||||
user_id_account_id: {
|
||||
user_id: user_id,
|
||||
account_id: account_id,
|
||||
account_id: account_id
|
||||
}
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
if (membership.access === ACCOUNT_ACCESS.OWNER) {
|
||||
throw new Error('UNABLE TO UPDATE MEMBERSHIP: use claimOwnershipOfAccount method to change ownership');
|
||||
throw new Error(
|
||||
'UNABLE TO UPDATE MEMBERSHIP: use claimOwnershipOfAccount method to change ownership'
|
||||
);
|
||||
}
|
||||
|
||||
return prisma_client.membership.update({
|
||||
where: {
|
||||
user_id_account_id: {
|
||||
user_id: user_id,
|
||||
account_id: account_id,
|
||||
account_id: account_id
|
||||
}
|
||||
},
|
||||
data: {
|
||||
access: access,
|
||||
access: access
|
||||
},
|
||||
include: {
|
||||
account: true
|
||||
@@ -301,40 +341,48 @@ export default class AccountService {
|
||||
}
|
||||
*/
|
||||
|
||||
async getAccountWithPeriodRollover (account_id: number){
|
||||
const account = await prisma_client.account.findFirstOrThrow({
|
||||
async getAccountWithPeriodRollover(account_id: number) {
|
||||
const account = await prisma_client.account.findFirstOrThrow({
|
||||
where: { id: account_id }
|
||||
});
|
||||
|
||||
if(account.plan_name === config.initialPlanName && account.current_period_ends < new Date()){
|
||||
if (
|
||||
account.plan_name === config.initialPlanName &&
|
||||
account.current_period_ends < new Date()
|
||||
) {
|
||||
return await prisma_client.account.update({
|
||||
where: { id: account.id },
|
||||
data: {
|
||||
current_period_ends: UtilService.addMonths(account.current_period_ends,1),
|
||||
current_period_ends: UtilService.addMonths(
|
||||
account.current_period_ends,
|
||||
1
|
||||
),
|
||||
// reset anything that is affected by the rollover
|
||||
ai_gen_count: 0,
|
||||
},
|
||||
ai_gen_count: 0
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
return account;
|
||||
}
|
||||
|
||||
async checkAIGenCount(account_id: number){
|
||||
const account = await this.getAccountWithPeriodRollover(account_id);
|
||||
|
||||
if(account.ai_gen_count >= account.ai_gen_max_pm){
|
||||
throw new AccountLimitError('Monthly AI gen limit reached, no new AI Generations can be made');
|
||||
}
|
||||
|
||||
return account;
|
||||
}
|
||||
|
||||
async incrementAIGenCount (account: any){
|
||||
async checkAIGenCount(account_id: number) {
|
||||
const account = await this.getAccountWithPeriodRollover(account_id);
|
||||
|
||||
if (account.ai_gen_count >= account.ai_gen_max_pm) {
|
||||
throw new AccountLimitError(
|
||||
'Monthly AI gen limit reached, no new AI Generations can be made'
|
||||
);
|
||||
}
|
||||
|
||||
return account;
|
||||
}
|
||||
|
||||
async incrementAIGenCount(account: any) {
|
||||
return await prisma_client.account.update({
|
||||
where: { id: account.id },
|
||||
data: {
|
||||
ai_gen_count: account.ai_gen_count + 1,
|
||||
ai_gen_count: account.ai_gen_count + 1
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -7,28 +7,36 @@ import generator from 'generate-password-ts';
|
||||
const config = useRuntimeConfig();
|
||||
|
||||
export default class AuthService {
|
||||
async getFullUserBySupabaseId(supabase_uid: string): Promise<FullDBUser | null> {
|
||||
return prisma_client.user.findFirst({
|
||||
where: { supabase_uid },
|
||||
async getFullUserBySupabaseId(
|
||||
supabase_uid: string
|
||||
): Promise<FullDBUser | null> {
|
||||
return prisma_client.user.findFirst({
|
||||
where: { supabase_uid },
|
||||
...fullDBUser
|
||||
});
|
||||
}
|
||||
|
||||
async getUserById(user_id: number): Promise<FullDBUser | null> {
|
||||
return prisma_client.user.findFirstOrThrow({
|
||||
where: { id: user_id },
|
||||
...fullDBUser
|
||||
return prisma_client.user.findFirstOrThrow({
|
||||
where: { id: user_id },
|
||||
...fullDBUser
|
||||
});
|
||||
}
|
||||
|
||||
async createUser( supabase_uid: string, display_name: string, email: string ): Promise<FullDBUser | null> {
|
||||
const trialPlan = await prisma_client.plan.findFirstOrThrow({ where: { name: config.initialPlanName}});
|
||||
async createUser(
|
||||
supabase_uid: string,
|
||||
display_name: string,
|
||||
email: string
|
||||
): Promise<FullDBUser | null> {
|
||||
const trialPlan = await prisma_client.plan.findFirstOrThrow({
|
||||
where: { name: config.initialPlanName }
|
||||
});
|
||||
const join_password: string = generator.generate({
|
||||
length: 10,
|
||||
numbers: true
|
||||
});
|
||||
return prisma_client.user.create({
|
||||
data:{
|
||||
data: {
|
||||
supabase_uid: supabase_uid,
|
||||
display_name: display_name,
|
||||
email: email,
|
||||
@@ -37,13 +45,16 @@ export default class AuthService {
|
||||
account: {
|
||||
create: {
|
||||
name: display_name,
|
||||
current_period_ends: UtilService.addMonths(new Date(), config.initialPlanActiveMonths),
|
||||
plan_id: trialPlan.id,
|
||||
current_period_ends: UtilService.addMonths(
|
||||
new Date(),
|
||||
config.initialPlanActiveMonths
|
||||
),
|
||||
plan_id: trialPlan.id,
|
||||
features: trialPlan.features,
|
||||
max_notes: trialPlan.max_notes,
|
||||
max_members: trialPlan.max_members,
|
||||
plan_name: trialPlan.name,
|
||||
join_password: join_password,
|
||||
join_password: join_password
|
||||
}
|
||||
},
|
||||
access: ACCOUNT_ACCESS.OWNER
|
||||
@@ -55,7 +66,7 @@ export default class AuthService {
|
||||
}
|
||||
|
||||
async deleteUser(user_id: number): Promise<FullDBUser> {
|
||||
return prisma_client.user.delete({
|
||||
return prisma_client.user.delete({
|
||||
where: { id: user_id },
|
||||
...fullDBUser
|
||||
});
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
export class AccountLimitError extends Error {
|
||||
constructor(message: string) {
|
||||
super(message);
|
||||
Object.setPrototypeOf(this, AccountLimitError.prototype);
|
||||
super(message);
|
||||
Object.setPrototypeOf(this, AccountLimitError.prototype);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,17 +16,19 @@ export default class NotesService {
|
||||
return prisma_client.note.findMany({ where: { account_id } });
|
||||
}
|
||||
|
||||
async createNote( account_id: number, note_text: string ) {
|
||||
async createNote(account_id: number, note_text: string) {
|
||||
const account = await prisma_client.account.findFirstOrThrow({
|
||||
where: { id: account_id},
|
||||
include: { notes: true}
|
||||
where: { id: account_id },
|
||||
include: { notes: true }
|
||||
});
|
||||
|
||||
if(account.notes.length>= account.max_notes){
|
||||
throw new AccountLimitError('Note Limit reached, no new notes can be added');
|
||||
if (account.notes.length >= account.max_notes) {
|
||||
throw new AccountLimitError(
|
||||
'Note Limit reached, no new notes can be added'
|
||||
);
|
||||
}
|
||||
|
||||
return prisma_client.note.create({ data: { account_id, note_text }});
|
||||
|
||||
return prisma_client.note.create({ data: { account_id, note_text } });
|
||||
}
|
||||
|
||||
async updateNote(id: number, note_text: string) {
|
||||
@@ -44,14 +46,14 @@ export default class NotesService {
|
||||
const prompt = `
|
||||
Write an interesting short note about ${userPrompt}.
|
||||
Restrict the note to a single paragraph.
|
||||
`
|
||||
`;
|
||||
const completion = await openai.createCompletion({
|
||||
model: "text-davinci-003",
|
||||
model: 'text-davinci-003',
|
||||
prompt,
|
||||
temperature: 0.6,
|
||||
stop: "\n\n",
|
||||
stop: '\n\n',
|
||||
max_tokens: 1000,
|
||||
n: 1,
|
||||
n: 1
|
||||
});
|
||||
|
||||
await accountService.incrementAIGenCount(account);
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { Configuration, OpenAIApi } from "openai";
|
||||
import { Configuration, OpenAIApi } from 'openai';
|
||||
|
||||
const config = useRuntimeConfig();
|
||||
|
||||
const configuration = new Configuration({
|
||||
apiKey: config.openAIKey,
|
||||
apiKey: config.openAIKey
|
||||
});
|
||||
|
||||
export const openai = new OpenAIApi(configuration);
|
||||
export const openai = new OpenAIApi(configuration);
|
||||
|
||||
@@ -1,25 +1,39 @@
|
||||
import { Prisma } from '@prisma/client';
|
||||
|
||||
export const membershipWithAccount = Prisma.validator<Prisma.MembershipArgs>()({
|
||||
include: { account: true },
|
||||
})
|
||||
export type MembershipWithAccount = Prisma.MembershipGetPayload<typeof membershipWithAccount>
|
||||
include: { account: true }
|
||||
});
|
||||
export type MembershipWithAccount = Prisma.MembershipGetPayload<
|
||||
typeof membershipWithAccount
|
||||
>;
|
||||
|
||||
export const membershipWithUser = Prisma.validator<Prisma.MembershipArgs>()({
|
||||
include: { user: true },
|
||||
})
|
||||
export type MembershipWithUser = Prisma.MembershipGetPayload<typeof membershipWithUser>
|
||||
include: { user: true }
|
||||
});
|
||||
export type MembershipWithUser = Prisma.MembershipGetPayload<
|
||||
typeof membershipWithUser
|
||||
>;
|
||||
|
||||
export const fullDBUser = Prisma.validator<Prisma.UserArgs>()({
|
||||
include: { memberships: {include: {
|
||||
account: true
|
||||
}}}
|
||||
include: {
|
||||
memberships: {
|
||||
include: {
|
||||
account: true
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
export type FullDBUser = Prisma.UserGetPayload<typeof fullDBUser> //TODO - I wonder if this could be replaced by just user level info
|
||||
export type FullDBUser = Prisma.UserGetPayload<typeof fullDBUser>; //TODO - I wonder if this could be replaced by just user level info
|
||||
|
||||
export const accountWithMembers = Prisma.validator<Prisma.AccountArgs>()({
|
||||
include: { members: {include: {
|
||||
user: true
|
||||
}} }
|
||||
})
|
||||
export type AccountWithMembers = Prisma.AccountGetPayload<typeof accountWithMembers> //TODO - I wonder if this could just be a list of full memberships
|
||||
include: {
|
||||
members: {
|
||||
include: {
|
||||
user: true
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
export type AccountWithMembers = Prisma.AccountGetPayload<
|
||||
typeof accountWithMembers
|
||||
>; //TODO - I wonder if this could just be a list of full memberships
|
||||
|
||||
@@ -9,14 +9,14 @@ export class UtilService {
|
||||
}
|
||||
|
||||
public static getErrorMessage(error: unknown) {
|
||||
if (error instanceof Error) return error.message
|
||||
return String(error)
|
||||
if (error instanceof Error) return error.message;
|
||||
return String(error);
|
||||
}
|
||||
|
||||
public static stringifySafely(obj: any) {
|
||||
let cache: any[] = [];
|
||||
let str = JSON.stringify(obj, function(key, value) {
|
||||
if (typeof value === "object" && value !== null) {
|
||||
let str = JSON.stringify(obj, function (key, value) {
|
||||
if (typeof value === 'object' && value !== null) {
|
||||
if (cache.indexOf(value) !== -1) {
|
||||
// Circular reference found, discard key
|
||||
return;
|
||||
@@ -28,5 +28,5 @@ export class UtilService {
|
||||
});
|
||||
cache = []; // reset the cache
|
||||
return str;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user