mirror of
https://github.com/Sonny93/my-links.git
synced 2025-12-10 15:35:35 +00:00
feat: store avatar and user name
This commit is contained in:
@@ -0,0 +1,3 @@
|
|||||||
|
-- AlterTable
|
||||||
|
ALTER TABLE `user` ADD COLUMN `name` VARCHAR(191) NULL AFTER `email`,
|
||||||
|
ADD COLUMN `image` VARCHAR(191) NULL AFTER `name`;
|
||||||
@@ -12,9 +12,11 @@ datasource db {
|
|||||||
}
|
}
|
||||||
|
|
||||||
model User {
|
model User {
|
||||||
id Int @id @default(autoincrement())
|
id Int @id @default(autoincrement())
|
||||||
google_id String @unique
|
google_id String @unique
|
||||||
email String @unique
|
email String @unique
|
||||||
|
name String?
|
||||||
|
image String?
|
||||||
|
|
||||||
categories Category[]
|
categories Category[]
|
||||||
links Link[]
|
links Link[]
|
||||||
|
|||||||
@@ -1,11 +1,13 @@
|
|||||||
|
import { User } from 'next-auth';
|
||||||
import prisma from 'utils/prisma';
|
import prisma from 'utils/prisma';
|
||||||
import { Profile } from 'next-auth';
|
|
||||||
|
|
||||||
export default async function createUser(profile: Profile) {
|
export default async function createUser(user: User) {
|
||||||
return await prisma.user.create({
|
return await prisma.user.create({
|
||||||
data: {
|
data: {
|
||||||
email: profile.email,
|
email: user.email,
|
||||||
google_id: profile.sub,
|
google_id: user.id,
|
||||||
|
name: user.name,
|
||||||
|
image: user.image,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +0,0 @@
|
|||||||
import { Profile } from 'next-auth';
|
|
||||||
import prisma from 'utils/prisma';
|
|
||||||
|
|
||||||
export default async function getUserByProfileProvider(profile: Profile) {
|
|
||||||
return await prisma.user.findFirst({
|
|
||||||
where: {
|
|
||||||
google_id: profile.sub,
|
|
||||||
email: profile.email,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
11
src/lib/user/getUserByUserProvider.ts
Normal file
11
src/lib/user/getUserByUserProvider.ts
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
import { User } from 'next-auth';
|
||||||
|
import prisma from 'utils/prisma';
|
||||||
|
|
||||||
|
export default async function getUserByUserProvider(user: User) {
|
||||||
|
return await prisma.user.findFirst({
|
||||||
|
where: {
|
||||||
|
google_id: user.id,
|
||||||
|
email: user.email,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -1,15 +1,17 @@
|
|||||||
|
import { User } from 'next-auth';
|
||||||
import prisma from '../../utils/prisma';
|
import prisma from '../../utils/prisma';
|
||||||
import { Profile } from 'next-auth';
|
|
||||||
|
|
||||||
export default async function updateUser(profile: Profile) {
|
export default async function updateUser(user: User) {
|
||||||
return await prisma.user.update({
|
return await prisma.user.update({
|
||||||
where: {
|
where: {
|
||||||
email: profile.email,
|
email: user.email,
|
||||||
google_id: profile.sub,
|
google_id: user.id,
|
||||||
},
|
},
|
||||||
data: {
|
data: {
|
||||||
email: profile.email,
|
email: user.email,
|
||||||
google_id: profile.sub,
|
google_id: user.id,
|
||||||
|
name: user.name,
|
||||||
|
image: user.image,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,23 +1,17 @@
|
|||||||
import PATHS from 'constants/paths';
|
import PATHS from 'constants/paths';
|
||||||
import NextAuth, { NextAuthOptions, Profile } from 'next-auth';
|
|
||||||
import GoogleProvider from 'next-auth/providers/google';
|
|
||||||
import getUserByProfileProvider from 'lib/user/getUserByProfileProvider';
|
|
||||||
import createUser from 'lib/user/createUser';
|
import createUser from 'lib/user/createUser';
|
||||||
|
import getUserByUserProvider from 'lib/user/getUserByUserProvider';
|
||||||
import updateUser from 'lib/user/updateUser';
|
import updateUser from 'lib/user/updateUser';
|
||||||
|
import NextAuth, { NextAuthOptions, User } from 'next-auth';
|
||||||
|
import GoogleProvider from 'next-auth/providers/google';
|
||||||
import prisma from 'utils/prisma';
|
import prisma from 'utils/prisma';
|
||||||
|
|
||||||
const authLogger = (profile: Profile, ...args: any[]) =>
|
const authLogger = (user: User, ...args: any[]) =>
|
||||||
console.log(
|
console.log('[AUTH]', user.email, `(${user.name} - ${user.id})`, ...args);
|
||||||
'[AUTH]',
|
|
||||||
profile.email,
|
|
||||||
`(${profile.name} - ${profile.sub})`,
|
|
||||||
...args,
|
|
||||||
);
|
|
||||||
const redirectUser = (errorKey: string) => `${PATHS.LOGIN}?error=${errorKey}`;
|
const redirectUser = (errorKey: string) => `${PATHS.LOGIN}?error=${errorKey}`;
|
||||||
|
|
||||||
const checkProvider = (provider: string) => provider === 'google';
|
const checkProvider = (provider: string) => provider === 'google';
|
||||||
const checkAccountDataReceived = (profile: Profile) =>
|
const checkAccountDataReceived = (user: User) => !!user?.id && !!user?.email;
|
||||||
!!profile?.sub && !!profile?.email;
|
|
||||||
|
|
||||||
const cookieOptions = {
|
const cookieOptions = {
|
||||||
sameSite: 'None',
|
sameSite: 'None',
|
||||||
@@ -47,30 +41,30 @@ export const authOptions = {
|
|||||||
});
|
});
|
||||||
return user ? session : undefined;
|
return user ? session : undefined;
|
||||||
},
|
},
|
||||||
async signIn({ account: accountParam, profile }) {
|
async signIn({ account: accountParam, user }) {
|
||||||
if (!checkProvider(accountParam.provider)) {
|
if (!checkProvider(accountParam.provider)) {
|
||||||
authLogger(profile, 'rejected : forbidden provider');
|
authLogger(user, 'rejected : forbidden provider');
|
||||||
return redirectUser('AUTH_REQUIRED');
|
return redirectUser('AUTH_REQUIRED');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!checkAccountDataReceived(profile)) {
|
if (!checkAccountDataReceived(user)) {
|
||||||
authLogger(profile, 'rejected : missing data from provider', profile);
|
authLogger(user, 'rejected : missing data from provider', user);
|
||||||
return redirectUser('MISSING_PROVIDER_VALUES');
|
return redirectUser('MISSING_PROVIDER_VALUES');
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const isUserExists = await getUserByProfileProvider(profile);
|
const isUserExists = await getUserByUserProvider(user);
|
||||||
if (isUserExists) {
|
if (isUserExists) {
|
||||||
await updateUser(profile);
|
await updateUser(user);
|
||||||
authLogger(profile, 'success : user updated');
|
authLogger(user, 'success : user updated');
|
||||||
} else {
|
} else {
|
||||||
await createUser(profile);
|
await createUser(user);
|
||||||
authLogger(profile, 'success : user created');
|
authLogger(user, 'success : user created');
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
authLogger(profile, 'rejected : unhandled error');
|
authLogger(user, 'rejected : unhandled error');
|
||||||
console.error(error);
|
console.error(error);
|
||||||
return redirectUser('AUTH_ERROR');
|
return redirectUser('AUTH_ERROR');
|
||||||
}
|
}
|
||||||
|
|||||||
14
src/types/types.d.ts
vendored
14
src/types/types.d.ts
vendored
@@ -1,4 +1,5 @@
|
|||||||
import { Category, User } from '@prisma/client';
|
import { Category, User } from '@prisma/client';
|
||||||
|
import { Profile } from 'next-auth';
|
||||||
|
|
||||||
export type CategoryWithLinks = Category & {
|
export type CategoryWithLinks = Category & {
|
||||||
author: User;
|
author: User;
|
||||||
@@ -23,3 +24,16 @@ export interface Favicon {
|
|||||||
type: string;
|
type: string;
|
||||||
size: number;
|
size: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface GoogleProfile extends Profile {
|
||||||
|
iss: string;
|
||||||
|
azp: string;
|
||||||
|
aud: string;
|
||||||
|
email_verified: boolean;
|
||||||
|
at_hash: string;
|
||||||
|
picture: string;
|
||||||
|
given_name: string;
|
||||||
|
locale: string;
|
||||||
|
iat: number;
|
||||||
|
exp: number;
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user