@@ -844,136 +844,7 @@ def import_from_cre_csv() -> Any:
844844 rows = list (csv .DictReader (decoded_contents .splitlines ()))
845845
846846 # ------------------------
847- # Schema / header validation
848- # ------------------------
849-
850- headers = [h .strip () for h in csv_read .fieldnames ]
851-
852- if not headers :
853- return (
854- jsonify (
855- {
856- "success" : False ,
857- "type" : "SCHEMA_ERROR" ,
858- "message" : "CSV header row is missing" ,
859- }
860- ),
861- 400 ,
862- )
863-
864- has_cre_column = any (h .startswith ("CRE" ) for h in headers )
865- if not has_cre_column :
866- return (
867- jsonify (
868- {
869- "success" : False ,
870- "type" : "SCHEMA_ERROR" ,
871- "message" : "At least one CRE column is required" ,
872- }
873- ),
874- 400 ,
875- )
876-
877- required_columns = ["standard|name" , "standard|id" ]
878- for col in required_columns :
879- if col not in headers :
880- return (
881- jsonify (
882- {
883- "success" : False ,
884- "type" : "SCHEMA_ERROR" ,
885- "message" : f"Missing required column: { col } " ,
886- }
887- ),
888- 400 ,
889- )
890-
891- # ------------------------
892- # Row-level validation (export-compatible)
893- # ------------------------
894-
895- rows = list (csv_read )
896- errors = []
897-
898- # 🚨 NEW: guard against misaligned rows (extra columns)
899- for row_index , row in enumerate (rows , start = 2 ):
900- if None in row :
901- return (
902- jsonify (
903- {
904- "success" : False ,
905- "type" : "SCHEMA_ERROR" ,
906- "message" : (
907- f"Row { row_index } has more columns than header. "
908- "Please ensure the CSV matches the exported template."
909- ),
910- }
911- ),
912- 400 ,
913- )
914-
915- for row_index , row in enumerate (rows , start = 2 ): # header is row 1
916- normalized_row = {
917- k : (v .strip () if isinstance (v , str ) else v ) for k , v in row .items ()
918- }
919-
920- # Skip completely empty rows (exported templates contain them)
921- if all (not v for v in normalized_row .values ()):
922- continue
923-
924- cre_values = [normalized_row .get (h ) for h in headers if h .startswith ("CRE" )]
925- cre_values = [v for v in cre_values if v ]
926-
927- # Rows without CRE are allowed by export format → skip
928- if not cre_values :
929- continue
930-
931- # Validate CRE format
932- for cre in cre_values :
933- if "|" not in cre :
934- errors .append (
935- {
936- "row" : row_index ,
937- "code" : "INVALID_CRE_FORMAT" ,
938- "message" : (
939- f"Invalid CRE entry '{ cre } ', expected '<CRE-ID>|<Name>'"
940- ),
941- }
942- )
943-
944- if errors :
945- return (
946- jsonify (
947- {
948- "success" : False ,
949- "type" : "ROW_VALIDATION_ERROR" ,
950- "errors" : errors ,
951- }
952- ),
953- 400 ,
954- )
955-
956- # ------------------------
957- # No-op import guard (IMPORTANT)
958- # ------------------------
959-
960- importable_rows = []
961- for row in rows :
962- if any (v for v in row .values ()):
963- importable_rows .append (row )
964-
965- if not importable_rows :
966- return jsonify (
967- {
968- "status" : "success" ,
969- "new_cres" : [],
970- "new_standards" : 0 ,
971- "import_type" : "empty" ,
972- }
973- )
974-
975- # ------------------------
976- # Import execution
847+ # Delegate validation + parsing
977848 # ------------------------
978849
979850 try :
0 commit comments