Add /admin page
This commit is contained in:
171
app/src/Admin.vue
Normal file
171
app/src/Admin.vue
Normal file
@@ -0,0 +1,171 @@
|
||||
<template lang="pug">
|
||||
.download-app
|
||||
.alert.alert-danger(v-show="error")
|
||||
strong
|
||||
i.fa.fa-exclamation-triangle
|
||||
| {{ error }}
|
||||
form.well(v-if='!loggedIn', @submit.stop.prevent="login")
|
||||
h3 Password
|
||||
.form-group
|
||||
input.form-control(type='password', v-model='password', autofocus="")
|
||||
p.text-danger(v-show='passwordWrong')
|
||||
strong Access denied!
|
||||
|
|
||||
button.btn.btn-primary(type="submit")
|
||||
i.fa.fa-sign-in
|
||||
| login
|
||||
|
||||
div(v-if="loggedIn")
|
||||
table.table.table-hover
|
||||
thead
|
||||
tr
|
||||
th SID
|
||||
th Created
|
||||
th Downloaded
|
||||
th Expire
|
||||
th Size
|
||||
template(v-for="(bucket, sid) in db")
|
||||
tbody(:class="{expanded: expand===sid}")
|
||||
tr.bucket(@click="expandView(sid)")
|
||||
td
|
||||
| {{ sid }}
|
||||
i.fa.fa-key.pull-right(v-if="sum[sid].password", title="Password protected")
|
||||
td {{ sum[sid].created | date }}
|
||||
td
|
||||
template(v-if="sum[sid].lastDownload") {{ sum[sid].lastDownload | date}}
|
||||
template(v-else="") -
|
||||
td
|
||||
template(v-if="typeof sum[sid].firstExpire === 'number'") {{ sum[sid].firstExpire | date }}
|
||||
template(v-else) {{ sum[sid].firstExpire }}
|
||||
td.text-right {{ humanFileSize(sum[sid].size) }}
|
||||
tbody.expanded(v-if="expand === sid")
|
||||
template(v-for="file in bucket")
|
||||
tr.file
|
||||
td {{ file.metadata.name }}
|
||||
td {{+file.metadata.createdAt | date}}
|
||||
td
|
||||
template(v-if="file.metadata.lastDownload") {{ +file.metadata.lastDownload | date}}
|
||||
template(v-else="") -
|
||||
td
|
||||
template(v-if="typeof file.expireDate === 'number'") {{ file.expireDate | date }}
|
||||
template(v-else) {{ file.expireDate }}
|
||||
td.text-right {{ humanFileSize(file.size) }}
|
||||
tfoot
|
||||
tr
|
||||
td(colspan="3")
|
||||
td.text-right(colspan="2") Sum: {{ humanFileSize(sizeSum) }}
|
||||
|
||||
</template>
|
||||
|
||||
|
||||
<script>
|
||||
"use strict";
|
||||
|
||||
export default {
|
||||
name: 'app',
|
||||
|
||||
data () {
|
||||
return {
|
||||
db: {},
|
||||
sum: {},
|
||||
loggedIn: false,
|
||||
password: '',
|
||||
error: '',
|
||||
passwordWrong: false,
|
||||
expand: false,
|
||||
sizeSum: 0
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
expandView(sid) {
|
||||
if(this.expand === sid) return this.expand = false;
|
||||
this.expand = sid;
|
||||
},
|
||||
|
||||
login() {
|
||||
const xhr = new XMLHttpRequest();
|
||||
xhr.open('GET', '/admin/data.json');
|
||||
xhr.setRequestHeader("x-passwd", this.password);
|
||||
xhr.onload = () => {
|
||||
if(xhr.status === 200) {
|
||||
try {
|
||||
this.db = JSON.parse(xhr.responseText);
|
||||
this.expandDb();
|
||||
this.loggedIn = true;
|
||||
}
|
||||
catch(e) {
|
||||
this.error = e.toString();
|
||||
}
|
||||
} else {
|
||||
if(xhr.status === 403) this.passwordWrong = true;
|
||||
else this.error = `${xhr.status} ${xhr.statusText}: ${xhr.responseText}`;
|
||||
}
|
||||
};
|
||||
xhr.send();
|
||||
},
|
||||
|
||||
expandDb() {
|
||||
Object.keys(this.db).forEach(sid => {
|
||||
const sum = {
|
||||
firstExpire: Number.MAX_SAFE_INTEGER,
|
||||
lastDownload: 0,
|
||||
created: Number.MAX_SAFE_INTEGER,
|
||||
password: false,
|
||||
size: 0
|
||||
};
|
||||
this.db[sid].forEach(file => {
|
||||
sum.size += file.size;
|
||||
if(file.metadata._password) {
|
||||
sum.password = true;
|
||||
}
|
||||
if(+file.metadata.createdAt < sum.created) {
|
||||
sum.created = +file.metadata.createdAt;
|
||||
}
|
||||
if(file.metadata.lastDownload && +file.metadata.lastDownload > sum.lastDownload) {
|
||||
sum.lastDownload = +file.metadata.lastDownload;
|
||||
}
|
||||
if(file.metadata.retention === 'one-time') {
|
||||
sum.firstExpire = 'one-time';
|
||||
file.expireDate = file.metadata.retention;
|
||||
}
|
||||
else {
|
||||
file.expireDate = +file.metadata.createdAt + (+file.metadata.retention * 1000);
|
||||
if(sum.firstExpire > file.expireDate) sum.firstExpire = file.expireDate;
|
||||
}
|
||||
});
|
||||
this.sizeSum += sum.size;
|
||||
this.$set(this.sum, sid, sum);
|
||||
});
|
||||
},
|
||||
|
||||
humanFileSize(fileSizeInBytes) {
|
||||
let i = -1;
|
||||
const byteUnits = [' kB', ' MB', ' GB', ' TB', 'PB', 'EB', 'ZB', 'YB'];
|
||||
do {
|
||||
fileSizeInBytes = fileSizeInBytes / 1024;
|
||||
i++;
|
||||
} while(fileSizeInBytes > 1024);
|
||||
return Math.max(fileSizeInBytes, 0.00).toFixed(2) + byteUnits[i];
|
||||
},
|
||||
|
||||
},
|
||||
|
||||
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.bucket {
|
||||
cursor: pointer;
|
||||
}
|
||||
.expanded {
|
||||
background: #fafafa;
|
||||
}
|
||||
.expanded .bucket td {
|
||||
font-weight: bold;
|
||||
}
|
||||
tfoot {
|
||||
font-weight: bold;
|
||||
}
|
||||
</style>
|
||||
34
app/src/admin.js
Normal file
34
app/src/admin.js
Normal file
@@ -0,0 +1,34 @@
|
||||
import 'babel-polyfill';
|
||||
import Vue from 'vue';
|
||||
import Admin from './Admin.vue';
|
||||
|
||||
function parseDate(str) {
|
||||
if(!str) return str;
|
||||
return new Date(str);
|
||||
}
|
||||
|
||||
function formatDate(dt) {
|
||||
if(dt === null) return "";
|
||||
const f = function(d) {
|
||||
return d < 10 ? '0' + d : d;
|
||||
};
|
||||
return dt.getFullYear() + '-' + f(dt.getMonth() + 1) + '-' + f(dt.getDate()) + ' ' + f(dt.getHours()) + ':' + f(dt.getMinutes());
|
||||
}
|
||||
function isDate(d) {
|
||||
return Object.prototype.toString.call(d) === '[object Date]';
|
||||
}
|
||||
|
||||
Vue.filter('date', function(val, format) {
|
||||
if(!isDate(val)) {
|
||||
val = parseDate(val);
|
||||
}
|
||||
return isDate(val) ? formatDate(val, format) : val;
|
||||
});
|
||||
|
||||
|
||||
new Vue({
|
||||
el: '#admin',
|
||||
render: h => h(Admin)
|
||||
});
|
||||
|
||||
window.PSITRANSFER_VERSION = PSITRANSFER_VERSION;
|
||||
@@ -12,6 +12,7 @@ module.exports = {
|
||||
entry: {
|
||||
upload: './src/upload.js',
|
||||
download: './src/download.js',
|
||||
admin: './src/admin.js',
|
||||
},
|
||||
output: {
|
||||
path: path.resolve(__dirname, '../public/app'),
|
||||
|
||||
Reference in New Issue
Block a user