From ce5cc193e7803fe9fa73bacd282810a17330727e Mon Sep 17 00:00:00 2001
From: nostrdev-com <support@nostrdev.com>
Date: Thu, 27 Mar 2025 17:40:24 +0300
Subject: [PATCH] feat: added nostr and review routes

---
 .vscode/settings.json            |  3 ++
 package.json                     |  3 +-
 src/index.ts                     |  4 ++-
 src/models/index.ts              |  3 ++
 src/models/nostrEvent.ts         | 10 +++++++
 src/models/review.ts             | 12 ++++++++
 src/models/user.ts               |  2 +-
 src/routes/index.ts              |  3 ++
 src/routes/nostr.router.ts       | 48 ++++++++++++++++++++++++++++++++
 src/routes/review.router.ts      | 45 ++++++++++++++++++++++++++++++
 src/routes/users.router.ts       | 19 ++++++++-----
 src/services/database.service.ts | 34 ++++++++++++++++------
 src/types/database.ts            |  5 ++++
 src/types/index.ts               |  1 +
 14 files changed, 174 insertions(+), 18 deletions(-)
 create mode 100644 .vscode/settings.json
 create mode 100644 src/models/index.ts
 create mode 100644 src/models/nostrEvent.ts
 create mode 100644 src/models/review.ts
 create mode 100644 src/routes/index.ts
 create mode 100644 src/routes/nostr.router.ts
 create mode 100644 src/routes/review.router.ts
 create mode 100644 src/types/database.ts
 create mode 100644 src/types/index.ts

diff --git a/.vscode/settings.json b/.vscode/settings.json
new file mode 100644
index 0000000..f5ce7d1
--- /dev/null
+++ b/.vscode/settings.json
@@ -0,0 +1,3 @@
+{
+  "cSpell.words": ["Nostr"]
+}
diff --git a/package.json b/package.json
index 037aedf..89a2494 100644
--- a/package.json
+++ b/package.json
@@ -15,7 +15,8 @@
     "lint": "eslint . --ext ts --report-unused-disable-directives --max-warnings 0",
     "lint:fix": "eslint . --fix --ext ts --report-unused-disable-directives --max-warnings 0",
     "lint:staged": "eslint --fix --ext ts --report-unused-disable-directives --max-warnings 0",
-    "lint-staged": "lint-staged"
+    "lint-staged": "lint-staged",
+    "start:db": "docker compose -f mongo-docker-compose.yml up -d"
   },
   "repository": {
     "type": "git",
diff --git a/src/index.ts b/src/index.ts
index ce1acc2..8a9f6e4 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -1,7 +1,7 @@
 import express, { Express } from 'express'
 import dotenv from 'dotenv'
 import { connectToDatabase } from './services/database.service'
-import { usersRouter } from './routes/users.router'
+import { usersRouter, nostrRouter, reviewRouter } from './routes'
 
 dotenv.config()
 
@@ -11,6 +11,8 @@ const port = process.env.PORT || 3000
 connectToDatabase()
   .then(() => {
     app.use('/users', usersRouter)
+    app.use('/nostr', nostrRouter)
+    app.use('/review', reviewRouter)
 
     app.listen(port, () => {
       console.log(`Server started at http://localhost:${port}`)
diff --git a/src/models/index.ts b/src/models/index.ts
new file mode 100644
index 0000000..e85d0a3
--- /dev/null
+++ b/src/models/index.ts
@@ -0,0 +1,3 @@
+export * from './user'
+export * from './nostrEvent'
+export * from './review'
diff --git a/src/models/nostrEvent.ts b/src/models/nostrEvent.ts
new file mode 100644
index 0000000..2d223f4
--- /dev/null
+++ b/src/models/nostrEvent.ts
@@ -0,0 +1,10 @@
+export class NostrEvent {
+  constructor(
+    public id: string,
+    public pubkey: string,
+    public created_at: number,
+    public kind: number,
+    public tags: [string][],
+    public content: string
+  ) {}
+}
diff --git a/src/models/review.ts b/src/models/review.ts
new file mode 100644
index 0000000..edf353d
--- /dev/null
+++ b/src/models/review.ts
@@ -0,0 +1,12 @@
+import { ObjectId } from 'mongodb'
+
+export class Review {
+  constructor(
+    public eventId: string,
+    public productId: string,
+    public rating: number,
+    public reviewText: string,
+    public testingNotes: string[],
+    public id?: ObjectId
+  ) {}
+}
diff --git a/src/models/user.ts b/src/models/user.ts
index 9792907..b5a2270 100644
--- a/src/models/user.ts
+++ b/src/models/user.ts
@@ -1,6 +1,6 @@
 import { ObjectId } from 'mongodb'
 
-export default class User {
+export class User {
   constructor(
     public name: string,
     public id?: ObjectId
diff --git a/src/routes/index.ts b/src/routes/index.ts
new file mode 100644
index 0000000..7fa2cc6
--- /dev/null
+++ b/src/routes/index.ts
@@ -0,0 +1,3 @@
+export * from './users.router'
+export * from './nostr.router'
+export * from './review.router'
diff --git a/src/routes/nostr.router.ts b/src/routes/nostr.router.ts
new file mode 100644
index 0000000..a9d86e5
--- /dev/null
+++ b/src/routes/nostr.router.ts
@@ -0,0 +1,48 @@
+// External Dependencies
+import express, { Request, Response } from 'express'
+import { collections } from '../services/database.service'
+import { NostrEvent } from '../models'
+
+// Global Config
+export const nostrRouter = express.Router()
+
+nostrRouter.use(express.json())
+
+// GET
+nostrRouter.get('/', async (_req: Request, res: Response) => {
+  try {
+    const nostrEvents = await collections.nostrEvents?.find({}).toArray()
+
+    res.status(200).send(nostrEvents)
+  } catch (error: unknown) {
+    console.error(error)
+
+    if (error instanceof Error) {
+      res.status(500).send(error.message)
+    }
+  }
+})
+
+// POST
+nostrRouter.post('/', async (req: Request, res: Response) => {
+  try {
+    const nostrEvent = req.body as NostrEvent
+    const result = await collections.nostrEvents?.insertOne(nostrEvent)
+
+    if (result) {
+      res
+        .status(201)
+        .send(
+          `Successfully created a new nostrEvent with id ${result.insertedId}`
+        )
+    } else {
+      res.status(500).send('Failed to create a new nostrEvent.')
+    }
+  } catch (error: unknown) {
+    console.error(error)
+
+    if (error instanceof Error) {
+      res.status(400).send(error.message)
+    }
+  }
+})
diff --git a/src/routes/review.router.ts b/src/routes/review.router.ts
new file mode 100644
index 0000000..7040cf4
--- /dev/null
+++ b/src/routes/review.router.ts
@@ -0,0 +1,45 @@
+import express, { Request, Response } from 'express'
+import { collections } from '../services/database.service'
+import { Review } from '../models'
+
+// Global Config
+export const reviewRouter = express.Router()
+
+reviewRouter.use(express.json())
+
+// GET
+reviewRouter.get('/', async (_req: Request, res: Response) => {
+  try {
+    const reviews = await collections.reviews?.find({}).toArray()
+
+    res.status(200).send(reviews)
+  } catch (error: unknown) {
+    console.error(error)
+
+    if (error instanceof Error) {
+      res.status(500).send(error.message)
+    }
+  }
+})
+
+// POST
+reviewRouter.post('/', async (req: Request, res: Response) => {
+  try {
+    const review = req.body as Review
+    const result = await collections.reviews?.insertOne(review)
+
+    if (result) {
+      res
+        .status(201)
+        .send(`Successfully created a new review with id ${result.insertedId}`)
+    } else {
+      res.status(500).send('Failed to create a new review.')
+    }
+  } catch (error: unknown) {
+    console.error(error)
+
+    if (error instanceof Error) {
+      res.status(400).send(error.message)
+    }
+  }
+})
diff --git a/src/routes/users.router.ts b/src/routes/users.router.ts
index b7e6b29..6da619a 100644
--- a/src/routes/users.router.ts
+++ b/src/routes/users.router.ts
@@ -1,7 +1,7 @@
 // External Dependencies
 import express, { Request, Response } from 'express'
 import { collections } from '../services/database.service'
-import User from '../models/user'
+import { User } from '../models'
 
 // Global Config
 export const usersRouter = express.Router()
@@ -14,9 +14,12 @@ usersRouter.get('/', async (_req: Request, res: Response) => {
     const users = await collections.users?.find({}).toArray()
 
     res.status(200).send(users)
-    // eslint-disable-next-line @typescript-eslint/no-explicit-any
-  } catch (error: any) {
-    res.status(500).send(error.message)
+  } catch (error: unknown) {
+    console.error(error)
+
+    if (error instanceof Error) {
+      res.status(500).send(error.message)
+    }
   }
 })
 
@@ -33,9 +36,11 @@ usersRouter.post('/', async (req: Request, res: Response) => {
     } else {
       res.status(500).send('Failed to create a new user.')
     }
-    // eslint-disable-next-line @typescript-eslint/no-explicit-any
-  } catch (error: any) {
+  } catch (error) {
     console.error(error)
-    res.status(400).send(error.message)
+
+    if (error instanceof Error) {
+      res.status(400).send(error.message)
+    }
   }
 })
diff --git a/src/services/database.service.ts b/src/services/database.service.ts
index e9647c8..c96715b 100644
--- a/src/services/database.service.ts
+++ b/src/services/database.service.ts
@@ -1,28 +1,46 @@
-// External Dependencies
 import * as mongoDB from 'mongodb'
 import * as dotenv from 'dotenv'
+import { DBcollections } from '../types'
 
 // Global Variables
-export const collections: { users?: mongoDB.Collection } = {}
+export const collections: {
+  [DBcollections.Users]?: mongoDB.Collection
+  [DBcollections.NostrEvents]?: mongoDB.Collection
+  [DBcollections.Reviews]?: mongoDB.Collection
+} = {}
 
 // Initialize Connection
 export async function connectToDatabase() {
   dotenv.config()
 
-  const client: mongoDB.MongoClient = new mongoDB.MongoClient(
-    // eslint-disable-next-line @typescript-eslint/no-explicit-any
-    process.env.DB_CONN_STRING as any
-  )
+  const { DB_CONN_STRING } = process.env
+
+  if (typeof DB_CONN_STRING !== 'string') {
+    throw new Error(`DB_CONN_STRING environmental variable is missing.`)
+  }
+
+  const client: mongoDB.MongoClient = new mongoDB.MongoClient(DB_CONN_STRING)
 
   await client.connect()
 
   const db: mongoDB.Db = client.db(process.env.DB_NAME)
 
-  const usersCollection: mongoDB.Collection = db.collection('users')
+  const usersCollection: mongoDB.Collection = db.collection(DBcollections.Users)
+  const nostrEventsCollection: mongoDB.Collection = db.collection(
+    DBcollections.NostrEvents
+  )
+  const reviewsCollection: mongoDB.Collection = db.collection(
+    DBcollections.Reviews
+  )
 
   collections.users = usersCollection
+  collections.nostrEvents = nostrEventsCollection
+  collections.reviews = reviewsCollection
 
   console.log(
-    `Successfully connected to database: ${db.databaseName} and collection: ${usersCollection.collectionName}`
+    `Successfully connected to database: ${db.databaseName} and collections:
+${Object.keys(collections)
+  .map((collection) => '- ' + collection)
+  .join('\n')}`
   )
 }
diff --git a/src/types/database.ts b/src/types/database.ts
new file mode 100644
index 0000000..93a45a5
--- /dev/null
+++ b/src/types/database.ts
@@ -0,0 +1,5 @@
+export enum DBcollections {
+  Users = 'users',
+  NostrEvents = 'nostrEvents',
+  Reviews = 'reviews'
+}
diff --git a/src/types/index.ts b/src/types/index.ts
new file mode 100644
index 0000000..e1ddd7b
--- /dev/null
+++ b/src/types/index.ts
@@ -0,0 +1 @@
+export * from './database'