({ domainId, dryrun }: { domainId: string, dryrun: boolean })
| 8 | pdoc: ProblemDoc; |
| 9 | |
| 10 | async submit({ domainId, dryrun }: { domainId: string, dryrun: boolean }) { |
| 11 | if (!this.tdoc || !ContestModel.isOngoing(this.tdoc, this.tsdoc)) return { error: 'Contest not live' }; |
| 12 | if (!this.tdoc.allowPrint) return { error: 'Not a on-site contest' }; |
| 13 | const file = this.request.files?.file; |
| 14 | if (!file) return { error: 'No file uploaded' }; |
| 15 | const filename = file.originalFilename.split('/').pop(); |
| 16 | if (!/^[A-Z]\./i.test(filename.toUpperCase())) return { error: 'Unsupported file name' }; |
| 17 | const pids = this.tdoc.pids; |
| 18 | const pidIndex = filename.toUpperCase().charCodeAt(0) - 'A'.charCodeAt(0); |
| 19 | if (pidIndex < 0 || pidIndex >= pids.length) return { error: 'Unsupported file name' }; |
| 20 | const pid = pids[pidIndex]; |
| 21 | this.pdoc = await ProblemModel.get(domainId, pid); |
| 22 | |
| 23 | const ext = filename.split('.').pop(); |
| 24 | let lang = ext.toLowerCase(); |
| 25 | |
| 26 | const config = this.pdoc.config; |
| 27 | const lengthLimit = SystemModel.get('limit.codelength') || 128 * 1024; |
| 28 | if (typeof config === 'string' || config === null) return { error: 'system error' }; |
| 29 | const sizeLimit = config.type === 'submit_answer' ? 128 * 1024 * 1024 : lengthLimit; |
| 30 | if (file.size > sizeLimit) return { error: 'File too large' }; |
| 31 | |
| 32 | if (['submit_answer', 'objective'].includes(config.type)) { |
| 33 | lang = '_'; |
| 34 | } else if ((config.langs && !config.langs.includes(lang)) || !SettingModel.langs[lang] || SettingModel.langs[lang].disabled) { |
| 35 | return { error: 'Unsupported language' }; |
| 36 | } |
| 37 | const shouldReadFile = () => { |
| 38 | if (config.type === 'objective') return true; |
| 39 | if (lang === '_') return false; |
| 40 | return file.size < lengthLimit && !file.filepath.endsWith('.zip') && !SettingModel.langs[lang].isBinary; |
| 41 | }; |
| 42 | let code = ''; |
| 43 | const files: Record<string, string> = {}; |
| 44 | if (shouldReadFile()) code = await fs.readFile(file.filepath, 'utf-8'); |
| 45 | else { |
| 46 | const id = nanoid(); |
| 47 | await StorageModel.put(`submission/${this.user._id}/${id}`, file.filepath, this.user._id); |
| 48 | files.code = `${this.user._id}/${id}#${file.originalFilename}`; |
| 49 | } |
| 50 | |
| 51 | if (!code) return { error: 'Cannot submit empty code' }; |
| 52 | |
| 53 | if (dryrun) { |
| 54 | return { |
| 55 | info: `Info |
| 56 | |
| 57 | Contest ${this.tdoc.title} |
| 58 | Problem ${this.pdoc.title} |
| 59 | User ${this.user.uname} |
| 60 | School ${this.user.school} |
| 61 | Language ${SettingModel.langs[lang].display} (${lang}) |
| 62 | `, |
| 63 | }; |
| 64 | } |
| 65 | |
| 66 | await this.limitRate('add_record', 60, SystemModel.get('limit.submission_user'), '{{user}}'); |
| 67 | await this.limitRate('add_record', 60, SystemModel.get('limit.submission')); |
no test coverage detected