UNPKG

strapi-plugin-filerobot

Version:

Strapi v3 plugin for Filerobot by Scaleflex

432 lines (334 loc) 12.9 kB
import React from "react"; import pluginId from '../../pluginId'; import $ from 'jquery'; import { Container, Row, Col, Form, Button } from 'react-bootstrap'; import { request, auth } from "strapi-helper-plugin"; import { sprintf } from 'sprintf-js'; import { useIntl } from 'react-intl'; // https://www.npmjs.com/package/react-popup-alert import Alert from 'react-popup-alert' import 'react-popup-alert/dist/index.css'; // https://react-bootstrap.github.io/components/progress/ // https://www.youtube.com/watch?v=3sH_Kq9e5hQ import ProgressBar from 'react-bootstrap/ProgressBar' const Configurations = (props) => { const intl = useIntl(); const config = props.config; React.useEffect(() => { if (!config.token || !config.sec_temp) { $("button.btn-secondary").attr("disabled", "disabled"); } else { $("button.btn-secondary").attr("disabled", false); } }, [config]); const [alert, setAlert] = React.useState({ type: 'warning', text: '', show: false }) function onCloseAlert() { setAlert({ type: '', text: '', show: false }) } function onShowAlert(type, text) { setAlert({ type: type, text: text, show: true }) } const [down, setDown] = React.useState(0); const [up, setUp] = React.useState(0); const filerobotApiDomain = 'https://api.filerobot.com'; const update = async (event) => { event.preventDefault(); $("button").attr("disabled", "disabled"); if (typeof(Storage) !== "undefined" && sessionStorage.getItem("sassKey")) { sessionStorage.removeItem("sassKey"); } var config = [...event.currentTarget.elements] .filter((ele) => ele.type !== "submit") .map((ele) => { return { [ele.getAttribute("name")]: ele.value, }; }) .reduce((a, b) => ({ ...a, [Object.keys(b)[0]]: b[Object.keys(b)[0]] }), {}); if (config.token === '' || config.sec_temp === '') { onShowAlert('warning', intl.formatMessage({id:`${pluginId}.notification.error.fill_required`})); $("button").attr("disabled", false); $("button.btn-secondary").attr("disabled", "disabled"); return; } await request(`/${pluginId}/update-config`, {method: 'PUT', headers:{'Authorization':`Bearer ${auth.getToken()}`}, body: config}); onShowAlert('warning', intl.formatMessage({id:`${pluginId}.notification.success.update_config`})); $("button").attr("disabled", false); await sleep(2000); window.location.reload(); } const sleep = (milliseconds) => { return new Promise(resolve => setTimeout(resolve, milliseconds)); } const check_connection = async () => { $("button").attr("disabled", "disabled"); var configs = await request(`/${pluginId}/config`, {method: 'GET', headers:{'Authorization':`Bearer ${auth.getToken()}`}}); var sass = await getSass(configs); if (sass === false) { onShowAlert('warning', intl.formatMessage({id:`${pluginId}.notification.error.wrong_sectmp`})); $("button").attr("disabled", false); return false; } var headers = new Headers(); headers.append("Content-Type", "application/json"); headers.append("X-Filerobot-Key", sass); var requestOptions = { method: 'GET', headers: headers }; var tokenCheck = await fetch(`${filerobotApiDomain}/${configs.token}/v4/files?folder=/&limit=1&`, requestOptions); if (tokenCheck.status != 200) { onShowAlert('warning', intl.formatMessage({id:`${pluginId}.notification.error.check_token_issue`})); $("button").attr("disabled", false); return false; } var tokenCheckJson = await tokenCheck.json(); if (tokenCheckJson.status !== 'success') { onShowAlert('warning', intl.formatMessage({id:`${pluginId}.notification.error.wrong_token`})); $("button").attr("disabled", false); return false; } onShowAlert('warning', intl.formatMessage({id:`${pluginId}.notification.success.sync_connection`})); $("button").attr("disabled", false); return true; } const sync_status = async () => { var { localMedia, filerobotMedia } = await getSyncStatus(); if (localMedia === false && filerobotMedia === false) { onShowAlert('warning', intl.formatMessage({id:`${pluginId}.notification.error.wrong_sectmp`})); $("button").attr("disabled", false); return false; } var toSyncUp = localMedia.nonFilerobot; var alreadyDown = localMedia.filerobot; var alreadyDownHashs = alreadyDown.map(x => x['hash']); var filerobotMediaHashs = filerobotMedia.map(x => x['hash']['sha1']); var toSyncDown = filerobotMediaHashs.filter(x => !alreadyDownHashs.includes(x)); onShowAlert('warning', sprintf(intl.formatMessage({id:`${pluginId}.notification.success.sync_status`}), toSyncUp.length, toSyncDown.length) ); $("button").attr("disabled", false); return true; } const trigger_sync = async () => { var { localMedia, filerobotMedia } = await getSyncStatus(); var toSyncUp = localMedia.nonFilerobot; var alreadyDown = localMedia.filerobot; // Better to sync down then up var downResult = await sync_down(filerobotMedia, alreadyDown); var upResult = await sync_up(toSyncUp); onShowAlert('warning', sprintf(intl.formatMessage({id:`${pluginId}.notification.success.sync_results`}), downResult, upResult) ); $("button").attr("disabled", false); return true; } async function sync_down(filerobotMedia, alreadyDown) { var alreadyDownHashs = alreadyDown.map(x => x['hash']); var filerobotMediaHashs = filerobotMedia.map(x => x['hash']['sha1']); var toSyncDown = filerobotMediaHashs.filter(x => !alreadyDownHashs.includes(x)); var count = 0; // https://advancedweb.hu/how-to-use-async-functions-with-array-foreach-in-javascript/ await Promise.all( $(filerobotMedia).map(async function( index ) { if ( !alreadyDownHashs.includes(this.hash.sha1) ) { var result = await request(`/${pluginId}/record-file`, {method: 'POST', headers:{'Authorization':`Bearer ${auth.getToken()}`}, body: {file:this, action:'sync-down', config:config}}); if (result !== false) { count++; } console.log(`Synced down ${count} / ${toSyncDown.length}`); var percentage = (toSyncDown.length === 0) ? 100 : Math.ceil(count/toSyncDown.length*100); setDown(percentage); } }) ); return `${count} / ${toSyncDown.length}`; } async function sync_up(toSyncUp) { var count = 0; await Promise.all( $(toSyncUp).map(async function( index ) { var result = await request(`/${pluginId}/sync-up`, {method: 'POST', headers:{'Authorization':`Bearer ${auth.getToken()}`}, body: {file:this, config:config}}); if (result !== false) { count++; } console.log(`Synced up ${count} / ${toSyncUp.length}`); var percentage = (toSyncUp.length === 0) ? 100 : Math.ceil(count/toSyncUp.length*100); setUp(percentage); }) ); return `${count} / ${toSyncUp.length}`; } async function getSyncStatus() { $("button").attr("disabled", "disabled"); var localMedia = await request(`/${pluginId}/db-files`, {method: 'GET', headers:{'Authorization':`Bearer ${auth.getToken()}`}}); var configs = await request(`/${pluginId}/config`, {method: 'GET', headers:{'Authorization':`Bearer ${auth.getToken()}`}}); var sass = await getSass(configs); if (sass === false) { onShowAlert('warning', intl.formatMessage({id:`${pluginId}.notification.error.check_sectmp_issue`})); $("button").attr("disabled", false); return {'localMedia':false, 'filerobotMedia':false}; } var headers = new Headers(); headers.append("Content-Type", "application/json"); headers.append("X-Filerobot-Key", sass); var requestOptions = { method: 'GET', headers: headers }; var filerobotDirectory = (configs.folder.charAt(0) === '/') ? configs.folder : `/${configs.folder}`; var filerobotResponse = await fetch(`${filerobotApiDomain}/${configs.token}/v4/files?folder=${filerobotDirectory}`, requestOptions); if (filerobotResponse.status != 200) { onShowAlert('warning', intl.formatMessage({id:`${pluginId}.notification.error.sync_status`})); $("button").attr("disabled", false); return {'localMedia':false, 'filerobotMedia':false}; } var filerobotResponseJson = await filerobotResponse.json(); var filerobotMedia = filerobotResponseJson.files; return {'localMedia':localMedia, 'filerobotMedia':filerobotMedia}; } async function validateSass(sassKey, token) { var headers = new Headers(); headers.append("Content-Type", "application/json"); headers.append("X-Filerobot-Key", sassKey); var requestOptions = { method: 'GET', headers: headers, redirect: 'follow' }; var response = await fetch(`${filerobotApiDomain}/${token}/v4/files/`, requestOptions); return response.json(); } async function getNewSassKey(config) { var sassReqHeaders = new Headers(); sassReqHeaders.append("Content-Type", "application/json"); var sassReqOpt = { method: 'GET', headers: sassReqHeaders }; var sassRes = await fetch(`${filerobotApiDomain}/${config.token}/key/${config.sec_temp}`, sassReqOpt); if (sassRes.status != 200) { return false; // @Todo: better erroneous return } var sassInfo = await sassRes.json(); if (sassInfo.status !== "success") { return false; // @Todo: better erroneous return } var sass = sassInfo.key; if (typeof(Storage) !== "undefined") { sessionStorage.setItem("sassKey", sass); } return sass; } async function getSass(config) { var sass = ''; if (typeof(Storage) !== "undefined" && sessionStorage.getItem("sassKey")) { sass = sessionStorage.getItem("sassKey"); var sassValidation = await validateSass(sass, config.token); if (sassValidation.code === 'KEY_EXPIRED' || sassValidation.code === 'UNAUTHORIZED') { sass = await getNewSassKey(config); if (sass === false) { return false; } } return sass; } else { sass = await getNewSassKey(config); if (sass === false) { return false; } return sass; } } return ( <div> <Container> <h2>Filerobot Configurations</h2> <Form onSubmit={update}> <Form.Group controlId="cname" className="form-group"> <Form.Label>CNAME</Form.Label> <Form.Control name="cname" type="text" defaultValue={config.cname} /> </Form.Group> <Form.Group controlId="token" className="form-group"> <Form.Label>Token *</Form.Label> <Form.Control name="token" type="text" defaultValue={config.token} /> </Form.Group> <Form.Group controlId="sec_temp" className="form-group"> <Form.Label>Security Template Identifier *</Form.Label> <Form.Control name="sec_temp" type="text" defaultValue={config.sec_temp} /> </Form.Group> <Form.Group controlId="folder" className="form-group"> <Form.Label>Folder</Form.Label> <Form.Control name="folder" type="text" defaultValue={config.folder} /> </Form.Group> <Form.Group className="btn-group"> <Button className="btn btn-primary" type="submit"> Submit </Button> </Form.Group> </Form> <div className="mb-2 btn-group"> <Button variant="secondary" size="sm" onClick={check_connection}>Check Connection</Button> <Button variant="secondary" size="sm" onClick={sync_status}>Synchronization Status</Button>{' '} <Button variant="secondary" size="sm" onClick={trigger_sync}>Trigger Synchronization</Button> </div> <Row className="progress-bars"> <Col> <ProgressBar now={down} label={`${down}%`} /> </Col> <Col> <ProgressBar now={up} label={`${up}%`} /> </Col> </Row> </Container> <Alert header={'Scaleflex Filerobot'} btnText={'Close'} text={alert.text} type={alert.type} show={alert.show} onClosePress={onCloseAlert} pressCloseOnOutsideClick={true} showBorderBottom={false} alertStyles={{'minHeight': 'fit-content', 'padding': '20px'}} headerStyles={{}} textStyles={{}} buttonStyles={{'backgroundColor': 'rgb(0,0,0,0.1)','color': 'black', 'margin': 0}} /> </div> ); }; export default Configurations;