Skip to content

Commit

Permalink
Merge pull request #69 from arteevraina/reports-ui
Browse files Browse the repository at this point in the history
Reports UI
  • Loading branch information
henilp105 authored Feb 28, 2024
2 parents ee50da6 + 3959d44 commit fae7a95
Show file tree
Hide file tree
Showing 8 changed files with 188 additions and 10 deletions.
4 changes: 3 additions & 1 deletion backend/packages.py
Original file line number Diff line number Diff line change
Expand Up @@ -993,12 +993,14 @@ def view_report():

if "admin" in user["roles"]:
non_viewed_reports = list()
malicious_reports = db.packages.find({"malicious_reports.isViewed": False})
malicious_reports = db.packages.find({"malicious_report.isViewed": False})
for package in list(malicious_reports):
for user_id, report in package.get("malicious_report", {}).get("users", {}).items():
if not report.get("isViewed", False):
report['name'] = db.users.find_one({"_id": ObjectId(user_id)}, {"username": 1})["username"]
del report["isViewed"]
report["package"] = package["name"]
report["namespace"] = db.namespaces.find_one({"_id": package["namespace"]}, {"namespace": 1})["namespace"]
non_viewed_reports.append(report)

return jsonify({"message": "Malicious Reports fetched Successfully", "code": 200, "reports": non_viewed_reports}), 200
Expand Down
5 changes: 4 additions & 1 deletion backend/user.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from app import swagger
from flasgger.utils import swag_from
from auth import forgot_password
from flask_jwt_extended import jwt_required, get_jwt_identity

load_dotenv()

Expand Down Expand Up @@ -194,8 +195,10 @@ def account():

@app.route("/users/admin", methods=["POST"])
@swag_from("documentation/check_admin_user.yaml", methods=["POST"])
@jwt_required()
def admin():
uuid = request.form.get("uuid")
uuid = get_jwt_identity()

if not uuid:
return jsonify({"message": "Unauthorized", "code": 401}), 401
else:
Expand Down
30 changes: 26 additions & 4 deletions frontend/src/pages/admin.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,18 +20,26 @@ import {
deleteRelease,
deprecatePackage,
} from "../store/actions/adminActions";
import ViewMalicousReports from "./viewMalicousReports";
import NoPage from "./404";

const AdminSection = () => {
const uuid = useSelector((state) => state.auth.uuid);
const accessToken = useSelector((state) => state.auth.accessToken);
const dispatch = useDispatch();
const message = useSelector((state) => state.admin.message);
const statuscode = useSelector((state) => state.admin.statuscode);
const isAuthenticated = useSelector((state) => state.auth.isAuthenticated);
const isAdmin = useSelector((state) => state.admin.isAdmin);

const [showReports, setShowReports] = useState(false);

const handleShowReports = (value) => {
setShowReports(value);
};

useEffect(() => {
dispatch(adminAuth(uuid));
dispatch(adminAuth(accessToken));
}, [isAuthenticated, uuid]);

useEffect(() => {
Expand Down Expand Up @@ -207,10 +215,18 @@ const AdminSection = () => {
// });
// };

return isAdmin? (
return isAdmin ? (
<Container>
<br></br>
<h2 style={{ textAlign: "left" }}>Admin Settings</h2>
<div style={{ marginBottom: "8px" }}>
<h4>View Malicious Reports</h4>
<Button
style={{ fontSize: 16 }}
onClick={() => handleShowReports(true)}
>
View Reports
</Button>
</div>
<div>
<h4>Delete package</h4>
<p style={{ textAlign: "left" }}>
Expand Down Expand Up @@ -361,6 +377,10 @@ const AdminSection = () => {
Change Password
</Button>
</div> */}
<ViewMalicousReports
show={showReports}
onHide={() => handleShowReports(false)}
/>
<MDBModal show={modalData.showModal} tabIndex="-1">
<MDBModalDialog>
<MDBModalContent>
Expand All @@ -386,7 +406,9 @@ const AdminSection = () => {
</MDBModalDialog>
</MDBModal>
</Container>
):(<NoPage/>);
) : (
<NoPage />
);
};

export default AdminSection;
60 changes: 60 additions & 0 deletions frontend/src/pages/viewMalicousReports.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import { useState, useEffect } from "react";
import { useDispatch, useSelector } from "react-redux";
import { Card, Container, Modal, Spinner } from "react-bootstrap";
import {
fetchMalicousReports,
resetData,
} from "../store/actions/viewMalicousReportActions";

const ViewMalicousReports = (props) => {
const accessToken = useSelector((state) => state.auth.accessToken);
const reports = useSelector((state) => state.malicousReport.reports);
const loading = useSelector((state) => state.malicousReport.isLoading);
const dispatch = useDispatch();

useEffect(() => {
if (!props.show) {
return;
}

dispatch(fetchMalicousReports(accessToken));
}, [props.show]);

const onExit = () => {
dispatch(resetData());
};

return (
<Modal show={props.show} onHide={props.onHide} onExit={onExit}>
<Modal.Header closeButton>
<Modal.Title>View Malicious Reports</Modal.Title>
</Modal.Header>
<Modal.Body>
{loading && (
<div className="d-flex justify-content-center">
<Spinner
animation="border"
role="status"
style={{ alignItems: "center" }}
>
<span className="visually-hidden">Loading...</span>
</Spinner>
</div>
)}
{reports.map((report, index) => {
return (
<Card key={index}>
<Card.Body>
<h5>Namespace - {report.namespace}</h5>
<h6>Package - {report.package}</h6>
<p style={{ textAlign: "left" }}>{report.reason}</p>
</Card.Body>
</Card>
);
})}
</Modal.Body>
</Modal>
);
};

export default ViewMalicousReports;
8 changes: 4 additions & 4 deletions frontend/src/store/actions/adminActions.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,9 @@ export const ADMIN_AUTH_SUCCESS = "ADMIN_AUTH_SUCCESS";
export const DELETE_PACKAGE_SUCCESS = "DELETE_PACKAGE_SUCCESS";
export const DELETE_PACKAGE_ERROR = "DELETE_PACKAGE_ERROR";

export const adminAuth = (uuid) => async (dispatch) => {
export const adminAuth = (accessToken) => async (dispatch) => {
// Make an api call to authenticate admin
let formData = new FormData();
formData.append("uuid", uuid);

try {
let result = await axios({
Expand All @@ -30,6 +29,7 @@ export const adminAuth = (uuid) => async (dispatch) => {
data: formData,
headers: {
"Content-Type": "multipart/form-data",
Authorization: `Bearer ${accessToken}`,
},
});

Expand Down Expand Up @@ -157,7 +157,7 @@ export const deleteNamespace = (namespace, uuid) => async (dispatch) => {

export const deletePackage =
(namespacename, packagename, uuid) => async (dispatch) => {
// Make an api call to delete package
// Make an api call to delete package
let formData = new FormData();

formData.append("uuid", uuid);
Expand Down Expand Up @@ -204,7 +204,7 @@ export const deletePackage =

export const deleteRelease =
(namespace_name, package_name, version, uuid) => async (dispatch) => {
// Make an api call to delete package release
// Make an api call to delete package release
let formData = new FormData();

formData.append("uuid", uuid);
Expand Down
43 changes: 43 additions & 0 deletions frontend/src/store/actions/viewMalicousReportActions.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import axios from "axios";

export const FETCH_MALICIOUS_REPORTS = "FETCH_MALICIOUS_REPORTS";
export const FETCH_MALICIOUS_REPORTS_SUCCESS =
"FETCH_MALICIOUS_REPORTS_SUCCESS";
export const FETCH_MALICIOUS_REPORTS_ERROR = "FETCH_MALICIOUS_REPORTS_ERROR";
export const RESET_DATA = "RESET_DATA";

export const fetchMalicousReports = (accessToken) => {
return async (dispatch) => {
dispatch({ type: FETCH_MALICIOUS_REPORTS });
try {
const result = await axios({
method: "get",
url: `${process.env.REACT_APP_REGISTRY_API_URL}/report/view`,
headers: {
Authorization: `Bearer ${accessToken}`,
},
});

dispatch({
type: FETCH_MALICIOUS_REPORTS_SUCCESS,
payload: {
reports: result.data.reports,
},
});
} catch (error) {
dispatch({
type: FETCH_MALICIOUS_REPORTS_ERROR,
payload: {
statuscode: error.response.data.code,
message: error.response.data.message,
},
});
}
};
};

export const resetData = () => (dispatch) => {
dispatch({
type: RESET_DATA,
});
};
2 changes: 2 additions & 0 deletions frontend/src/store/reducers/rootReducer.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import addRemoveNamespaceAdminReducer from "./namespaceAdminReducer";
import verifyEmailReducer from "./verifyEmailReducer";
import userListReducer from "./userListReducer";
import reportPackageReducer from "./reportPackageReducer";
import viewMalicousReportsReducer from "./viewMalicousReportsReducer";

const rootReducer = combineReducers({
auth: authReducer,
Expand All @@ -39,6 +40,7 @@ const rootReducer = combineReducers({
userList: userListReducer,
archives: archivesReducer,
reportPackage: reportPackageReducer,
malicousReport: viewMalicousReportsReducer,
});

export default rootReducer;
46 changes: 46 additions & 0 deletions frontend/src/store/reducers/viewMalicousReportsReducer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import {
FETCH_MALICIOUS_REPORTS,
FETCH_MALICIOUS_REPORTS_SUCCESS,
FETCH_MALICIOUS_REPORTS_ERROR,
RESET_DATA,
} from "../actions/viewMalicousReportActions";

const initialState = {
reports: [],
isLoading: false,
error: null,
};

const viewMalicousReportsReducer = (state = initialState, action) => {
switch (action.type) {
case FETCH_MALICIOUS_REPORTS:
return {
...state,
isLoading: true,
error: null,
};
case FETCH_MALICIOUS_REPORTS_SUCCESS:
return {
...state,
reports: action.payload.reports,
isLoading: false,
error: null,
};
case FETCH_MALICIOUS_REPORTS_ERROR:
return {
...state,
isLoading: false,
error: action.payload.message,
};
case RESET_DATA:
return {
reports: [],
isLoading: false,
error: null,
};
default:
return state;
}
};

export default viewMalicousReportsReducer;

0 comments on commit fae7a95

Please sign in to comment.