@@ -43,12 +43,6 @@ const langMap = {
4343 16 : 'js' ,
4444 17 : 'go' ,
4545} ;
46- const nameMap : Record < string , string > = {
47- 'sample.in' : 'sample0.in' ,
48- 'sample.out' : 'sample0.out' ,
49- 'test.in' : 'test0.in' ,
50- 'test.out' : 'test0.out' ,
51- } ;
5246
5347async function addContestFile ( domainId : string , tid : ObjectId , filename : string , filepath : string ) {
5448 const tdoc = await ContestModel . get ( domainId , tid ) ;
@@ -60,6 +54,18 @@ async function addContestFile(domainId: string, tid: ObjectId, filename: string,
6054 return true ;
6155}
6256
57+ function fixFileName ( fileName : string ) {
58+ if ( fileName . endsWith ( '.in' ) || fileName . endsWith ( '.out' ) ) {
59+ const dotAt = fileName . lastIndexOf ( '.' ) ;
60+ const name = fileName . slice ( 0 , dotAt ) ;
61+ const suffix = fileName . slice ( dotAt + 1 ) ;
62+ if ( ! name . match ( / [ 0 - 9 ] / ) ) {
63+ fileName = `${ name } 0.${ suffix } ` ;
64+ }
65+ }
66+ return fileName . replace ( / [ \\ / ? # ~ ! | * ] / g, '_' ) ;
67+ }
68+
6369export async function run ( {
6470 host = 'localhost' , port = 3306 , name = 'jol' ,
6571 username, password, domainId, contestType = 'oi' ,
@@ -186,11 +192,13 @@ export async function run({
186192 hint : pdoc . hint ,
187193 source : pdoc . source ,
188194 } , 'html' ) . replace ( / < m a t h x m < x > l n s = / g, '<math xmlns=' ) . replace ( / \[ \/ ? m d ] / g, '' ) ;
189- const uploadFiles = content . matchAll ( / (?: s r c | h r e f ) = " \/ u p l o a d \/ ( [ ^ " ] + \/ ( [ ^ " ] + ) ) " / g) ;
195+ const uploadFiles = content . matchAll ( / (?: s r c | h r e f ) = " \/ u p l o a d \/ ( [ ^ " / ] + ) (?: \/ ( [ ^ " / ] + ) ) ? \/ ( [ ^ " / ] + \. [ ^ " / . ] + ) " / g) ;
190196 for ( const file of uploadFiles ) {
191197 try {
192- files [ file [ 2 ] ] = await fs . readFile ( path . join ( uploadDir , file [ 1 ] ) ) ;
193- content = content . replace ( `/upload/${ file [ 1 ] } ` , `file://${ file [ 2 ] } ` ) ;
198+ const filename = fixFileName ( file [ 3 ] ) ;
199+ const fileWithPath = [ file [ 1 ] , ...( file [ 2 ] ? [ file [ 2 ] ] : [ ] ) , file [ 3 ] ] . join ( '/' ) ;
200+ files [ filename ] = await fs . readFile ( path . join ( uploadDir , fileWithPath ) ) ;
201+ content = content . replace ( `/upload/${ fileWithPath } ` , `file://${ filename } ` ) ;
194202 } catch ( e ) {
195203 report ( { message : `failed to read file: ${ path . join ( uploadDir , file [ 1 ] ) } ` } ) ;
196204 }
@@ -265,13 +273,19 @@ hydrooj install https://hydro.ac/hydroac-client.zip
265273 const pids = pdocs . map ( ( i ) => pidMap [ i . problem_id ] ) . filter ( ( i ) => i ) ;
266274 const files = { } ;
267275 let description = tdoc . description ;
268- const uploadFiles = description . matchAll ( / (?: s r c | h r e f ) = " \/ u p l o a d \/ ( [ ^ " ] + \/ ( [ ^ " ] + ) ) " / g) ;
276+ const uploadFiles = description . matchAll ( / (?: s r c | h r e f ) = " \/ u p l o a d \/ ( [ ^ " / ] + ) (?: \/ ( [ ^ " / ] + ) ) ? \/ ( [ ^ " / ] + \. [ ^ " / . ] + ) " / g) ;
269277 for ( const file of uploadFiles ) {
270- files [ file [ 2 ] ] = await fs . readFile ( path . join ( uploadDir , file [ 1 ] ) ) ;
271- description = description . replace ( `/upload/${ file [ 1 ] } ` , `file://${ file [ 2 ] } ` ) ;
278+ const filename = fixFileName ( file [ 3 ] ) ;
279+ const fileWithPath = [ file [ 1 ] , ...( file [ 2 ] ? [ file [ 2 ] ] : [ ] ) , file [ 3 ] ] . join ( '/' ) ;
280+ files [ filename ] = await fs . readFile ( path . join ( uploadDir , fileWithPath ) ) ;
281+ description = description . replace ( `/upload/${ fileWithPath } ` , `file://${ filename } ` ) ;
272282 }
273283 // WHY you allow contest with end time BEFORE start time? WHY???
274284 const endAt = moment ( tdoc . end_time ) . isSameOrBefore ( tdoc . start_time ) ? moment ( tdoc . end_time ) . add ( 1 , 'minute' ) . toDate ( ) : tdoc . end_time ;
285+ let isAssignMode = false ;
286+ if ( tdoc . private === 1 && tdoc . password === '' ) {
287+ isAssignMode = true ;
288+ }
275289 const tid = await ContestModel . add (
276290 domainId , tdoc . title , description || 'Description' ,
277291 adminUids [ 0 ] , contestType , tdoc . start_time , endAt , pids , true ,
@@ -281,6 +295,17 @@ hydrooj install https://hydro.ac/hydroac-client.zip
281295 await Promise . all ( Object . keys ( files ) . map ( ( filename ) => addContestFile ( domainId , tid , filename , files [ filename ] ) ) ) ;
282296 if ( Object . keys ( files ) . length ) report ( { message : `move ${ Object . keys ( files ) . length } file for contest ${ tidMap [ tdoc . contest_id ] } ` } ) ;
283297
298+ const allowedUser :{ user_id :string } [ ] = await query ( `SELECT * FROM privilege WHERE rightstr = 'c${ tdoc . contest_id } ';` ) ;
299+ const assignUserList = allowedUser . map ( ( i ) => uidMap [ i . user_id ] ) . filter ( ( i ) => i ) ;
300+ if ( isAssignMode ) {
301+ await ContestModel . edit ( domainId , tid , {
302+ assign : assignUserList . map ( ( uid ) => uid . toString ( ) ) ,
303+ } ) ;
304+ } else {
305+ for ( let i = 0 ; i < assignUserList . length ; i ++ ) {
306+ await ContestModel . attend ( domainId , tid , assignUserList [ i ] ) . catch ( noop ) ;
307+ }
308+ }
284309 if ( tidx % 100 === 0 ) {
285310 const progress = Math . round ( ( ( tidx + 1 ) / tdocs . length ) * 100 ) ;
286311 report ( {
@@ -374,7 +399,7 @@ hydrooj install https://hydro.ac/hydroac-client.zip
374399 report ( { message : `Syncing testdata for ${ file . name } ` } ) ;
375400 for ( const data of datas ) {
376401 if ( data . isDirectory ( ) ) continue ;
377- const filename = nameMap [ data . name ] || data . name ;
402+ const filename = fixFileName ( data . name ) ;
378403 await ProblemModel . addTestdata ( domainId , pdoc . docId , filename , `${ dataDir } /${ file . name } /${ data . name } ` ) ;
379404 }
380405 await ProblemModel . addTestdata ( domainId , pdoc . docId , 'config.yaml' , Buffer . from ( pdoc . config as string ) ) ;
0 commit comments