| 710 | @post('filename', Types.Filename, true) |
| 711 | @post('type', Types.Range(['testdata', 'additional_file']), true) |
| 712 | async postUploadFile(domainId: string, filename: string, type = 'testdata') { |
| 713 | const file = this.request.files.file; |
| 714 | if (!file) throw new ValidationError('file'); |
| 715 | filename ||= file.originalFilename || randomstring(16); |
| 716 | const files = []; |
| 717 | if (filename.endsWith('.zip') && type === 'testdata') { |
| 718 | const zip = new ZipReader(Readable.toWeb(createReadStream(file.filepath))); |
| 719 | let entries: Entry[]; |
| 720 | try { |
| 721 | entries = await zip.getEntries(); |
| 722 | } catch (e) { |
| 723 | throw new ValidationError('zip', null, e.message); |
| 724 | } |
| 725 | for (const entry of entries) { |
| 726 | if (!entry.filename || entry.directory === true) continue; |
| 727 | files.push({ |
| 728 | type, |
| 729 | name: sanitize(entry.filename), |
| 730 | size: entry.uncompressedSize, |
| 731 | data: () => { |
| 732 | const pass = new PassThrough(); |
| 733 | entry.getData(Writable.toWeb(pass)); |
| 734 | return pass; |
| 735 | }, |
| 736 | }); |
| 737 | } |
| 738 | } else { |
| 739 | files.push({ |
| 740 | type, |
| 741 | name: filename, |
| 742 | size: file.size, |
| 743 | data: () => file.filepath, |
| 744 | }); |
| 745 | } |
| 746 | if (!this.user.hasPriv(PRIV.PRIV_EDIT_SYSTEM)) { |
| 747 | if ((this.pdoc.data?.length || 0) |
| 748 | + (this.pdoc.additional_file?.length || 0) |
| 749 | + files.length |
| 750 | >= this.ctx.setting.get('limit.problem_files_max')) { |
| 751 | throw new FileLimitExceededError('count'); |
| 752 | } |
| 753 | const size = Math.sum( |
| 754 | (this.pdoc.data || []).map((i) => i.size), |
| 755 | (this.pdoc.additional_file || []).map((i) => i.size), |
| 756 | files.map((i) => i.size), |
| 757 | ); |
| 758 | if (size >= this.ctx.setting.get('limit.problem_files_max_size')) { |
| 759 | throw new FileLimitExceededError('size'); |
| 760 | } |
| 761 | } |
| 762 | for (const entry of files) { |
| 763 | const method = entry.type === 'testdata' ? 'addTestdata' : 'addAdditionalFile'; |
| 764 | // eslint-disable-next-line no-await-in-loop |
| 765 | await problem[method](domainId, this.pdoc.docId, entry.name, entry.data(), this.user._id); |
| 766 | } |
| 767 | this.back(); |
| 768 | } |
| 769 | |