chore: manually committing auth module to remoter
This commit is contained in:
22
packages/hoppscotch-backend/.vscode/settings.json
vendored
Normal file
22
packages/hoppscotch-backend/.vscode/settings.json
vendored
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
{
|
||||||
|
"workbench.colorCustomizations": {
|
||||||
|
"activityBar.activeBackground": "#93e6fc",
|
||||||
|
"activityBar.background": "#93e6fc",
|
||||||
|
"activityBar.foreground": "#15202b",
|
||||||
|
"activityBar.inactiveForeground": "#15202b99",
|
||||||
|
"activityBarBadge.background": "#fa45d4",
|
||||||
|
"activityBarBadge.foreground": "#15202b",
|
||||||
|
"commandCenter.border": "#15202b99",
|
||||||
|
"sash.hoverBorder": "#93e6fc",
|
||||||
|
"statusBar.background": "#61dafb",
|
||||||
|
"statusBar.foreground": "#15202b",
|
||||||
|
"statusBarItem.hoverBackground": "#2fcefa",
|
||||||
|
"statusBarItem.remoteBackground": "#61dafb",
|
||||||
|
"statusBarItem.remoteForeground": "#15202b",
|
||||||
|
"titleBar.activeBackground": "#61dafb",
|
||||||
|
"titleBar.activeForeground": "#15202b",
|
||||||
|
"titleBar.inactiveBackground": "#61dafb99",
|
||||||
|
"titleBar.inactiveForeground": "#15202b99"
|
||||||
|
},
|
||||||
|
"peacock.remoteColor": "#61dafb"
|
||||||
|
}
|
||||||
@@ -0,0 +1,158 @@
|
|||||||
|
-- CreateEnum
|
||||||
|
CREATE TYPE "TeamMemberRole" AS ENUM ('OWNER', 'VIEWER', 'EDITOR');
|
||||||
|
|
||||||
|
-- CreateTable
|
||||||
|
CREATE TABLE "Team" (
|
||||||
|
"id" TEXT NOT NULL,
|
||||||
|
"name" TEXT NOT NULL,
|
||||||
|
|
||||||
|
CONSTRAINT "Team_pkey" PRIMARY KEY ("id")
|
||||||
|
);
|
||||||
|
|
||||||
|
-- CreateTable
|
||||||
|
CREATE TABLE "TeamMember" (
|
||||||
|
"id" TEXT NOT NULL,
|
||||||
|
"role" "TeamMemberRole" NOT NULL,
|
||||||
|
"userUid" TEXT NOT NULL,
|
||||||
|
"teamID" TEXT NOT NULL,
|
||||||
|
|
||||||
|
CONSTRAINT "TeamMember_pkey" PRIMARY KEY ("id")
|
||||||
|
);
|
||||||
|
|
||||||
|
-- CreateTable
|
||||||
|
CREATE TABLE "TeamInvitation" (
|
||||||
|
"id" TEXT NOT NULL,
|
||||||
|
"teamID" TEXT NOT NULL,
|
||||||
|
"creatorUid" TEXT NOT NULL,
|
||||||
|
"inviteeEmail" TEXT NOT NULL,
|
||||||
|
"inviteeRole" "TeamMemberRole" NOT NULL,
|
||||||
|
|
||||||
|
CONSTRAINT "TeamInvitation_pkey" PRIMARY KEY ("id")
|
||||||
|
);
|
||||||
|
|
||||||
|
-- CreateTable
|
||||||
|
CREATE TABLE "TeamCollection" (
|
||||||
|
"id" TEXT NOT NULL,
|
||||||
|
"parentID" TEXT,
|
||||||
|
"teamID" TEXT NOT NULL,
|
||||||
|
"title" TEXT NOT NULL,
|
||||||
|
|
||||||
|
CONSTRAINT "TeamCollection_pkey" PRIMARY KEY ("id")
|
||||||
|
);
|
||||||
|
|
||||||
|
-- CreateTable
|
||||||
|
CREATE TABLE "TeamRequest" (
|
||||||
|
"id" TEXT NOT NULL,
|
||||||
|
"collectionID" TEXT NOT NULL,
|
||||||
|
"teamID" TEXT NOT NULL,
|
||||||
|
"title" TEXT NOT NULL,
|
||||||
|
"request" JSONB NOT NULL,
|
||||||
|
|
||||||
|
CONSTRAINT "TeamRequest_pkey" PRIMARY KEY ("id")
|
||||||
|
);
|
||||||
|
|
||||||
|
-- CreateTable
|
||||||
|
CREATE TABLE "Shortcode" (
|
||||||
|
"id" TEXT NOT NULL,
|
||||||
|
"request" JSONB NOT NULL,
|
||||||
|
"creatorUid" TEXT,
|
||||||
|
"createdOn" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
|
||||||
|
CONSTRAINT "Shortcode_pkey" PRIMARY KEY ("id")
|
||||||
|
);
|
||||||
|
|
||||||
|
-- CreateTable
|
||||||
|
CREATE TABLE "TeamEnvironment" (
|
||||||
|
"id" TEXT NOT NULL,
|
||||||
|
"teamID" TEXT NOT NULL,
|
||||||
|
"name" TEXT NOT NULL,
|
||||||
|
"variables" JSONB NOT NULL,
|
||||||
|
|
||||||
|
CONSTRAINT "TeamEnvironment_pkey" PRIMARY KEY ("id")
|
||||||
|
);
|
||||||
|
|
||||||
|
-- CreateTable
|
||||||
|
CREATE TABLE "User" (
|
||||||
|
"id" TEXT NOT NULL,
|
||||||
|
"name" TEXT,
|
||||||
|
"email" TEXT,
|
||||||
|
"image" TEXT,
|
||||||
|
"isAdmin" BOOLEAN NOT NULL DEFAULT false,
|
||||||
|
"refreshToken" TEXT,
|
||||||
|
"createdOn" TIMESTAMPTZ(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
|
||||||
|
CONSTRAINT "User_pkey" PRIMARY KEY ("id")
|
||||||
|
);
|
||||||
|
|
||||||
|
-- CreateTable
|
||||||
|
CREATE TABLE "Account" (
|
||||||
|
"id" TEXT NOT NULL,
|
||||||
|
"userId" TEXT NOT NULL,
|
||||||
|
"provider" TEXT NOT NULL,
|
||||||
|
"providerAccountId" TEXT NOT NULL,
|
||||||
|
"providerRefreshToken" TEXT,
|
||||||
|
"providerAccessToken" TEXT,
|
||||||
|
"providerScope" TEXT,
|
||||||
|
"loggedIn" TIMESTAMPTZ(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
|
||||||
|
CONSTRAINT "Account_pkey" PRIMARY KEY ("id")
|
||||||
|
);
|
||||||
|
|
||||||
|
-- CreateTable
|
||||||
|
CREATE TABLE "PasswordlessVerification" (
|
||||||
|
"deviceIdentifier" TEXT NOT NULL,
|
||||||
|
"token" TEXT NOT NULL,
|
||||||
|
"userUid" TEXT NOT NULL,
|
||||||
|
"expiresOn" TIMESTAMPTZ(3) NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE UNIQUE INDEX "TeamMember_teamID_userUid_key" ON "TeamMember"("teamID", "userUid");
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE INDEX "TeamInvitation_teamID_idx" ON "TeamInvitation"("teamID");
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE UNIQUE INDEX "TeamInvitation_teamID_inviteeEmail_key" ON "TeamInvitation"("teamID", "inviteeEmail");
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE UNIQUE INDEX "Shortcode_id_creatorUid_key" ON "Shortcode"("id", "creatorUid");
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE UNIQUE INDEX "User_email_key" ON "User"("email");
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE UNIQUE INDEX "Account_provider_providerAccountId_key" ON "Account"("provider", "providerAccountId");
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE UNIQUE INDEX "PasswordlessVerification_token_key" ON "PasswordlessVerification"("token");
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE UNIQUE INDEX "PasswordlessVerification_deviceIdentifier_token_key" ON "PasswordlessVerification"("deviceIdentifier", "token");
|
||||||
|
|
||||||
|
-- AddForeignKey
|
||||||
|
ALTER TABLE "TeamMember" ADD CONSTRAINT "TeamMember_teamID_fkey" FOREIGN KEY ("teamID") REFERENCES "Team"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||||
|
|
||||||
|
-- AddForeignKey
|
||||||
|
ALTER TABLE "TeamInvitation" ADD CONSTRAINT "TeamInvitation_teamID_fkey" FOREIGN KEY ("teamID") REFERENCES "Team"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||||
|
|
||||||
|
-- AddForeignKey
|
||||||
|
ALTER TABLE "TeamCollection" ADD CONSTRAINT "TeamCollection_parentID_fkey" FOREIGN KEY ("parentID") REFERENCES "TeamCollection"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||||
|
|
||||||
|
-- AddForeignKey
|
||||||
|
ALTER TABLE "TeamCollection" ADD CONSTRAINT "TeamCollection_teamID_fkey" FOREIGN KEY ("teamID") REFERENCES "Team"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||||
|
|
||||||
|
-- AddForeignKey
|
||||||
|
ALTER TABLE "TeamRequest" ADD CONSTRAINT "TeamRequest_collectionID_fkey" FOREIGN KEY ("collectionID") REFERENCES "TeamCollection"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||||
|
|
||||||
|
-- AddForeignKey
|
||||||
|
ALTER TABLE "TeamRequest" ADD CONSTRAINT "TeamRequest_teamID_fkey" FOREIGN KEY ("teamID") REFERENCES "Team"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||||
|
|
||||||
|
-- AddForeignKey
|
||||||
|
ALTER TABLE "TeamEnvironment" ADD CONSTRAINT "TeamEnvironment_teamID_fkey" FOREIGN KEY ("teamID") REFERENCES "Team"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||||
|
|
||||||
|
-- AddForeignKey
|
||||||
|
ALTER TABLE "Account" ADD CONSTRAINT "Account_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||||
|
|
||||||
|
-- AddForeignKey
|
||||||
|
ALTER TABLE "PasswordlessVerification" ADD CONSTRAINT "PasswordlessVerification_userUid_fkey" FOREIGN KEY ("userUid") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
# Please do not edit this file manually
|
||||||
|
# It should be added in your version-control system (i.e. Git)
|
||||||
|
provider = "postgresql"
|
||||||
14
packages/hoppscotch-backend/src/auth/auth.controller.ts
Normal file
14
packages/hoppscotch-backend/src/auth/auth.controller.ts
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
import { Body, Controller, Get, Post } from '@nestjs/common';
|
||||||
|
import { AuthService } from './auth.service';
|
||||||
|
import { signInMagicDto } from './dto/signin-magic.dto';
|
||||||
|
import { verifyMagicDto } from './dto/verify-magic.dto';
|
||||||
|
|
||||||
|
@Controller('auth')
|
||||||
|
export class AuthController {
|
||||||
|
constructor(private authService: AuthService) {}
|
||||||
|
|
||||||
|
@Post('signin')
|
||||||
|
async signIn(@Body() authData: signInMagicDto) {
|
||||||
|
return this.authService.signIn(authData.email);
|
||||||
|
}
|
||||||
|
}
|
||||||
13
packages/hoppscotch-backend/src/auth/auth.module.ts
Normal file
13
packages/hoppscotch-backend/src/auth/auth.module.ts
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
import { Module } from '@nestjs/common';
|
||||||
|
import { AuthService } from './auth.service';
|
||||||
|
import { AuthController } from './auth.controller';
|
||||||
|
import { UserModule } from 'src/user/user.module';
|
||||||
|
import { MailerModule } from 'src/mailer/mailer.module';
|
||||||
|
import { PrismaModule } from 'src/prisma/prisma.module';
|
||||||
|
|
||||||
|
@Module({
|
||||||
|
imports: [PrismaModule, UserModule, MailerModule],
|
||||||
|
providers: [AuthService],
|
||||||
|
controllers: [AuthController],
|
||||||
|
})
|
||||||
|
export class AuthModule {}
|
||||||
18
packages/hoppscotch-backend/src/auth/auth.service.spec.ts
Normal file
18
packages/hoppscotch-backend/src/auth/auth.service.spec.ts
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
import { Test, TestingModule } from '@nestjs/testing';
|
||||||
|
import { AuthService } from './auth.service';
|
||||||
|
|
||||||
|
describe('AuthService', () => {
|
||||||
|
let service: AuthService;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
const module: TestingModule = await Test.createTestingModule({
|
||||||
|
providers: [AuthService],
|
||||||
|
}).compile();
|
||||||
|
|
||||||
|
service = module.get<AuthService>(AuthService);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be defined', () => {
|
||||||
|
expect(service).toBeDefined();
|
||||||
|
});
|
||||||
|
});
|
||||||
68
packages/hoppscotch-backend/src/auth/auth.service.ts
Normal file
68
packages/hoppscotch-backend/src/auth/auth.service.ts
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
import { HttpException, HttpStatus, Injectable } from '@nestjs/common';
|
||||||
|
import { MailerService } from 'src/mailer/mailer.service';
|
||||||
|
import { PrismaService } from 'src/prisma/prisma.service';
|
||||||
|
import { User } from 'src/user/user.model';
|
||||||
|
import { UserService } from 'src/user/user.service';
|
||||||
|
import { verifyMagicDto } from './dto/verify-magic.dto';
|
||||||
|
import { DateTime } from 'luxon';
|
||||||
|
import * as argon2 from 'argon2';
|
||||||
|
import bcrypt from 'bcrypt';
|
||||||
|
import * as O from 'fp-ts/Option';
|
||||||
|
import * as E from 'fp-ts/Either';
|
||||||
|
import * as TE from 'fp-ts/TaskEither';
|
||||||
|
import { PasswordlessToken } from 'src/types/Passwordless';
|
||||||
|
import { EmailCodec } from 'src/types/Email';
|
||||||
|
import { INVALID_EMAIL } from 'src/errors';
|
||||||
|
import { pipe } from 'fp-ts/lib/function';
|
||||||
|
import { validateEmail } from 'src/utils';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class AuthService {
|
||||||
|
constructor(
|
||||||
|
private usersService: UserService,
|
||||||
|
private prismaService: PrismaService,
|
||||||
|
private readonly mailerService: MailerService,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
// generate Id and token for email magiclink
|
||||||
|
private async generatePasswordlessTokens(user: User) {
|
||||||
|
const salt = await bcrypt.genSalt(10);
|
||||||
|
const expiresOn = DateTime.now().plus({ hours: 3 }).toISO().toString();
|
||||||
|
|
||||||
|
const idToken: PasswordlessToken =
|
||||||
|
await this.prismaService.passwordlessVerification.create({
|
||||||
|
data: {
|
||||||
|
expiresOn: expiresOn,
|
||||||
|
deviceIdentifier: salt,
|
||||||
|
userUid: user.id,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return idToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
async signIn(email: string) {
|
||||||
|
if (!validateEmail(email)) return E.left(INVALID_EMAIL);
|
||||||
|
|
||||||
|
let user: User;
|
||||||
|
const queriedUser = await this.usersService.findUserByEmail(email);
|
||||||
|
|
||||||
|
if (O.isNone(queriedUser)) {
|
||||||
|
user = await this.usersService.createUser(email);
|
||||||
|
} else {
|
||||||
|
user = queriedUser.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
const generatedTokens = await this.generatePasswordlessTokens(user);
|
||||||
|
|
||||||
|
this.mailerService.sendMail(email, {
|
||||||
|
template: 'code-your-own',
|
||||||
|
variables: {
|
||||||
|
inviteeEmail: email,
|
||||||
|
magicLink: `${process.env.APP_DOMAIN}/magic-link?token=${generatedTokens.token}`,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return { deviceIdentifier: generatedTokens.deviceIdentifier };
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
export class refreshTokensDto {
|
||||||
|
refresh_token: string;
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
export class signInMagicDto {
|
||||||
|
email: string;
|
||||||
|
}
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
export class verifyMagicDto {
|
||||||
|
identifier: string;
|
||||||
|
token: string;
|
||||||
|
}
|
||||||
16
packages/hoppscotch-backend/src/mailer/MailDescriptions.ts
Normal file
16
packages/hoppscotch-backend/src/mailer/MailDescriptions.ts
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
export type MailDescription = {
|
||||||
|
template: 'team-invitation';
|
||||||
|
variables: {
|
||||||
|
invitee: string;
|
||||||
|
invite_team_name: string;
|
||||||
|
action_url: string;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export type UserMagicLinkMailDescription = {
|
||||||
|
template: 'code-your-own'; //Alias of template in Postmark, change this to env variable
|
||||||
|
variables: {
|
||||||
|
inviteeEmail: string;
|
||||||
|
magicLink: string;
|
||||||
|
};
|
||||||
|
};
|
||||||
8
packages/hoppscotch-backend/src/mailer/mailer.module.ts
Normal file
8
packages/hoppscotch-backend/src/mailer/mailer.module.ts
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
import { Module } from '@nestjs/common';
|
||||||
|
import { MailerService } from './mailer.service';
|
||||||
|
|
||||||
|
@Module({
|
||||||
|
providers: [MailerService],
|
||||||
|
exports: [MailerService],
|
||||||
|
})
|
||||||
|
export class MailerModule {}
|
||||||
40
packages/hoppscotch-backend/src/mailer/mailer.service.ts
Normal file
40
packages/hoppscotch-backend/src/mailer/mailer.service.ts
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
import { Injectable, OnModuleInit } from '@nestjs/common';
|
||||||
|
import { Email } from 'src/types/Email';
|
||||||
|
import {
|
||||||
|
MailDescription,
|
||||||
|
UserMagicLinkMailDescription,
|
||||||
|
} from './MailDescriptions';
|
||||||
|
import * as postmark from 'postmark';
|
||||||
|
import { throwErr } from 'src/utils';
|
||||||
|
import * as TE from 'fp-ts/TaskEither';
|
||||||
|
import { EMAIL_FAILED } from 'src/errors';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class MailerService implements OnModuleInit {
|
||||||
|
client: postmark.ServerClient;
|
||||||
|
|
||||||
|
onModuleInit() {
|
||||||
|
this.client = new postmark.ServerClient(
|
||||||
|
process.env.POSTMARK_SERVER_TOKEN ||
|
||||||
|
throwErr('No Postmark Server Token defined'),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
sendMail(
|
||||||
|
to: string,
|
||||||
|
mailDesc: MailDescription | UserMagicLinkMailDescription,
|
||||||
|
) {
|
||||||
|
return TE.tryCatch(
|
||||||
|
() =>
|
||||||
|
this.client.sendEmailWithTemplate({
|
||||||
|
To: to,
|
||||||
|
From:
|
||||||
|
process.env.POSTMARK_SENDER_EMAIL ||
|
||||||
|
throwErr('No Postmark Sender Email defined'),
|
||||||
|
TemplateAlias: mailDesc.template,
|
||||||
|
TemplateModel: mailDesc.variables,
|
||||||
|
}),
|
||||||
|
() => EMAIL_FAILED,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
17
packages/hoppscotch-backend/src/types/Email.ts
Normal file
17
packages/hoppscotch-backend/src/types/Email.ts
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
import * as t from 'io-ts';
|
||||||
|
|
||||||
|
interface EmailBrand {
|
||||||
|
readonly Email: unique symbol;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The validation branded type for an email
|
||||||
|
export const EmailCodec = t.brand(
|
||||||
|
t.string,
|
||||||
|
(x): x is t.Branded<string, EmailBrand> =>
|
||||||
|
/^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/.test(
|
||||||
|
x,
|
||||||
|
),
|
||||||
|
'Email',
|
||||||
|
);
|
||||||
|
|
||||||
|
export type Email = t.TypeOf<typeof EmailCodec>;
|
||||||
9
packages/hoppscotch-backend/src/types/Passwordless.ts
Normal file
9
packages/hoppscotch-backend/src/types/Passwordless.ts
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
import { User } from 'src/user/user.model';
|
||||||
|
|
||||||
|
export interface PasswordlessToken {
|
||||||
|
deviceIdentifier: string;
|
||||||
|
token: string;
|
||||||
|
userUid: string;
|
||||||
|
user?: User;
|
||||||
|
expiresOn: Date;
|
||||||
|
}
|
||||||
72
packages/hoppscotch-backend/src/user/user.service.ts
Normal file
72
packages/hoppscotch-backend/src/user/user.service.ts
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
import { Injectable } from '@nestjs/common';
|
||||||
|
import { PrismaService } from 'src/prisma/prisma.service';
|
||||||
|
import * as O from 'fp-ts/Option';
|
||||||
|
import { User } from './user.model';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class UserService {
|
||||||
|
constructor(private prisma: PrismaService) {}
|
||||||
|
|
||||||
|
async findUserByEmail(email: string) {
|
||||||
|
try {
|
||||||
|
const user: User = await this.prisma.user.findUniqueOrThrow({
|
||||||
|
where: {
|
||||||
|
email: email,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
return O.some(user);
|
||||||
|
} catch (error) {
|
||||||
|
return O.none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async createUser(email: string) {
|
||||||
|
const createdUser = await this.prisma.user.create({
|
||||||
|
data: {
|
||||||
|
email: email,
|
||||||
|
accounts: {
|
||||||
|
create: {
|
||||||
|
provider: 'magic',
|
||||||
|
providerAccountId: email,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return createdUser;
|
||||||
|
}
|
||||||
|
|
||||||
|
async createUserSSO(accessToken, refreshToken, profile) {
|
||||||
|
const createdUser = await this.prisma.user.create({
|
||||||
|
data: {
|
||||||
|
name: profile.displayName,
|
||||||
|
email: profile.emails[0].value,
|
||||||
|
image: profile.photos[0].value,
|
||||||
|
accounts: {
|
||||||
|
create: {
|
||||||
|
provider: profile.provider,
|
||||||
|
providerAccountId: profile.id,
|
||||||
|
providerRefreshToken: refreshToken,
|
||||||
|
providerAccessToken: accessToken,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return createdUser;
|
||||||
|
}
|
||||||
|
|
||||||
|
async createProviderAccount(user, accessToken, refreshToken, profile) {
|
||||||
|
const createdProvider = await this.prisma.account.create({
|
||||||
|
data: {
|
||||||
|
userId: user.id,
|
||||||
|
provider: profile.provider,
|
||||||
|
providerAccountId: profile.id,
|
||||||
|
providerRefreshToken: refreshToken ? refreshToken : null,
|
||||||
|
providerAccessToken: accessToken ? accessToken : null,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return createdProvider;
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user