Creating File Statistics page.

This commit is contained in:
Roland 2022-12-15 11:48:46 -07:00
parent fef8e123a0
commit e24990aae2
No known key found for this signature in database
GPG key ID: 9D6DBD3ACF11AB93
7 changed files with 165 additions and 2 deletions

View file

@ -661,3 +661,18 @@ export async function getAPIStatus() {
let response = await apiGet(`${API_URI}/echo`);
return response.status === 200;
}
export async function getFileStatistics() {
let response = await apiGet(`${API_URI}/files/statistics`);
if (response.status === 200) {
const contents = await response.json();
return contents['statistics'];
} else {
toast({
type: 'error',
title: 'Error!',
description: 'Unable to get file statistics',
time: 5000,
})
}
}

View file

@ -1,11 +1,12 @@
import React, {useContext} from 'react';
import {Divider, SegmentGroup} from "semantic-ui-react";
import {Divider, SegmentGroup, StatisticLabel, StatisticValue} from "semantic-ui-react";
import {Route, Routes} from "react-router-dom";
import "../static/wrolpi.css";
import {decryptOTP, encryptOTP} from "../api";
import {PageContainer, useTitle} from "./Common";
import {ThemeContext} from "../contexts/contexts";
import {Button, Header, Segment, TextArea} from "./Theme";
import {Button, Header, Loader, Segment, Statistic, StatisticGroup, TextArea} from "./Theme";
import {useFileStatistics} from "../hooks/customHooks";
class Encrypt extends React.Component {
constructor(props) {
@ -145,10 +146,72 @@ function OTP() {
</>
}
function FileStatistics() {
useTitle('File Statistics');
const {s} = useContext(ThemeContext);
const {statistics} = useFileStatistics();
let body = <Loader inline active/>;
if (statistics === undefined) {
body = <p {...s}>Failed to fetch statistics</p>;
}
if (statistics !== undefined && statistics !== null) {
const {total_count, video_count, pdf_count, ebook_count, archive_count, image_count, zip_count} = statistics;
body = <>
<StatisticGroup>
<Statistic>
<StatisticValue>{total_count}</StatisticValue>
<StatisticLabel>All Files</StatisticLabel>
</Statistic>
</StatisticGroup>
<StatisticGroup size='small'>
<Statistic color='blue'>
<StatisticValue>{video_count}</StatisticValue>
<StatisticLabel>Videos</StatisticLabel>
</Statistic>
<Statistic color='red'>
<StatisticValue>{pdf_count}</StatisticValue>
<StatisticLabel>PDFs</StatisticLabel>
</Statistic>
<Statistic color='yellow'>
<StatisticValue>{ebook_count}</StatisticValue>
<StatisticLabel>eBooks</StatisticLabel>
</Statistic>
<Statistic color='green'>
<StatisticValue>{archive_count}</StatisticValue>
<StatisticLabel>Archives</StatisticLabel>
</Statistic>
<Statistic color='pink'>
<StatisticValue>{image_count}</StatisticValue>
<StatisticLabel>Images</StatisticLabel>
</Statistic>
</StatisticGroup>
<StatisticGroup>
<Statistic color='grey'>
<StatisticValue>{zip_count}</StatisticValue>
<StatisticLabel>ZIP</StatisticLabel>
</Statistic>
</StatisticGroup>
</>;
}
return <>
<Header as='h1'>File Statistics</Header>
<Segment>
{body}
</Segment>
</>
}
export function AppsRoute(props) {
return (<PageContainer>
<Routes>
<Route path='otp' exact element={<OTP/>}/>
<Route path='file_statistics' exact element={<FileStatistics/>}/>
</Routes>
</PageContainer>)
}

View file

@ -16,6 +16,7 @@ const links = [
{
key: 'apps', text: 'Apps', links: [
{to: '/apps/otp', text: 'One Time Pad', end: true},
{to: '/apps/file_statistics', text: 'File Statistics', end: true},
]
},
];

View file

@ -10,6 +10,7 @@ import {
getDownloaders,
getDownloads,
getFiles,
getFileStatistics,
getInventory,
getSettings,
getStatistics,
@ -718,3 +719,22 @@ export const useInventory = (inventoryId) => {
return {byCategory, bySubcategory, byName, fetchInventory}
}
export const useFileStatistics = () => {
const [statistics, setStatistics] = useState();
const fetchFileStatistics = async () => {
try {
const statistics = await getFileStatistics();
setStatistics(statistics || undefined);
} catch (e) {
console.error(e);
}
}
useEffect(() => {
fetchFileStatistics();
}, []);
return {statistics};
}

View file

@ -135,3 +135,12 @@ def directories(_, body: schema.DirectoriesRequest):
body = {'directories': dirs, 'exists': path.exists(), 'is_dir': path.is_dir(), 'is_file': path.is_file()}
return response.json(body)
@bp.get('/statistics')
@openapi.definition(
summary='Get summary statistics of all files',
)
async def get_statistics(_):
statistics = await lib.get_file_statistics()
return json_response({'statistics': statistics})

View file

@ -621,3 +621,26 @@ def split_file_name_words(name: str) -> List[str]:
except Exception as e:
logger.error(f'Failed to split filename into words: {name}', exc_info=e)
return [name]
async def get_file_statistics():
with get_db_curs() as curs:
curs.execute('''
SELECT
COUNT(path) AS "total_count",
COUNT(path) FILTER (WHERE file.mimetype LIKE 'video/%') AS "video_count",
COUNT(path) FILTER (WHERE file.mimetype = 'application/pdf') AS "pdf_count",
COUNT(path) FILTER (WHERE file.mimetype LIKE 'image/%' AND file.associated = FALSE) AS "image_count",
COUNT(path) FILTER (WHERE file.mimetype = 'application/zip') AS "zip_count"
FROM
file
''')
statistics = dict(curs.fetchall()[0])
curs.execute('SELECT COUNT(*) FROM archive')
statistics['archive_count'] = curs.fetchall()[0][0]
curs.execute('SELECT COUNT(*) FROM ebook')
statistics['ebook_count'] = curs.fetchall()[0][0]
return statistics

View file

@ -242,3 +242,35 @@ def test_refresh_files_list(test_session, test_client, make_files_structure):
request, response = test_client.post('/api/files/refresh/list', content=content)
assert response.status_code == HTTPStatus.NO_CONTENT
assert test_session.query(File).count() == 1
def test_file_statistics(test_session, test_client, example_pdf, example_mobi, example_epub, video_file):
"""A summary of File statistics can be fetched."""
# Statistics can be fetched while empty.
request, response = test_client.get('/api/files/statistics')
assert response.status_code == HTTPStatus.OK
assert response.json == {
'statistics': {
'archive_count': 0,
'ebook_count': 0,
'image_count': 0,
'pdf_count': 0,
'total_count': 0,
'video_count': 0,
'zip_count': 0},
}
test_client.post('/api/files/refresh')
request, response = test_client.get('/api/files/statistics')
assert response.status_code == HTTPStatus.OK
assert response.json == {
'statistics': {
'archive_count': 0,
'ebook_count': 2,
'image_count': 0,
'pdf_count': 1,
'total_count': 5,
'video_count': 1,
'zip_count': 0},
}