Browse Source

PTN DE SYSTEMD DE MERDE

features/visibility
Astri4-4 4 months ago
parent
commit
0a9ff8eaa4
  1. 20
      backend/app/controllers/user.controller.js
  2. 6
      backend/app/routes/user.route.js
  3. 38
      backend/logs/access.log
  4. 14
      frontend/src/components/UserCard.jsx
  5. 83
      frontend/src/pages/AddVideo.jsx
  6. 19
      frontend/src/services/user.service.js

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

@ -447,3 +447,23 @@ export async function isSubscribed(req, res) {
return res.status(200).json({subscribed: false});
}
}
export async function searchByUsername(req, res) {
const username = req.query.username;
const client = await getClient();
const logger = req.body.logger;
logger.action("try to search user by username " + username);
const query = `SELECT * FROM users WHERE username ILIKE $1`;
const result = await client.query(query, [`%${username}%`]);
if (result.rows.length === 0) {
logger.write("no user found with username " + username, 404);
client.end();
return res.status(404).json({error: "User Not Found"});
}
logger.write("successfully found user with username " + username, 200);
client.end();
res.status(200).json(result.rows);
}

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

@ -8,7 +8,8 @@ import {
deleteUser,
getChannel, getHistory,
isSubscribed,
verifyEmail
verifyEmail,
searchByUsername
} from "../controllers/user.controller.js";
import {
UserRegister,
@ -58,4 +59,7 @@ router.get("/:id/channel/subscribed", [addLogger, isTokenValid, User.id, Channel
// VERIFY EMAIL
router.post("/verify-email", [addLogger, validator], verifyEmail);
// SEARCH BY USERNAME
router.get("/search", [addLogger, isTokenValid], searchByUsername);
export default router;

38
backend/logs/access.log

@ -7427,3 +7427,41 @@
[2025-08-17 10:06:21.133] [undefined] GET(/:id/history): try to retrieve history of user 2
[2025-08-17 10:06:21.138] [undefined] GET(/:id/history): failed to retrieve history of user 2 because it doesn't exist with status 404
[2025-08-17 10:06:21.148] [undefined] GET(/user/:id): Playlists retrieved for user with id 2 with status 200
[2025-08-17 10:24:55.268] [undefined] POST(/): try to create new channel with owner 2 and name astria
[2025-08-17 10:24:55.271] [undefined] POST(/): Successfully created new channel with name astria with status 200
[2025-08-17 10:24:55.288] [undefined] GET(/:id/channel): try to retrieve channel of user 2
[2025-08-17 10:24:55.292] [undefined] GET(/:id/channel): successfully retrieved channel of user 2 with status 200
[2025-08-17 10:24:56.366] [undefined] GET(/:id): try to get channel with id 1
[2025-08-17 10:24:56.380] [undefined] GET(/:id): Successfully get channel with id 1 with status 200
[2025-08-17 10:24:56.386] [undefined] GET(/:id/stats): try to get stats
[2025-08-17 10:24:56.395] [undefined] GET(/:id/stats): Successfully get stats with status 200
[2025-08-17 10:25:00.825] [undefined] GET(/:id/channel): try to retrieve channel of user 2
[2025-08-17 10:25:00.830] [undefined] GET(/:id/channel): successfully retrieved channel of user 2 with status 200
[2025-08-17 10:28:34.803] [undefined] GET(/:id/channel): try to retrieve channel of user 2
[2025-08-17 10:28:34.807] [undefined] GET(/:id/channel): successfully retrieved channel of user 2 with status 200
[2025-08-17 10:29:51.209] [undefined] GET(/:id/channel): try to retrieve channel of user 2
[2025-08-17 10:29:51.214] [undefined] GET(/:id/channel): successfully retrieved channel of user 2 with status 200
[2025-08-17 10:32:59.876] [undefined] GET(/:id/channel): try to retrieve channel of user 2
[2025-08-17 10:32:59.880] [undefined] GET(/:id/channel): successfully retrieved channel of user 2 with status 200
[2025-08-17 10:33:09.144] [undefined] GET(/:id/channel): try to retrieve channel of user 2
[2025-08-17 10:33:09.148] [undefined] GET(/:id/channel): successfully retrieved channel of user 2 with status 200
[2025-08-17 10:43:59.502] [undefined] GET(/:id/channel): try to retrieve channel of user 2
[2025-08-17 10:43:59.507] [undefined] GET(/:id/channel): successfully retrieved channel of user 2 with status 200
[2025-08-17 10:45:08.860] [undefined] GET(/:id/channel): try to retrieve channel of user 2
[2025-08-17 10:45:08.863] [undefined] GET(/:id/channel): successfully retrieved channel of user 2 with status 200
[2025-08-17 10:45:12.454] [undefined] GET(/:id): failed due to invalid values with status 400
[2025-08-17 10:46:31.555] [undefined] GET(/:id): failed due to invalid values with status 400
[2025-08-17 10:53:32.094] [undefined] POST(/): Invalid token with status 401
[2025-08-17 10:53:43.691] [undefined] POST(/): Invalid token with status 401
[2025-08-17 10:54:16.538] [undefined] POST(/): Invalid token with status 401
[2025-08-17 10:55:19.631] [undefined] GET(/:id/channel): try to retrieve channel of user 2
[2025-08-17 10:55:19.636] [undefined] GET(/:id/channel): successfully retrieved channel of user 2 with status 200
[2025-08-17 10:55:19.640] [undefined] GET(/:id/history): try to retrieve history of user 2
[2025-08-17 10:55:19.645] [undefined] GET(/:id/history): failed to retrieve history of user 2 because it doesn't exist with status 404
[2025-08-17 10:55:19.656] [undefined] GET(/user/:id): Playlists retrieved for user with id 2 with status 200
[2025-08-17 10:55:25.476] [undefined] POST(/): Playlist created with id 3 with status 200
[2025-08-17 10:55:25.497] [undefined] GET(/user/:id): Playlists retrieved for user with id 2 with status 200
[2025-08-17 10:55:57.559] [undefined] GET(/:id): Invalid token with status 401
[2025-08-17 10:59:30.938] [undefined] GET(/:id): Invalid token with status 401
[2025-08-17 11:04:33.569] [undefined] GET(/:id): Invalid token with status 401
[2025-08-17 11:07:46.550] [undefined] POST(/): Invalid token with status 401

14
frontend/src/components/UserCard.jsx

@ -0,0 +1,14 @@
export default function UserCard({user, doShowControls}) {
return (
<div className="flex items-center justify-between p-2 border-b border-gray-700">
<span className="text-white">{user.username}</span>
{doShowControls && (
<button className="text-red-500" onClick={() => {}}>
Supprimer
</button>
)}
</div>
);
}

83
frontend/src/pages/AddVideo.jsx

@ -1,8 +1,9 @@
import Navbar from "../components/Navbar.jsx";
import { useEffect, useState } from "react";
import Tag from "../components/Tag.jsx";
import { getChannel } from "../services/user.service.js";
import { getChannel, searchByUsername } from "../services/user.service.js";
import { uploadVideo, uploadThumbnail, uploadTags } from "../services/video.service.js";
import { on } from "node:events";
export default function AddVideo() {
@ -14,10 +15,13 @@ export default function AddVideo() {
const [videoTitle, setVideoTitle] = useState("");
const [videoDescription, setVideoDescription] = useState("");
const [videoTags, setVideoTags] = useState([]);
const [visibility, setVisibility] = useState("public");
const [visibility, setVisibility] = useState("private");
const [videoThumbnail, setVideoThumbnail] = useState(null);
const [videoFile, setVideoFile] = useState(null);
const [channel, setChannel] = useState(null);
const [searchUser, setSearchUser] = useState("");
const [authorizedUsers, setAuthorizedUsers] = useState([]);
const [searchResults, setSearchResults] = useState([]);
const [alerts, setAlerts] = useState([]);
useEffect(() => {
@ -102,6 +106,22 @@ export default function AddVideo() {
setAlerts(alerts.filter(alert => alert !== alertToRemove));
};
const onUserSearch = (e) => {
const searchUser = e.target.value;
if (searchUser.trim() !== "") {
// Call the API to search for users
searchByUsername(searchUser, token, addAlert)
.then((results) => {
setSearchResults(results);
})
.catch((error) => {
addAlert('error', 'Erreur lors de la recherche d\'utilisateurs.');
});
} else {
setSearchResults([]);
}
}
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} />
@ -166,6 +186,65 @@ export default function AddVideo() {
<option value="private">Privé</option>
</select>
{
visibility == "private" && (
<div className="mb-4">
<label className="block text-white text-xl font-montserrat font-semibold mb-2" htmlFor="authorizedUsers">Utilisateurs autorisés</label>
<div>
<input
type="text"
id="authorizedUsers"
name="authorizedUsers"
className="w-full p-2 mb-4 glassmorphism focus:outline-none font-inter text-xl text-white"
placeholder="Rechercher un utilisateur"
value={searchUser}
onChange={(e) => setSearchUser(e.target.value)}
onKeyDown={(e) => {
if (e.key === 'Enter' && searchUser.trim() !== "") {
onUserSearch(e);
}
}}
/>
<div>
</div>
</div>
<div className="max-h-40 overflow-y-auto">
{authorizedUsers.map((user, index) => (
<div key={index} className="flex items-center justify-between p-2 border-b border-gray-700">
<span className="text-white">{user}</span>
<button
className="text-red-500"
onClick={() => setAuthorizedUsers(authorizedUsers.filter((u) => u !== user))}
>
Supprimer
</button>
</div>
))}
</div>
</div>
)
}
<label className="block text-white text-xl font-montserrat font-semibold mb-2" htmlFor="videoThumbnail">Miniature</label>
<input
type="file"

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

@ -123,3 +123,22 @@ export async function verifyEmail(email, token, addAlert) {
addAlert('error', "Erreur lors de la vérification de l'email.");
}
}
export async function searchByUsername(username, token, addAlert) {
try {
const response = await fetch(`/api/users/search?username=${encodeURIComponent(username)}`, {
method: "GET",
headers: {
"Authorization": `Bearer ${token}`,
}
});
if (!response.ok) {
throw new Error("Failed to search user");
}
const data = await response.json();
return data;
} catch (error) {
console.error("Error searching user by username:", error);
addAlert('error', "Erreur lors de la recherche de l'utilisateur.");
}
}
Loading…
Cancel
Save