mirror of
https://github.com/jorgev259/soc_site-astro.git
synced 2025-06-29 07:57:41 +00:00
Migrate to Sequelize V7
This commit is contained in:
parent
a5a5f4ee2a
commit
a79cc8e172
45 changed files with 329 additions and 422 deletions
|
|
@ -2,26 +2,26 @@ import ApolloPackage from '@apollo/client'
|
|||
const { ApolloClient, InMemoryCache } = ApolloPackage;
|
||||
import { SchemaLink } from "@apollo/client/link/schema"
|
||||
import { makeExecutableSchema } from "@graphql-tools/schema";
|
||||
import { loadFilesSync } from '@graphql-tools/load-files'
|
||||
import { mergeResolvers } from '@graphql-tools/merge'
|
||||
import path from "node:path"
|
||||
|
||||
import { getSession } from 'auth-astro/server';
|
||||
import type { Session } from '@auth/core/types';
|
||||
import { typeDefs } from "./__generated__/typeDefs.generated";
|
||||
// import { resolvers } from "./__generated__/resolvers.generated";
|
||||
import db from "@/sequelize";
|
||||
import resolverArray from '@/graphql/resolvers'
|
||||
|
||||
export const resolvers = mergeResolvers(resolverArray)
|
||||
import resolvers from '@/graphql/resolvers'
|
||||
import type { MySqlDialect } from '@sequelize/mysql';
|
||||
import { Sequelize, type ModelStatic, type Options } from '@sequelize/core'
|
||||
|
||||
const schema = makeExecutableSchema({ typeDefs, resolvers })
|
||||
export type ResolverContext = { request?: Request, db: any /*session?: Session */ }
|
||||
export type ResolverContext = { request?: Request, session?: Session }
|
||||
|
||||
const envOptions: Options<MySqlDialect> = JSON.parse(import.meta.env.SEQUELIZE) || {}
|
||||
|
||||
export async function getApolloClient(request?: Request) {
|
||||
// const session = request ? await getSession(request) : undefined
|
||||
const session = request ? await getSession(request) : null
|
||||
const db = new Sequelize(envOptions)
|
||||
envOptions.models = Object.values<ModelStatic>(await import.meta.glob('@/sequelize/models/**/*.ts', { eager: true, import: 'default' }))
|
||||
|
||||
return new ApolloClient({
|
||||
ssrMode: true,
|
||||
link: new SchemaLink({ schema, context: { request, db } }),
|
||||
link: new SchemaLink({ schema, context: { request, session } }),
|
||||
cache: new InMemoryCache()
|
||||
})
|
||||
}
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
// import mutations from './mutations'
|
||||
import queries from './queries'
|
||||
import types from './types'
|
||||
import { mergeResolvers } from '@graphql-tools/merge'
|
||||
import type { IResolvers } from '@graphql-tools/utils'
|
||||
|
||||
const resolvers = { /*...mutations,*/ ...queries, ...types }
|
||||
const imports: IResolvers[] = Object.values(import.meta.glob('./**/*.ts', { eager: true, import: 'default' }))
|
||||
const resolvers = mergeResolvers(imports)
|
||||
|
||||
export default resolvers
|
||||
|
|
|
|||
|
|
@ -1,12 +0,0 @@
|
|||
import merge from 'lodash/merge'
|
||||
|
||||
import comments from './comments'
|
||||
import create from './create'
|
||||
import requests from './requests'
|
||||
import site from './site'
|
||||
import update from './update'
|
||||
import user from './user'
|
||||
|
||||
const mutations = merge(comments, create, requests, site, update, user)
|
||||
|
||||
export default mutations
|
||||
|
|
@ -1,26 +1,11 @@
|
|||
import bcrypt from 'bcrypt'
|
||||
import generator from 'generate-password'
|
||||
import { composeResolvers } from '@graphql-tools/resolvers-composition'
|
||||
import { DateTime } from 'luxon'
|
||||
import { Op } from 'sequelize'
|
||||
import path from 'path'
|
||||
import fs from 'fs-extra'
|
||||
import sharp from 'sharp'
|
||||
|
||||
import { createForgor } from '@/server/utils/forgor'
|
||||
import { isAuthedApp } from '@/server/utils/resolvers'
|
||||
import { processImage } from '@/server/utils/image'
|
||||
import { getSession, getUser } from '@/next/utils/getSession'
|
||||
import {
|
||||
ForbiddenError,
|
||||
UserInputError
|
||||
} from '@/next/server/utils/graphQLErrors'
|
||||
import type { Resolvers } from '@/graphql/__generated__/types.generated'
|
||||
|
||||
const resolversComposition = {
|
||||
'Mutation.updateUser': [isAuthedApp]
|
||||
//'Mutation.updateUser': [isAuthedApp]
|
||||
}
|
||||
|
||||
const streamToString = (stream) => {
|
||||
/* const streamToString = (stream) => {
|
||||
const chunks = []
|
||||
return new Promise((resolve, reject) => {
|
||||
stream.on('data', (chunk) => chunks.push(Buffer.from(chunk)))
|
||||
|
|
@ -45,51 +30,28 @@ async function cropPFP(streamItem, username, imgId) {
|
|||
sharpImage = sharpImage.extract(
|
||||
width > height
|
||||
? {
|
||||
left: Math.floor((width - height) / 2),
|
||||
top: 0,
|
||||
width: height,
|
||||
height
|
||||
}
|
||||
left: Math.floor((width - height) / 2),
|
||||
top: 0,
|
||||
width: height,
|
||||
height
|
||||
}
|
||||
: {
|
||||
left: 0,
|
||||
top: Math.floor((height - width) / 2),
|
||||
width,
|
||||
height: width
|
||||
}
|
||||
left: 0,
|
||||
top: Math.floor((height - width) / 2),
|
||||
width,
|
||||
height: width
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
await sharpImage.resize({ width: 200, height: 200 }).png().toFile(fullPath)
|
||||
|
||||
return await processImage(fullPath)
|
||||
}
|
||||
}*/
|
||||
|
||||
const resolvers = {
|
||||
const resolvers: Resolvers = {
|
||||
Mutation: {
|
||||
login: async (_, { username, password }, { db }) => {
|
||||
const user = await db.models.user.findByPk(username)
|
||||
if (!user) throw UserInputError()
|
||||
|
||||
const valid = await bcrypt.compare(password, user.password)
|
||||
if (!valid) throw UserInputError()
|
||||
|
||||
const session = await getSession()
|
||||
session.username = user.username
|
||||
// Remove this when new site version is fully implemented
|
||||
session.permissions = (await user.getRoles())
|
||||
.map((r) => r.permissions)
|
||||
.flat()
|
||||
await session.save()
|
||||
|
||||
return 200
|
||||
},
|
||||
logout: async () => {
|
||||
const session = await getSession()
|
||||
await session.destroy()
|
||||
|
||||
return 200
|
||||
},
|
||||
registerUser: async (_, { username, email, pfp }, { db }) => {
|
||||
/*registerUser: async (_, { username, email, pfp }, { db }) => {
|
||||
await Promise.all([
|
||||
db.models.user.findByPk(username).then((result) => {
|
||||
if (result) throw UserInputError('Username already in use')
|
||||
|
|
@ -213,7 +175,7 @@ const resolvers = {
|
|||
await role.destroy()
|
||||
|
||||
return name
|
||||
}
|
||||
}*/
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,9 +1,8 @@
|
|||
import type { Resolvers } from '@/graphql/__generated__/types.generated'
|
||||
import Sequelize from 'sequelize'
|
||||
import Sequelize from '@/sequelize'
|
||||
|
||||
const { Op } = Sequelize
|
||||
|
||||
const resolvers: Resolvers = {
|
||||
const resolvers = {
|
||||
Query: {
|
||||
artists: (parent, args, { db }, info) => db.models.artist.findAll(),
|
||||
platforms: (parent, args, { db }, info) => db.models.platform.findAll(),
|
||||
|
|
@ -19,9 +18,7 @@ const resolvers: Resolvers = {
|
|||
album: (_, { id }, { db }) => db.models.album.findByPk(id),
|
||||
downloads: (parent, { id }, { db }) =>
|
||||
db.models.download.findAll({ where: { albumId: id } }),
|
||||
albums: (_, __, { db }, info) =>
|
||||
db.models.album.findAll({
|
||||
}),
|
||||
albums: (_, __, { db }, info) => db.models.album.findAll({}),
|
||||
|
||||
platform: async (parent, { id }, { db }) => db.models.platform.findByPk(id),
|
||||
animation: (parent, { id }, { db }) => db.models.animation.findByPk(id),
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
import merge from 'lodash/merge'
|
||||
|
||||
import search from './search'
|
||||
import site from './site'
|
||||
/*
|
||||
import album from './album'
|
||||
import requests from './requests'
|
||||
|
||||
|
||||
import user from './user'
|
||||
import vgmdb from './vgmdb'
|
||||
*/
|
||||
|
||||
const queries = merge(search, site)
|
||||
|
||||
export default queries
|
||||
|
|
@ -1,24 +1,30 @@
|
|||
import { Op, fn, col, where } from 'sequelize'
|
||||
import { Op, fn, col, where } from '@/sequelize'
|
||||
|
||||
const resolvers = {
|
||||
Query: {
|
||||
requests: (_, {
|
||||
state = ['complete', 'hold', 'pending'],
|
||||
donator = [true, false]
|
||||
}, { db }) => db.models.request.findAll({ where: { state, donator } }),
|
||||
request: (_, { link }, { db }) => db.models.request.findOne({ where: { link } }),
|
||||
requests: (
|
||||
_,
|
||||
{ state = ['complete', 'hold', 'pending'], donator = [true, false] },
|
||||
{ db }
|
||||
) => db.models.request.findAll({ where: { state, donator } }),
|
||||
request: (_, { link }, { db }) =>
|
||||
db.models.request.findOne({ where: { link } }),
|
||||
|
||||
searchRequests: async (_, {
|
||||
state = ['complete', 'hold', 'pending'],
|
||||
donator = [true, false],
|
||||
limit = 10,
|
||||
page = 0,
|
||||
filter
|
||||
}, { db }) => {
|
||||
searchRequests: async (
|
||||
_,
|
||||
{
|
||||
state = ['complete', 'hold', 'pending'],
|
||||
donator = [true, false],
|
||||
limit = 10,
|
||||
page = 0,
|
||||
filter
|
||||
},
|
||||
{ db }
|
||||
) => {
|
||||
const options = { limit, offset: limit * page }
|
||||
const optionsWhere = { state, donator }
|
||||
|
||||
async function exactSearch () {
|
||||
async function exactSearch() {
|
||||
if (!filter) return
|
||||
|
||||
const results = await db.models.request.findAndCountAll({
|
||||
|
|
@ -37,7 +43,7 @@ const resolvers = {
|
|||
if (results.rows.length > 0) return results
|
||||
}
|
||||
|
||||
function looseSearch () {
|
||||
function looseSearch() {
|
||||
return db.models.request.findAndCountAll({
|
||||
where: [
|
||||
optionsWhere,
|
||||
|
|
@ -47,7 +53,7 @@ const resolvers = {
|
|||
})
|
||||
}
|
||||
|
||||
return await exactSearch() || looseSearch()
|
||||
return (await exactSearch()) || looseSearch()
|
||||
},
|
||||
|
||||
submissions: (_, args, context) => {
|
||||
|
|
@ -63,7 +69,9 @@ const resolvers = {
|
|||
{ id: filter },
|
||||
{ vgmdb: filter },
|
||||
{ userUsername: filter },
|
||||
where(fn('LOWER', col('title')), { [Op.like]: `%${filter.toLowerCase()}%` })
|
||||
where(fn('LOWER', col('title')), {
|
||||
[Op.like]: `%${filter.toLowerCase()}%`
|
||||
})
|
||||
]
|
||||
}
|
||||
]
|
||||
|
|
|
|||
|
|
@ -1,14 +1,14 @@
|
|||
//@ts-ignore
|
||||
import { Op, literal } from 'sequelize'
|
||||
import { Op, literal } from '@sequelize/core'
|
||||
import type { Resolvers } from '@/graphql/__generated__/types.generated'
|
||||
|
||||
|
||||
import Category from '@/sequelize/models/category'
|
||||
import Album from '@/sequelize/models/album'
|
||||
|
||||
const fuzzySearch = (words: string[]) => `^${words.map(w => `(?=.*\b${w}\b)`)}.+/i`
|
||||
|
||||
const resolvers: Resolvers = {
|
||||
Query: {
|
||||
searchAlbum: (_, args, { db }) => {
|
||||
searchAlbum: async (_, args, { db }) => {
|
||||
const { title, categories, limit = 10, offset = 0, order = ['createdAt'], mode = 'DESC', status = ['show'] } = args
|
||||
const fuzzyCondition = title ? {
|
||||
[Op.or]: [
|
||||
|
|
@ -18,9 +18,9 @@ const resolvers: Resolvers = {
|
|||
} : {}
|
||||
|
||||
const include = []
|
||||
if (categories) include.push({ model: db.models.category, where: { name: { [Op.in]: categories } } })
|
||||
if (categories) include.push({ model: Category, where: { name: { [Op.in]: categories } } })
|
||||
|
||||
return db.models.album.findAndCountAll({
|
||||
const result = await Album.findAndCountAll({
|
||||
limit, offset,
|
||||
where: {
|
||||
...fuzzyCondition,
|
||||
|
|
@ -29,6 +29,8 @@ const resolvers: Resolvers = {
|
|||
include,
|
||||
order: [literal('`album`.`status` = \'coming\' DESC'), ...order.map(o => [o, mode])]
|
||||
})
|
||||
|
||||
return result
|
||||
}
|
||||
/* searchAlbumByArtist: async (parent, { name, categories, limit, page = 0, order = ['createdAt'], mode = 'DESC', status = ['show'] }, { db }) => {
|
||||
const include = [{ model: db.models.artist, where: { name: { [Op.like]: `%${name}%` } } }]
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@
|
|||
import type { Resolvers } from '@/graphql/__generated__/types.generated'
|
||||
import { composeResolvers } from '@graphql-tools/resolvers-composition'
|
||||
|
||||
import Config from '@/sequelize/models/config'
|
||||
|
||||
// import { hasRole } from '@/server/utils/resolvers'
|
||||
|
||||
const resolversComposition = {
|
||||
|
|
@ -9,33 +11,31 @@ const resolversComposition = {
|
|||
}
|
||||
const resolvers: Resolvers = {
|
||||
Query: {
|
||||
config: (_, args, context) => {
|
||||
config: async (_, args) => {
|
||||
const { name } = args
|
||||
const { db } = context
|
||||
const [result] = await Config.findOrCreate({ where: { name } })
|
||||
|
||||
return db.models.config
|
||||
.findOrCreate({ where: { name } })
|
||||
.then(() => db.models.config.findByPk(name))
|
||||
return result
|
||||
},
|
||||
|
||||
highlight: async (parent, args, { db }) => {
|
||||
/* highlight: async (parent, args, { db }) => {
|
||||
const { value } = await db.models.config.findByPk('highlight')
|
||||
return db.models.album.findByPk(value)
|
||||
},
|
||||
},
|
||||
|
||||
/* banners: async (parent, args) => {
|
||||
banners: async (parent, args) => {
|
||||
const filePaths = await fg(['/var/www/soc_img/img/live/**/ /**.png'])
|
||||
const images = filePaths.map((f) => f.split('/').pop())
|
||||
|
||||
return images
|
||||
}, */
|
||||
},
|
||||
|
||||
recentComments: async (parent, { limit = 5 }, { db }) => {
|
||||
return db.models.comment.findAll({
|
||||
limit,
|
||||
order: [['updatedAt', 'DESC']]
|
||||
})
|
||||
}
|
||||
recentComments: async (parent, { limit = 5 }, { db }) => {
|
||||
return db.models.comment.findAll({
|
||||
limit,
|
||||
order: [['updatedAt', 'DESC']]
|
||||
})
|
||||
} */
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
// import { GraphQLUpload } from 'graphql-upload-minimal'
|
||||
import type { Resolvers } from "@/graphql/__generated__/types.generated"
|
||||
import type Album from "@/sequelize/models/album"
|
||||
|
||||
const resolvers: Resolvers = {
|
||||
// Upload: GraphQLUpload,
|
||||
Album: {
|
||||
// @ts-ignore
|
||||
artists: (parent, args, context, info) => parent.getArtists(),
|
||||
artists: (parent: Album, args, context, info) => parent.getArtists(),
|
||||
/* categories: (parent, args, context, info) => parent.getCategories(),
|
||||
classifications: (parent, args, context, info) =>
|
||||
parent.getClassifications(),
|
||||
|
|
|
|||
|
|
@ -1,8 +0,0 @@
|
|||
// import merge from 'lodash/merge'
|
||||
|
||||
import album from './album'
|
||||
// import user from './user'
|
||||
|
||||
const types = /*(merge(*/album/*, user)*/
|
||||
|
||||
export default types
|
||||
|
|
@ -1,31 +1,34 @@
|
|||
import { Op } from 'sequelize'
|
||||
import type { Resolvers } from '@/graphql/__generated__/types.generated'
|
||||
|
||||
import pages from '@/next/constants/pages.json'
|
||||
import { getUser } from '@/next/utils/getSession'
|
||||
|
||||
const userResolvable = {
|
||||
roles: parent => parent.getRoles(),
|
||||
const userResolvable: Resolvers = {
|
||||
/* roles: parent => parent.getRoles(),
|
||||
permissions: async parent => {
|
||||
const roles = await parent.getRoles()
|
||||
return roles.map(r => r.permissions).flat()
|
||||
},
|
||||
pages: async parent => {
|
||||
}, */
|
||||
pages: async (_, __, { session }) => {
|
||||
const roles = await parent.getRoles()
|
||||
const permissions = roles.map(r => r.permissions).flat()
|
||||
|
||||
return pages.filter(({ perms }) => perms.length === 0 || perms.some(r => permissions.includes(r)))
|
||||
},
|
||||
comments: (user, _, { db }) => user.getComments({ where: { albumId: { [Op.not]: null } } }),
|
||||
favorites: user => user.getAlbums(),
|
||||
imgUrl: async user => `https://cdn.sittingonclouds.net/user/${
|
||||
user.imgId ? `${user.username}_${user.imgId}` : 'default'
|
||||
}.png`
|
||||
/* comments: (user, _, { db }) => user.getComments({ where: { albumId: { [Op.not]: null } } }),
|
||||
favorites: user => user.getAlbums(),
|
||||
imgUrl: async user => `https://cdn.sittingonclouds.net/user/${user.imgId ? `${user.username}_${user.imgId}` : 'default'
|
||||
}.png` */
|
||||
}
|
||||
|
||||
const funcs = {
|
||||
User: userResolvable,
|
||||
UserMe: userResolvable,
|
||||
Role: { permissions: parent => typeof parent.permissions === 'string' || parent.permissions instanceof String ? JSON.parse(parent.permissions) : parent.permissions },
|
||||
const resolvers: Resolvers = {
|
||||
// User: userResolvable,
|
||||
UserMe: {
|
||||
pages: async (_, __, { session }) => {
|
||||
const roles = await parent.getRoles()
|
||||
const permissions = roles.map(r => r.permissions).flat()
|
||||
|
||||
return pages.filter(({ perms }) => perms.length === 0 || perms.some(r => permissions.includes(r)))
|
||||
},
|
||||
},
|
||||
/*Role: { permissions: parent => typeof parent.permissions === 'string' || parent.permissions instanceof String ? JSON.parse(parent.permissions) : parent.permissions },
|
||||
Submission: {
|
||||
submitter: submission => submission.getUser(),
|
||||
links: async (submission, _, { db }) => {
|
||||
|
|
@ -40,7 +43,7 @@ const funcs = {
|
|||
return submission.links
|
||||
},
|
||||
request: submission => submission.getRequest()
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
export default funcs
|
||||
export default resolvers
|
||||
|
|
|
|||
|
|
@ -1,57 +1,60 @@
|
|||
type User {
|
||||
username: String!
|
||||
roles: [Role]!
|
||||
permissions: [String]!
|
||||
pages: [Page]!
|
||||
createdAt: Float!
|
||||
placeholder: String!
|
||||
imgUrl: String!
|
||||
}
|
||||
type User {
|
||||
username: String!
|
||||
roles: [Role]!
|
||||
permissions: [String]!
|
||||
pages: [Page]!
|
||||
createdAt: Float!
|
||||
imgUrl: String!
|
||||
}
|
||||
|
||||
type UserMe {
|
||||
email: String!
|
||||
username: String!
|
||||
roles: [Role]!
|
||||
permissions: [String]!
|
||||
pages: [Page]!
|
||||
createdAt: Float!
|
||||
placeholder: String!
|
||||
imgUrl: String!
|
||||
}
|
||||
type UserMe {
|
||||
email: String!
|
||||
username: String!
|
||||
roles: [Role]!
|
||||
permissions: [String]!
|
||||
pages: [Page]!
|
||||
createdAt: Float!
|
||||
imgUrl: String!
|
||||
}
|
||||
|
||||
type Page {
|
||||
url: String!
|
||||
perms: [String!]!
|
||||
}
|
||||
type Page {
|
||||
url: String!
|
||||
perms: [String!]!
|
||||
}
|
||||
|
||||
type Role {
|
||||
name: String!
|
||||
permissions: [String]!
|
||||
}
|
||||
type Role {
|
||||
name: String!
|
||||
permissions: [String]!
|
||||
}
|
||||
|
||||
type Query {
|
||||
me: UserMe
|
||||
roles: [Role]!
|
||||
permissions: [String]!
|
||||
users(search: String): [User]!
|
||||
user(username: String!): User
|
||||
type Query {
|
||||
me: UserMe
|
||||
roles: [Role]!
|
||||
permissions: [String]!
|
||||
users(search: String): [User]!
|
||||
user(username: String!): User
|
||||
|
||||
login(username: String!, password: String!): Int!
|
||||
}
|
||||
login(username: String!, password: String!): Int!
|
||||
}
|
||||
|
||||
type Mutation {
|
||||
login(username: String!, password: String!): Int!
|
||||
logout: Int!
|
||||
|
||||
registerUser(email: String!, username: String!, pfp: Upload): Boolean!
|
||||
updateUserRoles(username: String!, roles: [String]!): Boolean!
|
||||
deleteUser(username: String!): Int
|
||||
type Mutation {
|
||||
login(username: String!, password: String!): Int!
|
||||
logout: Int!
|
||||
|
||||
createForgorLink(key: String!): Boolean!
|
||||
updatePass(key: String!, pass:String!): Boolean!
|
||||
updateUser(username: String, password: String, email: String, pfp: Upload): Boolean!
|
||||
registerUser(email: String!, username: String!, pfp: Upload): Boolean!
|
||||
updateUserRoles(username: String!, roles: [String]!): Boolean!
|
||||
deleteUser(username: String!): Int
|
||||
|
||||
createRole(name: String!, permissions: [String]!): Role
|
||||
updateRole(key:String!, name: String!, permissions: [String]!): Role
|
||||
deleteRole(name: String!): String
|
||||
}
|
||||
createForgorLink(key: String!): Boolean!
|
||||
updatePass(key: String!, pass: String!): Boolean!
|
||||
updateUser(
|
||||
username: String
|
||||
password: String
|
||||
email: String
|
||||
pfp: Upload
|
||||
): Boolean!
|
||||
|
||||
createRole(name: String!, permissions: [String]!): Role
|
||||
updateRole(key: String!, name: String!, permissions: [String]!): Role
|
||||
deleteRole(name: String!): String
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue