Social handles CRUD (admin side, nothing user-facing)
This commit is contained in:
12
api/db/migrations/20240819213158_social/migration.sql
Normal file
12
api/db/migrations/20240819213158_social/migration.sql
Normal file
@ -0,0 +1,12 @@
|
||||
-- CreateEnum
|
||||
CREATE TYPE "Handle" AS ENUM ('x', 'threads', 'instagram', 'facebook', 'tiktok', 'youtube', 'linkedin', 'github', 'email', 'custom');
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "Social" (
|
||||
"id" SERIAL NOT NULL,
|
||||
"name" TEXT NOT NULL,
|
||||
"type" "Handle" NOT NULL,
|
||||
"username" TEXT NOT NULL,
|
||||
|
||||
CONSTRAINT "Social_pkey" PRIMARY KEY ("id")
|
||||
);
|
@ -14,6 +14,19 @@ generator client {
|
||||
binaryTargets = "native"
|
||||
}
|
||||
|
||||
enum Handle {
|
||||
x
|
||||
threads
|
||||
instagram
|
||||
facebook
|
||||
tiktok
|
||||
youtube
|
||||
linkedin
|
||||
github
|
||||
email
|
||||
custom
|
||||
}
|
||||
|
||||
model User {
|
||||
id Int @id @default(autoincrement())
|
||||
username String @unique
|
||||
@ -23,3 +36,10 @@ model User {
|
||||
resetToken String?
|
||||
resetTokenExpiresAt DateTime?
|
||||
}
|
||||
|
||||
model Social {
|
||||
id Int @id @default(autoincrement())
|
||||
name String
|
||||
type Handle
|
||||
username String
|
||||
}
|
||||
|
44
api/src/graphql/socials.sdl.ts
Normal file
44
api/src/graphql/socials.sdl.ts
Normal file
@ -0,0 +1,44 @@
|
||||
export const schema = gql`
|
||||
type Social {
|
||||
id: Int!
|
||||
name: String!
|
||||
type: Handle!
|
||||
username: String!
|
||||
}
|
||||
|
||||
enum Handle {
|
||||
x
|
||||
threads
|
||||
instagram
|
||||
facebook
|
||||
tiktok
|
||||
youtube
|
||||
linkedin
|
||||
github
|
||||
email
|
||||
custom
|
||||
}
|
||||
|
||||
type Query {
|
||||
socials: [Social!]! @requireAuth
|
||||
social(id: Int!): Social @requireAuth
|
||||
}
|
||||
|
||||
input CreateSocialInput {
|
||||
name: String!
|
||||
type: Handle!
|
||||
username: String!
|
||||
}
|
||||
|
||||
input UpdateSocialInput {
|
||||
name: String
|
||||
type: Handle
|
||||
username: String
|
||||
}
|
||||
|
||||
type Mutation {
|
||||
createSocial(input: CreateSocialInput!): Social! @requireAuth
|
||||
updateSocial(id: Int!, input: UpdateSocialInput!): Social! @requireAuth
|
||||
deleteSocial(id: Int!): Social! @requireAuth
|
||||
}
|
||||
`
|
59
api/src/services/socials/socials.ts
Normal file
59
api/src/services/socials/socials.ts
Normal file
@ -0,0 +1,59 @@
|
||||
import type {
|
||||
QueryResolvers,
|
||||
MutationResolvers,
|
||||
CreateSocialInput,
|
||||
UpdateSocialInput,
|
||||
} from 'types/graphql'
|
||||
|
||||
import { ValidationError } from '@redwoodjs/graphql-server'
|
||||
|
||||
import { db } from 'src/lib/db'
|
||||
|
||||
const urlRegex =
|
||||
/^(?:(?:(?:https?|ftp):)?\/\/)(?:\S+(?::\S*)?@)?(?:(?!(?:10|127)(?:\.\d{1,3}){3})(?!(?:169\.254|192\.168)(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)(?:\.(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)*(?:\.(?:[a-z\u00a1-\uffff]{2,})))(?::\d{2,5})?(?:[/?#]\S*)?$/i
|
||||
|
||||
const emailRegex =
|
||||
/^([a-zA-Z0-9_\-\.]+)@([a-zA-Z0-9_\-]+)(\.[a-zA-Z]{2,5}){1,2}$/
|
||||
|
||||
export const socials: QueryResolvers['socials'] = () => db.social.findMany()
|
||||
|
||||
export const social: QueryResolvers['social'] = ({ id }) =>
|
||||
db.social.findUnique({
|
||||
where: { id },
|
||||
})
|
||||
|
||||
export const deleteSocial: MutationResolvers['deleteSocial'] = ({ id }) =>
|
||||
db.social.delete({
|
||||
where: { id },
|
||||
})
|
||||
|
||||
export const createSocial: MutationResolvers['createSocial'] = ({ input }) => {
|
||||
validateInput(input)
|
||||
return db.social.create({
|
||||
data: input,
|
||||
})
|
||||
}
|
||||
|
||||
export const updateSocial: MutationResolvers['updateSocial'] = ({
|
||||
id,
|
||||
input,
|
||||
}) => {
|
||||
validateInput(input)
|
||||
return db.social.update({
|
||||
data: input,
|
||||
where: { id },
|
||||
})
|
||||
}
|
||||
|
||||
const validateInput = (input: CreateSocialInput | UpdateSocialInput) => {
|
||||
if (!input.name || input.name.trim().length === 0)
|
||||
throw new ValidationError('Name is required')
|
||||
if (!input.type) throw new ValidationError('Type is required')
|
||||
|
||||
if (input.type === 'custom' && !urlRegex.test(input.username))
|
||||
throw new ValidationError('Invalid URL')
|
||||
else if (input.type === 'email' && !emailRegex.test(input.username))
|
||||
throw new ValidationError('Invalid Email')
|
||||
else if (input.username.trim().length === 0)
|
||||
throw new ValidationError('Username is required')
|
||||
}
|
Reference in New Issue
Block a user