diff --git a/frontend/src/pages/home.css b/frontend/src/assets/css/home.css similarity index 100% rename from frontend/src/pages/home.css rename to frontend/src/assets/css/home.css diff --git a/frontend/src/assets/css/login.css b/frontend/src/assets/css/login.css new file mode 100644 index 0000000..8b517fa --- /dev/null +++ b/frontend/src/assets/css/login.css @@ -0,0 +1,41 @@ +.login-block { + max-width: 300px; + margin: 20px auto; + padding: 20px; + border: 1px solid #ccc; + border-radius: 10px; + background-color: #f9f9f9; + text-align: center; +} + +.login-block input { + width: 100%; + padding: 10px; + margin: 10px -10px; + border: 1px solid #ccc; + border-radius: 5px; +} + +.button-group { + display: flex; + justify-content: space-between; +} + +.button-group button { + width: 45%; + padding: 10px; + background-color: #61dafb; + border: none; + border-radius: 5px; + cursor: pointer; + font-size: 1rem; +} + +.button-group button:hover { + background-color: #21a1f1; +} + +.error { + color: red; + margin-top: 10px; +} diff --git a/frontend/src/pages/pageLayout.css b/frontend/src/assets/css/pageLayout.css similarity index 100% rename from frontend/src/pages/pageLayout.css rename to frontend/src/assets/css/pageLayout.css diff --git a/frontend/src/pages/login.tsx b/frontend/src/components/login.tsx similarity index 66% rename from frontend/src/pages/login.tsx rename to frontend/src/components/login.tsx index 6c084d9..769a274 100644 --- a/frontend/src/pages/login.tsx +++ b/frontend/src/components/login.tsx @@ -1,6 +1,6 @@ // src/login.tsx import React, { useState } from 'react'; -import './login.css'; // Optional: For styling +import '../assets/css/login.css'; // Optional: For styling interface AuthForm { username: string; @@ -18,36 +18,54 @@ const Login: React.FC = () => { setFormData({ ...formData, [name]: value }); }; - // Handle login with GET request to /user/login + // Handle login with PUT request to /authenticate const handleLogin = async () => { + setError(null); // Reset any previous errors try { console.log('Attempting login with:', formData); - // Create query parameters - const queryParams = new URLSearchParams({ - username: formData.username, - password: formData.password, - }); + // Prepare the request body + const requestBody = { + User: { + name: formData.username, + isAdmin: false, // Adjust this if needed based on your logic + }, + Secret: { + password: formData.password, + }, + }; - const response = await fetch(`http://localhost:5000/user/login?${queryParams}`, { - method: 'GET', - }); + // const response = await fetch('http://localhost:5000/authenticate', { + // method: 'PUT', + // headers: { + // 'Content-Type': 'application/json', + // }, + // body: JSON.stringify(requestBody), + // }); - if (response.ok) { - const { token } = await response.json(); + if (true) { + const token = "bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"; + // if (response.status === 200) { + // const { token } = await response.json(); alert('Login successful!'); setIsLoggedIn(true); - localStorage.setItem('authToken', token); // Store the token - } else { - const errorData = await response.json(); - setError(errorData.message || 'Failed to login.'); + localStorage.setItem('authToken', token); // Store the token for future use + // } else if (response.status === 400) { + // setError('Missing fields or improperly formed request.'); + // } else if (response.status === 401) { + // setError('Invalid username or password.'); + // } else if (response.status === 501) { + // setError('Authentication not supported by the system.'); + // } else { + // setError('Failed to login due to an unknown error.'); } } catch (err) { + console.error('Error during login:', err); setError('Network error. Please try again later.'); } }; - // Handle sign-up with POST request to /user + // Handle sign-up logic (kept as-is) const handleSignUp = async () => { try { console.log('Attempting sign-up with:', formData); @@ -72,7 +90,7 @@ const Login: React.FC = () => { } }; - // Handle logout with GET request to /logout + // Handle logout logic (kept as-is) const handleLogout = async () => { try { console.log('Attempting logout...'); @@ -103,7 +121,7 @@ const Login: React.FC = () => { ) : (
e.preventDefault()}> -

User Login / Sign Up

+

User Login

{ + const [packageName, setPackageName] = useState(''); + const [results, setResults] = useState([]); + const [authToken, setAuthToken] = useState(null); + const [error, setError] = useState(null); + const [offset, setOffset] = useState(0); + + // Retrieve auth token from localStorage on component mount + useEffect(() => { + const token = localStorage.getItem('authToken'); + if (token) { + setAuthToken(token); + } else { + alert('Authentication token not found. Please log in.'); + } + }, []); + + const handleSearch = async (e: React.FormEvent) => { + e.preventDefault(); + setError(null); + + if (!authToken) { + alert('Authentication token is missing. Please log in.'); + return; + } + + try { + const requestBody = [{ Name: packageName }]; + + // const response = await fetch(`/packages?offset=${offset}`, { + // method: 'POST', + // headers: { + // 'Content-Type': 'application/json', + // 'X-Authorization': authToken, + // }, + // body: JSON.stringify(requestBody), + // }); + + const response1 = JSON.stringify({ + status: 200, + data: [ + { + packageName: 'example-package', + version: '1.0.0', + description: 'Sample description for testing purposes.', + fileUrl: 'https://example.com/uploads/example-package-v1.0.0.zip', + uploadDate: '2024-11-03T14:30:00Z', + debloatEnabled: true, + }, + { + packageName: 'another-package', + version: '2.0.1', + description: 'Another example package for testing.', + fileUrl: 'https://example.com/uploads/another-package-v2.0.1.zip', + uploadDate: '2024-11-02T10:15:00Z', + debloatEnabled: false, + }, + ], + headers: { + offset: '10', + }, + }); + + // Parse the response as JSON + const response = JSON.parse(response1); + + if (response.status === 200) { + const data: PackageMetadata[] = await response.json(); + setResults(data); + const newOffset = parseInt(response.headers.get('offset') || '0', 10); + setOffset(newOffset); + } else if (response.status === 400) { + setError('Search failed: Missing fields or invalid query.'); + } else if (response.status === 403) { + setError('Search failed: Authentication failed due to invalid or missing AuthenticationToken.'); + } else if (response.status === 413) { + setError('Search failed: Too many packages returned.'); + } else { + setError('Search failed with an unknown error.'); + } + } catch (err) { + console.error('Error during search:', err); + setError('An error occurred while searching for packages.'); + } + }; + + return ( +
+

Search for Packages

+ + + + + + {error &&

{error}

} + + {results.length > 0 && ( +
+

Search Results

+
    + {results.map((pkg) => ( +
  • + Name: {pkg.Name} | Version: {pkg.Version} | ID: {pkg.ID} +
  • + ))} +
+
+ )} +
+ ); +}; + +export default SearchByName; diff --git a/frontend/src/pages/download.tsx b/frontend/src/pages/download.tsx index 3a4940a..3a788d2 100644 --- a/frontend/src/pages/download.tsx +++ b/frontend/src/pages/download.tsx @@ -1,10 +1,178 @@ -import React from 'react'; +import React, { useState, useEffect } from 'react'; import PageLayout from './pageLayout'; +interface PackageMetadata { + ID: string; + Name: string; + Version: string; +} + const DownloadPage: React.FC = () => { + const [searchTerm, setSearchTerm] = useState(''); + const [packages, setPackages] = useState([]); + const [authToken, setAuthToken] = useState(null); + const [error, setError] = useState(null); + const [offset, setOffset] = useState(0); + + // Retrieve auth token from localStorage on component mount + useEffect(() => { + const token = localStorage.getItem('authToken'); + if (token) { + setAuthToken(token); + } else { + alert('Authentication token not found. Please log in.'); + } + }, []); + + const handleSearch = async (e: React.FormEvent) => { + e.preventDefault(); + setError(null); + + if (!authToken) { + alert('Authentication token is missing. Please log in.'); + return; + } + + try { + const requestBody = [{ Name: searchTerm }]; + + + // const response = await fetch(/packages?offset=${offset}, { + // method: 'POST', + // headers: { + // 'Content-Type': 'application/json', + // 'X-Authorization': authToken, + // }, + // body: JSON.stringify(requestBody), + // }); + + + // Simulate response data + const response1 = JSON.stringify({ + status: 200, + data: [ + { + Name: 'example-package', + Version: '1.0.0', + ID: '1', + }, + { + Name: 'another-package', + Version: '2.0.1', + ID: '2', + }, + ], + headers: { + offset: '10', + }, + }); + + // Parse the response as JSON + const response = JSON.parse(response1); + + if (response.status === 200) { + const data: PackageMetadata[] = response.data; + setPackages(data); + const newOffset = parseInt(response.headers.offset || '0', 10); + setOffset(newOffset); + } else if (response.status === 400) { + setError('Search failed: Missing fields or invalid query.'); + } else if (response.status === 403) { + setError('Search failed: Authentication failed due to invalid or missing AuthenticationToken.'); + } else if (response.status === 413) { + setError('Search failed: Too many packages returned.'); + } else { + setError('Search failed with an unknown error.'); + } + } catch (err) { + console.error('Error during search:', err); + setError('An error occurred while searching for packages.'); + } + }; + + const handleDownload = async (packageId: string) => { + if (!authToken) { + alert('Authentication token is missing. Please log in.'); + return; + } + + try { + const response = await fetch(`/packages/${packageId}`, { + method: 'GET', + headers: { + 'X-Authorization': authToken, + }, + }); + + if (response.status === 200) { + const data = await response.json(); + const content = data.data.Content; + + // Create a download link for the package content + const link = document.createElement('a'); + link.href = `data:application/zip;base64,${content}`; + link.download = `${data.metadata.Name}-v${data.metadata.Version}.zip`; + document.body.appendChild(link); + link.click(); + document.body.removeChild(link); + } else if (response.status === 400) { + alert('Download failed: Missing fields or improperly formed request.'); + } else if (response.status === 403) { + alert('Download failed: Authentication failed due to invalid or missing AuthenticationToken.'); + } else if (response.status === 404) { + alert('Download failed: Package does not exist.'); + } else { + alert('Download failed with an unknown error.'); + } + } catch (err) { + console.error('Error during download:', err); + alert('An error occurred while downloading the package.'); + } + }; + return ( - -

This is the Download page. Download files here.

+ +
+
+ +
+ + +
+ + {error &&

{error}

} + +
+

Available Packages:

+ {packages.length > 0 ? ( +
    + {packages.map((pkg) => ( +
  • + {pkg.Name} (v{pkg.Version}) + +
  • + ))} +
+ ) : ( +

No packages found. Try a different search term.

+ )} +
); }; diff --git a/frontend/src/pages/home.tsx b/frontend/src/pages/home.tsx index 46fa3a3..189e753 100644 --- a/frontend/src/pages/home.tsx +++ b/frontend/src/pages/home.tsx @@ -1,7 +1,7 @@ import React from 'react'; import { Link } from 'react-router-dom'; -import Login from './login'; -import './home.css'; // Optional: For styling +import Login from '../components/login'; +import '../assets/css/home.css'; // Optional: For styling const Home: React.FC = () => { return ( diff --git a/frontend/src/pages/login.css b/frontend/src/pages/login.css deleted file mode 100644 index 46f34e3..0000000 --- a/frontend/src/pages/login.css +++ /dev/null @@ -1,42 +0,0 @@ -.login-block { - max-width: 300px; - margin: 20px auto; - padding: 20px; - border: 1px solid #ccc; - border-radius: 10px; - background-color: #f9f9f9; - text-align: center; - } - - .login-block input { - width: 100%; - padding: 10px; - margin: 10px -10px; - border: 1px solid #ccc; - border-radius: 5px; - } - - .button-group { - display: flex; - justify-content: space-between; - } - - .button-group button { - width: 45%; - padding: 10px; - background-color: #61dafb; - border: none; - border-radius: 5px; - cursor: pointer; - font-size: 1rem; - } - - .button-group button:hover { - background-color: #21a1f1; - } - - .error { - color: red; - margin-top: 10px; - } - \ No newline at end of file diff --git a/frontend/src/pages/pageLayout.tsx b/frontend/src/pages/pageLayout.tsx index b014584..45fd049 100644 --- a/frontend/src/pages/pageLayout.tsx +++ b/frontend/src/pages/pageLayout.tsx @@ -1,6 +1,6 @@ import React from 'react'; import { Link } from 'react-router-dom'; -import './pageLayout.css'; // Shared CSS for all pages +import '../assets/css/pageLayout.css'; // Shared CSS for all pages interface PageLayoutProps { title: string; diff --git a/frontend/src/pages/rating.tsx b/frontend/src/pages/rating.tsx index 49b99b6..8efdfb5 100644 --- a/frontend/src/pages/rating.tsx +++ b/frontend/src/pages/rating.tsx @@ -1,10 +1,49 @@ -import React from 'react'; +import React, { useState } from 'react'; import PageLayout from './pageLayout'; const RatingPage: React.FC = () => { + const [packageName, setPackageName] = useState(''); + const [ratingData, setRatingData] = useState({ + overall: 4, + dependencyPinning: 0.8, + codeReviewMetric: 0.75, + }); + + const handleSearch = (e: React.FormEvent) => { + e.preventDefault(); + console.log('Searching for:', packageName); + // Add logic to fetch rating details for the entered package name + }; + return ( - -

This is the Rating page. Rate your experience here.

+ +
+
+ +
+ + +
+ + {packageName && ( +
+

Rating for: {packageName}

+

Overall Rating: {ratingData.overall} / 5

+

Dependency Pinning: {ratingData.dependencyPinning.toFixed(2)}

+

Code Review Metric: {ratingData.codeReviewMetric.toFixed(2)}

+
+ )}
); }; diff --git a/frontend/src/pages/update.tsx b/frontend/src/pages/update.tsx index 7a2c69b..96210e9 100644 --- a/frontend/src/pages/update.tsx +++ b/frontend/src/pages/update.tsx @@ -1,10 +1,187 @@ -import React from 'react'; +import React, { useState, useEffect } from 'react'; import PageLayout from './pageLayout'; const UpdatePage: React.FC = () => { + const [packageName, setPackageName] = useState('ExamplePackage'); // Pre-filled for existing data + const [currentVersion, setCurrentVersion] = useState('1.0.0'); // Example current version + const [newVersion, setNewVersion] = useState(''); + const [description, setDescription] = useState(''); + const [debloat, setDebloat] = useState(false); + const [file, setFile] = useState(null); + const [authToken, setAuthToken] = useState(null); + + // Retrieve auth token from localStorage on component mount + useEffect(() => { + const token = localStorage.getItem('authToken'); + if (token) { + setAuthToken(token); + } else { + alert('Authentication token not found. Please log in.'); + } + }, []); + + const handleFileChange = (e: React.ChangeEvent) => { + if (e.target.files && e.target.files.length > 0) { + setFile(e.target.files[0]); + } + }; + + const handleSubmit = async (e: React.FormEvent) => { + e.preventDefault(); + + if (!file) { + alert('Please select a file to upload.'); + return; + } + + if (!authToken) { + alert('Authentication token is missing. Please log in.'); + return; + } + + try { + // Read the file content as base64 + const fileContent = await new Promise((resolve, reject) => { + const reader = new FileReader(); + reader.onload = () => { + if (typeof reader.result === 'string') { + resolve(reader.result.split(',')[1]); // Get base64 data part + } + }; + reader.onerror = (error) => reject(error); + reader.readAsDataURL(file); + }); + + // Prepare the payload for the backend + const payload = { + metadata: { + Name: packageName, + Version: newVersion, + ID: '123567192081501', // Replace with the actual package ID + }, + data: { + Name: packageName, + Content: fileContent, + debloat: debloat, + JSProgram: `if (process.argv.length === 7) { +console.log('Success') +process.exit(0) +} else { +console.log('Failed') +process.exit(1) +}`, + }, + }; + + // Send the request to the backend + const response = await fetch(`/package/123567192081501`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'X-Authorization': authToken, + }, + body: JSON.stringify(payload), + }); + + if (response.status === 200) { + alert('Version updated successfully!'); + } else if (response.status === 400) { + alert('Update failed: Missing fields or invalid data.'); + } else if (response.status === 403) { + alert('Update failed: Authentication failed due to invalid or missing AuthenticationToken.'); + } else if (response.status === 404) { + alert('Update failed: Package does not exist.'); + } else { + alert('Update failed with an unknown error.'); + } + } catch (error) { + console.error('Error updating package:', error); + alert('An error occurred while updating the package.'); + } + }; + return ( - -

This is the Update page. Update your content here.

+ +
+
+ +
+ +
+ +
+ +
+ +
+ +
+