You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
636 lines
26 KiB
636 lines
26 KiB
import { getClient } from "../utils/database.js";
|
|
import * as path from "node:path";
|
|
import * as fs from "node:fs";
|
|
import { fileURLToPath } from 'url';
|
|
import { dirname } from 'path';
|
|
import jwt from "jsonwebtoken";
|
|
import { sendEmail } from "../utils/mail.js";
|
|
const __filename = fileURLToPath(import.meta.url);
|
|
const __dirname = dirname(__filename);
|
|
|
|
export async function upload(req, res) {
|
|
|
|
// HANDLE VIDEO FILE
|
|
const fileBuffer = req.file.buffer;
|
|
let isGenerate = false;
|
|
while (isGenerate === false) {
|
|
const client = await getClient();
|
|
let letters = "0123456789ABCDEF";
|
|
let hex = '';
|
|
for (let i = 0; i < 16; i++)
|
|
hex += letters[(Math.floor(Math.random() * 16))];
|
|
|
|
|
|
const query = `SELECT * FROM videos WHERE slug = $1`;
|
|
const result = await client.query(query, [hex]);
|
|
client.end();
|
|
if (result.rows.length === 0) {
|
|
isGenerate = true;
|
|
req.body.slug = hex;
|
|
}
|
|
}
|
|
|
|
const finalName = req.body.slug + "." + req.file.originalname.split(".")[1];
|
|
const destinationPath = path.join(__dirname, "../uploads/videos/" + finalName)
|
|
|
|
fs.writeFileSync(destinationPath, fileBuffer);
|
|
const client = await getClient();
|
|
const video = {
|
|
title: req.body.title,
|
|
description: req.body.description,
|
|
//TODO thumbnail
|
|
file: "/api/media/video/" + finalName,
|
|
channel: req.body.channel,
|
|
slug: req.body.slug,
|
|
format: req.file.originalname.split(".")[1],
|
|
visibility: req.body.visibility,
|
|
}
|
|
|
|
// HANDLE VIDEO DETAILS
|
|
const logger = req.body.logger;
|
|
logger.write("try to upload video");
|
|
const releaseDate = new Date(Date.now()).toISOString();
|
|
|
|
const query = `INSERT INTO videos (title, thumbnail, description, channel, visibility, file, slug, format, release_date) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9) RETURNING id`;
|
|
const idResult = await client.query(query, [video.title, 'null', video.description, video.channel, video.visibility, video.file, video.slug, video.format, releaseDate]);
|
|
const id = idResult.rows[0].id;
|
|
|
|
console.log(req.body.visibility, req.body.authorizedUsers)
|
|
|
|
// HANDLE AUTHORIZED USERS
|
|
if (req.body.visibility === "private" && req.body.authorizedUsers) {
|
|
let authorizedUsers = req.body.authorizedUsers;
|
|
|
|
// Parse if still a string (safety check)
|
|
if (typeof authorizedUsers === 'string') {
|
|
try {
|
|
authorizedUsers = JSON.parse(authorizedUsers);
|
|
} catch (error) {
|
|
console.error("Failed to parse authorizedUsers:", error);
|
|
authorizedUsers = [];
|
|
}
|
|
}
|
|
|
|
if (Array.isArray(authorizedUsers) && authorizedUsers.length > 0) {
|
|
for (let i = 0; i < authorizedUsers.length; i++) {
|
|
const user = authorizedUsers[i];
|
|
console.log("authorized user", user);
|
|
const query = `INSERT INTO video_authorized_users (video_id, user_id) VALUES ($1, $2)`;
|
|
|
|
// SEND EMAIL TO AUTHORIZED USER
|
|
const emailQuery = `SELECT email FROM users WHERE id = $1`;
|
|
const emailResult = await client.query(emailQuery, [user]);
|
|
const email = emailResult.rows[0].email;
|
|
|
|
const textMessage = `Vous êtes autorisé à visionner une vidéo privée. ${process.env.FRONTEND_URL}/videos/${id}`;
|
|
const htmlMessage = `
|
|
<!DOCTYPE html>
|
|
<html>
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>Accès à une vidéo privée - Freetube</title>
|
|
</head>
|
|
<body style="margin: 0; padding: 0; font-family: Arial, sans-serif; background-color: #f4f4f4;">
|
|
<div style="max-width: 600px; margin: 0 auto; background-color: #ffffff; border-radius: 8px; overflow: hidden; box-shadow: 0 2px 10px rgba(0,0,0,0.1);">
|
|
<!-- Header -->
|
|
<div style="background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); padding: 40px 20px; text-align: center;">
|
|
<h1 style="color: #ffffff; margin: 0; font-size: 28px; font-weight: bold;">
|
|
🔐 Vidéo privée partagée avec vous!
|
|
</h1>
|
|
</div>
|
|
|
|
<!-- Content -->
|
|
<div style="padding: 40px 30px;">
|
|
<h2 style="color: #333333; margin-top: 0; font-size: 24px;">
|
|
Bonjour! 👋
|
|
</h2>
|
|
|
|
<p style="color: #666666; font-size: 16px; line-height: 1.6; margin: 20px 0;">
|
|
Vous avez été autorisé(e) à visionner une vidéo privée sur <strong>Freetube</strong>!
|
|
</p>
|
|
|
|
<p style="color: #666666; font-size: 16px; line-height: 1.6; margin: 20px 0;">
|
|
<strong>On vous a partagé une vidéo privée avec vous. Cliquez sur le bouton ci-dessous pour la regarder :
|
|
</p>
|
|
|
|
<!-- Video Info Box -->
|
|
<div style="background-color: #f8f9fa; border: 2px dashed #667eea; border-radius: 8px; padding: 25px; margin: 30px 0;">
|
|
<h3 style="color: #333333; font-size: 18px; margin: 0 0 10px 0; text-align: center;">
|
|
${video.title}
|
|
</h3>
|
|
<p style="color: #666666; font-size: 14px; margin: 0 0 20px 0; text-align: center; line-height: 1.4;">
|
|
${video.description}
|
|
</p>
|
|
<div style="text-align: center;">
|
|
<a href="${process.env.FRONTEND_URL}/videos/${video.id}" style="background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: #ffffff; text-decoration: none; padding: 12px 25px; border-radius: 6px; font-size: 16px; font-weight: bold; display: inline-block;">
|
|
▶️ Regarder la vidéo
|
|
</a>
|
|
</div>
|
|
</div>
|
|
|
|
<p style="color: #999999; font-size: 14px; line-height: 1.5; margin: 30px 0 10px 0;">
|
|
🔒 Cette vidéo est privée et n'est accessible qu'aux personnes autorisées.
|
|
</p>
|
|
|
|
<p style="color: #999999; font-size: 14px; line-height: 1.5; margin: 10px 0;">
|
|
Si vous pensez avoir reçu cet e-mail par erreur, vous pouvez l'ignorer.
|
|
</p>
|
|
</div>
|
|
|
|
<!-- Footer -->
|
|
<div style="background-color: #f8f9fa; padding: 20px 30px; border-top: 1px solid #eee;">
|
|
<p style="color: #999999; font-size: 12px; margin: 0; text-align: center;">
|
|
© 2025 Freetube. Tous droits réservés.
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</body>
|
|
</html>
|
|
`;
|
|
|
|
sendEmail(email, "Invitation à visionner une vidéo privée", textMessage, htmlMessage);
|
|
|
|
await client.query(query, [id, user]);
|
|
}
|
|
}
|
|
}
|
|
|
|
logger.write("successfully uploaded video", 200);
|
|
await client.end()
|
|
res.status(200).json({ "message": "Successfully uploaded video", "id": id });
|
|
|
|
}
|
|
|
|
export async function uploadThumbnail(req, res) {
|
|
const fileBuffer = req.file.buffer;
|
|
const client = await getClient();
|
|
const videoId = req.body.video;
|
|
const videoSlugQuery = `SELECT * from videos WHERE id = $1`;
|
|
const result = await client.query(videoSlugQuery, [videoId]);
|
|
|
|
const fileName = result.rows[0].slug + "." + req.file.originalname.split(".")[1];
|
|
const destinationPath = path.join(__dirname, "../uploads/thumbnails/", fileName);
|
|
fs.writeFileSync(destinationPath, fileBuffer);
|
|
|
|
const logger = req.body.logger;
|
|
logger.action("try to add thumbnail to video " + req.body.video);
|
|
|
|
const file = "/api/media/thumbnail/" + fileName;
|
|
|
|
const updateQuery = `UPDATE videos SET thumbnail = $1 WHERE id = $2`;
|
|
await client.query(updateQuery, [file, req.body.video]);
|
|
logger.write("successfully uploaded thumbnail", 200);
|
|
await client.end();
|
|
res.status(200).json({ "message": "Successfully uploaded thumbnail" });
|
|
}
|
|
|
|
export async function getById(req, res) {
|
|
const id = req.params.id;
|
|
|
|
const logger = req.body.logger;
|
|
logger.action("try to get video " + id);
|
|
const client = await getClient();
|
|
const query = `SELECT * FROM videos WHERE id = $1`;
|
|
const result = await client.query(query, [id]);
|
|
const video = result.rows[0];
|
|
|
|
// GET VIEWS AND LIKES COUNT
|
|
const viewsQuery = `SELECT COUNT(*) AS view_count FROM history WHERE video = $1`;
|
|
const viewsResult = await client.query(viewsQuery, [id]);
|
|
const likesQuery = `SELECT COUNT(*) AS like_count FROM likes WHERE video = $1`;
|
|
const likesResult = await client.query(likesQuery, [id]);
|
|
video.views = viewsResult.rows[0].view_count;
|
|
video.likes = likesResult.rows[0].like_count;
|
|
|
|
// GET COMMENTS
|
|
const commentsQuery = `SELECT c.id, c.content, c.created_at, u.username, u.picture FROM comments c JOIN users u ON c.author = u.id WHERE c.video = $1 ORDER BY c.created_at DESC`;
|
|
const commentsResult = await client.query(commentsQuery, [id]);
|
|
video.comments = commentsResult.rows;
|
|
|
|
// GET CREATOR
|
|
const creatorQuery = `SELECT c.id, c.name, c.owner FROM channels c JOIN videos v ON c.id = v.channel WHERE v.id = $1`;
|
|
const creatorResult = await client.query(creatorQuery, [id]);
|
|
video.creator = creatorResult.rows[0];
|
|
|
|
// GET CREATOR PROFILE PICTURE
|
|
const profilePictureQuery = `SELECT picture FROM users WHERE id = $1`;
|
|
const profilePictureResult = await client.query(profilePictureQuery, [video.creator.owner]);
|
|
video.creator.profile_picture = profilePictureResult.rows[0].picture;
|
|
|
|
// GET CREATOR SUBSCRIBERS COUNT
|
|
const subscribersQuery = `SELECT COUNT(*) AS subscriber_count FROM subscriptions WHERE channel = $1`;
|
|
const subscribersResult = await client.query(subscribersQuery, [video.creator.id]);
|
|
video.creator.subscribers = subscribersResult.rows[0].subscriber_count;
|
|
|
|
// GET TAGS
|
|
const tagsQuery = `SELECT t.name FROM tags t JOIN video_tags vt ON t.id = vt.tag WHERE vt.video = $1`;
|
|
const tagsResult = await client.query(tagsQuery, [id]);
|
|
video.tags = tagsResult.rows.map(tag => tag.name);
|
|
|
|
// GET AUTHORIZED USERS
|
|
const authorizedUsersQuery = `SELECT u.id, u.username, u.picture FROM users u JOIN video_authorized_users vp ON u.id = vp.user_id WHERE vp.video_id = $1`;
|
|
const authorizedUsersResult = await client.query(authorizedUsersQuery, [id]);
|
|
video.authorizedUsers = authorizedUsersResult.rows;
|
|
|
|
logger.write("successfully get video " + id, 200);
|
|
client.end()
|
|
res.status(200).json(video);
|
|
}
|
|
|
|
export async function getByChannel(req, res) {
|
|
const id = req.params.id;
|
|
const logger = req.body.logger;
|
|
logger.action("try to get video from channel " + id);
|
|
const client = await getClient();
|
|
const query = `SELECT * FROM videos WHERE channel = $1`;
|
|
const result = await client.query(query, [id]);
|
|
logger.write("successfully get video from channel " + id, 200);
|
|
client.end()
|
|
res.status(200).json(result.rows);
|
|
}
|
|
|
|
export async function update(req, res) {
|
|
const id = req.params.id;
|
|
const logger = req.body.logger;
|
|
logger.action("try to update video " + id);
|
|
const client = await getClient();
|
|
const query = `UPDATE videos SET title = $1, description = $2, visibility = $3 WHERE id = $4`;
|
|
await client.query(query, [req.body.title, req.body.description, req.body.visibility, id]);
|
|
|
|
const resultQuery = `
|
|
SELECT
|
|
videos.id,
|
|
videos.title,
|
|
videos.thumbnail,
|
|
videos.channel,
|
|
videos.file,
|
|
videos.description,
|
|
videos.visibility,
|
|
videos.release_date,
|
|
COUNT(DISTINCT l.id) AS likes_count,
|
|
COUNT(DISTINCT h.id) AS history_count,
|
|
JSON_AGG(
|
|
JSON_BUILD_OBJECT(
|
|
'id', c.id,
|
|
'content', c.content,
|
|
'username', u.username,
|
|
'video', c.video,
|
|
'created_at', c.created_at,
|
|
'picture', u.picture
|
|
)
|
|
) FILTER (
|
|
WHERE
|
|
c.id IS NOT NULL
|
|
) AS comments,
|
|
JSON_AGG(DISTINCT t.name) FILTER (WHERE t.name IS NOT NULL) AS tags
|
|
FROM public.videos
|
|
LEFT JOIN public.likes l ON l.video = videos.id
|
|
LEFT JOIN public.history h ON h.video = videos.id
|
|
LEFT JOIN public.comments c ON c.video = videos.id
|
|
LEFT JOIN public.video_tags vt ON vt.video = videos.id
|
|
LEFT JOIN public.tags t ON vt.tag = t.id
|
|
LEFT JOIN public.users u ON u.id = c.author
|
|
WHERE
|
|
videos.id = $1
|
|
GROUP BY public.videos.id
|
|
`;
|
|
const result = await client.query(resultQuery, [id]);
|
|
logger.write("successfully updated video", 200);
|
|
client.end()
|
|
res.status(200).json(result.rows[0]);
|
|
}
|
|
|
|
export async function updateVideo(req, res) {
|
|
const id = req.params.id;
|
|
const logger = req.body.logger;
|
|
logger.action("try to update video file " + id);
|
|
const client = await getClient();
|
|
const videoQuery = `SELECT slug, format FROM videos WHERE id = $1`;
|
|
const videoResult = await client.query(videoQuery, [id]);
|
|
const video = videoResult.rows[0];
|
|
const slug = video.slug;
|
|
const format = video.format;
|
|
const pathToDelete = path.join(__dirname, "../uploads/videos/", slug + "." + format);
|
|
fs.unlink(pathToDelete, (error) => {
|
|
if (error) {
|
|
logger.write(error, 500);
|
|
client.end()
|
|
res.status(500).json({ "message": "Failed to delete video" });
|
|
return
|
|
}
|
|
logger.action("successfully deleted video " + slug + "." + format);
|
|
const fileBuffer = req.file.buffer;
|
|
const finalName = slug + "." + format;
|
|
const destinationPath = path.join(__dirname, "../uploads/videos/" + finalName)
|
|
|
|
fs.writeFileSync(destinationPath, fileBuffer);
|
|
|
|
logger.write("successfully updated video", 200);
|
|
client.end()
|
|
res.status(200).json({ "message": "Successfully updated video" });
|
|
})
|
|
|
|
|
|
}
|
|
|
|
export async function del(req, res) {
|
|
const id = req.params.id;
|
|
const logger = req.body.logger;
|
|
logger.action("try to delete video " + id);
|
|
const client = await getClient();
|
|
const query = `SELECT slug, format, thumbnail FROM videos WHERE id = $1`;
|
|
const result = await client.query(query, [id]);
|
|
const video = result.rows[0];
|
|
const slug = video.slug;
|
|
const format = video.format;
|
|
const thumbnailFile = video.thumbnail.split("/")[4];
|
|
let pathToDelete = path.join(__dirname, "../uploads/videos/", slug + "." + format);
|
|
fs.unlink(pathToDelete, (error) => {
|
|
if (error) {
|
|
logger.write(error, 500);
|
|
client.end()
|
|
res.status(500).json({ "message": "Failed to delete video" });
|
|
return
|
|
}
|
|
|
|
pathToDelete = path.join(__dirname, "../uploads/thumbnails/", thumbnailFile);
|
|
fs.unlink(pathToDelete, async (error) => {
|
|
if (error) {
|
|
logger.write(error, 500);
|
|
res.status(500).json({ "message": "Failed to delete video" });
|
|
return
|
|
}
|
|
const query = `DELETE FROM videos WHERE id = $1`;
|
|
await client.query(query, [id]);
|
|
logger.write("successfully deleted video", 200);
|
|
client.end()
|
|
res.status(200).json({ "message": "Successfully deleted video" });
|
|
})
|
|
})
|
|
|
|
|
|
|
|
}
|
|
|
|
export async function toggleLike(req, res) {
|
|
const id = req.params.id;
|
|
const logger = req.body.logger;
|
|
logger.action("try to toggle like on video " + id);
|
|
const token = req.headers.authorization.split(" ")[1];
|
|
const claims = jwt.decode(token);
|
|
const client = await getClient();
|
|
const userId = claims.id;
|
|
|
|
const getLikeQuery = `SELECT * FROM likes WHERE owner = $1 AND video = $2`;
|
|
const likeResult = await client.query(getLikeQuery, [userId, id]);
|
|
|
|
if (likeResult.rows.length === 0) {
|
|
const query = `INSERT INTO likes (video, owner) VALUES ($1, $2)`;
|
|
await client.query(query, [id, userId]);
|
|
|
|
// GET LIKES COUNT
|
|
const likesCountQuery = `SELECT COUNT(*) AS like_count FROM likes WHERE video = $1`;
|
|
const likesCountResult = await client.query(likesCountQuery, [id]);
|
|
const likesCount = likesCountResult.rows[0].like_count;
|
|
|
|
logger.write("no likes found adding likes for video " + id, 200);
|
|
client.end();
|
|
res.status(200).json({ "message": "Successfully added like", "likes": likesCount });
|
|
} else {
|
|
const query = `DELETE FROM likes WHERE owner = $1 AND video = $2`;
|
|
await client.query(query, [userId, id]);
|
|
|
|
// GET LIKES COUNT
|
|
const likesCountQuery = `SELECT COUNT(*) AS like_count FROM likes WHERE video = $1`;
|
|
const likesCountResult = await client.query(likesCountQuery, [id]);
|
|
const likesCount = likesCountResult.rows[0].like_count;
|
|
|
|
logger.write("likes found, removing like for video " + id, 200);
|
|
client.end();
|
|
res.status(200).json({ "message": "Successfully removed like", "likes": likesCount });
|
|
}
|
|
|
|
|
|
}
|
|
|
|
export async function addTags(req, res) {
|
|
const tags = req.body.tags;
|
|
const videoId = req.params.id;
|
|
|
|
const logger = req.body.logger;
|
|
logger.action("try to add tags to video " + videoId);
|
|
|
|
const client = await getClient();
|
|
|
|
// DECREASE USAGE COUNT FOR ALL TAGS
|
|
const decreaseUsageCountQuery = `UPDATE tags SET usage_count = usage_count - 1 WHERE id IN (SELECT tag FROM video_tags WHERE video = $1)`;
|
|
await client.query(decreaseUsageCountQuery, [videoId]);
|
|
|
|
// DELETE ALL TAGS FOR VIDEO
|
|
let deleteQuery = `DELETE FROM video_tags WHERE video = $1`;
|
|
await client.query(deleteQuery, [videoId]);
|
|
|
|
// INSERT NEW TAGS
|
|
for (const tag of tags) {
|
|
const tagQuery = `SELECT * FROM tags WHERE name = $1`;
|
|
const tagResult = await client.query(tagQuery, [tag]);
|
|
let id = null;
|
|
|
|
if (tagResult.rows.length === 0) {
|
|
const insertTagQuery = `INSERT INTO tags (name, usage_count) VALUES ($1, 1) RETURNING id`;
|
|
const result = await client.query(insertTagQuery, [tag]);
|
|
id = result.rows[0].id;
|
|
} else {
|
|
logger.write("Tag " + tag + " already exists for video " + videoId, 200);
|
|
const getTagQuery = `SELECT usage_count FROM tags WHERE name = $1`;
|
|
const getTagResult = await client.query(getTagQuery, [tag]);
|
|
const usageCount = getTagResult.rows[0].usage_count + 1;
|
|
const updateTagQuery = `UPDATE tags SET usage_count = $1 WHERE name = $2`;
|
|
await client.query(updateTagQuery, [usageCount, tag]);
|
|
id = tagResult.rows[0].id;
|
|
}
|
|
|
|
// INSERT INTO video_tags
|
|
const insertVideoTagQuery = `INSERT INTO video_tags (tag, video) VALUES ($1, $2)`;
|
|
await client.query(insertVideoTagQuery, [id, videoId]);
|
|
}
|
|
|
|
// GET UPDATED TAGS FOR VIDEO
|
|
const updatedTagsQuery = `SELECT t.name FROM tags t JOIN video_tags vt ON t.id = vt.tag WHERE vt.video = $1`;
|
|
const updatedTagsResult = await client.query(updatedTagsQuery, [videoId]);
|
|
const updatedTags = updatedTagsResult.rows;
|
|
|
|
logger.write("successfully added tags to video " + videoId, 200);
|
|
await client.end();
|
|
res.status(200).json({ "message": "Successfully added tags to video", "tags": updatedTags.map(tag => tag.name) });
|
|
|
|
}
|
|
|
|
export async function getSimilarVideos(req, res) {
|
|
const id = req.params.id;
|
|
const logger = req.body.logger;
|
|
logger.action("try to get similar videos for video " + id);
|
|
|
|
const client = await getClient();
|
|
|
|
// Get tags for the video
|
|
const tagsQuery = `SELECT t.name FROM tags t JOIN video_tags vt ON t.id = vt.tag WHERE vt.video = $1`;
|
|
const tagsResult = await client.query(tagsQuery, [id]);
|
|
const tags = tagsResult.rows.map(row => row.name);
|
|
|
|
if (tags.length === 0) {
|
|
logger.write("No tags found for video " + id, 404);
|
|
res.status(404).json({ "message": "No similar videos found" });
|
|
return;
|
|
}
|
|
|
|
// Find similar videos based on tags which are not the same as the current video and limit to 10 results
|
|
const similarVideosQuery = `
|
|
SELECT v.id, v.title, v.thumbnail, v.file, v.slug, v.format, v.release_date, c.name AS creator_name, c.id AS creator_id, c.owner AS creator_owner
|
|
FROM videos v
|
|
JOIN video_tags vt ON v.id = vt.video
|
|
JOIN tags t ON vt.tag = t.id
|
|
JOIN channels c ON v.channel = c.id
|
|
WHERE t.name = ANY($1) AND v.id != $2
|
|
GROUP BY v.id, c.name, c.id
|
|
LIMIT 10;
|
|
`;
|
|
|
|
const result = await client.query(similarVideosQuery, [tags, id]);
|
|
|
|
for (let video of result.rows) {
|
|
// Get views count for each video
|
|
const viewsQuery = `SELECT COUNT(*) AS view_count FROM history WHERE video = $1`;
|
|
const viewsResult = await client.query(viewsQuery, [video.id]);
|
|
video.views = viewsResult.rows[0].view_count;
|
|
|
|
// Get creator profile picture
|
|
const profilePictureQuery = `SELECT picture FROM users WHERE id = $1`;
|
|
const profilePictureResult = await client.query(profilePictureQuery, [video.creator_owner]);
|
|
|
|
// Put creator info in video.creator
|
|
video.creator = {
|
|
id: video.creator_id,
|
|
name: video.creator_name,
|
|
profilePicture: profilePictureResult.rows[0].picture
|
|
};
|
|
// Remove creator_id and creator_name from the video object
|
|
delete video.creator_id;
|
|
delete video.creator_name;
|
|
|
|
}
|
|
|
|
logger.write("successfully get similar videos for video " + id, 200);
|
|
await client.end();
|
|
res.status(200).json(result.rows);
|
|
}
|
|
|
|
export async function getLikesPerDay(req, res) {
|
|
const id = req.params.id;
|
|
const logger = req.body.logger;
|
|
logger.action("try to get likes per day");
|
|
|
|
const client = await getClient();
|
|
|
|
try {
|
|
const response = {}
|
|
|
|
const likeQuery = `
|
|
SELECT
|
|
DATE(created_at) as date,
|
|
COUNT(*) as count
|
|
FROM likes
|
|
WHERE video = $1
|
|
GROUP BY DATE(created_at)
|
|
ORDER BY date DESC
|
|
LIMIT 30
|
|
`;
|
|
|
|
const viewQuery = `
|
|
SELECT
|
|
DATE(viewed_at) as date,
|
|
COUNT(*) as count
|
|
FROM history
|
|
WHERE video = $1
|
|
GROUP BY DATE(viewed_at)
|
|
ORDER BY date DESC
|
|
LIMIT 30
|
|
`;
|
|
|
|
const resultViews = await client.query(viewQuery, [id]);
|
|
|
|
response.views = resultViews.rows;
|
|
|
|
const resultLikes = await client.query(likeQuery, [id]);
|
|
response.likes = resultLikes.rows;
|
|
|
|
console.log(response);
|
|
|
|
logger.write("successfully retrieved likes per day", 200);
|
|
res.status(200).json(response);
|
|
} catch (error) {
|
|
logger.write("Error retrieving likes per day: " + error.message, 500);
|
|
res.status(500).json({ error: "Internal server error" });
|
|
} finally {
|
|
await client.end();
|
|
}
|
|
}
|
|
|
|
export async function addViews(req, res) {
|
|
const id = req.params.id;
|
|
const logger = req.body.logger;
|
|
logger.action("try to add views for video " + id);
|
|
const token = req.headers.authorization.split(" ")[1];
|
|
const claims = jwt.decode(token);
|
|
const userId = claims.id;
|
|
|
|
// ADD VIEW TO HISTORY IF NOT EXISTS
|
|
const client = await getClient();
|
|
const query = `SELECT * FROM history WHERE video = $1 AND user_id = $2`;
|
|
const result = await client.query(query, [id, userId]);
|
|
|
|
if (result.rows.length === 0) {
|
|
const insertQuery = `INSERT INTO history (video, user_id) VALUES ($1, $2)`;
|
|
await client.query(insertQuery, [id, userId]);
|
|
}
|
|
|
|
logger.write("successfully added views for video " + id, 200);
|
|
await client.end();
|
|
res.status(200).json({ "message": "Successfully added views" });
|
|
}
|
|
|
|
export async function updateAuthorizedUsers(req, res) {
|
|
const id = req.params.id;
|
|
const logger = req.body.logger;
|
|
logger.action("try to update authorized users for video " + id);
|
|
|
|
const { authorizedUsers } = req.body;
|
|
|
|
console.log(authorizedUsers);
|
|
|
|
const client = await getClient();
|
|
|
|
try {
|
|
// Remove all existing authorized users
|
|
const deleteQuery = `DELETE FROM video_authorized_users WHERE video_id = $1`;
|
|
console.log(`DELETE FROM video_authorized_users WHERE video_id = ${id}`);
|
|
await client.query(deleteQuery, [id]);
|
|
|
|
// Add new authorized users
|
|
const insertQuery = `INSERT INTO video_authorized_users (video_id, user_id) VALUES ($1, $2)`;
|
|
for (let i = 0; i < authorizedUsers.length; i++) {
|
|
const user = authorizedUsers[i];
|
|
console.log(`INSERT INTO video_authorized_users (video_id, user_id) VALUES (${id}, ${user})`)
|
|
await client.query(insertQuery, [id, user]);
|
|
}
|
|
|
|
logger.write("successfully updated authorized users for video " + id, 200);
|
|
res.status(200).json({ "message": "Successfully updated authorized users" });
|
|
} catch (error) {
|
|
logger.write("Error updating authorized users: " + error.message, 500);
|
|
res.status(500).json({ error: "Internal server error" });
|
|
} finally {
|
|
await client.end();
|
|
}
|
|
}
|