Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
292072f
Create Profile model
pudkipz Feb 27, 2025
5a44949
Merge pull request #19 from boolean-uk/5-api-create-profile-page-model
Dev-Marlin Feb 27, 2025
fd5836a
Profile controller made
Feb 27, 2025
be62ad8
Merge pull request #20 from boolean-uk/6-api-create-profile-page-cont…
Dev-Marlin Feb 27, 2025
4100f10
Profile routing with simple authentication.
Feb 27, 2025
c1fa6ef
Merge branch 'main' of github.com:boolean-uk/team-dev-server-2025-t1 …
Feb 27, 2025
d45a6f4
added password validation
Dev-Marlin Feb 27, 2025
827d076
Merge branch 'main' of https://github.com/boolean-uk/team-dev-server-…
Dev-Marlin Feb 27, 2025
d9d9de2
Merge pull request #21 from boolean-uk/4-api-password-for-a-new-user-…
Dev-Marlin Feb 27, 2025
6c5e600
Profile routes fixed
Feb 27, 2025
660ab6d
Merge pull request #22 from boolean-uk/7-api-add-route-for-profile-page
Dev-Marlin Feb 27, 2025
a52de20
added email validation
Dev-Marlin Feb 27, 2025
3adc3b5
Merge pull request #23 from boolean-uk/3-api-email-must-be-in-a-valid…
Dev-Marlin Feb 27, 2025
b8edc9b
Update prisma schema and seed
pudkipz Feb 27, 2025
a085fd8
Merge branch 'main' of github.com:boolean-uk/team-dev-server-2025-t1 …
pudkipz Feb 27, 2025
54cdfd6
Merge pull request #24 from boolean-uk/16-17-18-db-posts-comments-lik…
Dev-Marlin Feb 27, 2025
85b4497
Create Like model
pudkipz Feb 27, 2025
63b0494
Create like model and controller
pudkipz Feb 28, 2025
4e7ab0c
Create temporary empty comment model
pudkipz Feb 28, 2025
a3f334a
Create post model and controller
pudkipz Feb 28, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .env.example
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
PORT=4000
DATABASE_URL="<your_database_url>?schema=prisma"
SHADOW_DATABASE_URL="<your_shadow_database_url>?schema=shadow"
DATABASE_URL=
SHADOW_DATABASE_URL=
JWT_SECRET="somesecurestring"
JWT_EXPIRY="24h"
45 changes: 45 additions & 0 deletions prisma/migrations/20250227123420_better_posts/migration.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/*
Warnings:

- Added the required column `createdAt` to the `Post` table without a default value. This is not possible if the table is not empty.
- Added the required column `updatedAt` to the `Post` table without a default value. This is not possible if the table is not empty.

*/
-- AlterTable
ALTER TABLE "Post" ADD COLUMN "createdAt" TIMESTAMP(3) NOT NULL,
ADD COLUMN "updatedAt" TIMESTAMP(3) NOT NULL;

-- CreateTable
CREATE TABLE "Like" (
"id" SERIAL NOT NULL,
"postId" INTEGER NOT NULL,
"userId" INTEGER NOT NULL,
"createdAt" TIMESTAMP(3) NOT NULL,
"updatedAt" TIMESTAMP(3) NOT NULL,

CONSTRAINT "Like_pkey" PRIMARY KEY ("id")
);

-- CreateTable
CREATE TABLE "Comment" (
"id" SERIAL NOT NULL,
"postId" INTEGER NOT NULL,
"userId" INTEGER NOT NULL,
"content" TEXT NOT NULL,
"createdAt" TIMESTAMP(3) NOT NULL,
"updatedAt" TIMESTAMP(3) NOT NULL,

CONSTRAINT "Comment_pkey" PRIMARY KEY ("id")
);

-- AddForeignKey
ALTER TABLE "Like" ADD CONSTRAINT "Like_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE;

-- AddForeignKey
ALTER TABLE "Like" ADD CONSTRAINT "Like_postId_fkey" FOREIGN KEY ("postId") REFERENCES "Post"("id") ON DELETE RESTRICT ON UPDATE CASCADE;

-- AddForeignKey
ALTER TABLE "Comment" ADD CONSTRAINT "Comment_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE;

-- AddForeignKey
ALTER TABLE "Comment" ADD CONSTRAINT "Comment_postId_fkey" FOREIGN KEY ("postId") REFERENCES "Post"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
35 changes: 31 additions & 4 deletions prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ model User {
cohort Cohort? @relation(fields: [cohortId], references: [id])
posts Post[]
deliveryLogs DeliveryLog[]
comments Comment[]
likes Like[]
}

model Profile {
Expand All @@ -45,10 +47,35 @@ model Cohort {
}

model Post {
id Int @id @default(autoincrement())
content String
userId Int
user User @relation(fields: [userId], references: [id])
id Int @id @default(autoincrement())
content String
userId Int
user User @relation(fields: [userId], references: [id])
likes Like[]
comments Comment[]
createdAt DateTime
updatedAt DateTime
}

model Like {
id Int @id @default(autoincrement())
postId Int
post Post @relation(fields: [postId], references: [id])
userId Int
user User @relation(fields: [userId], references: [id])
createdAt DateTime
updatedAt DateTime
}

model Comment {
id Int @id @default(autoincrement())
postId Int
post Post @relation(fields: [postId], references: [id])
userId Int
user User @relation(fields: [userId], references: [id])
content String
createdAt DateTime
updatedAt DateTime
}

model DeliveryLog {
Expand Down
10 changes: 8 additions & 2 deletions prisma/seed.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,12 @@ async function seed() {
async function createPost(userId, content) {
const post = await prisma.post.create({
data: {
userId,
content
userId: userId,
content: content,
// likes: [],
// comments: [],
createdAt: new Date(),
updatedAt: new Date()
},
include: {
user: true
Expand Down Expand Up @@ -81,6 +85,8 @@ async function createUser(
githubUrl
}
}
// comments: [],
// likes: []
},
include: {
profile: true
Expand Down
14 changes: 14 additions & 0 deletions src/controllers/like.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { sendDataResponse } from '../utils/responses'

export const create = async (req, res) => {
const { postId, userId } = req.body

try {
const post = await Post.findById
if (!(postId && userId))
return sendDataResponse(res, 400, { content: 'Must provide post ID' })

} catch (error) {}
}

}
47 changes: 30 additions & 17 deletions src/controllers/post.js
Original file line number Diff line number Diff line change
@@ -1,28 +1,41 @@
import Post from '../domain/post.js'
import User from '../domain/user.js'
import { sendDataResponse } from '../utils/responses.js'

export const create = async (req, res) => {
const { content } = req.body
const timestamp = new Date()
const postToCreate = await Post.fromJson({
...req.body,
createdAt: timestamp,
updatedAt: timestamp
})

if (!User.findById(postToCreate.userId))
return sendDataResponse(res, 400, { content: 'No user with ID' })

// if (!postToCreate.content) {
// return sendDataResponse(res, 400, { content: 'Must provide content' })
// }

if (!content) {
return sendDataResponse(res, 400, { content: 'Must provide content' })
}
const createdPost = await postToCreate.save()

return sendDataResponse(res, 201, { post: { id: 1, content } })
return sendDataResponse(res, 201, { post: createdPost })
}

export const getAllByUserId = async (req, res) => {
const foundPosts = (await Post.findByUserId(req.body)).map((post) => {
return { ...post.toJson().post }
})
return sendDataResponse(res, 200, {
posts: foundPosts
})
}

export const getAll = async (req, res) => {
const foundPosts = (await Post.findAll()).map((post) => {
return { ...post.toJson().post }
})
return sendDataResponse(res, 200, {
posts: [
{
id: 1,
content: 'Hello world!',
author: { ...req.user }
},
{
id: 2,
content: 'Hello from the void!',
author: { ...req.user }
}
]
posts: foundPosts
})
}
48 changes: 48 additions & 0 deletions src/controllers/profile.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import Profile from '../domain/profile.js'
import { sendDataResponse, sendMessageResponse } from '../utils/responses.js'

export const create = async (req, res) => {
const profileToCreate = await Profile.fromJson(req.body)

try {
const existingProfileWithUser = await Profile.findByUserId(
profileToCreate.userId
)

if (existingProfileWithUser) {
return sendDataResponse(res, 400, { email: 'You already have a profile' })
}

const createdProfile = await profileToCreate.save()

return sendDataResponse(res, 201, createdProfile)
} catch (error) {
return sendMessageResponse(res, 500, 'Unable to create new profile')
}
}

export const getById = async (req, res) => {
const id = parseInt(req.params.id)

try {
const foundProfile = await Profile.findById(id)

if (!foundProfile) {
return sendDataResponse(res, 404, { id: 'User not found' })
}

return sendDataResponse(res, 200, foundProfile)
} catch (e) {
return sendMessageResponse(res, 500, 'Unable to get user')
}
}

export const updateById = async (req, res) => {
const { user_id: userId } = req.body

if (!userId) {
return sendDataResponse(res, 400, { user_id: 'User ID is required' })
}

return sendDataResponse(res, 201, { user: { user_id: userId } })
}
12 changes: 11 additions & 1 deletion src/controllers/user.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,24 @@ import { sendDataResponse, sendMessageResponse } from '../utils/responses.js'

export const create = async (req, res) => {
const userToCreate = await User.fromJson(req.body)

try {
const existingUser = await User.findByEmail(userToCreate.email)
// eslint-disable-next-line
const passwordRegex = /(?=.*[a-z])(?=.*[A-Z{1,}])(?=.*[0-9{1,}])(?=.*[!-\/:-@[-`{-~{1,}]).{8,}/
const emailRegex = /[^@]{1,}[@]{1}[^@]{1,}/

if (existingUser) {
return sendDataResponse(res, 400, { email: 'Email already in use' })
}

if (!passwordRegex.test(req.body.password)) {
return sendDataResponse(res, 400, { password: 'Invalid password' })
}

if (!emailRegex.test(req.body.email)) {
return sendDataResponse(res, 400, { email: 'Invalid email' })
}

const createdUser = await userToCreate.save()

return sendDataResponse(res, 201, createdUser)
Expand Down
1 change: 1 addition & 0 deletions src/domain/comment.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export default class Comment {}
101 changes: 101 additions & 0 deletions src/domain/like.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
import dbClient from '../utils/dbClient'

export default class Like {
static fromDb(like) {
return new Like(
like.id,
like.postId,
like.userId,
like.createdAt,
like.updatedAt
)
}

static async fromJson(json) {
const { postId, userId, createdAt, updatedAt } = json
return new Like(null, postId, userId, createdAt, updatedAt)
}

constructor(id, postId, userId, createdAt, updatedAt) {
this.id = id
this.postId = postId
this.userId = userId
this.createdAt = createdAt
this.updatedAt = updatedAt
}

toJson() {
return {
like: {
id: this.id,
postId: this.postId,
userId: this.userId,
createdAt: this.createdAt,
updatedAt: this.updatedAt
}
}
}

async save() {
const data = {
createdAt: this.createdAt,
updatedAt: this.updatedAt
}

if (this.postId) {
data.postId = {
connectOrCreate: {
id: this.postId
}
}
}

if (this.userId) {
data.user = {
connectOrCreate: {
id: this.userId
}
}
}

const createdLike = await dbClient.like.create({
data,
include: {
post: true,
user: true
}
})
return Like.fromDb(createdLike)
}

static async findAll() {
return Like._findMany()
}

static async findByPostId(postId) {
return Like._findMany('postId', postId)
}

static async findByUserId(userId) {
return Like._findMany('userId', userId)
}

static async _findMany(key, value) {
const query = {
include: {
post: true
}
}

if (key && value) {
query.where = {
post: {
[key]: value
}
}
}

const foundLikes = await dbClient.like.findMany(query)
return foundLikes.map((like) => Like.fromDb(like))
}
}
Loading
Loading