Skip to content

Commit 63871ba

Browse files
committed
feat: search functionality
1 parent 2782446 commit 63871ba

11 files changed

Lines changed: 155 additions & 86 deletions

File tree

docker-compose.yml

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
version: "3.8"
22
services:
3-
app:
4-
build: .
5-
container_name: my_app
6-
depends_on:
7-
- postgres
8-
env_file:
9-
- .env
10-
ports:
11-
- "8081:8081"
12-
restart: unless-stopped
3+
# app:
4+
# build: .
5+
# container_name: my_app
6+
# depends_on:
7+
# - postgres
8+
# env_file:
9+
# - .env
10+
# ports:
11+
# - "8081:8081"
12+
# restart: unless-stopped
1313

1414
postgres:
1515
image: postgres:latest

src/index.d.ts

Lines changed: 0 additions & 9 deletions
This file was deleted.

src/index.ts

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,28 +8,30 @@ import swagger from "@fastify/swagger"
88
import swaggerUI from "@fastify/swagger-ui"
99
import * as dotenv from "dotenv"
1010
import fastify from "fastify"
11-
import nodemailer, { type SentMessageInfo } from "nodemailer"
12-
import type { DataSource } from "typeorm"
11+
import nodemailer, { SentMessageInfo } from "nodemailer"
1312
import authRoutes from "./routes/v1/Auth/routes"
1413
import { characterRoutes } from "./routes/v1/Characters/routes"
1514
import profileRoutes from "./routes/v1/Profile/routes"
16-
import verifyToken from "./utils/auth"
15+
import { authMiddleware, optionalAuthMiddleware } from "./utils/auth"
1716
import connectDatabase from "./utils/database"
1817
import { checkModAbovePermissions } from "./utils/permission"
1918
import artRoutes from "./routes/v1/Art/routes"
2019
import relationshipRoutes from "./routes/v1/Relationships/routes"
2120
import StaffRoutes from "./routes/v1/Staff/routes"
2221
import { oauthProviders } from "./config/oauth"
23-
import fastifyOauth2 from "@fastify/oauth2"
22+
import fastifyOauth2, { OAuth2Namespace } from "@fastify/oauth2"
2423
import fastifySession from "@fastify/session"
2524
import folderRoutes from "./routes/v1/Folder/routes"
2625
import dashboardRoutes from "./routes/v1/Dashboard/routes"
26+
import { DataSource } from "typeorm"
27+
import { generalRoutes } from "./routes/v1/General/routes"
2728

2829
declare module "fastify" {
2930
interface FastifyInstance {
3031
db: DataSource
3132
auth: any
3233
permissionAboveMod: any
34+
optionalAuth: any
3335
mailer: nodemailer.Transporter<SentMessageInfo>
3436
s3: S3Client
3537
}
@@ -40,6 +42,11 @@ declare module "fastify" {
4042
profileId: string
4143
}
4244
}
45+
46+
interface FastifyInstance {
47+
facebookOAuth2: OAuth2Namespace;
48+
googleOAuth: OAuth2Namespace;
49+
}
4350
}
4451

4552
const app = async () => {
@@ -76,7 +83,8 @@ const app = async () => {
7683
// server.decorateRequest('db', connection);
7784

7885
// Auth Decorator
79-
server.decorate("auth", verifyToken)
86+
server.decorate("auth", authMiddleware)
87+
server.decorate("optionalAuth", optionalAuthMiddleware)
8088

8189
// Register all OAuth providers
8290
oauthProviders.forEach(({ name, config }) => {
@@ -161,6 +169,7 @@ const app = async () => {
161169
server.register(folderRoutes, { prefix: "/v1/folders" })
162170
server.register(dashboardRoutes, { prefix: "/v1/dashboard" })
163171
server.register(artRoutes, { prefix: "/v1/art" })
172+
server.register(generalRoutes, { prefix: "/v1" })
164173
server.register(StaffRoutes, { prefix: "/v1/staff" })
165174

166175
// Starting server

src/models/Notifications.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import {
1010
import User from "./Users"
1111
import Artwork from "./Artwork"
1212
import Comment from "./Comments"
13+
import Character from "./Character"
1314

1415
@Entity("notifications")
1516
export default class Notification {
@@ -38,6 +39,10 @@ export default class Notification {
3839
@JoinColumn()
3940
comment: Comment
4041

42+
@ManyToOne(() => Character, { nullable: true, onDelete: "CASCADE" })
43+
@JoinColumn()
44+
character: Character
45+
4146
@CreateDateColumn()
4247
createdAt: Date
4348
}

src/models/Users.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,9 @@ export default class User {
179179
@OneToMany(() => Dashboard, (dashboard) => dashboard.user)
180180
dashboards: Dashboard[];
181181

182+
@Column("jsonb", { default: [], nullable: true })
183+
recentSearches: string[]
184+
182185

183186
// Statistics
184187

src/routes/v1/Art/controllers.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import type { FastifyReply, FastifyRequest } from "fastify"
22
import { Character, Commission, Image, User } from "../../../models"
33
import Artwork from "../../../models/Artwork"
4-
import { Comment } from "../../../models/Comments"
5-
import { Notification } from "../../../models/Notifications"
4+
import Comment from "../../../models/Comments"
5+
import Notification from "../../../models/Notifications"
66
import { sendNotification } from "../../../utils/notification"
77

88
export const uploadArt = async (request: FastifyRequest, reply: FastifyReply) => {
@@ -179,7 +179,7 @@ export const commentArtwork = async (request: FastifyRequest, reply: FastifyRepl
179179
await sendNotification(
180180
request.server.db,
181181
author,
182-
`${author.handle} commented on your artwork`,
182+
`%user% commented on your artwork`,
183183
artwork.owner,
184184
artwork,
185185
comment

src/routes/v1/Auth/controllers.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -282,7 +282,12 @@ export const whoami = async (request: FastifyRequest, reply: FastifyReply) => {
282282
relations: {
283283
user: {
284284
characters: true,
285-
notifications: true,
285+
notifications: {
286+
sender: true,
287+
artwork: true,
288+
comment: true,
289+
character: true
290+
},
286291
}
287292
}
288293
})
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
import { FastifyReply, FastifyRequest } from "fastify"
2+
import { Artwork, Character, User } from "../../../models"
3+
4+
export const search = async (request: FastifyRequest, reply: FastifyReply) => {
5+
const { query, type } = request.query as { query?: string; type?: string }
6+
const profileId = request.user as { id: string; profileId?: string }
7+
8+
if (!query) {
9+
return reply.status(400).send({ error: "Search query is required" })
10+
}
11+
12+
const repoMap = {
13+
artwork: { entity: Artwork, fields: ["title"] },
14+
user: { entity: User, fields: ["displayName", "handle"] },
15+
character: { entity: Character, fields: ["name"] },
16+
}
17+
18+
const searchTypes = type && type in repoMap ? [type] : Object.keys(repoMap)
19+
20+
const results = await Promise.all(
21+
searchTypes.map(async (key) => {
22+
const { entity, fields } = repoMap[key as keyof typeof repoMap]
23+
const repo = request.server.db.getRepository(entity)
24+
25+
let queryBuilder = repo.createQueryBuilder(key)
26+
27+
fields.forEach((field, index) => {
28+
if (index === 0) {
29+
queryBuilder.where(`${key}.${field} ILIKE :query`, { query: `%${query}%` })
30+
} else {
31+
queryBuilder.orWhere(`${key}.${field} ILIKE :query`, { query: `%${query}%` })
32+
}
33+
})
34+
35+
return queryBuilder
36+
.getMany()
37+
.then((res) => ({ type: key, results: res }))
38+
})
39+
)
40+
41+
if (profileId) {
42+
const user = await request.server.db.getRepository(User).findOne({ where: { id: profileId} })
43+
if (!user) {
44+
return reply.status(404).send({ error: "User not found" })
45+
}
46+
const recentSearches = new Set([query, ...(user.recentSearches || []).slice(0, 4)])
47+
user.recentSearches = [...recentSearches]
48+
await request.server.db.getRepository(User).save(user)
49+
}
50+
51+
return results.reduce((acc: Record<string, any[]>, res) => {
52+
if (res.results.length) acc[res.type] = res.results
53+
return acc
54+
}, {})
55+
}

src/routes/v1/General/routes.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import { FastifyInstance } from "fastify";
2+
import { search } from "./controllers";
3+
4+
export async function generalRoutes(server: FastifyInstance) {
5+
server.get('/search', { onRequest: [server.optionalAuth] }, search)
6+
}

src/routes/v1/Profile/controllers.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,7 @@ export const commentProfile = async (request: FastifyRequest, reply: FastifyRepl
177177
return reply.code(500).send({ error: "Error commenting" })
178178
}
179179

180-
await sendNotification(request.server.db, profile, "New comment on your profile", author, undefined, comment)
180+
await sendNotification(request.server.db, profile, "%user% commented on your profile", author, undefined, comment)
181181

182182
return reply.code(200).send({ message: "Commented" })
183183
}

0 commit comments

Comments
 (0)