 17b3ee6eaf
			
		
	
	17b3ee6eaf
	
	
	
		
			
			* Core: warn if a yaml is empty * WebHost: ignore empty yaml Generate: log which yaml documents are empty * Actually remove empty yamls from weight_cache * More verbose variable name --------- Co-authored-by: NewSoupVi <57900059+NewSoupVi@users.noreply.github.com>
		
			
				
	
	
		
			119 lines
		
	
	
		
			5.5 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			119 lines
		
	
	
		
			5.5 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| import os
 | |
| import zipfile
 | |
| import base64
 | |
| from typing import Union, Dict, Set, Tuple
 | |
| 
 | |
| from flask import request, flash, redirect, url_for, render_template
 | |
| from markupsafe import Markup
 | |
| 
 | |
| from WebHostLib import app
 | |
| from WebHostLib.upload import allowed_options, allowed_options_extensions, banned_file
 | |
| 
 | |
| from Generate import roll_settings, PlandoOptions
 | |
| from Utils import parse_yamls
 | |
| 
 | |
| 
 | |
| @app.route('/check', methods=['GET', 'POST'])
 | |
| def check():
 | |
|     if request.method == 'POST':
 | |
|         # check if the post request has the file part
 | |
|         if 'file' not in request.files:
 | |
|             flash('No file part')
 | |
|         else:
 | |
|             files = request.files.getlist('file')
 | |
|             options = get_yaml_data(files)
 | |
|             if isinstance(options, str):
 | |
|                 flash(options)
 | |
|             else:
 | |
|                 results, _ = roll_options(options)
 | |
|                 if len(options) > 1:
 | |
|                     # offer combined file back
 | |
|                     combined_yaml = "\n---\n".join(f"# original filename: {file_name}\n{file_content.decode('utf-8-sig')}"
 | |
|                                                  for file_name, file_content in options.items())
 | |
|                     combined_yaml = base64.b64encode(combined_yaml.encode("utf-8-sig")).decode()
 | |
|                 else:
 | |
|                     combined_yaml = ""
 | |
|                 return render_template("checkResult.html",
 | |
|                                        results=results, combined_yaml=combined_yaml)
 | |
|     return render_template("check.html")
 | |
| 
 | |
| 
 | |
| @app.route('/mysterycheck')
 | |
| def mysterycheck():
 | |
|     return redirect(url_for("check"), 301)
 | |
| 
 | |
| 
 | |
| def get_yaml_data(files) -> Union[Dict[str, str], str, Markup]:
 | |
|     options = {}
 | |
|     for uploaded_file in files:
 | |
|         if banned_file(uploaded_file.filename):
 | |
|             return ("Uploaded data contained a rom file, which is likely to contain copyrighted material. "
 | |
|                     "Your file was deleted.")
 | |
|         # If the user does not select file, the browser will still submit an empty string without a file name.
 | |
|         elif uploaded_file.filename == "":
 | |
|             return "No selected file."
 | |
|         elif uploaded_file.filename in options:
 | |
|             return f"Conflicting files named {uploaded_file.filename} submitted."
 | |
|         elif uploaded_file and allowed_options(uploaded_file.filename):
 | |
|             if uploaded_file.filename.endswith(".zip"):
 | |
|                 if not zipfile.is_zipfile(uploaded_file):
 | |
|                     return f"Uploaded file {uploaded_file.filename} is not a valid .zip file and cannot be opened."
 | |
| 
 | |
|                 uploaded_file.seek(0)  # offset from is_zipfile check
 | |
|                 with zipfile.ZipFile(uploaded_file, "r") as zfile:
 | |
|                     for file in zfile.infolist():
 | |
|                         # Remove folder pathing from str (e.g. "__MACOSX/" folder paths from archives created by macOS).
 | |
|                         base_filename = os.path.basename(file.filename)
 | |
| 
 | |
|                         if base_filename.endswith(".archipelago"):
 | |
|                             return Markup("Error: Your .zip file contains an .archipelago file. "
 | |
|                                           'Did you mean to <a href="/uploads">host a game</a>?')
 | |
|                         elif base_filename.endswith(".zip"):
 | |
|                             return "Nested .zip files inside a .zip are not supported."
 | |
|                         elif banned_file(base_filename):
 | |
|                             return ("Uploaded data contained a rom file, which is likely to contain copyrighted "
 | |
|                                     "material. Your file was deleted.")
 | |
|                         # Ignore dot-files.
 | |
|                         elif not base_filename.startswith(".") and allowed_options(base_filename):
 | |
|                             options[file.filename] = zfile.open(file, "r").read()
 | |
|             else:
 | |
|                 options[uploaded_file.filename] = uploaded_file.read()
 | |
| 
 | |
|     if not options:
 | |
|         return f"Did not find any valid files to process. Accepted formats: {allowed_options_extensions}"
 | |
|     return options
 | |
| 
 | |
| 
 | |
| def roll_options(options: Dict[str, Union[dict, str]],
 | |
|                  plando_options: Set[str] = frozenset({"bosses", "items", "connections", "texts"})) -> \
 | |
|         Tuple[Dict[str, Union[str, bool]], Dict[str, dict]]:
 | |
|     plando_options = PlandoOptions.from_set(set(plando_options))
 | |
|     results = {}
 | |
|     rolled_results = {}
 | |
|     for filename, text in options.items():
 | |
|         try:
 | |
|             if type(text) is dict:
 | |
|                 yaml_datas = (text, )
 | |
|             else:
 | |
|                 yaml_datas = tuple(parse_yamls(text))
 | |
|         except Exception as e:
 | |
|             results[filename] = f"Failed to parse YAML data in {filename}: {e}"
 | |
|         else:
 | |
|             try:
 | |
|                 if len(yaml_datas) == 1:
 | |
|                     rolled_results[filename] = roll_settings(yaml_datas[0],
 | |
|                                                              plando_options=plando_options)
 | |
|                 else:
 | |
|                     for i, yaml_data in enumerate(yaml_datas):
 | |
|                         if yaml_data is not None:
 | |
|                             rolled_results[f"{filename}/{i + 1}"] = roll_settings(yaml_data,
 | |
|                                                                                   plando_options=plando_options)
 | |
|             except Exception as e:
 | |
|                 if e.__cause__:
 | |
|                     results[filename] = f"Failed to generate options in {filename}: {e} - {e.__cause__}"
 | |
|                 else:
 | |
|                     results[filename] = f"Failed to generate options in {filename}: {e}"
 | |
|             else:
 | |
|                 results[filename] = True
 | |
|     return results, rolled_results
 |