* Added an API endpoint to check the existence of the file

* fix #2773: Now we can prevent users from posting the same images

* bug fix
This commit is contained in:
sei0o inoue 2018-10-07 16:51:46 +09:00 committed by syuilo
parent d0570d7fe3
commit 3e897727ca
3 changed files with 106 additions and 34 deletions

View File

@ -0,0 +1,8 @@
const crypto = require('crypto');
export default (data: ArrayBuffer) => {
const buf = new Buffer(data);
const hash = crypto.createHash("md5");
hash.update(buf);
return hash.digest("hex");
};

View File

@ -20,6 +20,7 @@
<script lang="ts"> <script lang="ts">
import Vue from 'vue'; import Vue from 'vue';
import { apiUrl } from '../../../config'; import { apiUrl } from '../../../config';
import getMD5 from '../../scripts/get-md5';
export default Vue.extend({ export default Vue.extend({
data() { data() {
@ -28,53 +29,78 @@ export default Vue.extend({
}; };
}, },
methods: { methods: {
upload(file, folder) { checkExistence(fileData: ArrayBuffer): Promise<any> {
return new Promise((resolve, reject) => {
const data = new FormData();
data.append('md5', getMD5(fileData));
(this as any).api('drive/files/check_existence', {
md5: getMD5(fileData)
}).then(resp => {
resolve(resp.file);
});
});
},
upload(file: File, folder: any) {
if (folder && typeof folder == 'object') folder = folder.id; if (folder && typeof folder == 'object') folder = folder.id;
const id = Math.random(); const id = Math.random();
const ctx = {
id: id,
name: file.name || 'untitled',
progress: undefined,
img: undefined
};
this.uploads.push(ctx);
this.$emit('change', this.uploads);
const reader = new FileReader(); const reader = new FileReader();
reader.onload = (e: any) => { reader.onload = (e: any) => {
ctx.img = e.target.result; this.checkExistence(e.target.result).then(result => {
}; console.log(result);
reader.readAsDataURL(file); if (result !== null) {
this.$emit('uploaded', result);
return;
}
const data = new FormData(); // Upload if the file didn't exist yet
data.append('i', this.$store.state.i.token); const buf = new Uint8Array(e.target.result);
data.append('file', file); let bin = "";
// We use for-of loop instead of apply() to avoid RangeError
// SEE: https://stackoverflow.com/questions/9267899/arraybuffer-to-base64-encoded-string
for (const byte of buf) bin += String.fromCharCode(byte);
const ctx = {
id: id,
name: file.name || 'untitled',
progress: undefined,
img: 'data:*/*;base64,' + btoa(bin)
};
if (folder) data.append('folderId', folder); this.uploads.push(ctx);
this.$emit('change', this.uploads);
const xhr = new XMLHttpRequest(); const data = new FormData();
xhr.open('POST', apiUrl + '/drive/files/create', true); data.append('i', this.$store.state.i.token);
xhr.onload = (e: any) => { data.append('file', file);
const driveFile = JSON.parse(e.target.response);
this.$emit('uploaded', driveFile); if (folder) data.append('folderId', folder);
this.uploads = this.uploads.filter(x => x.id != id); const xhr = new XMLHttpRequest();
this.$emit('change', this.uploads); xhr.open('POST', apiUrl + '/drive/files/create', true);
}; xhr.onload = (e: any) => {
const driveFile = JSON.parse(e.target.response);
xhr.upload.onprogress = e => { this.$emit('uploaded', driveFile);
if (e.lengthComputable) {
if (ctx.progress == undefined) ctx.progress = {};
ctx.progress.max = e.total;
ctx.progress.value = e.loaded;
}
};
xhr.send(data); this.uploads = this.uploads.filter(x => x.id != id);
this.$emit('change', this.uploads);
};
xhr.upload.onprogress = e => {
if (e.lengthComputable) {
if (ctx.progress == undefined) ctx.progress = {};
ctx.progress.max = e.total;
ctx.progress.value = e.loaded;
}
};
xhr.send(data);
})
}
reader.readAsArrayBuffer(file);
} }
} }
}); });

View File

@ -0,0 +1,38 @@
import $ from 'cafy';
import DriveFile, { pack } from '../../../../../models/drive-file';
import { ILocalUser } from '../../../../../models/user';
export const meta = {
desc: {
'ja-JP': '与えられたMD5ハッシュ値を持つファイルがドライブに存在するかどうかを返します。',
'en-US': 'Returns whether the file with the given MD5 hash exists in the user\'s drive.'
},
requireCredential: true,
kind: 'drive-read',
params: {
md5: $.str.note({
desc: {
'ja-JP': 'ファイルのMD5ハッシュ'
}
})
}
};
export default (params: any, user: ILocalUser) => new Promise(async (res, rej) => {
const [md5, md5Err] = $.str.get(params.md5);
if (md5Err) return rej('invalid md5 param');
const file = await DriveFile.findOne({
md5: md5,
'metadata.userId': user._id
});
if (file === null) {
res({ file: null });
} else {
res({ file: await pack(file) });
}
});