Skip to content

Commit fae7a95

Browse files
authored
Merge pull request #69 from arteevraina/reports-ui
Reports UI
2 parents ee50da6 + 3959d44 commit fae7a95

File tree

8 files changed

+188
-10
lines changed

8 files changed

+188
-10
lines changed

backend/packages.py

+3-1
Original file line numberDiff line numberDiff line change
@@ -993,12 +993,14 @@ def view_report():
993993

994994
if "admin" in user["roles"]:
995995
non_viewed_reports = list()
996-
malicious_reports = db.packages.find({"malicious_reports.isViewed": False})
996+
malicious_reports = db.packages.find({"malicious_report.isViewed": False})
997997
for package in list(malicious_reports):
998998
for user_id, report in package.get("malicious_report", {}).get("users", {}).items():
999999
if not report.get("isViewed", False):
10001000
report['name'] = db.users.find_one({"_id": ObjectId(user_id)}, {"username": 1})["username"]
10011001
del report["isViewed"]
1002+
report["package"] = package["name"]
1003+
report["namespace"] = db.namespaces.find_one({"_id": package["namespace"]}, {"namespace": 1})["namespace"]
10021004
non_viewed_reports.append(report)
10031005

10041006
return jsonify({"message": "Malicious Reports fetched Successfully", "code": 200, "reports": non_viewed_reports}), 200

backend/user.py

+4-1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
from app import swagger
88
from flasgger.utils import swag_from
99
from auth import forgot_password
10+
from flask_jwt_extended import jwt_required, get_jwt_identity
1011

1112
load_dotenv()
1213

@@ -194,8 +195,10 @@ def account():
194195

195196
@app.route("/users/admin", methods=["POST"])
196197
@swag_from("documentation/check_admin_user.yaml", methods=["POST"])
198+
@jwt_required()
197199
def admin():
198-
uuid = request.form.get("uuid")
200+
uuid = get_jwt_identity()
201+
199202
if not uuid:
200203
return jsonify({"message": "Unauthorized", "code": 401}), 401
201204
else:

frontend/src/pages/admin.js

+26-4
Original file line numberDiff line numberDiff line change
@@ -20,18 +20,26 @@ import {
2020
deleteRelease,
2121
deprecatePackage,
2222
} from "../store/actions/adminActions";
23+
import ViewMalicousReports from "./viewMalicousReports";
2324
import NoPage from "./404";
2425

2526
const AdminSection = () => {
2627
const uuid = useSelector((state) => state.auth.uuid);
28+
const accessToken = useSelector((state) => state.auth.accessToken);
2729
const dispatch = useDispatch();
2830
const message = useSelector((state) => state.admin.message);
2931
const statuscode = useSelector((state) => state.admin.statuscode);
3032
const isAuthenticated = useSelector((state) => state.auth.isAuthenticated);
3133
const isAdmin = useSelector((state) => state.admin.isAdmin);
3234

35+
const [showReports, setShowReports] = useState(false);
36+
37+
const handleShowReports = (value) => {
38+
setShowReports(value);
39+
};
40+
3341
useEffect(() => {
34-
dispatch(adminAuth(uuid));
42+
dispatch(adminAuth(accessToken));
3543
}, [isAuthenticated, uuid]);
3644

3745
useEffect(() => {
@@ -207,10 +215,18 @@ const AdminSection = () => {
207215
// });
208216
// };
209217

210-
return isAdmin? (
218+
return isAdmin ? (
211219
<Container>
212-
<br></br>
213220
<h2 style={{ textAlign: "left" }}>Admin Settings</h2>
221+
<div style={{ marginBottom: "8px" }}>
222+
<h4>View Malicious Reports</h4>
223+
<Button
224+
style={{ fontSize: 16 }}
225+
onClick={() => handleShowReports(true)}
226+
>
227+
View Reports
228+
</Button>
229+
</div>
214230
<div>
215231
<h4>Delete package</h4>
216232
<p style={{ textAlign: "left" }}>
@@ -361,6 +377,10 @@ const AdminSection = () => {
361377
Change Password
362378
</Button>
363379
</div> */}
380+
<ViewMalicousReports
381+
show={showReports}
382+
onHide={() => handleShowReports(false)}
383+
/>
364384
<MDBModal show={modalData.showModal} tabIndex="-1">
365385
<MDBModalDialog>
366386
<MDBModalContent>
@@ -386,7 +406,9 @@ const AdminSection = () => {
386406
</MDBModalDialog>
387407
</MDBModal>
388408
</Container>
389-
):(<NoPage/>);
409+
) : (
410+
<NoPage />
411+
);
390412
};
391413

392414
export default AdminSection;
+60
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
import { useState, useEffect } from "react";
2+
import { useDispatch, useSelector } from "react-redux";
3+
import { Card, Container, Modal, Spinner } from "react-bootstrap";
4+
import {
5+
fetchMalicousReports,
6+
resetData,
7+
} from "../store/actions/viewMalicousReportActions";
8+
9+
const ViewMalicousReports = (props) => {
10+
const accessToken = useSelector((state) => state.auth.accessToken);
11+
const reports = useSelector((state) => state.malicousReport.reports);
12+
const loading = useSelector((state) => state.malicousReport.isLoading);
13+
const dispatch = useDispatch();
14+
15+
useEffect(() => {
16+
if (!props.show) {
17+
return;
18+
}
19+
20+
dispatch(fetchMalicousReports(accessToken));
21+
}, [props.show]);
22+
23+
const onExit = () => {
24+
dispatch(resetData());
25+
};
26+
27+
return (
28+
<Modal show={props.show} onHide={props.onHide} onExit={onExit}>
29+
<Modal.Header closeButton>
30+
<Modal.Title>View Malicious Reports</Modal.Title>
31+
</Modal.Header>
32+
<Modal.Body>
33+
{loading && (
34+
<div className="d-flex justify-content-center">
35+
<Spinner
36+
animation="border"
37+
role="status"
38+
style={{ alignItems: "center" }}
39+
>
40+
<span className="visually-hidden">Loading...</span>
41+
</Spinner>
42+
</div>
43+
)}
44+
{reports.map((report, index) => {
45+
return (
46+
<Card key={index}>
47+
<Card.Body>
48+
<h5>Namespace - {report.namespace}</h5>
49+
<h6>Package - {report.package}</h6>
50+
<p style={{ textAlign: "left" }}>{report.reason}</p>
51+
</Card.Body>
52+
</Card>
53+
);
54+
})}
55+
</Modal.Body>
56+
</Modal>
57+
);
58+
};
59+
60+
export default ViewMalicousReports;

frontend/src/store/actions/adminActions.js

+4-4
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,9 @@ export const ADMIN_AUTH_SUCCESS = "ADMIN_AUTH_SUCCESS";
1818
export const DELETE_PACKAGE_SUCCESS = "DELETE_PACKAGE_SUCCESS";
1919
export const DELETE_PACKAGE_ERROR = "DELETE_PACKAGE_ERROR";
2020

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

2625
try {
2726
let result = await axios({
@@ -30,6 +29,7 @@ export const adminAuth = (uuid) => async (dispatch) => {
3029
data: formData,
3130
headers: {
3231
"Content-Type": "multipart/form-data",
32+
Authorization: `Bearer ${accessToken}`,
3333
},
3434
});
3535

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

158158
export const deletePackage =
159159
(namespacename, packagename, uuid) => async (dispatch) => {
160-
// Make an api call to delete package
160+
// Make an api call to delete package
161161
let formData = new FormData();
162162

163163
formData.append("uuid", uuid);
@@ -204,7 +204,7 @@ export const deletePackage =
204204

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

210210
formData.append("uuid", uuid);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import axios from "axios";
2+
3+
export const FETCH_MALICIOUS_REPORTS = "FETCH_MALICIOUS_REPORTS";
4+
export const FETCH_MALICIOUS_REPORTS_SUCCESS =
5+
"FETCH_MALICIOUS_REPORTS_SUCCESS";
6+
export const FETCH_MALICIOUS_REPORTS_ERROR = "FETCH_MALICIOUS_REPORTS_ERROR";
7+
export const RESET_DATA = "RESET_DATA";
8+
9+
export const fetchMalicousReports = (accessToken) => {
10+
return async (dispatch) => {
11+
dispatch({ type: FETCH_MALICIOUS_REPORTS });
12+
try {
13+
const result = await axios({
14+
method: "get",
15+
url: `${process.env.REACT_APP_REGISTRY_API_URL}/report/view`,
16+
headers: {
17+
Authorization: `Bearer ${accessToken}`,
18+
},
19+
});
20+
21+
dispatch({
22+
type: FETCH_MALICIOUS_REPORTS_SUCCESS,
23+
payload: {
24+
reports: result.data.reports,
25+
},
26+
});
27+
} catch (error) {
28+
dispatch({
29+
type: FETCH_MALICIOUS_REPORTS_ERROR,
30+
payload: {
31+
statuscode: error.response.data.code,
32+
message: error.response.data.message,
33+
},
34+
});
35+
}
36+
};
37+
};
38+
39+
export const resetData = () => (dispatch) => {
40+
dispatch({
41+
type: RESET_DATA,
42+
});
43+
};

frontend/src/store/reducers/rootReducer.js

+2
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import addRemoveNamespaceAdminReducer from "./namespaceAdminReducer";
1818
import verifyEmailReducer from "./verifyEmailReducer";
1919
import userListReducer from "./userListReducer";
2020
import reportPackageReducer from "./reportPackageReducer";
21+
import viewMalicousReportsReducer from "./viewMalicousReportsReducer";
2122

2223
const rootReducer = combineReducers({
2324
auth: authReducer,
@@ -39,6 +40,7 @@ const rootReducer = combineReducers({
3940
userList: userListReducer,
4041
archives: archivesReducer,
4142
reportPackage: reportPackageReducer,
43+
malicousReport: viewMalicousReportsReducer,
4244
});
4345

4446
export default rootReducer;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import {
2+
FETCH_MALICIOUS_REPORTS,
3+
FETCH_MALICIOUS_REPORTS_SUCCESS,
4+
FETCH_MALICIOUS_REPORTS_ERROR,
5+
RESET_DATA,
6+
} from "../actions/viewMalicousReportActions";
7+
8+
const initialState = {
9+
reports: [],
10+
isLoading: false,
11+
error: null,
12+
};
13+
14+
const viewMalicousReportsReducer = (state = initialState, action) => {
15+
switch (action.type) {
16+
case FETCH_MALICIOUS_REPORTS:
17+
return {
18+
...state,
19+
isLoading: true,
20+
error: null,
21+
};
22+
case FETCH_MALICIOUS_REPORTS_SUCCESS:
23+
return {
24+
...state,
25+
reports: action.payload.reports,
26+
isLoading: false,
27+
error: null,
28+
};
29+
case FETCH_MALICIOUS_REPORTS_ERROR:
30+
return {
31+
...state,
32+
isLoading: false,
33+
error: action.payload.message,
34+
};
35+
case RESET_DATA:
36+
return {
37+
reports: [],
38+
isLoading: false,
39+
error: null,
40+
};
41+
default:
42+
return state;
43+
}
44+
};
45+
46+
export default viewMalicousReportsReducer;

0 commit comments

Comments
 (0)