11import dataclasses
2- import functools
32import io
43import pathlib
54import zipfile
87from django .core .files .base import ContentFile
98from django .core .files .uploadedfile import UploadedFile
109
11- from kirovy import typing as t , constants
10+ from kirovy import typing as t , constants , exceptions
1211from kirovy .constants .api_codes import LegacyUploadApiCodes
1312from kirovy .exceptions import view_exceptions
14- from kirovy .services .cnc_gen_2_services import CncGen2MapParser
13+ from kirovy .services .cnc_gen_2_services import MapConfigParser , CncGen2MapParser
1514from kirovy .utils import file_utils
1615from kirovy .utils .file_utils import ByteSized
1716
1817
1918@dataclasses .dataclass
2019class ExpectedFile :
2120 possible_extensions : t .Set [str ]
22- file_validator : t .Callable [[str , ContentFile , zipfile .ZipInfo ], bool ]
21+ file_validator : t .Callable [[str , ContentFile , zipfile .ZipInfo ], None ]
2322 required : bool = True
2423 """attr: If false, this file is not required to be present."""
2524
@@ -53,15 +52,15 @@ def expected_files(self) -> t.List[ExpectedFile]:
5352 raise NotImplementedError ("This Game's map validator hasn't implemented the expectd file structure." )
5453
5554 def multi_file_validator (self ):
56- file_list = self ._file .infolist ()
55+ zip_file_list = self ._file .infolist ()
5756 min_files = len ([x for x in self .expected_files if x .required ])
5857 max_files = len (self .expected_files )
59- if min_files > len (file_list ) > max_files :
58+ if min_files > len (zip_file_list ) > max_files :
6059 raise view_exceptions .KirovyValidationError (
6160 "Incorrect file count" , code = LegacyUploadApiCodes .BAD_ZIP_STRUCTURE
6261 )
6362
64- for file_info in file_list :
63+ for file_info in zip_file_list :
6564 expected_file = self ._get_expected_file_for_extension (file_info )
6665 expected_file .file_validator (self ._file .filename , ContentFile (self ._file .read (file_info )), file_info )
6766
@@ -101,8 +100,11 @@ def file_contents_merged(self) -> io.BytesIO:
101100 """
102101 output = io .BytesIO ()
103102 for expected_file in self .expected_files :
104- file_info = self ._find_file_info_by_extension (expected_file .possible_extensions )
105- output .write (self ._file .read (file_info ))
103+ file_info = self ._find_file_info_by_extension (
104+ expected_file .possible_extensions , is_required = expected_file .required
105+ )
106+ if file_info :
107+ output .write (self ._file .read (file_info ))
106108 output .seek (0 )
107109 return output
108110
@@ -111,9 +113,13 @@ def map_name(self) -> str:
111113 ini_file_info = self ._find_file_info_by_extension (self .ini_extensions )
112114 fallback = f"legacy_client_upload_{ self .map_sha1_from_filename } "
113115 ini_file = ContentFile (self ._file .read (ini_file_info ))
114- return CncGen2MapParser (ini_file ).ini .get ("Basic" , "Name" , fallback = fallback )
116+ try :
117+ return MapConfigParser .from_file (ini_file ).get ("Basic" , "Name" , fallback = fallback )
118+ except exceptions .InvalidMapFile :
119+ # Having a bad map name for a temporary upload is better than a 500 error.
120+ return fallback
115121
116- def _find_file_info_by_extension (self , extensions : t .Set [str ]) -> zipfile .ZipInfo :
122+ def _find_file_info_by_extension (self , extensions : t .Set [str ], is_required : bool = True ) -> zipfile .ZipInfo | None :
117123 """Find the zipinfo object for a file by a set of possible file extensions.
118124
119125 This is meant to be used to find specific files in the zip.
@@ -132,11 +138,12 @@ def _find_file_info_by_extension(self, extensions: t.Set[str]) -> zipfile.ZipInf
132138 for file in self ._file .infolist ():
133139 if pathlib .Path (file .filename ).suffix in extensions :
134140 return file
135- raise view_exceptions .KirovyValidationError (
136- "No file matching the expected extensions was found" ,
137- LegacyUploadApiCodes .NO_VALID_MAP_FILE ,
138- {"expected" : extensions },
139- )
141+ if is_required :
142+ raise view_exceptions .KirovyValidationError (
143+ "No file matching the expected extensions was found" ,
144+ LegacyUploadApiCodes .NO_VALID_MAP_FILE ,
145+ {"expected" : extensions },
146+ )
140147
141148 def _get_expected_file_for_extension (self , zip_info : zipfile .ZipInfo ) -> ExpectedFile :
142149 """Get the ``expected_file`` class instance corresponding to the file in the zipfile.
0 commit comments