Skip to content

Commit 212ba9d

Browse files
committed
Fix small issue with the file head endpoint
1 parent 9606dbb commit 212ba9d

File tree

9 files changed

+223
-23
lines changed

9 files changed

+223
-23
lines changed

packages/dashboard-v2/src/appUtils.js

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ export const apiHandler = {
7070
key: encode(key)
7171
})
7272
},
73-
downloadFile: (bucket, file, previewConfig, onDownloadProgress, abortControl) => {
73+
downloadFile: (bucket, key, previewConfig, onDownloadProgress, abortControl) => {
7474
const extra = {};
7575
if (previewConfig.downloadType === "objectUrl" || previewConfig.downloadType === "blob") {
7676
extra.responseType = "arraybuffer";
@@ -83,26 +83,27 @@ export const apiHandler = {
8383
}
8484

8585
return api.get(
86-
`/buckets/${bucket}/${encode(file.key)}`,
86+
`/buckets/${bucket}/${encode(key)}`,
8787
extra
8888
);
8989
},
90+
headFile: (bucket, key) => {
91+
return api.get(`/buckets/${bucket}/${encode(key)}/head`);
92+
},
9093
// renameObject: (oldName, newName) => {
9194
// return axios.post(`/buckets/${store.state.activeBucket}/move`, {
9295
// oldKey: encodeKey(oldName, store.state.currentFolder),
9396
// newKey: encodeKey(newName, store.state.currentFolder)
9497
// })
9598
// },
96-
// updateMetadata: (file, metadata) => {
97-
// const filePath = encodeKey(file.name, getCurrentFolder())
98-
//
99-
// return axios.post(
100-
// `/buckets/${store.state.activeBucket}/${filePath}`,
101-
// {
102-
// customMetadata: metadata
103-
// }
104-
// )
105-
// },
99+
updateMetadata: (bucket, key, metadata) => {
100+
return api.post(
101+
`/buckets/${bucket}/${encode(key)}`,
102+
{
103+
customMetadata: metadata
104+
}
105+
)
106+
},
106107
multipartCreate: (file, key, bucket) => {
107108
return api.post(`/buckets/${bucket}/multipart/create`, null, {
108109
params: {
@@ -134,7 +135,7 @@ export const apiHandler = {
134135
})
135136
},
136137
uploadObjects: (file, key, bucket, callback) => {
137-
console.log(key)
138+
// console.log(key)
138139
return api.post(`/buckets/${bucket}/upload`, file, {
139140
params: {
140141
key: encode(key),

packages/dashboard-v2/src/components/preview/FilePreview.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,7 @@ export default {
221221
if (previewConfig) {
222222
this.type = previewConfig.type;
223223
224-
const response = await apiHandler.downloadFile(this.$route.params.bucket, file, previewConfig, (progressEvent) => {
224+
const response = await apiHandler.downloadFile(this.$route.params.bucket, file.key, previewConfig, (progressEvent) => {
225225
this.downloadProgress = progressEvent.loaded / progressEvent.total;
226226
}, this.abortControl);
227227
Lines changed: 179 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,179 @@
1+
<template>
2+
<template v-if="this.file">
3+
<div>
4+
<q-card>
5+
<q-card-section class="bg-grey-3 text-black" vertical>
6+
<q-btn-group push>
7+
<q-btn push icon="arrow_back" :to="{ name: `email-folder`, params: { bucket: $route.params.bucket, folder: $route.params.folder }}" />
8+
<q-btn push icon="chevron_left" />
9+
<q-btn push icon="chevron_right" />
10+
</q-btn-group>
11+
</q-card-section>
12+
13+
<q-card-section vertical>
14+
<h5 class="font-18">{{ file.subject }}</h5>
15+
</q-card-section>
16+
17+
<q-card-section horizontal class="q-px-sm">
18+
<div class="d-flex row">
19+
<q-icon name="account_circle" size="xl" class="q-mr-sm"/>
20+
<div class="d-flex column">
21+
<span>{{ file.from.name }} <small class="text-muted">&lt;{{ file.from.address }}></small></span>
22+
<span>{{ file.to[0].address }}</span>
23+
</div>
24+
</div>
25+
26+
<div class="q-ml-auto">
27+
<small class="">{{ file.date }} ({{timeSince(new Date(file.date))}})</small>
28+
</div>
29+
</q-card-section>
30+
31+
<q-card-actions vertical>
32+
<div class="overflow-auto d-block email-wrapper">
33+
<iframe v-if="file.html" frameborder="0" scrolling="no" class="w-100 d-block" @load="contentFinishedLoading"
34+
ref="renderWindow"
35+
:srcdoc="file.html"
36+
sandbox="allow-popups allow-popups-to-escape-sandbox allow-same-origin"
37+
csp="script-src 'none'"
38+
/>
39+
<div v-else v-html="file.text.replaceAll('\n', '<br>')"></div>
40+
</div>
41+
</q-card-actions>
42+
43+
<q-card-actions vertical v-if="file.attachments.length > 0">
44+
<h6 class="q-mb-3">Attachments</h6>
45+
46+
<div class="row">
47+
<div class="col-xl-4 col-lg-6 col-md-6" v-for="attachment of file.attachments" :key="attachment.filename">
48+
<div class="card mb-1 shadow-none border">
49+
<div class="p-2">
50+
<div class="row align-items-center">
51+
<div class="col-auto">
52+
<div class="avatar-sm">
53+
<span class="avatar-title bg-soft-primary text-primary rounded">
54+
.{{ attachment.filename.split(".").pop() }}
55+
</span>
56+
</div>
57+
</div>
58+
<div class="col ps-0">
59+
<span class="text-muted fw-bold">{{ attachment.filename }}</span>
60+
<!-- <p class="mb-0">{{ bytesToSize(attachment.size) }}</p>-->
61+
</div>
62+
<div class="col-auto">
63+
<a :href="attachment.downloadUrl" class="btn btn-link btn-lg text-muted">
64+
<i class="bi bi-download"></i>
65+
</a>
66+
</div>
67+
</div>
68+
</div>
69+
</div>
70+
</div>
71+
</div>
72+
</q-card-actions>
73+
</q-card>
74+
75+
</div>
76+
</template>
77+
78+
<template v-else>
79+
<div class="text-center q-my-lg">
80+
<q-spinner
81+
color="primary"
82+
size="3em"
83+
/>
84+
</div>
85+
</template>
86+
87+
</template>
88+
89+
<script>
90+
import { defineComponent } from "vue";
91+
import { api } from "boot/axios";
92+
import { useMainStore } from "stores/main-store";
93+
import { apiHandler, decode, encode, timeSince } from "../../appUtils";
94+
95+
export default defineComponent({
96+
name: "EmailFolderPage",
97+
data: function() {
98+
return {
99+
file: null,
100+
timeInterval: null
101+
};
102+
},
103+
computed: {
104+
selectedBucket: function() {
105+
return this.$route.params.bucket;
106+
},
107+
selectedFolder: function() {
108+
return this.$route.params.folder;
109+
},
110+
selectedFile: function() {
111+
return this.$route.params.file;
112+
}
113+
},
114+
watch: {
115+
selectedBucket(newVal) {
116+
this.$router.push({ name: `email-folder`, params: { bucket: newVal, folder: encode(this.selectedFolder) }})
117+
}
118+
},
119+
methods: {
120+
timeSince,
121+
contentFinishedLoading() {
122+
clearInterval(this.timeInterval)
123+
this.timeInterval = null
124+
125+
this.resizeIframe()
126+
},
127+
resizeIframe() {
128+
this.$refs.renderWindow.style.height = this.$refs.renderWindow.contentWindow.document.documentElement.scrollHeight + "px";
129+
},
130+
131+
fetchEmail: async function() {
132+
const fileName = decode(this.selectedFile)
133+
const filePath = `.r2-explorer/emails/${this.selectedFolder}/${fileName}`
134+
135+
const fileData = await apiHandler.downloadFile(this.selectedBucket, filePath, {})
136+
137+
const filename = fileName.split(".json")[0];
138+
for (const att of fileData.data.attachments) {
139+
att.downloadUrl = `${this.mainStore.serverUrl}/api/buckets/${this.selectedBucket}/${encode(`${filename}/${att.filename}`)}`;
140+
}
141+
this.file = fileData.data;
142+
console.log(this.file)
143+
144+
this.timeInterval = setInterval(function() {
145+
this.resizeIframe()
146+
}, 400);
147+
148+
try {
149+
// Up to 1.0.6 there was a bug in the file head endpoint
150+
const fileHead = await apiHandler.headFile(this.selectedBucket, filePath)
151+
152+
if (fileHead.data.customMetadata.read === false) {
153+
await apiHandler.updateMetadata(this.selectedBucket, filePath, {
154+
...fileHead.data.customMetadata,
155+
read: true
156+
});
157+
}
158+
} catch (e) {
159+
// Empty
160+
}
161+
162+
}
163+
},
164+
created() {
165+
this.fetchEmail();
166+
},
167+
setup() {
168+
return {
169+
mainStore: useMainStore()
170+
};
171+
}
172+
});
173+
</script>
174+
175+
<style scoped lang="scss">
176+
iframe {
177+
width: 100%;
178+
}
179+
</style>

packages/dashboard-v2/src/pages/email/EmailFolderPage.vue

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@
6161
import { defineComponent } from "vue";
6262
import { api } from "boot/axios";
6363
import { useMainStore } from "stores/main-store";
64-
import { encode, timeSince } from "../../appUtils";
64+
import { decode, encode, timeSince } from "../../appUtils";
6565
6666
export default defineComponent({
6767
name: 'EmailFolderPage',
@@ -113,7 +113,10 @@ export default defineComponent({
113113
},
114114
methods: {
115115
rowClick: function(evt, row, index) {
116-
console.log(row)
116+
const file = row.key.replace(/^.*[\\/]/, '')
117+
// const folder = row.key.replace(file, '')
118+
119+
this.$router.push({ name: `email-file`, params: { bucket: this.selectedBucket, folder: 'inbox', file: encode(file) }})
117120
},
118121
fetchFiles: async function () {
119122
const self = this

packages/dashboard-v2/src/router/routes.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ const routes = [
1818

1919
{ path: '/:bucket/email', name: 'email-home', component: () => import('pages/email/EmailFolderPage.vue') },
2020
{ path: '/:bucket/email/:folder', name: 'email-folder', component: () => import('pages/email/EmailFolderPage.vue') },
21-
{ path: '/:bucket/email/:folder/:file', name: 'email-file', component: () => import('pages/email/EmailFolderPage.vue') }
21+
{ path: '/:bucket/email/:folder/:file', name: 'email-file', component: () => import('pages/email/EmailFilePage.vue') }
2222
]
2323
},
2424

worker/src/buckets/api/getObject.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,12 @@ export class GetObject extends OpenAPIRoute {
2828
) {
2929
const bucket = env[data.params.bucket]
3030

31-
const filePath = decodeURIComponent(escape(atob(data.params.key)));
31+
let filePath
32+
try {
33+
filePath = decodeURIComponent(escape(atob(data.params.key)));
34+
} catch (e) {
35+
filePath = decodeURIComponent(escape(atob(decodeURIComponent(data.params.key))));
36+
}
3237

3338
const object = await bucket.get(filePath)
3439

worker/src/buckets/api/headObject.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ export class HeadObject extends OpenAPIRoute {
1010
summary: 'Get Object',
1111
parameters: {
1212
bucket: Path(String),
13-
key: Query(z.string().describe('base64 encoded file key')),
13+
key: Path(z.string().describe('base64 encoded file key')),
1414
},
1515
}
1616

@@ -21,7 +21,13 @@ export class HeadObject extends OpenAPIRoute {
2121
data: any
2222
) {
2323
const bucket = env[data.params.bucket]
24-
const filePath = decodeURIComponent(escape(atob(data.params.key)));
24+
25+
let filePath
26+
try {
27+
filePath = decodeURIComponent(escape(atob(data.params.key)));
28+
} catch (e) {
29+
filePath = decodeURIComponent(escape(atob(decodeURIComponent(data.params.key))));
30+
}
2531

2632
const object = await bucket.head(filePath)
2733

worker/src/buckets/api/putMetadata.ts

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,14 @@ export class PutMetadata extends OpenAPIRoute {
2727

2828
const bucket = env[data.params.bucket]
2929

30-
const key = decodeURIComponent(escape(atob(data.params.key)))
30+
let filePath
31+
try {
32+
filePath = decodeURIComponent(escape(atob(data.params.key)));
33+
} catch (e) {
34+
filePath = decodeURIComponent(escape(atob(decodeURIComponent(data.params.key))));
35+
}
3136

32-
const object = await bucket.get(key)
33-
return await bucket.put(key, object.body, {customMetadata: data.body.customMetadata})
37+
const object = await bucket.get(filePath)
38+
return await bucket.put(filePath, object.body, {customMetadata: data.body.customMetadata})
3439
}
3540
}

worker/src/buckets/router.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,5 +30,6 @@ bucketsRouter.post('/:bucket/multipart/upload', PartUpload)
3030
bucketsRouter.post('/:bucket/multipart/complete', CompleteUpload)
3131
bucketsRouter.post('/:bucket/delete', DeleteObject)
3232
bucketsRouter.head('/:bucket/:key', HeadObject)
33+
bucketsRouter.get('/:bucket/:key/head', HeadObject) // There are some issues with calling the head method
3334
bucketsRouter.get('/:bucket/:key', GetObject)
3435
bucketsRouter.post('/:bucket/:key', PutMetadata)

0 commit comments

Comments
 (0)