Skip to content

Commit

Permalink
Merge branch 'main' into main
Browse files Browse the repository at this point in the history
  • Loading branch information
henilp105 committed Feb 24, 2024
2 parents 1c39a17 + ee50da6 commit e9f6d46
Show file tree
Hide file tree
Showing 9 changed files with 295 additions and 44 deletions.
76 changes: 35 additions & 41 deletions backend/packages.py
Original file line number Diff line number Diff line change
Expand Up @@ -893,35 +893,49 @@ def post_ratings(namespace, package):
}
return jsonify({"message": error_message}), 404

if user["_id"] in package_doc["ratings"]["users"] and package_doc["ratings"][
"users"
][user["_id"]] == int(rating):
return jsonify({"message": "Ratings Submitted Successfully", "code": 200}), 200

if user["_id"] in package_doc["ratings"]["users"] and package_doc["ratings"][
"users"
][user["_id"]] != int(rating):
package_version_doc = db.packages.update_one(
{"name": package, "namespace": namespace_doc["_id"]},
{
"$set": {
f"ratings.users.{user['_id']}": int(rating),
},
},
)
return jsonify({"message": "Ratings Updated Successfully", "code": 200}), 200

package_version_doc = db.packages.update_one(
db.packages.update_one(
{"name": package, "namespace": namespace_doc["_id"]},
{
"$set": {
f"ratings.users.{user['_id']}": int(rating),
},
"$inc": {
"ratings.total_count": 1,
},
)

# Iterate through ratings and calculate how many users rated 5, 4, 3, 2, 1.
ratings = db.packages.find_one(
{"name": package, "namespace": namespace_doc["_id"]}
)["ratings"]["users"]

ratings_count = {
"5": 0,
"4": 0,
"3": 0,
"2": 0,
"1": 0,
}

for user_id, user_rating in ratings.items():
if user_rating == 5:
ratings_count["5"] += 1
elif user_rating == 4:
ratings_count["4"] += 1
elif user_rating == 3:
ratings_count["3"] += 1
elif user_rating == 2:
ratings_count["2"] += 1
elif user_rating == 1:
ratings_count["1"] += 1

db.packages.update_one(
{"name": package, "namespace": namespace_doc["_id"]},
{
"$set": {
"ratings.counts": ratings_count,
},
},
)

return jsonify({"message": "Ratings Submitted Successfully", "code": 200}), 200


Expand Down Expand Up @@ -958,26 +972,6 @@ def post_malicious(namespace, package):
}
return jsonify({"message": error_message}), 404

if user["_id"] in package_doc["malicious_report"]["users"] and package_doc["malicious_report"][
"users"
][user["_id"]]['reason'] == str(reason):
return jsonify({"message": "Malicious Report Submitted Successfully", "code": 200}), 200

if user["_id"] in package_doc["malicious_report"]["users"] and package_doc["malicious_report"][
"users"
][user["_id"]]['reason'] != str(reason):
package_version_doc = db.packages.update_one(
{"name": package, "namespace": namespace_doc["_id"]},
{
"$set": {
f"malicious_report.users.{user['_id']}": { 'reason': str(reason), 'isViewed': False },
"malicious_report.isViewed": False,

},
},
)
return jsonify({"message": "Malicious Report Updated Successfully", "code": 200}), 200

package_version_doc = db.packages.update_one(
{"name": package, "namespace": namespace_doc["_id"]},
{
Expand Down
2 changes: 1 addition & 1 deletion backend/user.py
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ def profile(username):
"name": package["name"],
"namespace": namespace["namespace"],
"description": package["description"],
"updatedAt": package["updatedAt"],
"updatedAt": package["updated_at"],
"isNamespaceMaintainer": isNamespaceMaintainer,
"isPackageMaintainer": isPackageMaintainer,
}
Expand Down
1 change: 1 addition & 0 deletions frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
"react-router-dom": "^6.11.2",
"react-scripts": "5.0.1",
"react-toastify": "^9.1.3",
"recharts": "^2.12.0",
"redux": "^4.2.1",
"redux-persist": "^6.0.0",
"styled-components": "^5.3.10",
Expand Down
34 changes: 32 additions & 2 deletions frontend/src/pages/package.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ import {
verifyUserRole,
} from "../store/actions/packageActions";
import ShowUserListDialog from "./showUserListDialog";
import ReportPackageForm from "./reportPackageForm";
import { Button } from "react-bootstrap";
import PackageRatingGraph from "./packageRatingGraph";

const PackagePage = () => {
const [iconsActive, setIconsActive] = useState("readme");
Expand All @@ -33,6 +36,7 @@ const PackagePage = () => {
const navigate = useNavigate();
const [togglePackageMaintainersDialog, settogglePackageMaintainersDialog] =
useState(false);
const [showReportForm, setShowReportForm] = useState(false);

const handleIconsClick = (value) => {
if (value === iconsActive) {
Expand Down Expand Up @@ -103,6 +107,14 @@ const PackagePage = () => {
<MDBIcon fas icon="tag" className="me-2" /> Versions
</MDBTabsLink>
</MDBTabsItem>
<MDBTabsItem>
<MDBTabsLink
onClick={() => handleIconsClick("stats")}
active={iconsActive === "stats"}
>
<MDBIcon fas icon="chart-bar" className="me-2" /> Stats
</MDBTabsLink>
</MDBTabsItem>
</MDBTabs>

<MDBTabsContent sm={4}>
Expand All @@ -111,7 +123,7 @@ const PackagePage = () => {
<MDBRow>
<MDBCol size="9">{data.description}</MDBCol>

{sideBar(data)}
{sideBar(data, setShowReportForm)}
</MDBRow>
</MDBContainer>
</MDBTabsPane>
Expand Down Expand Up @@ -176,7 +188,18 @@ const PackagePage = () => {
</MDBRow>
</MDBContainer>
</MDBTabsPane>
<MDBTabsPane show={iconsActive === "stats"}>
<MDBContainer>
<PackageRatingGraph data={data.ratings_count} />
</MDBContainer>
</MDBTabsPane>
</MDBTabsContent>
<ReportPackageForm
namespace={namespace_name}
package={package_name}
show={showReportForm}
onHide={() => setShowReportForm(false)}
/>
</Container>
) : (
<Container style={{ margin: "200px" }}>
Expand Down Expand Up @@ -226,7 +249,7 @@ const ViewPackageMaintainersButton = ({
);
};

const sideBar = (data) => {
const sideBar = (data, setShowReportForm) => {
return (
<MDBCol size="3">
<p style={{ fontSize: 16, textAlign: "left" }}>Install</p>
Expand All @@ -248,6 +271,13 @@ const sideBar = (data) => {
<p style={{ fontSize: 16, textAlign: "left" }}>Last publish</p>
{updatedDays(data.updated_at)} days ago
<hr></hr>
<Button
variant="danger"
style={{ margin: 0 }}
onClick={() => setShowReportForm(true)}
>
Report
</Button>
</MDBCol>
);
};
Expand Down
26 changes: 26 additions & 0 deletions frontend/src/pages/packageRatingGraph.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import React from "react";
import { BarChart, Bar, XAxis, Tooltip } from "recharts";

const PackageRatingGraph = ({ data }) => {
const graphData = data;

const parsedArray = Object.entries(graphData).map(([key, value]) => ({
name: `${key} ⭐`,
star: value,
}));

return parsedArray.length === 0 ? (
<div>
No stats available right now. This will update as soon as the package gets
rated.
</div>
) : (
<BarChart width={600} height={500} data={parsedArray}>
<XAxis dataKey="name" />
<Bar dataKey="star" fill="#8884d8" />
<Tooltip />
</BarChart>
);
};

export default PackageRatingGraph;
98 changes: 98 additions & 0 deletions frontend/src/pages/reportPackageForm.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
import React, { useEffect, useState } from "react";
import { Form, Button, Modal, Spinner } from "react-bootstrap";
import { useDispatch, useSelector } from "react-redux";
import {
reportPackage,
resetErrorMessage,
} from "../store/actions/reportPackageActions";
import { toast, ToastContainer } from "react-toastify";
import { reset } from "../store/actions/accountActions";

const ReportPackageForm = (props) => {
const dispatch = useDispatch();
const [reason, setReason] = useState("");
const accessToken = useSelector((state) => state.auth.accessToken);
const isLoading = useSelector((state) => state.reportPackage.isLoading);
const statusCode = useSelector((state) => state.reportPackage.statuscode);
const message = useSelector((state) => state.reportPackage.message);

const handleSubmit = async (e) => {
e.preventDefault();
dispatch(
reportPackage(
{ reason: reason, namespace: props.namespace, package: props.package },
accessToken
)
);
};

useEffect(() => {
if (statusCode === 200) {
toast.success(message);
} else {
toast.error(message);
}

dispatch(resetErrorMessage());
}, [statusCode]);

return (
<Form onSubmit={handleSubmit}>
<Modal {...props} size="lg">
<Modal.Header closeButton>
<Modal.Title>Report Package</Modal.Title>
</Modal.Header>
<ToastContainer
position="top-center"
autoClose={5000}
hideProgressBar={false}
newestOnTop={false}
closeOnClick
rtl={false}
pauseOnFocusLoss
pauseOnHover
theme="light"
/>
<Modal.Body>
<Form.Group
className="mb-3"
controlId="formReportPackage"
id="namespace-description-textfield"
>
<Form.Label>Reason for reporting package</Form.Label>
<Form.Control
type="text"
placeholder="Describe the reason for reporting the package"
as="textarea"
name="report_description"
value={reason}
onChange={(e) => setReason(e.target.value)}
/>
<Form.Text className="text-muted">
Write a brief description of the reason for reporting the package.
</Form.Text>
</Form.Group>
</Modal.Body>
<Modal.Footer>
{!isLoading ? (
<Button variant="primary" type="submit" onClick={handleSubmit}>
Submit
</Button>
) : (
<div style={{ margin: 0 }}>
<Spinner
className="spinner-border m-3"
animation="border"
role="status"
>
<span className="visually-hidden">Loading...</span>
</Spinner>
</div>
)}
</Modal.Footer>
</Modal>
</Form>
);
};

export default ReportPackageForm;
52 changes: 52 additions & 0 deletions frontend/src/store/actions/reportPackageActions.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import axios from "axios";

export const REPORT_PACKAGE_REQUEST = "REPORT_PACKAGE_REQUEST";
export const REPORT_PACKAGE_SUCCESS = "REPORT_PACKAGE_SUCCESS";
export const REPORT_PACKAGE_FAILURE = "REPORT_PACKAGE_FAILURE";

export const RESET_ERROR_MESSAGE = "RESET_ERROR_MESSAGE";

export const reportPackage = (data, access_token) => async (dispatch) => {
let formData = new FormData();
formData.append("reason", data.reason);

let package_name = data.package;
let namespace_name = data.namespace;

try {
dispatch({
type: REPORT_PACKAGE_REQUEST,
});

const result = await axios({
method: "post",
url: `${process.env.REACT_APP_REGISTRY_API_URL}/report/${namespace_name}/${package_name}`,
data: formData,
headers: {
Authorization: `Bearer ${access_token}`,
},
});

dispatch({
type: REPORT_PACKAGE_SUCCESS,
payload: {
message: result.data.message,
statuscode: result.data.code,
},
});
} catch (error) {
dispatch({
type: REPORT_PACKAGE_FAILURE,
payload: {
message: error.response.data.message,
statuscode: error.response.data.code,
},
});
}
};

export const resetErrorMessage = () => (dispatch) => {
dispatch({
type: RESET_ERROR_MESSAGE,
});
};
Loading

0 comments on commit e9f6d46

Please sign in to comment.