|
| 1 | +<template lang="pug"> |
| 2 | + .download-app |
| 3 | + .alert.alert-danger(v-show="error") |
| 4 | + strong |
| 5 | + i.fa.fa-exclamation-triangle |
| 6 | + | {{ error }} |
| 7 | + form.well(v-if='!loggedIn', @submit.stop.prevent="login") |
| 8 | + h3 Password |
| 9 | + .form-group |
| 10 | + input.form-control(type='password', v-model='password', autofocus="") |
| 11 | + p.text-danger(v-show='passwordWrong') |
| 12 | + strong Access denied! |
| 13 | + | |
| 14 | + button.btn.btn-primary(type="submit") |
| 15 | + i.fa.fa-sign-in |
| 16 | + | login |
| 17 | + |
| 18 | + div(v-if="loggedIn") |
| 19 | + table.table.table-hover |
| 20 | + thead |
| 21 | + tr |
| 22 | + th SID |
| 23 | + th Created |
| 24 | + th Downloaded |
| 25 | + th Expire |
| 26 | + th Size |
| 27 | + template(v-for="(bucket, sid) in db") |
| 28 | + tbody(:class="{expanded: expand===sid}") |
| 29 | + tr.bucket(@click="expandView(sid)") |
| 30 | + td |
| 31 | + | {{ sid }} |
| 32 | + i.fa.fa-key.pull-right(v-if="sum[sid].password", title="Password protected") |
| 33 | + td {{ sum[sid].created | date }} |
| 34 | + td |
| 35 | + template(v-if="sum[sid].lastDownload") {{ sum[sid].lastDownload | date}} |
| 36 | + template(v-else="") - |
| 37 | + td |
| 38 | + template(v-if="typeof sum[sid].firstExpire === 'number'") {{ sum[sid].firstExpire | date }} |
| 39 | + template(v-else) {{ sum[sid].firstExpire }} |
| 40 | + td.text-right {{ humanFileSize(sum[sid].size) }} |
| 41 | + tbody.expanded(v-if="expand === sid") |
| 42 | + template(v-for="file in bucket") |
| 43 | + tr.file |
| 44 | + td {{ file.metadata.name }} |
| 45 | + td {{+file.metadata.createdAt | date}} |
| 46 | + td |
| 47 | + template(v-if="file.metadata.lastDownload") {{ +file.metadata.lastDownload | date}} |
| 48 | + template(v-else="") - |
| 49 | + td |
| 50 | + template(v-if="typeof file.expireDate === 'number'") {{ file.expireDate | date }} |
| 51 | + template(v-else) {{ file.expireDate }} |
| 52 | + td.text-right {{ humanFileSize(file.size) }} |
| 53 | + tfoot |
| 54 | + tr |
| 55 | + td(colspan="3") |
| 56 | + td.text-right(colspan="2") Sum: {{ humanFileSize(sizeSum) }} |
| 57 | + |
| 58 | +</template> |
| 59 | + |
| 60 | + |
| 61 | +<script> |
| 62 | + "use strict"; |
| 63 | +
|
| 64 | + export default { |
| 65 | + name: 'app', |
| 66 | +
|
| 67 | + data () { |
| 68 | + return { |
| 69 | + db: {}, |
| 70 | + sum: {}, |
| 71 | + loggedIn: false, |
| 72 | + password: '', |
| 73 | + error: '', |
| 74 | + passwordWrong: false, |
| 75 | + expand: false, |
| 76 | + sizeSum: 0 |
| 77 | + } |
| 78 | + }, |
| 79 | +
|
| 80 | + methods: { |
| 81 | + expandView(sid) { |
| 82 | + if(this.expand === sid) return this.expand = false; |
| 83 | + this.expand = sid; |
| 84 | + }, |
| 85 | +
|
| 86 | + login() { |
| 87 | + const xhr = new XMLHttpRequest(); |
| 88 | + xhr.open('GET', '/admin/data.json'); |
| 89 | + xhr.setRequestHeader("x-passwd", this.password); |
| 90 | + xhr.onload = () => { |
| 91 | + if(xhr.status === 200) { |
| 92 | + try { |
| 93 | + this.db = JSON.parse(xhr.responseText); |
| 94 | + this.expandDb(); |
| 95 | + this.loggedIn = true; |
| 96 | + } |
| 97 | + catch(e) { |
| 98 | + this.error = e.toString(); |
| 99 | + } |
| 100 | + } else { |
| 101 | + if(xhr.status === 403) this.passwordWrong = true; |
| 102 | + else this.error = `${xhr.status} ${xhr.statusText}: ${xhr.responseText}`; |
| 103 | + } |
| 104 | + }; |
| 105 | + xhr.send(); |
| 106 | + }, |
| 107 | +
|
| 108 | + expandDb() { |
| 109 | + Object.keys(this.db).forEach(sid => { |
| 110 | + const sum = { |
| 111 | + firstExpire: Number.MAX_SAFE_INTEGER, |
| 112 | + lastDownload: 0, |
| 113 | + created: Number.MAX_SAFE_INTEGER, |
| 114 | + password: false, |
| 115 | + size: 0 |
| 116 | + }; |
| 117 | + this.db[sid].forEach(file => { |
| 118 | + sum.size += file.size; |
| 119 | + if(file.metadata._password) { |
| 120 | + sum.password = true; |
| 121 | + } |
| 122 | + if(+file.metadata.createdAt < sum.created) { |
| 123 | + sum.created = +file.metadata.createdAt; |
| 124 | + } |
| 125 | + if(file.metadata.lastDownload && +file.metadata.lastDownload > sum.lastDownload) { |
| 126 | + sum.lastDownload = +file.metadata.lastDownload; |
| 127 | + } |
| 128 | + if(file.metadata.retention === 'one-time') { |
| 129 | + sum.firstExpire = 'one-time'; |
| 130 | + file.expireDate = file.metadata.retention; |
| 131 | + } |
| 132 | + else { |
| 133 | + file.expireDate = +file.metadata.createdAt + (+file.metadata.retention * 1000); |
| 134 | + if(sum.firstExpire > file.expireDate) sum.firstExpire = file.expireDate; |
| 135 | + } |
| 136 | + }); |
| 137 | + this.sizeSum += sum.size; |
| 138 | + this.$set(this.sum, sid, sum); |
| 139 | + }); |
| 140 | + }, |
| 141 | +
|
| 142 | + humanFileSize(fileSizeInBytes) { |
| 143 | + let i = -1; |
| 144 | + const byteUnits = [' kB', ' MB', ' GB', ' TB', 'PB', 'EB', 'ZB', 'YB']; |
| 145 | + do { |
| 146 | + fileSizeInBytes = fileSizeInBytes / 1024; |
| 147 | + i++; |
| 148 | + } while(fileSizeInBytes > 1024); |
| 149 | + return Math.max(fileSizeInBytes, 0.00).toFixed(2) + byteUnits[i]; |
| 150 | + }, |
| 151 | +
|
| 152 | + }, |
| 153 | +
|
| 154 | +
|
| 155 | + } |
| 156 | +</script> |
| 157 | + |
| 158 | +<style> |
| 159 | + .bucket { |
| 160 | + cursor: pointer; |
| 161 | + } |
| 162 | + .expanded { |
| 163 | + background: #fafafa; |
| 164 | + } |
| 165 | + .expanded .bucket td { |
| 166 | + font-weight: bold; |
| 167 | + } |
| 168 | + tfoot { |
| 169 | + font-weight: bold; |
| 170 | + } |
| 171 | +</style> |
0 commit comments