add social links
This commit is contained in:
parent
c63592448a
commit
5d347acf88
@ -8,23 +8,37 @@ datasource db {
|
|||||||
url = env("POSTGRES_URI")
|
url = env("POSTGRES_URI")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
model SocialLink {
|
||||||
|
id String @id @default(uuid())
|
||||||
|
title String
|
||||||
|
url String
|
||||||
|
position Int
|
||||||
|
user User? @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||||
|
userId String? @map("user_id")
|
||||||
|
createdAt DateTime @default(now()) @map("created_at")
|
||||||
|
updatedAt DateTime @updatedAt @map("updated_at")
|
||||||
|
|
||||||
|
@@map("social_links")
|
||||||
|
}
|
||||||
|
|
||||||
model User {
|
model User {
|
||||||
id String @id @default(uuid())
|
id String @id @default(uuid())
|
||||||
email String @unique
|
email String @unique
|
||||||
password String
|
password String
|
||||||
name String @unique
|
name String @unique
|
||||||
displayName String @map("display_name")
|
displayName String @map("display_name")
|
||||||
avatar String?
|
avatar String?
|
||||||
bio String?
|
bio String?
|
||||||
token Token[]
|
token Token[]
|
||||||
isVerified Boolean @default(false) @map("is_verified")
|
isVerified Boolean @default(false) @map("is_verified")
|
||||||
isEmailVerified Boolean @default(false) @map("is_email_verified")
|
isEmailVerified Boolean @default(false) @map("is_email_verified")
|
||||||
isTotpEnabled Boolean @default(false) @map("is_totp_enabled")
|
isTotpEnabled Boolean @default(false) @map("is_totp_enabled")
|
||||||
isDeactivated Boolean @default(false) @map("is_deactivated")
|
isDeactivated Boolean @default(false) @map("is_deactivated")
|
||||||
deactivatedAt DateTime? @map("deactivated_at")
|
deactivatedAt DateTime? @map("deactivated_at")
|
||||||
totpSecret String? @map("totp_secret")
|
socialLink SocialLink[]
|
||||||
createdAt DateTime @default(now()) @map("created_at")
|
totpSecret String? @map("totp_secret")
|
||||||
updatedAt DateTime @updatedAt @map("updated_at")
|
createdAt DateTime @default(now()) @map("created_at")
|
||||||
|
updatedAt DateTime @updatedAt @map("updated_at")
|
||||||
|
|
||||||
@@map("users")
|
@@map("users")
|
||||||
}
|
}
|
||||||
|
|||||||
@ -69,6 +69,7 @@ type Mutation {
|
|||||||
changeProfileAvatar(avatar: Upload!): Boolean!
|
changeProfileAvatar(avatar: Upload!): Boolean!
|
||||||
changeProfileInfo(data: ChangeProfileInfoInput!): UserModel!
|
changeProfileInfo(data: ChangeProfileInfoInput!): UserModel!
|
||||||
clearSessionCookie: Boolean!
|
clearSessionCookie: Boolean!
|
||||||
|
createSocialLink(data: SocialLinkInput!): SocialLinkModel!
|
||||||
createUser(data: CreateUserInput!): UserModel!
|
createUser(data: CreateUserInput!): UserModel!
|
||||||
deactivateAccount(data: DeactivateAccountInput!): AuthModel!
|
deactivateAccount(data: DeactivateAccountInput!): AuthModel!
|
||||||
disableTotp: Boolean!
|
disableTotp: Boolean!
|
||||||
@ -77,8 +78,11 @@ type Mutation {
|
|||||||
logoutUser: Boolean!
|
logoutUser: Boolean!
|
||||||
removeProfileAvatar: Boolean!
|
removeProfileAvatar: Boolean!
|
||||||
removeSession(id: String!): Boolean!
|
removeSession(id: String!): Boolean!
|
||||||
|
removeSocialLink(id: String!): Boolean!
|
||||||
|
reorderSocialLink(list: [SocialLinkOrderInput!]!): Boolean!
|
||||||
resetPassword(data: ResetPasswordInput!): Boolean!
|
resetPassword(data: ResetPasswordInput!): Boolean!
|
||||||
setNewPassword(data: NewPasswordInput!): Boolean!
|
setNewPassword(data: NewPasswordInput!): Boolean!
|
||||||
|
updateSocialLink(data: SocialLinkInput!, id: String!): SocialLinkModel!
|
||||||
verifyAccount(data: VerificationInput!): UserModel!
|
verifyAccount(data: VerificationInput!): UserModel!
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -92,6 +96,7 @@ type Query {
|
|||||||
findCurrentSession: SessionModel!
|
findCurrentSession: SessionModel!
|
||||||
findProfile: UserModel!
|
findProfile: UserModel!
|
||||||
findSessionsByUser: [SessionModel!]!
|
findSessionsByUser: [SessionModel!]!
|
||||||
|
findSocialLinks: [SocialLinkModel!]!
|
||||||
generateTotpSecret: TotpModel!
|
generateTotpSecret: TotpModel!
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -112,6 +117,26 @@ type SessionModel {
|
|||||||
userId: String!
|
userId: String!
|
||||||
}
|
}
|
||||||
|
|
||||||
|
input SocialLinkInput {
|
||||||
|
title: String!
|
||||||
|
url: String!
|
||||||
|
}
|
||||||
|
|
||||||
|
type SocialLinkModel {
|
||||||
|
createdAt: DateTime!
|
||||||
|
id: ID!
|
||||||
|
position: Float!
|
||||||
|
title: String!
|
||||||
|
updatedAt: DateTime!
|
||||||
|
url: String!
|
||||||
|
userId: ID!
|
||||||
|
}
|
||||||
|
|
||||||
|
input SocialLinkOrderInput {
|
||||||
|
id: String!
|
||||||
|
position: Float!
|
||||||
|
}
|
||||||
|
|
||||||
type TotpModel {
|
type TotpModel {
|
||||||
qrcodeUrl: String!
|
qrcodeUrl: String!
|
||||||
secret: String!
|
secret: String!
|
||||||
@ -134,6 +159,7 @@ type UserModel {
|
|||||||
isVerified: Boolean!
|
isVerified: Boolean!
|
||||||
name: String!
|
name: String!
|
||||||
password: String!
|
password: String!
|
||||||
|
socialLink: [SocialLinkModel!]!
|
||||||
totpSecret: String
|
totpSecret: String
|
||||||
updatedAt: DateTime!
|
updatedAt: DateTime!
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
import { SocialLinkModel } from '@/src/module/auth/profile/inputs/models/social-link.model';
|
||||||
import { Field, ID, ObjectType } from '@nestjs/graphql'
|
import { Field, ID, ObjectType } from '@nestjs/graphql'
|
||||||
import { User } from '@prisma/generated'
|
import { User } from '@prisma/generated'
|
||||||
|
|
||||||
@ -42,6 +43,9 @@ export class UserModel implements User {
|
|||||||
@Field(() => String, { nullable: true })
|
@Field(() => String, { nullable: true })
|
||||||
totpSecret: string
|
totpSecret: string
|
||||||
|
|
||||||
|
@Field(() => [SocialLinkModel])
|
||||||
|
socialLink: SocialLinkModel[]
|
||||||
|
|
||||||
@Field(() => Date)
|
@Field(() => Date)
|
||||||
createdAt: Date
|
createdAt: Date
|
||||||
|
|
||||||
|
|||||||
@ -0,0 +1,27 @@
|
|||||||
|
import { UserModel } from '@/src/module/auth/account/models/user.model'
|
||||||
|
import { Field, ID, ObjectType } from '@nestjs/graphql'
|
||||||
|
import { SocialLink } from '@prisma/generated'
|
||||||
|
|
||||||
|
@ObjectType()
|
||||||
|
export class SocialLinkModel implements SocialLink {
|
||||||
|
@Field(() => ID)
|
||||||
|
id: string
|
||||||
|
|
||||||
|
@Field(() => ID)
|
||||||
|
userId: UserModel['id']
|
||||||
|
|
||||||
|
@Field(() => String)
|
||||||
|
title: string
|
||||||
|
|
||||||
|
@Field(() => String)
|
||||||
|
url: string
|
||||||
|
|
||||||
|
@Field(() => Number)
|
||||||
|
position: number
|
||||||
|
|
||||||
|
@Field(() => Date)
|
||||||
|
updatedAt: Date
|
||||||
|
|
||||||
|
@Field(() => Date)
|
||||||
|
createdAt: Date
|
||||||
|
}
|
||||||
29
backend/src/module/auth/profile/inputs/social-link.input.ts
Normal file
29
backend/src/module/auth/profile/inputs/social-link.input.ts
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
import { Field, InputType } from '@nestjs/graphql'
|
||||||
|
import { IsNotEmpty, IsNumber, IsString, IsUrl } from 'class-validator'
|
||||||
|
|
||||||
|
@InputType()
|
||||||
|
export class SocialLinkInput {
|
||||||
|
@Field(() => String)
|
||||||
|
@IsString()
|
||||||
|
@IsNotEmpty()
|
||||||
|
title: string
|
||||||
|
|
||||||
|
@Field(() => String)
|
||||||
|
@IsString()
|
||||||
|
@IsNotEmpty()
|
||||||
|
@IsUrl()
|
||||||
|
url: string
|
||||||
|
}
|
||||||
|
|
||||||
|
@InputType()
|
||||||
|
export class SocialLinkOrderInput {
|
||||||
|
@Field(() => String)
|
||||||
|
@IsString()
|
||||||
|
@IsNotEmpty()
|
||||||
|
id: string
|
||||||
|
|
||||||
|
@Field(() => Number)
|
||||||
|
@IsNumber()
|
||||||
|
@IsNotEmpty()
|
||||||
|
position: number
|
||||||
|
}
|
||||||
@ -1,9 +1,14 @@
|
|||||||
import { UserModel } from '@/src/module/auth/account/models/user.model'
|
import { UserModel } from '@/src/module/auth/account/models/user.model'
|
||||||
import { ChangeProfileInfoInput } from '@/src/module/auth/profile/inputs/change-profile-info.input'
|
import { ChangeProfileInfoInput } from '@/src/module/auth/profile/inputs/change-profile-info.input'
|
||||||
|
import { SocialLinkModel } from '@/src/module/auth/profile/inputs/models/social-link.model'
|
||||||
|
import {
|
||||||
|
SocialLinkInput,
|
||||||
|
SocialLinkOrderInput,
|
||||||
|
} from '@/src/module/auth/profile/inputs/social-link.input'
|
||||||
import { Authorization } from '@/src/shared/decorators/auth.decorator'
|
import { Authorization } from '@/src/shared/decorators/auth.decorator'
|
||||||
import { Authorized } from '@/src/shared/decorators/authorized.decorator'
|
import { Authorized } from '@/src/shared/decorators/authorized.decorator'
|
||||||
import { FileValidationPipe } from '@/src/shared/pipes/file-validation.pipe'
|
import { FileValidationPipe } from '@/src/shared/pipes/file-validation.pipe'
|
||||||
import { Args, Mutation, Resolver } from '@nestjs/graphql'
|
import { Args, Mutation, Query, Resolver } from '@nestjs/graphql'
|
||||||
import { ProfileService } from './profile.service'
|
import { ProfileService } from './profile.service'
|
||||||
import { User } from '@/prisma/generated'
|
import { User } from '@/prisma/generated'
|
||||||
import * as Upload from 'graphql-upload/Upload.js'
|
import * as Upload from 'graphql-upload/Upload.js'
|
||||||
@ -36,4 +41,44 @@ export class ProfileResolver {
|
|||||||
) {
|
) {
|
||||||
return this.profileService.changeInfo(user, input)
|
return this.profileService.changeInfo(user, input)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Authorization()
|
||||||
|
@Mutation(() => SocialLinkModel, { name: 'createSocialLink' })
|
||||||
|
public async createSocialLink(
|
||||||
|
@Authorized() user: User,
|
||||||
|
@Args('data') input: SocialLinkInput,
|
||||||
|
) {
|
||||||
|
return this.profileService.createSocialLink(user, input)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Authorization()
|
||||||
|
@Mutation(() => Boolean, { name: 'reorderSocialLink' })
|
||||||
|
public async reorderSocialLinks(
|
||||||
|
@Args('list', { type: () => [SocialLinkOrderInput] }) list: SocialLinkOrderInput[],
|
||||||
|
) {
|
||||||
|
return this.profileService.reorderSocialLinks(list)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Authorization()
|
||||||
|
@Mutation(() => SocialLinkModel, { name: 'updateSocialLink' })
|
||||||
|
public async updateSocialLink(
|
||||||
|
@Args('id') id: string,
|
||||||
|
@Args('data') input: SocialLinkInput,
|
||||||
|
) {
|
||||||
|
return this.profileService.updateSocialLink(id, input)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Authorization()
|
||||||
|
@Mutation(() => Boolean, { name: 'removeSocialLink' })
|
||||||
|
public async removeSocialLink(
|
||||||
|
@Args('id') id: string,
|
||||||
|
) {
|
||||||
|
return this.profileService.removeSocialLink(id)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Authorization()
|
||||||
|
@Query(() => [SocialLinkModel], { name: 'findSocialLinks' })
|
||||||
|
public async findSocialLink(@Authorized() user: User) {
|
||||||
|
return this.profileService.findSocialLink(user)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,9 +1,13 @@
|
|||||||
import { PrismaService } from '@/src/core/prisma/prisma.service'
|
import { PrismaService } from '@/src/core/prisma/prisma.service'
|
||||||
import { ChangeProfileInfoInput } from '@/src/module/auth/profile/inputs/change-profile-info.input'
|
import { ChangeProfileInfoInput } from '@/src/module/auth/profile/inputs/change-profile-info.input'
|
||||||
|
import {
|
||||||
|
SocialLinkInput,
|
||||||
|
SocialLinkOrderInput,
|
||||||
|
} from '@/src/module/auth/profile/inputs/social-link.input'
|
||||||
import { ConflictException, Injectable } from '@nestjs/common'
|
import { ConflictException, Injectable } from '@nestjs/common'
|
||||||
import sharp from 'sharp'
|
import sharp from 'sharp'
|
||||||
import { StorageService } from '../../libs/storage/storage.service'
|
import { StorageService } from '../../libs/storage/storage.service'
|
||||||
import { User } from '@/prisma/generated'
|
import { SocialLink, User } from '@/prisma/generated'
|
||||||
import * as Upload from 'graphql-upload/Upload.js'
|
import * as Upload from 'graphql-upload/Upload.js'
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
@ -72,4 +76,65 @@ export class ProfileService {
|
|||||||
data: { bio, displayName, name },
|
data: { bio, displayName, name },
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async createSocialLink(user: User, input: SocialLinkInput) {
|
||||||
|
const { title, url } = input
|
||||||
|
|
||||||
|
const lastSocialLink = await this.prismaService.socialLink.findFirst({
|
||||||
|
where: { userId: user.id },
|
||||||
|
orderBy: { position: 'desc' },
|
||||||
|
})
|
||||||
|
|
||||||
|
return this.prismaService.socialLink.create({
|
||||||
|
data: {
|
||||||
|
url,
|
||||||
|
title,
|
||||||
|
position: lastSocialLink ? lastSocialLink.position + 1 : 1,
|
||||||
|
user: {
|
||||||
|
connect: {
|
||||||
|
id: user.id,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
public async findSocialLink(user: User) {
|
||||||
|
return this.prismaService.socialLink.findMany({
|
||||||
|
where: { userId: user.id },
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
public async reorderSocialLinks(list: SocialLinkOrderInput[]) {
|
||||||
|
if (list.length === 0) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const updatePromises = list.map((socialLink) => {
|
||||||
|
return this.prismaService.socialLink.update({
|
||||||
|
where: { id: socialLink.id },
|
||||||
|
data: { position: Number(socialLink.position) },
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
await Promise.all(updatePromises)
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
public async updateSocialLink(id: SocialLink['id'], input: SocialLinkInput) {
|
||||||
|
const { title, url } = input
|
||||||
|
return this.prismaService.socialLink.update({
|
||||||
|
where: { id },
|
||||||
|
data: { title, url },
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
public async removeSocialLink(id: SocialLink['id']) {
|
||||||
|
await this.prismaService.socialLink.delete({
|
||||||
|
where: { id },
|
||||||
|
})
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user