mirror of
https://github.com/bubblecup-12/VogelSocialMedia.git
synced 2025-07-09 00:08:46 +00:00
added endpoints for profile and feed
This commit is contained in:
parent
9e6eeb27fd
commit
1800056918
22 changed files with 952 additions and 110 deletions
235
code/backend/src/controllers/profileController.ts
Normal file
235
code/backend/src/controllers/profileController.ts
Normal file
|
@ -0,0 +1,235 @@
|
|||
import express, { Request, Response } from "express";
|
||||
import { JwtPayload } from "jsonwebtoken";
|
||||
import { PrismaClient } from "../../prisma/app/generated/prisma/client";
|
||||
import dotenv from "dotenv";
|
||||
import { StatusCodes } from "http-status-codes";
|
||||
import multer from "multer";
|
||||
import { minioClient } from "../server";
|
||||
|
||||
const app = express();
|
||||
app.use(express.json());
|
||||
const prisma = new PrismaClient();
|
||||
// load environment variables from .env file
|
||||
dotenv.config();
|
||||
|
||||
type PublicUser = {
|
||||
id: string;
|
||||
username: string;
|
||||
bio: string | null;
|
||||
profilePictureUrl: string | null;
|
||||
followers: number;
|
||||
following: number;
|
||||
};
|
||||
const getUser: (userId: string) => Promise<PublicUser | undefined> = async (
|
||||
userId: string
|
||||
) => {
|
||||
const user = await prisma.user.findUnique({
|
||||
where: { id: userId },
|
||||
include: { profilePicture: true },
|
||||
});
|
||||
if (user) {
|
||||
let profilePictureUrl: string | null = null;
|
||||
if (user.profilePicture) {
|
||||
profilePictureUrl = await minioClient.presignedGetObject(
|
||||
user.profilePicture.bucket,
|
||||
user.profilePicture.objectName,
|
||||
60 * 10
|
||||
);
|
||||
}
|
||||
const followerCount = await prisma.follow.count({
|
||||
where: {
|
||||
followedUserId: userId,
|
||||
},
|
||||
});
|
||||
|
||||
const followingCount = await prisma.follow.count({
|
||||
where: {
|
||||
followingUserId: userId,
|
||||
},
|
||||
});
|
||||
const publicUser: PublicUser = {
|
||||
id: user.id,
|
||||
username: user.username,
|
||||
bio: user.bio,
|
||||
profilePictureUrl,
|
||||
followers: followerCount,
|
||||
following: followingCount,
|
||||
};
|
||||
return publicUser;
|
||||
}
|
||||
return undefined;
|
||||
};
|
||||
|
||||
export const uploadProfilePicture = async (req: Request, res: Response) => {
|
||||
const user: JwtPayload = req.user!;
|
||||
const file = req.file as Express.Multer.File;
|
||||
const BUCKET = "images"; // Name of the bucket where the images are stored
|
||||
try {
|
||||
const objectName = `${user.sub}/profile.${file.mimetype.split("/")[1]}`;
|
||||
await minioClient.putObject(BUCKET, objectName, file.buffer);
|
||||
const url = await minioClient.presignedGetObject(
|
||||
BUCKET,
|
||||
objectName,
|
||||
60 * 10
|
||||
);
|
||||
const oldImage = await prisma.user.findUnique({
|
||||
where: { id: user.sub },
|
||||
select: { profilePictureId: true },
|
||||
});
|
||||
|
||||
const media = await prisma.media.create({
|
||||
data: {
|
||||
originalFilename: file.originalname,
|
||||
objectName: objectName,
|
||||
mimeType: file.mimetype,
|
||||
size: file.size,
|
||||
bucket: BUCKET,
|
||||
uploader: { connect: { id: user.sub } },
|
||||
},
|
||||
});
|
||||
|
||||
await prisma.user.update({
|
||||
where: { id: user.sub },
|
||||
data: {
|
||||
profilePicture: {
|
||||
connect: { id: media.id },
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
if (oldImage?.profilePictureId && oldImage.profilePictureId !== media.id) {
|
||||
await prisma.media.delete({
|
||||
where: { id: oldImage.profilePictureId },
|
||||
});
|
||||
}
|
||||
|
||||
res.status(StatusCodes.CREATED).json({
|
||||
originalName: file.originalname,
|
||||
objectName: objectName,
|
||||
size: file.size,
|
||||
mimetype: file.mimetype,
|
||||
url: url,
|
||||
});
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
res.status(StatusCodes.INTERNAL_SERVER_ERROR).json({
|
||||
error: "Upload failed",
|
||||
details: [{ message: "Internal server error" }],
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export const getProfilePicture = async (req: Request, res: Response) => {
|
||||
const username: string = req.params.username;
|
||||
if (!username) {
|
||||
res.status(StatusCodes.BAD_REQUEST).json({
|
||||
error: "no username",
|
||||
details: [{ message: "Username is required" }],
|
||||
});
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const user = await prisma.user.findUnique({
|
||||
where: { username },
|
||||
include: { profilePicture: true },
|
||||
});
|
||||
|
||||
if (!user) {
|
||||
res.status(StatusCodes.NOT_FOUND).json({
|
||||
error: "User not found",
|
||||
details: [
|
||||
{ message: `User with username '${username}' does not exist.` },
|
||||
],
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (!user.profilePicture) {
|
||||
res.status(StatusCodes.NOT_FOUND).json({
|
||||
error: "No profile picture",
|
||||
details: [{ message: "This user does not have a profile picture." }],
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const profilePictureUrl = await minioClient.presignedGetObject(
|
||||
user.profilePicture.bucket,
|
||||
user.profilePicture.objectName,
|
||||
60 * 10 // 10 minutes expiration
|
||||
);
|
||||
|
||||
res.status(StatusCodes.OK).json({ url: profilePictureUrl });
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
res.status(StatusCodes.INTERNAL_SERVER_ERROR).json({
|
||||
error: "Retrieving image failed",
|
||||
details: ["Internal server error"],
|
||||
});
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
export const updateBio = async (req: Request, res: Response) => {
|
||||
const user: JwtPayload = req.user!;
|
||||
const bio: string = req.body.bio;
|
||||
try {
|
||||
const updatedUser = await prisma.user.update({
|
||||
where: { id: user.sub },
|
||||
data: {
|
||||
bio: bio,
|
||||
},
|
||||
});
|
||||
const publicUser: PublicUser | undefined = await getUser(user.sub!);
|
||||
res.status(StatusCodes.OK).json({
|
||||
message: "User found",
|
||||
data: publicUser,
|
||||
});
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
res.status(StatusCodes.INTERNAL_SERVER_ERROR).json({
|
||||
error: "Updating bio failed",
|
||||
details: [{ message: "Internal Server error" }],
|
||||
});
|
||||
}
|
||||
};
|
||||
// Endpoint to get user data
|
||||
export const getProfile = async (req: Request, res: Response) => {
|
||||
const username: string = req.params.username as string;
|
||||
if (!username) {
|
||||
res.status(StatusCodes.BAD_REQUEST).json({
|
||||
error: "no username",
|
||||
details: [{ message: "Username is required" }],
|
||||
});
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const user = await prisma.user.findUnique({
|
||||
where: { username },
|
||||
include: { profilePicture: true },
|
||||
});
|
||||
|
||||
if (!user) {
|
||||
res.status(StatusCodes.NOT_FOUND).json({
|
||||
error: "User not found",
|
||||
details: [
|
||||
{ message: `User with username '${username}' does not exist.` },
|
||||
],
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const publicUser: PublicUser | undefined = await getUser(user.id);
|
||||
|
||||
res.status(StatusCodes.OK).json({
|
||||
message: "User found",
|
||||
data: publicUser,
|
||||
});
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
res.status(StatusCodes.INTERNAL_SERVER_ERROR).json({
|
||||
error: "Retrieving image failed",
|
||||
details: ["Error while retrieving the image"],
|
||||
});
|
||||
return;
|
||||
}
|
||||
};
|
Loading…
Add table
Add a link
Reference in a new issue