diff --git a/lib/db/cache.ts b/lib/db/cache.ts index e5511e27..679c46db 100644 --- a/lib/db/cache.ts +++ b/lib/db/cache.ts @@ -2,11 +2,8 @@ import Redis from 'ioredis' import * as process from 'process' import { Types } from '../../types/Components' -import { findOne, getAll } from './db' - -import { getUser, getUsers } from './users' -import { getItem } from './items' import { singularToPlural } from '../utils' +import { findOneTyped, getAllTyped } from './dbTyped' const uri = 'CACHE_URL' in process.env ? process.env.CACHE_URL : 'redis://localhost' @@ -21,13 +18,7 @@ export async function getSingleCache( ): Promise { let data = await getCache(type + '-' + _id) if (data === null) { - if (type === Types.user) { - data = await getUser(_id) - } else if (type === Types.item) { - data = await getItem(_id) - } else { - data = await findOne(singularToPlural(type), { _id: _id }) - } + data = await findOneTyped(type, _id) if (data === null) { return null @@ -49,11 +40,7 @@ export async function updateSingleCache( data?: string | object ) { if (typeof data === 'undefined') { - if (type === Types.user) { - data = await getUser(_id) - } else { - data = await findOne(singularToPlural(type), { _id: _id }) - } + data = await findOneTyped(type, _id) } await setCache(type + '-' + _id, data) @@ -67,11 +54,8 @@ export async function getAllCache(type: Types): Promise { let data = await getCache(plural) if (data === null) { - if (type === Types.user) { - data = await getUsers() - } else { - data = await getAll(plural) - } + data = await getAllTyped(type) + if (data === null) { return [] } @@ -87,11 +71,7 @@ export async function getAllCache(type: Types): Promise { */ export async function updateAllCache(type: Types, data?: string | object) { if (typeof data === 'undefined') { - if (type === Types.user) { - data = await getUsers() - } else { - data = await getAll(singularToPlural(type)) - } + data = await getAllTyped(type) } await setCache(singularToPlural(type), data) diff --git a/lib/db/dbTyped.ts b/lib/db/dbTyped.ts new file mode 100644 index 00000000..2318e282 --- /dev/null +++ b/lib/db/dbTyped.ts @@ -0,0 +1,155 @@ +import { Types } from '../../types/Components' +import { count, deleteOne, find, findOne, getAll, insert, updateOne } from './db' +import type { User, UserUpdate } from '../../types/User' +import type { List } from '../../types/List' +import type { Library } from '../../types/Library' +import type { Item } from '../../types/Item' +import type { Column } from '../../types/Column' +import type { Collection } from '../../types/Collection' +import { gatherUserInfo } from './users' +import { getSingleCache } from './cache' +import { getLastViews } from './views' + +export async function getAllTyped(type: Types) { + switch (type) { + case Types.collection: + return (await getAll('collections')) as Collection[] + case Types.column: + return (await getAll('columns')) as Column[] + case Types.item: + return (await getAll('items')) as Item[] + case Types.library: + return (await getAll('libraries')) as Library[] + case Types.list: + return (await getAll('lists')) as List[] + case Types.user: + const users = (await getAll('users')) as User[] + return await Promise.all( + users.map( + async ({ uid }) => (await getSingleCache(Types.user, uid)) as User + ) + ) + } +} + +export async function findTyped(type: Types, query: Record) { + switch (type) { + case Types.collection: + return (await find('collections', query)) as Collection[] + case Types.column: + return (await find('columns', query)) as Column[] + case Types.item: + return (await find('items', query)) as Item[] + case Types.library: + return (await find('libraries', query)) as Library[] + case Types.list: + return (await find('lists', query)) as List[] + case Types.user: + return (await find('users', query)) as User[] + } +} + +export async function findOneTyped(type: Types, _id: string | Record) { + switch (type) { + case Types.collection: + return (await findOne('collections', typeof _id === 'string' ? { _id } : _id)) as Collection | null + case Types.column: + return (await findOne('columns', typeof _id === 'string' ? { _id } : _id)) as Column | null + case Types.item: + const item = (await findOne('items', typeof _id === 'string' ? { _id } : _id)) as Item | null + if (item !== null) { + item.stars = await countTyped(Types.user, { favs: [_id] }) + item.views = 0 // await count(Types.item, 1000) + } + return item + case Types.library: + return (await findOne('libraries', typeof _id === 'string' ? { _id } : _id)) as Library | null + case Types.list: + return (await findOne('lists', typeof _id === 'string' ? { _id } : _id)) as List | null + case Types.user: + const user = (await findOne('users', typeof _id === 'string' ? { uid: _id } : _id)) as User | null + return await gatherUserInfo(user) + } +} + +export async function countTyped(type: Types, query?: Record) { + switch (type) { + case Types.collection: + return await count('collections', query) + case Types.column: + return await count('columns', query) + case Types.item: + return await count('items', query) + case Types.library: + return await count('libraries', query) + case Types.list: + return await count('lists', query) + case Types.user: + return await count('users', query) + } +} + +export async function getByUrlIdTyped( + type: Types, + urlId: string +) { + return findOneTyped(type, {urlId}) +} + +export async function insertTyped( + type: Types, + data: UserUpdate | Record +) { + switch (type) { + case Types.collection: + return await insert('collections', data) + case Types.column: + return await insert('columns', data) + case Types.item: + return await insert('items', data) + case Types.library: + return await insert('libraries', data) + case Types.list: + return await insert('lists', data) + case Types.user: + if (instanceof data UserUpdate) + return await insert('users', data) + } +} + +export async function updateOneTyped(type: Types, _id: string | Record, data) { + switch (type) { + case Types.collection: + return await updateOne('collections', typeof _id === 'string' ? { _id } : _id, data) + case Types.column: + return await updateOne('columns', typeof _id === 'string' ? { _id } : _id, data) + case Types.item: + return await updateOne('items', typeof _id === 'string' ? { _id } : _id, data) + case Types.library: + return await updateOne('libraries', typeof _id === 'string' ? { _id } : _id, data) + case Types.list: + return await updateOne('lists', typeof _id === 'string' ? { _id } : _id, data) + case Types.user: + return await updateOne('users', typeof _id === 'string' ? { uid: _id } : _id, data) + } +} + +export async function deleteOneTyped( + type: Types, + query: Record +) { + switch (type) { + case Types.collection: + return await deleteOne('collections', query) + case Types.column: + return await deleteOne('columns', query) + case Types.item: + return await deleteOne('items', query) + case Types.library: + return await deleteOne('libraries', query) + case Types.list: + return await deleteOne('lists', query) + case Types.user: + return await deleteOne('users', query) + } +} diff --git a/lib/db/lists.ts b/lib/db/lists.ts index 7442bcba..a160a6a3 100644 --- a/lib/db/lists.ts +++ b/lib/db/lists.ts @@ -1,9 +1,10 @@ import { deleteOne, find, findOne, getAll, insert, updateOne } from './db' import { clearSingleCache, updateAllCache, updateSingleCache } from './cache' import { Types } from '../../types/Components' -import { getUser, updateUser } from './users' -import { List, ListUpdate } from '../../types/List' -import { User } from '../../types/User' +import { updateUser } from './users' +import type { List, ListUpdate } from '../../types/List' +import type { User } from '../../types/User' +import { findOneTyped } from './dbTyped' export async function getLists(): Promise { return (await getAll('lists')) as List[] @@ -69,7 +70,7 @@ export async function updateList( export async function deleteList(_id: string) { // remove list entry from owner const list = await getList(_id) - const owner = await getUser(list.owner) + const owner = await findOneTyped(Types.user, list.owner) as User owner.lists = owner.lists.filter((userList) => userList !== _id) await updateUser(owner.uid, { diff --git a/pages/api/auth/[...nextauth].ts b/pages/api/auth/[...nextauth].ts index bb6f8d10..d8bfa1ad 100644 --- a/pages/api/auth/[...nextauth].ts +++ b/pages/api/auth/[...nextauth].ts @@ -1,11 +1,13 @@ import NextAuth from 'next-auth' import DiscordProvider from 'next-auth/providers/discord' -import { addUser, getUser } from '../../../lib/db/users' -import { AccountType } from '../../../types/User' +import { addUser } from '../../../lib/db/users' +import { AccountType, type User } from '../../../types/User' import { MongoDBAdapter } from '@next-auth/mongodb-adapter' import { dbClient } from '../../../lib/db/db' import { ObjectId } from 'mongodb' import type { AuthOptions } from 'next-auth' +import { findOneTyped } from '../../../lib/db/dbTyped' +import { Types } from '../../../types/Components' export const authOptions: AuthOptions = { providers: [ @@ -26,7 +28,7 @@ export const authOptions: AuthOptions = { const id = user.id.toString() session.user.uid = id - const userData = await getUser(id) + const userData = await findOneTyped(Types.user, id) as User // create user account if not found if (userData === null) { console.log( diff --git a/pages/api/edit/user.ts b/pages/api/edit/user.ts index 87dc9ec4..8066e5b9 100644 --- a/pages/api/edit/user.ts +++ b/pages/api/edit/user.ts @@ -1,10 +1,12 @@ import { authOptions } from '../auth/[...nextauth]' import { getServerSession } from 'next-auth/next' import { isAdmin, isCurrentUser } from '../../../lib/session' -import { getUser, updateUser } from '../../../lib/db/users' +import { updateUser } from '../../../lib/db/users' import { updateAllCache, updateSingleCache } from '../../../lib/db/cache' import { Types } from '../../../types/Components' import { NextApiRequest, NextApiResponse } from 'next' +import { findOneTyped } from '../../../lib/db/dbTyped' +import type { User } from '../../../types/User' export default async function apiEditUser( req: NextApiRequest, @@ -18,7 +20,7 @@ export default async function apiEditUser( delete d.accountType } // @ts-ignore - const oldUser = await getUser(d.uid === 'me' ? session.user.uid : d.uid) + const oldUser = await findOneTyped(Types.user, d.uid === 'me' ? session.user.uid : d.uid) as User // @ts-ignore await updateUser(d.uid === 'me' ? session.user.uid : d.uid, d) diff --git a/pages/edit/user/[id].tsx b/pages/edit/user/[id].tsx index 4a6e654f..776a0096 100644 --- a/pages/edit/user/[id].tsx +++ b/pages/edit/user/[id].tsx @@ -1,12 +1,13 @@ import Head from 'next/head' import { useSession } from 'next-auth/react' import Link from 'next/link' -import { getUser } from '../../../lib/db/users' import { isAdmin, isCurrentUser } from '../../../lib/session' import EditUser from '../../../components/edit/EditUser' import NotAdmin from '../../../components/layout/NotAdmin' import ViewAllButton from '../../../components/buttons/ViewAllButton' import { Types } from '../../../types/Components' +import { findOneTyped } from '../../../lib/db/dbTyped' +import type { User } from '../../../types/User' export default function EditorUser({ uid, user }) { const { data: session } = useSession() @@ -56,7 +57,7 @@ export default function EditorUser({ uid, user }) { EditorUser.auth = {} export async function getServerSideProps({ params }) { - const user = await getUser(params.id) + const user = await findOneTyped(Types.user, params.id) as User if (!user) { return { notFound: true, diff --git a/pages/user/[id].tsx b/pages/user/[id].tsx index 497899fd..567cbd6c 100644 --- a/pages/user/[id].tsx +++ b/pages/user/[id].tsx @@ -5,7 +5,6 @@ import { useSession } from 'next-auth/react' import { isAdmin, isCurrentUser } from '../../lib/session' import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' import DataBadge from '../../components/data/DataBadge' -import { getUser } from '../../lib/db/users' import ListBoard from '../../components/boards/ListBoard' import ItemBoard from '../../components/boards/ItemBoard' import Meta from '../../components/layout/Meta' @@ -13,12 +12,13 @@ import React, { FC } from 'react' import useSWR from 'swr' import { getAllCache } from '../../lib/db/cache' import { Types } from '../../types/Components' -import { User } from '../../types/User' -import { List } from '../../types/List' -import { Item } from '../../types/Item' -import { Column } from '../../types/Column' +import type { User } from '../../types/User' +import type { List } from '../../types/List' +import type { Item } from '../../types/Item' +import type { Column } from '../../types/Column' import { faCog } from '@fortawesome/free-solid-svg-icons/faCog' import AccountTypeBadge from '../../components/badge/AccountTypeBadge' +import { findOneTyped } from '../../lib/db/dbTyped' type Props = { user: User @@ -217,7 +217,7 @@ const User: FC = ({ user, lists, items, columns }) => { export default User export async function getServerSideProps({ params }) { - const user = await getUser(params.id) + const user = await findOneTyped(Types.user, params.id) as User if (!user) { return { diff --git a/types/Collection.ts b/types/Collection.ts index 206cdeed..21073859 100644 --- a/types/Collection.ts +++ b/types/Collection.ts @@ -7,6 +7,7 @@ export interface Collection { description: string columns: string[] items: string[] + views: number } export interface CollectionUpdate { diff --git a/types/Column.ts b/types/Column.ts index 7e114d4e..5b4046b6 100644 --- a/types/Column.ts +++ b/types/Column.ts @@ -6,6 +6,7 @@ export interface Column { description: string type: ColumnType values: string[] + views: number } export enum ColumnType { diff --git a/types/Item.ts b/types/Item.ts index ac2e179a..fc08a75c 100644 --- a/types/Item.ts +++ b/types/Item.ts @@ -8,6 +8,7 @@ export interface Item { description: string data: Record stars: number + views: number } export interface ItemUpdate { diff --git a/types/Library.ts b/types/Library.ts index c8d4efe2..977b776e 100644 --- a/types/Library.ts +++ b/types/Library.ts @@ -9,6 +9,7 @@ export interface Library { description: string collections: string[] order: number + views: number } export interface LibraryWithCollection { diff --git a/types/List.ts b/types/List.ts index 8f986d3a..d024e6f0 100644 --- a/types/List.ts +++ b/types/List.ts @@ -6,6 +6,7 @@ export interface List { description: string items: string[] columns: string[] + views: number } export interface ListUpdate { diff --git a/types/User.ts b/types/User.ts index 928e469c..54ee4680 100644 --- a/types/User.ts +++ b/types/User.ts @@ -9,16 +9,18 @@ export interface User { lists: string[] followLists: string[] createdAt: string + views: number } export enum AccountType { admin = 'admin', editor = 'editor', user = 'user', - views: number } export interface UserUpdate { + name?: string + image?: string accountType?: AccountType description?: string favs?: string[]