Browse Source

Added delete buttons

pull/10/head
astria 4 months ago
parent
commit
7de2dac68a
  1. 85
      backend/app/controllers/user.controller.js
  2. 10
      backend/app/routes/user.route.js
  3. 392
      backend/logs/access.log
  4. 2
      frontend/src/components/Navbar.jsx
  5. 2
      frontend/src/modals/VerificationModal.jsx
  6. 31
      frontend/src/pages/Account.jsx
  7. 28
      frontend/src/pages/ManageChannel.jsx
  8. 23
      frontend/src/pages/ManageVideo.jsx
  9. 38
      frontend/src/pages/Subscription.jsx
  10. 9
      frontend/src/routes/routes.jsx
  11. 24
      frontend/src/services/channel.service.js
  12. 21
      frontend/src/services/user.service.js
  13. 23
      frontend/src/services/video.service.js

85
backend/app/controllers/user.controller.js

@ -467,3 +467,88 @@ export async function searchByUsername(req, res) {
client.end(); client.end();
res.status(200).json(result.rows); res.status(200).json(result.rows);
} }
export async function getAllSubscriptions(req,res) {
const userId = req.params.id;
const client = await getClient();
const logger = req.body.logger;
logger.action("try to retrieve all subscriptions of user " + userId);
const query = `
SELECT
subscriptions.id,
channels.id AS channel_id,
channels.name AS channel_name,
users.picture
FROM
subscriptions
LEFT JOIN channels ON subscriptions.channel = channels.id
LEFT JOIN users ON channels.owner = users.id
WHERE
subscriptions.owner = $1
`;
const result = await client.query(query, [userId]);
if (result.rows.length === 0) {
logger.write("no subscriptions found for user " + userId, 404);
client.end();
return res.status(404).json({ error: "No Subscriptions Found" });
}
logger.write("successfully retrieved all subscriptions of user " + userId, 200);
client.end();
res.status(200).json(result.rows);
}
export async function getAllSubscriptionVideos(req, res) {
const userId = req.params.id;
const client = await getClient();
const logger = req.body.logger;
logger.action("try to retrieve all subscriptions of user " + userId);
const query = `
SELECT
videos.id,
videos.title,
videos.thumbnail,
channels.id AS channel,
videos.visibility,
videos.file,
videos.format,
videos.release_date,
channels.id AS channel_id,
channels.owner,
COUNT(history.id) AS views,
JSON_BUILD_OBJECT(
'name', channels.name,
'profilePicture', users.picture,
'description', channels.description
) AS creator
FROM
subscriptions
LEFT JOIN channels ON subscriptions.channel = channels.id
LEFT JOIN users ON channels.owner = users.id
LEFT JOIN videos ON channels.id = videos.channel
LEFT JOIN history ON videos.id = history.video
WHERE
subscriptions.owner = $4
GROUP BY
videos.id,
channels.id,
users.id;
`;
const result = await client.query(query, [userId]);
if (result.rows.length === 0) {
logger.write("no subscriptions found for user " + userId, 404);
client.end();
return res.status(404).json({ error: "No Subscriptions Found" });
}
logger.write("successfully retrieved all subscriptions of user " + userId, 200);
client.end();
res.status(200).json(result.rows);
}

10
backend/app/routes/user.route.js

@ -9,7 +9,9 @@ import {
getChannel, getHistory, getChannel, getHistory,
isSubscribed, isSubscribed,
verifyEmail, verifyEmail,
searchByUsername searchByUsername,
getAllSubscriptions,
getAllSubscriptionVideos
} from "../controllers/user.controller.js"; } from "../controllers/user.controller.js";
import { import {
UserRegister, UserRegister,
@ -63,4 +65,10 @@ router.get("/:id/channel/subscribed", [addLogger, isTokenValid, User.id, Channel
// VERIFY EMAIL // VERIFY EMAIL
router.post("/verify-email", [addLogger, validator], verifyEmail); router.post("/verify-email", [addLogger, validator], verifyEmail);
// GET ALL SUBSCRIPTIONS
router.get("/:id/subscriptions", [addLogger, isTokenValid, User.id, validator, doUserExists], getAllSubscriptions);
// GET ALL SUBSCRIPTIONS VIDEOS
router.get("/:id/subscriptions/videos", [addLogger, isTokenValid, User.id, validator, doUserExists], getAllSubscriptionVideos);
export default router; export default router;

392
backend/logs/access.log

@ -10067,3 +10067,395 @@
[2025-08-26 15:36:07.000] [undefined] POST(/:id/subscribe): try to toggle subscription for channel with id 1 [2025-08-26 15:36:07.000] [undefined] POST(/:id/subscribe): try to toggle subscription for channel with id 1
[2025-08-26 15:36:07.027] [undefined] POST(/:id/subscribe): Successfully subscribed to channel with status 200 [2025-08-26 15:36:07.027] [undefined] POST(/:id/subscribe): Successfully subscribed to channel with status 200
[2025-08-26 15:36:13.655] [undefined] GET(/see-later): 'See Later' playlist retrieved for user with id 6 with status 200 [2025-08-26 15:36:13.655] [undefined] GET(/see-later): 'See Later' playlist retrieved for user with id 6 with status 200
[2025-08-26 15:41:26.274] [undefined] GET(/:id/channel): try to retrieve channel of user 6
[2025-08-26 15:41:26.279] [undefined] GET(/:id/history): try to retrieve history of user 6
[2025-08-26 15:41:26.288] [undefined] GET(/:id/channel): successfully retrieved channel of user 6 with status 200
[2025-08-26 15:41:26.293] [undefined] GET(/:id/history): successfully retrieved history of user 6 with status 200
[2025-08-26 15:41:26.301] [undefined] GET(/user/:id): Playlists retrieved for user with id 6 with status 200
[2025-08-26 15:41:50.682] [undefined] GET(/:id/channel): try to retrieve channel of user 6
[2025-08-26 15:41:50.686] [undefined] GET(/:id/channel): successfully retrieved channel of user 6 with status 200
[2025-08-26 15:41:50.695] [undefined] GET(/:id/history): try to retrieve history of user 6
[2025-08-26 15:41:50.703] [undefined] GET(/:id/history): successfully retrieved history of user 6 with status 200
[2025-08-26 15:41:50.714] [undefined] GET(/user/:id): Playlists retrieved for user with id 6 with status 200
[2025-08-26 15:42:35.491] [undefined] GET(/:id/channel): try to retrieve channel of user 6
[2025-08-26 15:42:35.497] [undefined] GET(/:id/channel): successfully retrieved channel of user 6 with status 200
[2025-08-26 15:42:35.506] [undefined] GET(/:id/history): try to retrieve history of user 6
[2025-08-26 15:42:35.512] [undefined] GET(/:id/history): successfully retrieved history of user 6 with status 200
[2025-08-26 15:42:35.523] [undefined] GET(/user/:id): Playlists retrieved for user with id 6 with status 200
[2025-08-26 15:42:49.724] [undefined] GET(/:id/history): try to retrieve history of user 6
[2025-08-26 15:42:49.729] [undefined] GET(/:id/channel): try to retrieve channel of user 6
[2025-08-26 15:42:49.738] [undefined] GET(/:id/channel): successfully retrieved channel of user 6 with status 200
[2025-08-26 15:42:49.744] [undefined] GET(/:id/history): successfully retrieved history of user 6 with status 200
[2025-08-26 15:42:49.757] [undefined] GET(/user/:id): Playlists retrieved for user with id 6 with status 200
[2025-08-26 15:42:55.139] [undefined] GET(/:id/history): try to retrieve history of user 6
[2025-08-26 15:42:55.144] [undefined] GET(/:id/channel): try to retrieve channel of user 6
[2025-08-26 15:42:55.153] [undefined] GET(/:id/channel): successfully retrieved channel of user 6 with status 200
[2025-08-26 15:42:55.157] [undefined] GET(/:id/history): successfully retrieved history of user 6 with status 200
[2025-08-26 15:42:55.168] [undefined] GET(/user/:id): Playlists retrieved for user with id 6 with status 200
[2025-08-26 15:43:15.023] [undefined] GET(/:id/channel): try to retrieve channel of user 6
[2025-08-26 15:43:15.028] [undefined] GET(/:id/channel): successfully retrieved channel of user 6 with status 200
[2025-08-26 15:43:15.032] [undefined] GET(/:id/history): try to retrieve history of user 6
[2025-08-26 15:43:15.037] [undefined] GET(/:id/history): successfully retrieved history of user 6 with status 200
[2025-08-26 15:43:15.045] [undefined] GET(/user/:id): Playlists retrieved for user with id 6 with status 200
[2025-08-26 15:43:26.176] [undefined] GET(/:id/channel): try to retrieve channel of user 6
[2025-08-26 15:43:26.181] [undefined] GET(/:id/channel): successfully retrieved channel of user 6 with status 200
[2025-08-26 15:43:26.187] [undefined] GET(/:id/history): try to retrieve history of user 6
[2025-08-26 15:43:26.194] [undefined] GET(/:id/history): successfully retrieved history of user 6 with status 200
[2025-08-26 15:43:26.204] [undefined] GET(/user/:id): Playlists retrieved for user with id 6 with status 200
[2025-08-26 15:44:08.173] [undefined] GET(/:id/channel): try to retrieve channel of user 6
[2025-08-26 15:44:08.178] [undefined] GET(/:id/channel): successfully retrieved channel of user 6 with status 200
[2025-08-26 15:44:08.186] [undefined] GET(/:id/history): try to retrieve history of user 6
[2025-08-26 15:44:08.192] [undefined] GET(/:id/history): successfully retrieved history of user 6 with status 200
[2025-08-26 15:44:08.199] [undefined] GET(/user/:id): Playlists retrieved for user with id 6 with status 200
[2025-08-26 15:44:25.097] [undefined] GET(/:id/channel): try to retrieve channel of user 6
[2025-08-26 15:44:25.102] [undefined] GET(/:id/history): try to retrieve history of user 6
[2025-08-26 15:44:25.110] [undefined] GET(/:id/channel): successfully retrieved channel of user 6 with status 200
[2025-08-26 15:44:25.116] [undefined] GET(/:id/history): successfully retrieved history of user 6 with status 200
[2025-08-26 15:44:25.125] [undefined] GET(/user/:id): Playlists retrieved for user with id 6 with status 200
[2025-08-26 15:44:41.414] [undefined] GET(/:id/channel): try to retrieve channel of user 6
[2025-08-26 15:44:41.419] [undefined] GET(/:id/channel): successfully retrieved channel of user 6 with status 200
[2025-08-26 15:44:41.427] [undefined] GET(/:id/history): try to retrieve history of user 6
[2025-08-26 15:44:41.436] [undefined] GET(/:id/history): successfully retrieved history of user 6 with status 200
[2025-08-26 15:44:41.449] [undefined] GET(/user/:id): Playlists retrieved for user with id 6 with status 200
[2025-08-26 15:45:51.589] [undefined] GET(/:id/history): try to retrieve history of user 6
[2025-08-26 15:45:51.594] [undefined] GET(/:id/channel): try to retrieve channel of user 6
[2025-08-26 15:45:51.601] [undefined] GET(/:id/channel): successfully retrieved channel of user 6 with status 200
[2025-08-26 15:45:51.605] [undefined] GET(/:id/history): successfully retrieved history of user 6 with status 200
[2025-08-26 15:45:51.616] [undefined] GET(/user/:id): Playlists retrieved for user with id 6 with status 200
[2025-08-26 15:46:27.177] [undefined] GET(/:id/channel): try to retrieve channel of user 6
[2025-08-26 15:46:27.181] [undefined] GET(/:id/channel): successfully retrieved channel of user 6 with status 200
[2025-08-26 15:46:27.191] [undefined] GET(/:id/history): try to retrieve history of user 6
[2025-08-26 15:46:27.200] [undefined] GET(/:id/history): successfully retrieved history of user 6 with status 200
[2025-08-26 15:46:27.209] [undefined] GET(/user/:id): Playlists retrieved for user with id 6 with status 200
[2025-08-26 15:46:33.985] [undefined] GET(/:id/channel): try to retrieve channel of user 6
[2025-08-26 15:46:33.990] [undefined] GET(/:id/history): try to retrieve history of user 6
[2025-08-26 15:46:33.998] [undefined] GET(/:id/channel): successfully retrieved channel of user 6 with status 200
[2025-08-26 15:46:34.004] [undefined] GET(/:id/history): successfully retrieved history of user 6 with status 200
[2025-08-26 15:46:34.017] [undefined] GET(/user/:id): Playlists retrieved for user with id 6 with status 200
[2025-08-26 15:46:49.302] [undefined] GET(/:id/channel): try to retrieve channel of user 6
[2025-08-26 15:46:49.308] [undefined] GET(/:id/history): try to retrieve history of user 6
[2025-08-26 15:46:49.316] [undefined] GET(/:id/channel): successfully retrieved channel of user 6 with status 200
[2025-08-26 15:46:49.323] [undefined] GET(/:id/history): successfully retrieved history of user 6 with status 200
[2025-08-26 15:46:49.334] [undefined] GET(/user/:id): Playlists retrieved for user with id 6 with status 200
[2025-08-26 15:48:01.797] [undefined] GET(/:id/channel): try to retrieve channel of user 6
[2025-08-26 15:48:01.803] [undefined] GET(/:id/channel): successfully retrieved channel of user 6 with status 200
[2025-08-26 15:48:01.813] [undefined] GET(/:id/history): try to retrieve history of user 6
[2025-08-26 15:48:01.822] [undefined] GET(/:id/history): successfully retrieved history of user 6 with status 200
[2025-08-26 15:48:01.833] [undefined] GET(/user/:id): Playlists retrieved for user with id 6 with status 200
[2025-08-26 15:48:04.117] [undefined] DELETE(/:id): try to delete user 6
[2025-08-26 15:48:04.135] [undefined] DELETE(/:id): successfully deleted user 6 with status undefined
[2025-08-26 15:48:12.208] [undefined] GET(/:id/channel): try to retrieve channel of user 6
[2025-08-26 15:48:12.216] [undefined] GET(/:id/channel): failed to retrieve channel of user 6 because it doesn't exist with status 404
[2025-08-26 15:48:12.225] [undefined] GET(/:id/history): try to retrieve history of user 6
[2025-08-26 15:48:12.232] [undefined] GET(/user/:id): failed because user doesn't exists with status 404
[2025-08-26 15:48:12.238] [undefined] GET(/:id/history): failed to retrieve history of user 6 because it doesn't exist with status 404
[2025-08-26 15:48:24.141] [undefined] GET(/:id/history): try to retrieve history of user 6
[2025-08-26 15:48:24.147] [undefined] GET(/:id/history): failed to retrieve history of user 6 because it doesn't exist with status 404
[2025-08-26 15:48:24.155] [undefined] GET(/:id/channel): try to retrieve channel of user 6
[2025-08-26 15:48:24.158] [undefined] GET(/user/:id): failed because user doesn't exists with status 404
[2025-08-26 15:48:24.162] [undefined] GET(/:id/channel): failed to retrieve channel of user 6 because it doesn't exist with status 404
[2025-08-26 15:48:26.460] [undefined] GET(/see-later): No 'See Later' playlist found for user with id 6 with status 404
[2025-08-26 15:48:28.549] [undefined] GET(/see-later): No 'See Later' playlist found for user with id 6 with status 404
[2025-08-26 15:48:29.648] [undefined] GET(/:id/channel): try to retrieve channel of user 6
[2025-08-26 15:48:29.653] [undefined] GET(/:id/channel): failed to retrieve channel of user 6 because it doesn't exist with status 404
[2025-08-26 15:48:29.657] [undefined] GET(/:id/history): try to retrieve history of user 6
[2025-08-26 15:48:29.662] [undefined] GET(/user/:id): failed because user doesn't exists with status 404
[2025-08-26 15:48:29.667] [undefined] GET(/:id/history): failed to retrieve history of user 6 because it doesn't exist with status 404
[2025-08-26 15:48:31.930] [undefined] DELETE(/:id): failed because user doesn't exists with status 404
[2025-08-26 15:48:38.126] [undefined] POST(/login): try to login with username 'astria'
[2025-08-26 15:48:38.185] [undefined] POST(/login): Successfully logged in with status 200
[2025-08-26 15:48:38.274] [undefined] GET(/see-later): 'See Later' playlist retrieved for user with id 1 with status 200
[2025-08-26 15:48:50.976] [undefined] GET(/see-later): 'See Later' playlist retrieved for user with id 1 with status 200
[2025-08-26 15:48:54.169] [undefined] GET(/:id/channel): try to retrieve channel of user 1
[2025-08-26 15:48:54.173] [undefined] GET(/:id/history): try to retrieve history of user 1
[2025-08-26 15:48:54.182] [undefined] GET(/:id/channel): successfully retrieved channel of user 1 with status 200
[2025-08-26 15:48:54.191] [undefined] GET(/:id/history): successfully retrieved history of user 1 with status 200
[2025-08-26 15:48:54.200] [undefined] GET(/user/:id): Playlists retrieved for user with id 1 with status 200
[2025-08-26 15:48:57.070] [undefined] GET(/:id): Playlist retrieved with id 1 with status 200
[2025-08-26 15:48:59.285] [undefined] GET(/:id/channel): try to retrieve channel of user 1
[2025-08-26 15:48:59.289] [undefined] GET(/:id/channel): successfully retrieved channel of user 1 with status 200
[2025-08-26 15:48:59.302] [undefined] GET(/:id/history): try to retrieve history of user 1
[2025-08-26 15:48:59.307] [undefined] GET(/:id/history): successfully retrieved history of user 1 with status 200
[2025-08-26 15:48:59.315] [undefined] GET(/user/:id): Playlists retrieved for user with id 1 with status 200
[2025-08-26 15:49:01.900] [undefined] GET(/:id): try to get channel with id 1
[2025-08-26 15:49:01.914] [undefined] GET(/:id/stats): try to get stats
[2025-08-26 15:49:01.919] [undefined] GET(/:id): Successfully get channel with id 1 with status 200
[2025-08-26 15:49:01.929] [undefined] GET(/:id/stats): Successfully get stats with status 200
[2025-08-26 15:49:43.316] [undefined] GET(/:id): try to get channel with id 1
[2025-08-26 15:49:43.326] [undefined] GET(/:id/stats): try to get stats
[2025-08-26 15:49:43.332] [undefined] GET(/:id): Successfully get channel with id 1 with status 200
[2025-08-26 15:49:43.339] [undefined] GET(/:id/stats): Successfully get stats with status 200
[2025-08-26 15:50:04.443] [undefined] GET(/:id): try to get channel with id 1
[2025-08-26 15:50:04.456] [undefined] GET(/:id/stats): try to get stats
[2025-08-26 15:50:04.459] [undefined] GET(/:id): Successfully get channel with id 1 with status 200
[2025-08-26 15:50:04.470] [undefined] GET(/:id/stats): Successfully get stats with status 200
[2025-08-26 15:50:10.998] [undefined] GET(/:id): try to get channel with id 1
[2025-08-26 15:50:11.012] [undefined] GET(/:id/stats): try to get stats
[2025-08-26 15:50:11.016] [undefined] GET(/:id): Successfully get channel with id 1 with status 200
[2025-08-26 15:50:11.026] [undefined] GET(/:id/stats): Successfully get stats with status 200
[2025-08-26 15:50:41.680] [undefined] GET(/:id): try to get channel with id 1
[2025-08-26 15:50:41.693] [undefined] GET(/:id/stats): try to get stats
[2025-08-26 15:50:41.700] [undefined] GET(/:id): Successfully get channel with id 1 with status 200
[2025-08-26 15:50:41.711] [undefined] GET(/:id/stats): Successfully get stats with status 200
[2025-08-26 15:50:48.472] [undefined] GET(/:id): try to get channel with id 1
[2025-08-26 15:50:48.487] [undefined] GET(/:id/stats): try to get stats
[2025-08-26 15:50:48.493] [undefined] GET(/:id): Successfully get channel with id 1 with status 200
[2025-08-26 15:50:48.504] [undefined] GET(/:id/stats): Successfully get stats with status 200
[2025-08-26 15:52:15.045] [undefined] GET(/:id): try to get channel with id 1
[2025-08-26 15:52:15.060] [undefined] GET(/:id): Successfully get channel with id 1 with status 200
[2025-08-26 15:52:15.068] [undefined] GET(/:id/stats): try to get stats
[2025-08-26 15:52:15.087] [undefined] GET(/:id/stats): Successfully get stats with status 200
[2025-08-26 15:52:33.686] [undefined] GET(/:id): try to get channel with id 1
[2025-08-26 15:52:33.702] [undefined] GET(/:id/stats): try to get stats
[2025-08-26 15:52:33.709] [undefined] GET(/:id): Successfully get channel with id 1 with status 200
[2025-08-26 15:52:33.719] [undefined] GET(/:id/stats): Successfully get stats with status 200
[2025-08-26 15:53:06.388] [undefined] GET(/:id): try to get channel with id 1
[2025-08-26 15:53:06.398] [undefined] GET(/:id/stats): try to get stats
[2025-08-26 15:53:06.402] [undefined] GET(/:id): Successfully get channel with id 1 with status 200
[2025-08-26 15:53:06.419] [undefined] GET(/:id/stats): Successfully get stats with status 200
[2025-08-26 15:53:17.500] [undefined] GET(/:id): try to get channel with id 1
[2025-08-26 15:53:17.514] [undefined] GET(/:id/stats): try to get stats
[2025-08-26 15:53:17.521] [undefined] GET(/:id): Successfully get channel with id 1 with status 200
[2025-08-26 15:53:17.534] [undefined] GET(/:id/stats): Successfully get stats with status 200
[2025-08-26 15:53:29.874] [undefined] GET(/:id): try to get channel with id 1
[2025-08-26 15:53:29.888] [undefined] GET(/:id/stats): try to get stats
[2025-08-26 15:54:48.374] [undefined] GET(/:id/channel): try to retrieve channel of user 1
[2025-08-26 15:54:48.380] [undefined] GET(/:id/channel): successfully retrieved channel of user 1 with status 200
[2025-08-26 15:54:48.388] [undefined] GET(/:id/history): try to retrieve history of user 1
[2025-08-26 15:54:48.395] [undefined] GET(/:id/history): successfully retrieved history of user 1 with status 200
[2025-08-26 15:54:48.402] [undefined] GET(/user/:id): Playlists retrieved for user with id 1 with status 200
[2025-08-26 15:54:49.010] [undefined] GET(/:id): try to get channel with id 1
[2025-08-26 15:54:49.025] [undefined] GET(/:id/stats): try to get stats
[2025-08-26 15:54:49.033] [undefined] GET(/:id): Successfully get channel with id 1 with status 200
[2025-08-26 15:54:49.043] [undefined] GET(/:id/stats): Successfully get stats with status 200
[2025-08-26 15:54:58.353] [undefined] GET(/:id): try to get channel with id 1
[2025-08-26 15:54:58.366] [undefined] GET(/:id/stats): try to get stats
[2025-08-26 15:54:58.371] [undefined] GET(/:id): Successfully get channel with id 1 with status 200
[2025-08-26 15:54:58.379] [undefined] GET(/:id/stats): Successfully get stats with status 200
[2025-08-26 15:55:00.659] [undefined] DELETE(/:id): try to delete channel with id 1
[2025-08-26 15:55:00.678] [undefined] DELETE(/:id): Successfully deleted channel with status 200
[2025-08-26 15:55:00.737] [undefined] GET(/:id/channel): try to retrieve channel of user 1
[2025-08-26 15:55:00.741] [undefined] GET(/:id/channel): failed to retrieve channel of user 1 because it doesn't exist with status 404
[2025-08-26 15:55:00.747] [undefined] GET(/:id/history): try to retrieve history of user 1
[2025-08-26 15:55:00.753] [undefined] GET(/:id/history): successfully retrieved history of user 1 with status 200
[2025-08-26 15:55:00.762] [undefined] GET(/user/:id): Playlists retrieved for user with id 1 with status 200
[2025-08-26 15:55:08.732] [undefined] POST(/): try to create new channel with owner 1 and name lol
[2025-08-26 15:55:08.737] [undefined] POST(/): Successfully created new channel with name lol with status 200
[2025-08-26 15:55:08.756] [undefined] GET(/:id/channel): try to retrieve channel of user 1
[2025-08-26 15:55:08.760] [undefined] GET(/:id/channel): successfully retrieved channel of user 1 with status 200
[2025-08-26 15:55:10.726] [undefined] GET(/:id): try to get channel with id 4
[2025-08-26 15:55:10.738] [undefined] GET(/:id/stats): try to get stats
[2025-08-26 15:55:10.743] [undefined] GET(/:id): Successfully get channel with id 4 with status 200
[2025-08-26 15:55:10.751] [undefined] GET(/:id/stats): Successfully get stats with status 200
[2025-08-26 15:55:12.338] [undefined] GET(/:id/channel): try to retrieve channel of user 1
[2025-08-26 15:55:12.344] [undefined] GET(/:id/channel): successfully retrieved channel of user 1 with status 200
[2025-08-26 15:55:32.631] [undefined] POST(/): try to upload video with status undefined
[2025-08-26 15:55:32.636] [undefined] POST(/): successfully uploaded video with status 200
[2025-08-26 15:55:32.709] [undefined] POST(/thumbnail): try to add thumbnail to video 6
[2025-08-26 15:55:32.713] [undefined] POST(/thumbnail): successfully uploaded thumbnail with status 200
[2025-08-26 15:55:32.738] [undefined] PUT(/:id/tags): try to add tags to video 6
[2025-08-26 15:55:32.748] [undefined] PUT(/:id/tags): successfully added tags to video 6 with status 200
[2025-08-26 15:55:35.088] [undefined] GET(/see-later): 'See Later' playlist retrieved for user with id 1 with status 200
[2025-08-26 15:55:39.465] [undefined] GET(/:id/channel): try to retrieve channel of user 1
[2025-08-26 15:55:39.470] [undefined] GET(/:id/channel): successfully retrieved channel of user 1 with status 200
[2025-08-26 15:55:39.483] [undefined] GET(/:id/history): try to retrieve history of user 1
[2025-08-26 15:55:39.488] [undefined] GET(/:id/history): successfully retrieved history of user 1 with status 200
[2025-08-26 15:55:39.496] [undefined] GET(/user/:id): Playlists retrieved for user with id 1 with status 200
[2025-08-26 15:55:41.408] [undefined] GET(/:id): try to get channel with id 4
[2025-08-26 15:55:41.420] [undefined] GET(/:id/stats): try to get stats
[2025-08-26 15:55:41.424] [undefined] GET(/:id): Successfully get channel with id 4 with status 200
[2025-08-26 15:55:41.433] [undefined] GET(/:id/stats): Successfully get stats with status 200
[2025-08-26 15:55:44.085] [undefined] DELETE(/:id): try to delete channel with id 4
[2025-08-26 15:55:44.105] [undefined] DELETE(/:id): Successfully deleted channel with status 200
[2025-08-26 15:55:44.165] [undefined] GET(/:id/channel): try to retrieve channel of user 1
[2025-08-26 15:55:44.168] [undefined] GET(/:id/channel): failed to retrieve channel of user 1 because it doesn't exist with status 404
[2025-08-26 15:55:44.173] [undefined] GET(/:id/history): try to retrieve history of user 1
[2025-08-26 15:55:44.178] [undefined] GET(/:id/history): successfully retrieved history of user 1 with status 200
[2025-08-26 15:55:44.185] [undefined] GET(/user/:id): Playlists retrieved for user with id 1 with status 200
[2025-08-26 15:55:45.728] [undefined] GET(/see-later): 'See Later' playlist retrieved for user with id 1 with status 200
[2025-08-26 15:55:48.768] [undefined] GET(/:id/channel): try to retrieve channel of user 1
[2025-08-26 15:55:48.773] [undefined] GET(/:id/channel): failed to retrieve channel of user 1 because it doesn't exist with status 404
[2025-08-26 15:55:48.782] [undefined] GET(/:id/history): try to retrieve history of user 1
[2025-08-26 15:55:48.788] [undefined] GET(/:id/history): successfully retrieved history of user 1 with status 200
[2025-08-26 15:55:48.796] [undefined] GET(/user/:id): Playlists retrieved for user with id 1 with status 200
[2025-08-26 15:57:00.479] [undefined] GET(/see-later): No 'See Later' playlist found for user with id 6 with status 404
[2025-08-26 15:57:04.027] [undefined] GET(/:id/channel): try to retrieve channel of user 6
[2025-08-26 15:57:04.030] [undefined] GET(/:id/history): try to retrieve history of user 6
[2025-08-26 15:57:04.044] [undefined] GET(/user/:id): failed because user doesn't exists with status 404
[2025-08-26 15:57:04.047] [undefined] GET(/:id/channel): failed to retrieve channel of user 6 because it doesn't exist with status 404
[2025-08-26 15:57:04.054] [undefined] GET(/:id/history): failed to retrieve history of user 6 because it doesn't exist with status 404
[2025-08-26 15:57:05.125] [undefined] GET(/see-later): No 'See Later' playlist found for user with id 6 with status 404
[2025-08-26 16:09:56.968] [undefined] GET(/:id/channel): try to retrieve channel of user 1
[2025-08-26 16:09:56.972] [undefined] GET(/:id/channel): failed to retrieve channel of user 1 because it doesn't exist with status 404
[2025-08-26 16:10:03.448] [undefined] GET(/see-later): 'See Later' playlist retrieved for user with id 4 with status 200
[2025-08-26 16:10:06.841] [undefined] GET(/:id/channel): try to retrieve channel of user 4
[2025-08-26 16:10:06.845] [undefined] GET(/:id/history): try to retrieve history of user 4
[2025-08-26 16:10:06.859] [undefined] GET(/:id/channel): successfully retrieved channel of user 4 with status 200
[2025-08-26 16:10:06.863] [undefined] GET(/:id/history): successfully retrieved history of user 4 with status 200
[2025-08-26 16:10:06.871] [undefined] GET(/user/:id): Playlists retrieved for user with id 4 with status 200
[2025-08-26 16:10:08.135] [undefined] GET(/:id): try to get channel with id 2
[2025-08-26 16:10:08.146] [undefined] GET(/:id/stats): try to get stats
[2025-08-26 16:10:08.153] [undefined] GET(/:id): Successfully get channel with id 2 with status 200
[2025-08-26 16:10:08.159] [undefined] GET(/:id/stats): Successfully get stats with status 200
[2025-08-26 16:10:09.575] [undefined] GET(/:id/channel): try to retrieve channel of user 4
[2025-08-26 16:10:09.580] [undefined] GET(/:id/channel): successfully retrieved channel of user 4 with status 200
[2025-08-26 16:10:10.872] [undefined] GET(/:id): try to get channel with id 2
[2025-08-26 16:10:10.885] [undefined] GET(/:id/stats): try to get stats
[2025-08-26 16:10:10.890] [undefined] GET(/:id): Successfully get channel with id 2 with status 200
[2025-08-26 16:10:10.897] [undefined] GET(/:id/stats): Successfully get stats with status 200
[2025-08-26 16:10:11.917] [undefined] GET(/:id/likes/day): try to get likes per day
[2025-08-26 16:10:11.945] [undefined] GET(/:id): try to get video 1
[2025-08-26 16:10:11.950] [undefined] GET(/:id/likes/day): successfully retrieved likes per day with status 200
[2025-08-26 16:10:11.960] [undefined] GET(/:id): successfully get video 1 with status 200
[2025-08-26 16:11:12.845] [undefined] GET(/:id/likes/day): try to get likes per day
[2025-08-26 16:11:12.860] [undefined] GET(/:id/likes/day): successfully retrieved likes per day with status 200
[2025-08-26 16:11:12.866] [undefined] GET(/:id): try to get video 1
[2025-08-26 16:11:12.879] [undefined] GET(/:id): successfully get video 1 with status 200
[2025-08-26 16:13:04.558] [undefined] GET(/:id/likes/day): try to get likes per day
[2025-08-26 16:13:04.568] [undefined] GET(/:id): try to get video 1
[2025-08-26 16:13:04.573] [undefined] GET(/:id/likes/day): successfully retrieved likes per day with status 200
[2025-08-26 16:13:04.585] [undefined] GET(/:id): successfully get video 1 with status 200
[2025-08-26 16:13:25.046] [undefined] GET(/:id/likes/day): try to get likes per day
[2025-08-26 16:13:25.058] [undefined] GET(/:id): try to get video 1
[2025-08-26 16:13:25.062] [undefined] GET(/:id/likes/day): successfully retrieved likes per day with status 200
[2025-08-26 16:13:25.072] [undefined] GET(/:id): successfully get video 1 with status 200
[2025-08-26 16:13:40.023] [undefined] GET(/:id/likes/day): try to get likes per day
[2025-08-26 16:13:40.037] [undefined] GET(/:id): try to get video 1
[2025-08-26 16:13:40.041] [undefined] GET(/:id/likes/day): successfully retrieved likes per day with status 200
[2025-08-26 16:13:40.055] [undefined] GET(/:id): successfully get video 1 with status 200
[2025-08-26 16:14:34.733] [undefined] GET(/:id/likes/day): try to get likes per day
[2025-08-26 16:14:34.746] [undefined] GET(/:id): try to get video 1
[2025-08-26 16:14:34.750] [undefined] GET(/:id/likes/day): successfully retrieved likes per day with status 200
[2025-08-26 16:14:34.759] [undefined] GET(/:id): successfully get video 1 with status 200
[2025-08-26 16:14:58.054] [undefined] GET(/:id/likes/day): try to get likes per day
[2025-08-26 16:14:58.068] [undefined] GET(/:id): try to get video 1
[2025-08-26 16:14:58.074] [undefined] GET(/:id/likes/day): successfully retrieved likes per day with status 200
[2025-08-26 16:14:58.084] [undefined] GET(/:id): successfully get video 1 with status 200
[2025-08-26 16:15:10.520] [undefined] GET(/:id/likes/day): try to get likes per day
[2025-08-26 16:15:10.536] [undefined] GET(/:id): try to get video 1
[2025-08-26 16:15:10.540] [undefined] GET(/:id/likes/day): successfully retrieved likes per day with status 200
[2025-08-26 16:15:10.553] [undefined] GET(/:id): successfully get video 1 with status 200
[2025-08-26 16:15:12.810] [undefined] DELETE(/:id): failed due to invalid values with status 400
[2025-08-26 16:15:18.652] [undefined] DELETE(/:id): failed due to invalid values with status 400
[2025-08-26 16:15:43.306] [undefined] GET(/:id/likes/day): try to get likes per day
[2025-08-26 16:15:43.315] [undefined] GET(/:id): try to get video 1
[2025-08-26 16:15:43.320] [undefined] GET(/:id/likes/day): successfully retrieved likes per day with status 200
[2025-08-26 16:15:43.329] [undefined] GET(/:id): successfully get video 1 with status 200
[2025-08-26 16:16:01.555] [undefined] GET(/:id/likes/day): try to get likes per day
[2025-08-26 16:16:01.569] [undefined] GET(/:id): try to get video 1
[2025-08-26 16:16:01.573] [undefined] GET(/:id/likes/day): successfully retrieved likes per day with status 200
[2025-08-26 16:16:01.587] [undefined] GET(/:id): successfully get video 1 with status 200
[2025-08-26 16:16:03.631] [undefined] DELETE(/:id): try to delete video 1
[2025-08-26 16:16:03.654] [undefined] DELETE(/:id): successfully deleted video with status 200
[2025-08-26 16:16:10.685] [undefined] GET(/:id): failed because video not found with status 404
[2025-08-26 16:16:10.689] [undefined] GET(/:id/likes/day): failed because video not found with status 404
[2025-08-26 16:16:14.087] [undefined] GET(/:id/channel): try to retrieve channel of user 4
[2025-08-26 16:16:14.091] [undefined] GET(/:id/channel): successfully retrieved channel of user 4 with status 200
[2025-08-26 16:16:14.096] [undefined] GET(/:id/history): try to retrieve history of user 4
[2025-08-26 16:16:14.102] [undefined] GET(/:id/history): failed to retrieve history of user 4 because it doesn't exist with status 404
[2025-08-26 16:16:14.114] [undefined] GET(/user/:id): Playlists retrieved for user with id 4 with status 200
[2025-08-26 16:16:16.462] [undefined] GET(/:id): try to get channel with id 2
[2025-08-26 16:16:16.475] [undefined] GET(/:id/stats): try to get stats
[2025-08-26 16:16:16.480] [undefined] GET(/:id): Successfully get channel with id 2 with status 200
[2025-08-26 16:16:16.488] [undefined] GET(/:id/stats): Successfully get stats with status 200
[2025-08-26 16:16:18.484] [undefined] GET(/:id/likes/day): try to get likes per day
[2025-08-26 16:16:18.498] [undefined] GET(/:id): try to get video 2
[2025-08-26 16:16:18.502] [undefined] GET(/:id/likes/day): successfully retrieved likes per day with status 200
[2025-08-26 16:16:18.512] [undefined] GET(/:id): successfully get video 2 with status 200
[2025-08-26 16:16:28.707] [undefined] GET(/:id/likes/day): try to get likes per day
[2025-08-26 16:16:28.718] [undefined] GET(/:id): try to get video 2
[2025-08-26 16:16:28.722] [undefined] GET(/:id/likes/day): successfully retrieved likes per day with status 200
[2025-08-26 16:16:28.740] [undefined] GET(/:id): successfully get video 2 with status 200
[2025-08-26 16:16:39.033] [undefined] DELETE(/:id): try to delete video 2
[2025-08-26 16:16:39.059] [undefined] DELETE(/:id): successfully deleted video with status 200
[2025-08-26 16:16:54.602] [undefined] DELETE(/:id): failed because video not found with status 404
[2025-08-26 16:17:04.670] [undefined] GET(/:id): try to get channel with id 2
[2025-08-26 16:17:04.684] [undefined] GET(/:id/stats): try to get stats
[2025-08-26 16:17:04.689] [undefined] GET(/:id): Successfully get channel with id 2 with status 200
[2025-08-26 16:17:04.697] [undefined] GET(/:id/stats): Successfully get stats with status 200
[2025-08-26 16:17:20.798] [undefined] GET(/:id): try to get channel with id 2
[2025-08-26 16:17:20.811] [undefined] GET(/:id/stats): try to get stats
[2025-08-26 16:17:20.822] [undefined] GET(/:id): Successfully get channel with id 2 with status 200
[2025-08-26 16:17:20.829] [undefined] GET(/:id/stats): Successfully get stats with status 200
[2025-08-26 16:17:22.400] [undefined] GET(/:id/channel): try to retrieve channel of user 4
[2025-08-26 16:17:22.404] [undefined] GET(/:id/channel): successfully retrieved channel of user 4 with status 200
[2025-08-26 16:17:34.376] [undefined] POST(/): try to upload video with status undefined
[2025-08-26 16:17:34.380] [undefined] POST(/): successfully uploaded video with status 200
[2025-08-26 16:17:34.446] [undefined] POST(/thumbnail): try to add thumbnail to video 7
[2025-08-26 16:17:34.450] [undefined] POST(/thumbnail): successfully uploaded thumbnail with status 200
[2025-08-26 16:17:55.921] [undefined] GET(/see-later): 'See Later' playlist retrieved for user with id 4 with status 200
[2025-08-26 16:17:59.436] [undefined] GET(/:id/channel): try to retrieve channel of user 4
[2025-08-26 16:17:59.439] [undefined] GET(/:id/channel): successfully retrieved channel of user 4 with status 200
[2025-08-26 16:17:59.445] [undefined] GET(/:id/history): try to retrieve history of user 4
[2025-08-26 16:17:59.451] [undefined] GET(/:id/history): failed to retrieve history of user 4 because it doesn't exist with status 404
[2025-08-26 16:17:59.458] [undefined] GET(/user/:id): Playlists retrieved for user with id 4 with status 200
[2025-08-26 16:18:01.471] [undefined] GET(/:id): try to get channel with id 2
[2025-08-26 16:18:01.481] [undefined] GET(/:id/stats): try to get stats
[2025-08-26 16:18:01.487] [undefined] GET(/:id): Successfully get channel with id 2 with status 200
[2025-08-26 16:18:01.497] [undefined] GET(/:id/stats): Successfully get stats with status 200
[2025-08-26 16:18:02.554] [undefined] GET(/:id/likes/day): try to get likes per day
[2025-08-26 16:18:02.568] [undefined] GET(/:id): try to get video 7
[2025-08-26 16:18:02.574] [undefined] GET(/:id/likes/day): successfully retrieved likes per day with status 200
[2025-08-26 16:18:02.585] [undefined] GET(/:id): successfully get video 7 with status 200
[2025-08-26 16:18:05.795] [undefined] DELETE(/:id): try to delete video 7
[2025-08-26 16:18:05.820] [undefined] DELETE(/:id): successfully deleted video with status 200
[2025-08-26 16:18:05.860] [undefined] GET(/:id): try to get channel with id 2
[2025-08-26 16:18:05.873] [undefined] GET(/:id/stats): try to get stats
[2025-08-26 16:18:05.878] [undefined] GET(/:id): Successfully get channel with id 2 with status 200
[2025-08-26 16:18:05.887] [undefined] GET(/:id/stats): Successfully get stats with status 200
[2025-08-26 16:18:11.746] [undefined] GET(/see-later): 'See Later' playlist retrieved for user with id 4 with status 200
[2025-08-26 16:25:37.703] [undefined] POST(/login): try to login with username 'sacha'
[2025-08-26 16:25:37.762] [undefined] POST(/login): Successfully logged in with status 200
[2025-08-26 16:25:37.885] [undefined] GET(/see-later): 'See Later' playlist retrieved for user with id 2 with status 200
[2025-08-26 16:25:41.326] [undefined] GET(/:id/channel): try to retrieve channel of user 2
[2025-08-26 16:25:41.329] [undefined] GET(/:id/history): try to retrieve history of user 2
[2025-08-26 16:25:41.337] [undefined] GET(/:id/channel): failed to retrieve channel of user 2 because it doesn't exist with status 404
[2025-08-26 16:25:41.341] [undefined] GET(/:id/history): failed to retrieve history of user 2 because it doesn't exist with status 404
[2025-08-26 16:25:41.351] [undefined] GET(/user/:id): Playlists retrieved for user with id 2 with status 200
[2025-08-26 16:25:46.533] [undefined] POST(/): try to create new channel with owner 2 and name sacha
[2025-08-26 16:25:46.538] [undefined] POST(/): Successfully created new channel with name sacha with status 200
[2025-08-26 16:25:46.555] [undefined] GET(/:id/channel): try to retrieve channel of user 2
[2025-08-26 16:25:46.559] [undefined] GET(/:id/channel): successfully retrieved channel of user 2 with status 200
[2025-08-26 16:25:48.209] [undefined] GET(/:id): try to get channel with id 5
[2025-08-26 16:25:48.222] [undefined] GET(/:id/stats): try to get stats
[2025-08-26 16:25:48.227] [undefined] GET(/:id): Successfully get channel with id 5 with status 200
[2025-08-26 16:25:48.236] [undefined] GET(/:id/stats): Successfully get stats with status 200
[2025-08-26 16:25:49.322] [undefined] GET(/:id/channel): try to retrieve channel of user 2
[2025-08-26 16:25:49.329] [undefined] GET(/:id/channel): successfully retrieved channel of user 2 with status 200
[2025-08-26 16:26:10.503] [undefined] POST(/): try to upload video with status undefined
[2025-08-26 16:26:10.508] [undefined] POST(/): successfully uploaded video with status 200
[2025-08-26 16:26:10.845] [undefined] POST(/thumbnail): try to add thumbnail to video 8
[2025-08-26 16:26:10.859] [undefined] POST(/thumbnail): successfully uploaded thumbnail with status 200
[2025-08-26 16:26:10.883] [undefined] PUT(/:id/tags): try to add tags to video 8
[2025-08-26 16:26:10.894] [undefined] PUT(/:id/tags): successfully added tags to video 8 with status 200
[2025-08-26 16:26:13.101] [undefined] GET(/see-later): 'See Later' playlist retrieved for user with id 2 with status 200
[2025-08-26 16:26:14.108] [undefined] GET(/:id/channel): try to retrieve channel of user 2
[2025-08-26 16:26:14.114] [undefined] GET(/:id/history): try to retrieve history of user 2
[2025-08-26 16:26:14.118] [undefined] GET(/:id/channel): successfully retrieved channel of user 2 with status 200
[2025-08-26 16:26:14.124] [undefined] GET(/:id/history): failed to retrieve history of user 2 because it doesn't exist with status 404
[2025-08-26 16:26:14.133] [undefined] GET(/user/:id): Playlists retrieved for user with id 2 with status 200
[2025-08-26 16:27:03.028] [undefined] GET(/see-later): 'See Later' playlist retrieved for user with id 2 with status 200
[2025-08-26 16:27:10.881] [undefined] GET(/see-later): 'See Later' playlist retrieved for user with id 4 with status 200
[2025-08-26 16:27:15.161] [undefined] GET(/see-later): 'See Later' playlist retrieved for user with id 4 with status 200
[2025-08-26 16:27:22.771] [undefined] GET(/:id): try to get video 8
[2025-08-26 16:27:22.774] [undefined] GET(/user/:id): Playlists retrieved for user with id 4 with status 200
[2025-08-26 16:27:22.788] [undefined] GET(/:id): successfully get video 8 with status 200
[2025-08-26 16:27:22.828] [undefined] GET(/:id/similar): try to get similar videos for video 8
[2025-08-26 16:27:22.844] [undefined] GET(/:id/similar): successfully get similar videos for video 8 with status 200
[2025-08-26 16:27:22.884] [undefined] GET(/:id/views): try to add views for video 8
[2025-08-26 16:27:22.896] [undefined] GET(/:id/views): successfully added views for video 8 with status 200
[2025-08-26 16:27:23.971] [undefined] POST(/:id/subscribe): try to toggle subscription for channel with id 5
[2025-08-26 16:27:23.986] [undefined] POST(/:id/subscribe): Successfully subscribed to channel with status 200
[2025-08-26 16:35:12.279] [undefined] GET(/:id): try to get video 8
[2025-08-26 16:35:12.283] [undefined] GET(/user/:id): Playlists retrieved for user with id 4 with status 200
[2025-08-26 16:35:12.305] [undefined] GET(/:id): successfully get video 8 with status 200
[2025-08-26 16:35:12.352] [undefined] GET(/:id/similar): try to get similar videos for video 8
[2025-08-26 16:35:12.381] [undefined] GET(/:id/similar): successfully get similar videos for video 8 with status 200
[2025-08-26 16:35:12.452] [undefined] GET(/:id/views): try to add views for video 8
[2025-08-26 16:35:12.468] [undefined] GET(/:id/views): successfully added views for video 8 with status 200
[2025-08-26 16:35:13.888] [undefined] GET(/see-later): 'See Later' playlist retrieved for user with id 4 with status 200
[2025-08-26 16:35:18.862] [undefined] GET(/see-later): 'See Later' playlist retrieved for user with id 4 with status 200
[2025-08-26 16:35:19.678] [undefined] GET(/see-later): 'See Later' playlist retrieved for user with id 4 with status 200
[2025-08-26 16:35:20.454] [undefined] GET(/see-later): 'See Later' playlist retrieved for user with id 4 with status 200
[2025-08-26 16:35:21.161] [undefined] GET(/see-later): 'See Later' playlist retrieved for user with id 4 with status 200
[2025-08-26 16:35:47.725] [undefined] GET(/see-later): 'See Later' playlist retrieved for user with id 4 with status 200

2
frontend/src/components/Navbar.jsx

@ -52,7 +52,7 @@ export default function Navbar({ isSearchPage = false, alerts = [], onCloseAlert
<li><a href="/">Accueil</a></li> <li><a href="/">Accueil</a></li>
{isAuthenticated ? ( {isAuthenticated ? (
<> <>
<li><a href="/">Abonnements</a></li> <li><a href="/subscriptions">Abonnements</a></li>
<li> <li>
<a href="/profile" className="flex items-center space-x-4"> <a href="/profile" className="flex items-center space-x-4">
<span className="text-2xl">{user?.username}</span> <span className="text-2xl">{user?.username}</span>

2
frontend/src/modals/VerificationModal.jsx

@ -4,7 +4,7 @@ export default function VerificationModal({title, onConfirm, onCancel, isOpen})
if (!isOpen) return null; if (!isOpen) return null;
return ( return (
<div className="fixed inset-0 flex items-center justify-center px-5 lg:px-0"> <div className="fixed z-40 inset-0 flex items-center justify-center px-5 lg:px-0">
<div className="glassmorphism w-full lg:w-auto p-6"> <div className="glassmorphism w-full lg:w-auto p-6">
<h2 className="text-lg text-white font-semibold mb-4">{title}</h2> <h2 className="text-lg text-white font-semibold mb-4">{title}</h2>
<div className="flex justify-start lg:justify-end"> <div className="flex justify-start lg:justify-end">

31
frontend/src/pages/Account.jsx

@ -5,7 +5,8 @@ import VideoCard from "../components/VideoCard.jsx";
import { useNavigate } from "react-router-dom"; import { useNavigate } from "react-router-dom";
import CreateChannelModal from "../modals/CreateChannelModal.jsx"; import CreateChannelModal from "../modals/CreateChannelModal.jsx";
import CreatePlaylistModal from "../modals/CreatePlaylistModal.jsx"; import CreatePlaylistModal from "../modals/CreatePlaylistModal.jsx";
import { getChannel, getUserHistory, getPlaylists, updateUser } from "../services/user.service.js"; import { getChannel, getUserHistory, getPlaylists, updateUser, deleteUser } from "../services/user.service.js";
import VerificationModal from "../modals/VerificationModal.jsx";
export default function Account() { export default function Account() {
@ -24,6 +25,7 @@ export default function Account() {
const [isModalOpen, setIsModalOpen] = useState(false); const [isModalOpen, setIsModalOpen] = useState(false);
const [isCreatePlaylistModalOpen, setIsCreatePlaylistModalOpen] = useState(false); const [isCreatePlaylistModalOpen, setIsCreatePlaylistModalOpen] = useState(false);
const [alerts, setAlerts] = useState([]); const [alerts, setAlerts] = useState([]);
const [isVerificationModalOpen, setIsVerificationModalOpen] = useState(false);
const navigation = useNavigate(); const navigation = useNavigate();
@ -90,6 +92,11 @@ export default function Account() {
setIsCreatePlaylistModalOpen(false); setIsCreatePlaylistModalOpen(false);
fetchUserPlaylists(); fetchUserPlaylists();
} }
const onDeleteAccount = async () => {
await deleteUser(user.id, token, addAlert);
localStorage.removeItem("user");
navigation("/login");
}
return ( return (
<div className="min-w-screen min-h-screen bg-linear-to-br from-left-gradient to-right-gradient"> <div className="min-w-screen min-h-screen bg-linear-to-br from-left-gradient to-right-gradient">
@ -99,7 +106,8 @@ export default function Account() {
{/* Left side */} {/* Left side */}
{/* Profile / Edit profile */} {/* Profile / Edit profile */}
<form className="glassmorphism lg:w-1/3 p-10"> <div className=" lg:w-1/3 ">
<form className="glassmorphism p-10">
<div className="relative w-1/3 aspect-square overflow-hidden mb-3 mx-auto" onMouseEnter={() => setIsPictureEditActive(true)} onMouseLeave={() => setIsPictureEditActive(false)} > <div className="relative w-1/3 aspect-square overflow-hidden mb-3 mx-auto" onMouseEnter={() => setIsPictureEditActive(true)} onMouseLeave={() => setIsPictureEditActive(false)} >
<label htmlFor="image"> <label htmlFor="image">
<img <img
@ -126,7 +134,6 @@ export default function Account() {
placeholder="Nom d'utilisateur" placeholder="Nom d'utilisateur"
disabled={!editMode} disabled={!editMode}
/> />
<label htmlFor="email" className="text-xl lg:text-2xl text-white mb-1 mt-4 block font-montserrat"> <label htmlFor="email" className="text-xl lg:text-2xl text-white mb-1 mt-4 block font-montserrat">
Adresse e-mail Adresse e-mail
</label> </label>
@ -139,7 +146,6 @@ export default function Account() {
placeholder="Adresse mail" placeholder="Adresse mail"
disabled={!editMode} disabled={!editMode}
/> />
{editMode && ( {editMode && (
<> <>
<label htmlFor="password" className="text-xl lg:text-2xl text-white mb-1 mt-4 block font-montserrat"> <label htmlFor="password" className="text-xl lg:text-2xl text-white mb-1 mt-4 block font-montserrat">
@ -154,7 +160,6 @@ export default function Account() {
placeholder="**************" placeholder="**************"
disabled={!editMode} disabled={!editMode}
/> />
<label htmlFor="confirm-password" className="text-xl lg:text-2xl text-white mb-1 mt-4 block font-montserrat"> <label htmlFor="confirm-password" className="text-xl lg:text-2xl text-white mb-1 mt-4 block font-montserrat">
Confirmer le mot de passe Confirmer le mot de passe
</label> </label>
@ -169,9 +174,7 @@ export default function Account() {
/> />
</> </>
) )
} }
<div className="flex justify-center mt-5"> <div className="flex justify-center mt-5">
{ {
editMode ? ( editMode ? (
@ -203,6 +206,20 @@ export default function Account() {
} }
</div> </div>
</form> </form>
<button
className="bg-red-500 p-3 rounded-sm text-white font-montserrat text-lg lg:text-2xl font-bold cursor-pointer mt-4 w-full"
onClick={() => setIsVerificationModalOpen(true)}
>
Supprimer le compte
</button>
<VerificationModal
title="Confirmer la suppression du compte"
isOpen={isVerificationModalOpen}
onCancel={() => setIsVerificationModalOpen(false)}
onConfirm={() => onDeleteAccount()}
/>
</div>
{ /* Right side */} { /* Right side */}

28
frontend/src/pages/ManageChannel.jsx

@ -3,7 +3,8 @@ import {useEffect, useState} from "react";
import {useNavigate, useParams} from "react-router-dom"; import {useNavigate, useParams} from "react-router-dom";
import {useAuth} from "../contexts/AuthContext.jsx"; import {useAuth} from "../contexts/AuthContext.jsx";
import VideoStatListElement from "../components/VideoStatListElement.jsx"; import VideoStatListElement from "../components/VideoStatListElement.jsx";
import {fetchChannelDetails, fetchChannelStats, updateChannel} from "../services/channel.service.js"; import {fetchChannelDetails, fetchChannelStats, updateChannel, deleteChannel} from "../services/channel.service.js";
import VerificationModal from "../modals/VerificationModal.jsx";
export default function ManageChannel() { export default function ManageChannel() {
@ -18,6 +19,7 @@ export default function ManageChannel() {
const [description, setDescription] = useState(null); const [description, setDescription] = useState(null);
const [editMode, setEditMode] = useState(false); const [editMode, setEditMode] = useState(false);
const [alerts, setAlerts] = useState([]); const [alerts, setAlerts] = useState([]);
const [isVerificationModalOpen, setIsVerificationModalOpen] = useState(false);
const token = localStorage.getItem("token"); const token = localStorage.getItem("token");
const nonEditModeClasses = "text-2xl font-bold text-white p-2 focus:text-white focus:outline-none w-full font-montserrat resizable-none text-center"; const nonEditModeClasses = "text-2xl font-bold text-white p-2 focus:text-white focus:outline-none w-full font-montserrat resizable-none text-center";
@ -64,6 +66,11 @@ export default function ManageChannel() {
setAlerts([...alerts, newAlert]); setAlerts([...alerts, newAlert]);
}; };
const onDeleteChannel = async () => {
await deleteChannel(id, token, addAlert);
navigate("/profile");
}
return ( return (
<div className="min-w-screen min-h-screen bg-linear-to-br from-left-gradient to-right-gradient"> <div className="min-w-screen min-h-screen bg-linear-to-br from-left-gradient to-right-gradient">
<Navbar isSearchPage={false} alerts={alerts} onCloseAlert={onCloseAlert} /> <Navbar isSearchPage={false} alerts={alerts} onCloseAlert={onCloseAlert} />
@ -71,7 +78,8 @@ export default function ManageChannel() {
<main className="pt-[48px] lg:pt-[118px] px-5 lg:px-36 lg:flex pb-10"> <main className="pt-[48px] lg:pt-[118px] px-5 lg:px-36 lg:flex pb-10">
{/* LEFT SIDE */} {/* LEFT SIDE */}
<form className="glassmorphism lg:w-1/3 py-10 px-4 h-max"> <div className="lg:w-1/3">
<form className="glassmorphism py-10 px-4 h-max">
<img src={user.picture} className="w-1/3 aspect-square object-cover rounded-full mx-auto" alt=""/> <img src={user.picture} className="w-1/3 aspect-square object-cover rounded-full mx-auto" alt=""/>
<label htmlFor="name" className={`text-2xl text-white mb-1 block font-montserrat ${editMode ? "block" : "hidden"} `}> <label htmlFor="name" className={`text-2xl text-white mb-1 block font-montserrat ${editMode ? "block" : "hidden"} `}>
Nom de chaine Nom de chaine
@ -85,7 +93,6 @@ export default function ManageChannel() {
placeholder="Nom d'utilisateur" placeholder="Nom d'utilisateur"
disabled={!editMode} disabled={!editMode}
/> />
<label htmlFor="name" className={`text-2xl text-white mb-1 block font-montserrat`}> <label htmlFor="name" className={`text-2xl text-white mb-1 block font-montserrat`}>
Description Description
</label> </label>
@ -98,7 +105,6 @@ export default function ManageChannel() {
placeholder="Description de votre chaine" placeholder="Description de votre chaine"
disabled={!editMode} disabled={!editMode}
></textarea> ></textarea>
{ {
editMode ? ( editMode ? (
<div className="mt-4"> <div className="mt-4">
@ -127,8 +133,20 @@ export default function ManageChannel() {
</button> </button>
) )
} }
</form> </form>
<button
className="bg-red-500 p-3 rounded-sm text-white font-montserrat text-2xl font-black cursor-pointer mt-4 w-full"
onClick={() => setIsVerificationModalOpen(true)}
>
Supprimer la chaîne
</button>
<VerificationModal
title="Êtes-vous sûr de vouloir supprimer cette chaîne ?"
isOpen={isVerificationModalOpen}
onCancel={() => setIsVerificationModalOpen(false)}
onConfirm={onDeleteChannel}
/>
</div>
{/* RIGHT SIDE */} {/* RIGHT SIDE */}
<div className="lg:w-2/3 lg:pl-10 mt-4 lg:mt-0" > <div className="lg:w-2/3 lg:pl-10 mt-4 lg:mt-0" >

23
frontend/src/pages/ManageVideo.jsx

@ -6,8 +6,10 @@ import LinearGraph from "../components/LinearGraph.jsx";
import Comment from "../components/Comment.jsx"; import Comment from "../components/Comment.jsx";
import Tag from "../components/Tag.jsx"; import Tag from "../components/Tag.jsx";
import UserCard from "../components/UserCard.jsx"; import UserCard from "../components/UserCard.jsx";
import {getVideoById, getLikesPerDay, updateVideo, updateVideoFile, uploadThumbnail, uploadTags, updateAuthorizedUsers} from "../services/video.service.js"; import {getVideoById, getLikesPerDay, updateVideo, updateVideoFile, uploadThumbnail, uploadTags, updateAuthorizedUsers, deleteVideo} from "../services/video.service.js";
import {searchByUsername} from "../services/user.service.js"; import {searchByUsername} from "../services/user.service.js";
import VerificationModal from "../modals/VerificationModal.jsx";
import {useNavigate} from "react-router-dom";
export default function ManageVideo() { export default function ManageVideo() {
@ -15,6 +17,7 @@ export default function ManageVideo() {
const { user } = useAuth(); const { user } = useAuth();
const token = localStorage.getItem("token"); const token = localStorage.getItem("token");
const {id} = useParams(); const {id} = useParams();
const navigate = useNavigate();
const [video, setVideo] = useState(null); const [video, setVideo] = useState(null);
const [likesPerDay, setLikesPerDay] = useState([]); const [likesPerDay, setLikesPerDay] = useState([]);
@ -28,6 +31,7 @@ export default function ManageVideo() {
const [alerts, setAlerts] = useState([]); const [alerts, setAlerts] = useState([]);
const [searchUser, setSearchUser] = useState(""); const [searchUser, setSearchUser] = useState("");
const [searchResults, setSearchResults] = useState([]); const [searchResults, setSearchResults] = useState([]);
const [isVerificationModalOpen, setIsVerificationModalOpen] = useState(false);
const nonEditModeClasses = "text-md font-normal text-white p-2 focus:text-white focus:outline-none w-full font-montserrat resizable-none"; const nonEditModeClasses = "text-md font-normal text-white p-2 focus:text-white focus:outline-none w-full font-montserrat resizable-none";
const editModeClasses = nonEditModeClasses + " glassmorphism"; const editModeClasses = nonEditModeClasses + " glassmorphism";
@ -198,6 +202,11 @@ export default function ManageVideo() {
addAlert('success', "Utilisateur supprimé avec succès."); addAlert('success', "Utilisateur supprimé avec succès.");
} }
const onDeleteVideo = async () => {
await deleteVideo(id, video.channel, token, addAlert);
navigate("/manage-channel/" + video.channel);
}
return ( return (
<div className="min-w-screen min-h-screen bg-linear-to-br from-left-gradient to-right-gradient"> <div className="min-w-screen min-h-screen bg-linear-to-br from-left-gradient to-right-gradient">
@ -385,6 +394,18 @@ export default function ManageVideo() {
) )
} }
<button
className="bg-red-600 p-3 rounded-sm text-white font-montserrat text-2xl font-black cursor-pointer mt-4 w-full"
onClick={() => setIsVerificationModalOpen(true)}
>
Supprimer la vidéo
</button>
<VerificationModal
title="Êtes-vous sûr de vouloir supprimer cette vidéo ?"
isOpen={isVerificationModalOpen}
onCancel={() => setIsVerificationModalOpen(false)}
onConfirm={onDeleteVideo}
/>
</div> </div>

38
frontend/src/pages/Subscription.jsx

@ -0,0 +1,38 @@
import React from "react";
export default function Subscription() {
const [alerts, setAlerts] = React.useState([]);
const [subscriptions, setSubscriptions] = React.useState([]);
const fetchSubscriptions = async () => {
const token = localStorage.getItem('token');
if (!token) {
addAlert('error', "User not authenticated");
return;
}
const data = await getAllSubscriptions(userId, token, addAlert);
if (data) {
setSubscriptions(data);
}
};
const addAlert = (type, message) => {
const newAlert = { type, message, id: Date.now() }; // Add unique ID
setAlerts([...alerts, newAlert]);
};
const onCloseAlert = (alertToRemove) => {
setAlerts(alerts.filter(alert => alert !== alertToRemove));
};
return (
<div className="min-w-screen min-h-screen bg-linear-to-br from-left-gradient to-right-gradient">
<Navbar isSearchPage={false} alerts={alerts} onCloseAlert={onCloseAlert} />
<main className="px-5 lg:px-36 w-full pt-[48px] lg:pt-[118px]">
</main>
</div>
);
}

9
frontend/src/routes/routes.jsx

@ -11,6 +11,7 @@ import Search from "../pages/Search.jsx";
import Channel from "../pages/Channel.jsx"; import Channel from "../pages/Channel.jsx";
import Playlist from "../pages/Playlist.jsx"; import Playlist from "../pages/Playlist.jsx";
import LoginSuccess from '../pages/LoginSuccess.jsx' import LoginSuccess from '../pages/LoginSuccess.jsx'
import Subscriptions from '../pages/Subscription.jsx'
const routes = [ const routes = [
{ path: "/", element: <Home/> }, { path: "/", element: <Home/> },
@ -95,6 +96,14 @@ const routes = [
element: ( element: (
<LoginSuccess/> <LoginSuccess/>
) )
},
{
path: "/subscriptions",
element: (
<ProtectedRoute requireAuth={true}>
<Subscriptions/>
</ProtectedRoute>
)
} }
] ]

24
frontend/src/services/channel.service.js

@ -98,3 +98,27 @@ export async function createChannel(body, token, addAlert) {
const data = await request.json(); const data = await request.json();
return data; return data;
} }
export async function deleteChannel(channelId, token, addAlert) {
try {
const response = await fetch(`/api/channels/${channelId}`, {
method: "DELETE",
headers: {
"Authorization": `Bearer ${token}`
}
});
if (response.ok) {
addAlert('success', 'Chaîne supprimée avec succès');
return true;
} else {
const errorData = await response.json();
addAlert('error', errorData.message || 'Erreur lors de la suppression de la chaîne');
return false;
}
} catch (error) {
console.error("Error deleting channel:", error);
addAlert('error', 'Erreur lors de la suppression de la chaîne');
return false;
}
}

21
frontend/src/services/user.service.js

@ -1,3 +1,5 @@
import { getAllSubscriptions } from "../../../backend/app/controllers/user.controller";
export async function isSubscribed(channelId, addAlert) { export async function isSubscribed(channelId, addAlert) {
const token = localStorage.getItem('token'); const token = localStorage.getItem('token');
if (!token) { if (!token) {
@ -150,3 +152,22 @@ export async function searchByUsername(username, token, addAlert) {
addAlert('error', error.message || "Erreur lors de la recherche de l'utilisateur."); addAlert('error', error.message || "Erreur lors de la recherche de l'utilisateur.");
} }
} }
export async function deleteUser(userId, token, addAlert) {
try {
const response = await fetch(`/api/users/${userId}`, {
method: "DELETE",
headers: {
"Authorization": `Bearer ${token}`,
}
});
if (!response.ok) {
throw new Error("Failed to delete user");
}
const data = await response.json();
return data;
} catch (error) {
console.error("Error deleting user:", error);
addAlert('error', "Erreur lors de la suppression de l'utilisateur.");
}
}

23
frontend/src/services/video.service.js

@ -241,3 +241,26 @@ export async function updateAuthorizedUsers(id, body, token, addAlert) {
addAlert('error', 'Erreur lors de la mise à jour des utilisateurs autorisés'); addAlert('error', 'Erreur lors de la mise à jour des utilisateurs autorisés');
} }
} }
export async function deleteVideo(id, channel, token, addAlert) {
try {
const request = await fetch(`/api/videos/${id}`, {
method: 'DELETE',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${token}`
},
body: JSON.stringify({ channel })
});
if (!request.ok) {
const errorData = await request.json();
console.error("Backend validation errors:", errorData);
addAlert('error', 'Erreur lors de la suppression de la vidéo');
return;
}
return request;
} catch (error) {
console.error("Error deleting video:", error);
addAlert('error', 'Erreur lors de la suppression de la vidéo');
}
}
Loading…
Cancel
Save