diff --git a/.gitignore b/.gitignore index 3f6febc1..53c3ba4d 100644 --- a/.gitignore +++ b/.gitignore @@ -104,4 +104,7 @@ ENV/ .vscode/ # SQLite data -flask-backend/api/db.sqlite3 \ No newline at end of file +flask-backend/api/db.sqlite3 + +# Extracted data +data/ \ No newline at end of file diff --git a/React-frontend/package-lock.json b/React-frontend/package-lock.json index ce2194e4..82763158 100644 --- a/React-frontend/package-lock.json +++ b/React-frontend/package-lock.json @@ -32499,4 +32499,4 @@ } } } -} +} \ No newline at end of file diff --git a/React-frontend/src/App.js b/React-frontend/src/App.js index c058b90d..c9f68318 100644 --- a/React-frontend/src/App.js +++ b/React-frontend/src/App.js @@ -5,21 +5,23 @@ import { Route, Switch } from 'react-router-dom'; import LoginPage from './pages/LoginPage'; import HomePage from './pages/HomePage'; import AboutPage from './pages/AboutPage'; -import ContactPage from './pages/ContactPage' -import Alert from './components/core/Alert' +import ContactPage from './pages/ContactPage'; +import Alert from './components/core/Alert'; import store from './store/store'; +import ExtractionPage from './pages/ExtractionPage'; function App() { return ( -
+
- + +
diff --git a/React-frontend/src/components/Extractor/DeviceItem.js b/React-frontend/src/components/Extractor/DeviceItem.js new file mode 100644 index 00000000..4adcc55f --- /dev/null +++ b/React-frontend/src/components/Extractor/DeviceItem.js @@ -0,0 +1,17 @@ +import React from 'react'; + +import DeviceImage from '../../images/Dashboard/device.png'; + +const DeviceItem = ({ device, onClick }) => { + return ( +
+ Device +

{device.device_codename}

+ +
+ ); +}; + +export default DeviceItem; diff --git a/React-frontend/src/components/Extractor/ExtractDataModal.js b/React-frontend/src/components/Extractor/ExtractDataModal.js new file mode 100644 index 00000000..6b3f58a0 --- /dev/null +++ b/React-frontend/src/components/Extractor/ExtractDataModal.js @@ -0,0 +1,82 @@ +import React, { useReducer } from 'react'; +import { + MDBBtn, + MDBModal, + MDBModalBody, + MDBModalHeader, + MDBModalFooter, + MDBInput, +} from 'mdbreact'; +import { useDispatch, useSelector } from 'react-redux'; +import { extractData } from '../../store/actions/extraction'; +import Dropdown from '../core/Dropdown'; +import formReducer from '../../utils/formReducer'; +import { setAlert } from '../../store/actions/alerts'; + +const ExtractDataModal = ({ isOpen, onToggle }) => { + const dispatch = useDispatch(); + const options = ['all', 'facebook', 'whatsapp', 'phone', 'report']; + const initialFormData = { + case_name: '', + data: options[0], + }; + + const [formData, setFormData] = useReducer(formReducer, initialFormData); + const { isLoading, currentDevice } = useSelector(state => state.extraction); + + const extractDataHandler = () => { + if (!formData.case_name) { + dispatch(setAlert('Please enter case name', 'warning')); + return; + } + const config = { + device_id: currentDevice.transpot_id, + ...formData, + }; + dispatch(extractData(config, () => onToggle(false))); + }; + + return ( + + Extract Data + + {isLoading ? ( +

Extracting data

+ ) : ( +
+ setFormData(event.target)} + /> + setFormData(event.target)} + /> +
+ )} +
+ + onToggle(false)}> + Cancel + + + Extract Data + + +
+ ); +}; + +export default ExtractDataModal; diff --git a/React-frontend/src/components/Sidebar.js b/React-frontend/src/components/Sidebar.js index 2fd271ce..13d71ad1 100644 --- a/React-frontend/src/components/Sidebar.js +++ b/React-frontend/src/components/Sidebar.js @@ -3,16 +3,19 @@ import { Link } from 'react-router-dom'; const Sidebar = () => { return ( -
-
- -
Home
+
+
+ +
Home
- -
About
+ +
About
- -
Contact
+ +
Contact
+ + +
Extraction
diff --git a/React-frontend/src/components/core/Dropdown.js b/React-frontend/src/components/core/Dropdown.js new file mode 100644 index 00000000..069c0d60 --- /dev/null +++ b/React-frontend/src/components/core/Dropdown.js @@ -0,0 +1,21 @@ +import React from 'react'; +import { InputGroup, FormControl } from 'react-bootstrap'; + +const Dropdown = ({ name, label, options = [], onChange }) => { + return ( + + +

{label}

+
+ + {options.map(element => ( + + ))} + +
+ ); +}; + +export default Dropdown; diff --git a/React-frontend/src/pages/ExtractionPage.js b/React-frontend/src/pages/ExtractionPage.js new file mode 100644 index 00000000..4419c33e --- /dev/null +++ b/React-frontend/src/pages/ExtractionPage.js @@ -0,0 +1,45 @@ +import React, { useEffect, useState } from 'react'; +import { useDispatch, useSelector } from 'react-redux'; + +import Layout from '../components/core/Layout'; +import DeviceItem from '../components/Extractor/DeviceItem'; +import ExtractDataModal from '../components/Extractor/ExtractDataModal'; +import { fetchLiveDevices, selectDevice } from '../store/actions/extraction'; + +const ExtractionPage = () => { + const dispatch = useDispatch(); + const [showModal, toggleShowModal] = useState(false); + const { isLoading, devices } = useSelector(state => state.extraction); + + useEffect(() => { + dispatch(fetchLiveDevices()); + }, [dispatch]); + + const selectDeviceHandler = device => { + toggleShowModal(true); + dispatch(selectDevice(device)); + }; + + return ( + +
+

Live Devices

+ {isLoading ? ( +

Loading

+ ) : ( +
+ {devices.map(device => ( + selectDeviceHandler(device)} + /> + ))} +
+ )} + +
+
+ ); +}; + +export default ExtractionPage; diff --git a/React-frontend/src/store/actions/extraction.js b/React-frontend/src/store/actions/extraction.js new file mode 100644 index 00000000..1561bcf5 --- /dev/null +++ b/React-frontend/src/store/actions/extraction.js @@ -0,0 +1,38 @@ +import axios from '../../axios'; +import { setAlert } from './alerts'; + +export const EXTRACT_DATA = 'EXTRACT_DATA'; +export const SELECT_DEVICE = 'SELECT_DEVICE'; +export const FETCH_DEVICES = 'FETCH_DEVICES'; +export const TOGGLE_EXTRACTION_LOADING = 'TOGGLE_EXTRACTION_LOADING'; + +export const selectDevice = device => dispatch => { + dispatch({ type: SELECT_DEVICE, payload: device }); +}; + +export const fetchLiveDevices = () => async dispatch => { + try { + dispatch({ type: TOGGLE_EXTRACTION_LOADING, payload: true }); + const res = await axios.get('/extraction/list_devices'); + const devices = res.data; + dispatch({ type: FETCH_DEVICES, payload: devices }); + } catch (error) { + dispatch({ type: TOGGLE_EXTRACTION_LOADING, payload: false }); + dispatch(setAlert(error.response, 'danger')); + } +}; + +export const extractData = (config, callback) => async dispatch => { + try { + dispatch({ type: TOGGLE_EXTRACTION_LOADING, payload: true }); + const res = await axios.post('/extraction/extract_data', config); + const message = res.data.message; + dispatch({ type: EXTRACT_DATA }); + dispatch(setAlert(message, 'success')); + callback(); + } catch (error) { + dispatch({ type: TOGGLE_EXTRACTION_LOADING, payload: false }); + dispatch(setAlert(error.response, 'danger')); + callback(); + } +}; diff --git a/React-frontend/src/store/reducers/extraction.js b/React-frontend/src/store/reducers/extraction.js new file mode 100644 index 00000000..af34354a --- /dev/null +++ b/React-frontend/src/store/reducers/extraction.js @@ -0,0 +1,43 @@ +import { + EXTRACT_DATA, + SELECT_DEVICE, + FETCH_DEVICES, + TOGGLE_EXTRACTION_LOADING, +} from '../actions/extraction'; + +const initialState = { + devices: [], + isLoading: false, + currentDevice: null, +}; + +const reducer = (state = initialState, action) => { + const { type, payload } = action; + switch (type) { + case EXTRACT_DATA: + return { + ...state, + isLoading: false, + }; + case FETCH_DEVICES: + return { + ...state, + devices: payload, + isLoading: false, + }; + case SELECT_DEVICE: + return { + ...state, + currentDevice: payload, + }; + case TOGGLE_EXTRACTION_LOADING: + return { + ...state, + isLoading: payload, + }; + default: + return state; + } +}; + +export default reducer; diff --git a/React-frontend/src/store/store.js b/React-frontend/src/store/store.js index f3d0541b..900b4e9f 100644 --- a/React-frontend/src/store/store.js +++ b/React-frontend/src/store/store.js @@ -4,11 +4,13 @@ import { createStore, combineReducers, applyMiddleware } from 'redux'; import auth from './reducers/auth'; import alerts from './reducers/alerts'; +import extraction from './reducers/extraction'; // Combine each reducer here const rootReducer = combineReducers({ auth, alerts, + extraction, }); const initialState = {}; diff --git a/apiUtility/apiUtils.py b/apiUtility/apiUtils.py index ccc66901..89b32113 100644 --- a/apiUtility/apiUtils.py +++ b/apiUtility/apiUtils.py @@ -1,6 +1,5 @@ import sys -sys.path.append('/home/cobalt/osp/OpenMF/') -sys.path.append('/home/cobalt/osp/OpenMF/') +sys.path.append('../') from data_store.report_helper import generate_pdf_report from scripts.extract_all import extract_all_data_toTsv from scripts.fb_reader import store_fb_data diff --git a/flask-backend/api/routes/extraction.py b/flask-backend/api/routes/extraction.py index 83bfd5b0..2a98e57c 100644 --- a/flask-backend/api/routes/extraction.py +++ b/flask-backend/api/routes/extraction.py @@ -13,6 +13,7 @@ case_schema = CaseSchema() cases_schema = CaseSchema(many=True) dirname = os.path.dirname(__file__) +extract_data_path = os.path.join(dirname, '../../../apiUtility') adb_path=os.path.join(dirname, '../../../ExtraResources/adbLinux') extraction = Blueprint('extraction', __name__, url_prefix='/extraction') @@ -60,7 +61,7 @@ def extract(): except KeyError as err: return f'please provide {str(err)}', 400 - sys.path.append('/home/cobalt/osp/OpenMF/apiUtility') + sys.path.append(extract_data_path) from apiUtils import apiExtactAll, apiExtractFb, apiExtractWa, apiExtractPhone, apiReport if(data == 'all'): apiExtactAll(case_name)