| 
									
										
										
										
											2021-05-16 01:16:51 +02:00
										 |  |  | import base64 | 
					
						
							| 
									
										
										
										
											2022-10-17 01:08:31 +02:00
										 |  |  | import json | 
					
						
							|  |  |  | import typing | 
					
						
							| 
									
										
										
										
											2021-09-18 01:02:26 +02:00
										 |  |  | import uuid | 
					
						
							| 
									
										
										
										
											2022-10-17 01:08:31 +02:00
										 |  |  | import zipfile | 
					
						
							| 
									
										
										
										
											2022-03-18 04:53:09 +01:00
										 |  |  | from io import BytesIO | 
					
						
							| 
									
										
										
										
											2020-06-26 19:29:33 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | from flask import request, flash, redirect, url_for, session, render_template | 
					
						
							| 
									
										
										
										
											2021-05-14 15:25:57 +02:00
										 |  |  | from pony.orm import flush, select | 
					
						
							| 
									
										
										
										
											2020-06-26 19:29:33 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-17 01:08:31 +02:00
										 |  |  | import MultiServer | 
					
						
							|  |  |  | from NetUtils import NetworkSlot, SlotType | 
					
						
							| 
									
										
										
										
											2022-09-30 00:36:30 +02:00
										 |  |  | from Utils import VersionException, __version__ | 
					
						
							|  |  |  | from worlds.Files import AutoPatchRegister | 
					
						
							| 
									
										
										
										
											2022-10-17 01:08:31 +02:00
										 |  |  | from . import app | 
					
						
							|  |  |  | from .models import Seed, Room, Slot | 
					
						
							| 
									
										
										
										
											2020-06-26 19:29:33 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | banned_zip_contents = (".sfc",) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-18 01:02:26 +02:00
										 |  |  | def upload_zip_to_db(zfile: zipfile.ZipFile, owner=None, meta={"race": False}, sid=None): | 
					
						
							|  |  |  |     if not owner: | 
					
						
							|  |  |  |         owner = session["_id"] | 
					
						
							|  |  |  |     infolist = zfile.infolist() | 
					
						
							| 
									
										
										
										
											2022-09-28 14:54:10 -07:00
										 |  |  |     slots: typing.Set[Slot] = set() | 
					
						
							| 
									
										
										
										
											2021-09-18 01:02:26 +02:00
										 |  |  |     spoiler = "" | 
					
						
							|  |  |  |     multidata = None | 
					
						
							|  |  |  |     for file in infolist: | 
					
						
							| 
									
										
										
										
											2022-03-18 04:53:09 +01:00
										 |  |  |         handler = AutoPatchRegister.get_handler(file.filename) | 
					
						
							| 
									
										
										
										
											2021-09-18 01:02:26 +02:00
										 |  |  |         if file.filename.endswith(banned_zip_contents): | 
					
						
							|  |  |  |             return "Uploaded data contained a rom file, which is likely to contain copyrighted material. " \ | 
					
						
							|  |  |  |                    "Your file was deleted." | 
					
						
							| 
									
										
										
										
											2022-03-18 04:53:09 +01:00
										 |  |  |         elif handler: | 
					
						
							|  |  |  |             raw = zfile.open(file, "r").read() | 
					
						
							|  |  |  |             patch = handler(BytesIO(raw)) | 
					
						
							|  |  |  |             patch.read() | 
					
						
							|  |  |  |             slots.add(Slot(data=raw, | 
					
						
							|  |  |  |                            player_name=patch.player_name, | 
					
						
							|  |  |  |                            player_id=patch.player, | 
					
						
							|  |  |  |                            game=patch.game)) | 
					
						
							| 
									
										
										
										
											2021-09-18 01:02:26 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |         elif file.filename.endswith(".apmc"): | 
					
						
							|  |  |  |             data = zfile.open(file, "r").read() | 
					
						
							|  |  |  |             metadata = json.loads(base64.b64decode(data).decode("utf-8")) | 
					
						
							| 
									
										
										
										
											2022-03-18 04:53:09 +01:00
										 |  |  |             slots.add(Slot(data=data, | 
					
						
							|  |  |  |                            player_name=metadata["player_name"], | 
					
						
							| 
									
										
										
										
											2021-09-18 01:02:26 +02:00
										 |  |  |                            player_id=metadata["player_id"], | 
					
						
							|  |  |  |                            game="Minecraft")) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-12 22:05:54 +01:00
										 |  |  |         elif file.filename.endswith(".apv6"): | 
					
						
							|  |  |  |             _, seed_name, slot_id, slot_name = file.filename.split('.')[0].split('_', 3) | 
					
						
							|  |  |  |             slots.add(Slot(data=zfile.open(file, "r").read(), player_name=slot_name, | 
					
						
							|  |  |  |                            player_id=int(slot_id[1:]), game="VVVVVV")) | 
					
						
							| 
									
										
										
										
											2022-03-18 04:53:09 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-12 22:05:54 +01:00
										 |  |  |         elif file.filename.endswith(".apsm64ex"): | 
					
						
							|  |  |  |             _, seed_name, slot_id, slot_name = file.filename.split('.')[0].split('_', 3) | 
					
						
							|  |  |  |             slots.add(Slot(data=zfile.open(file, "r").read(), player_name=slot_name, | 
					
						
							|  |  |  |                            player_id=int(slot_id[1:]), game="Super Mario 64")) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-18 01:02:26 +02:00
										 |  |  |         elif file.filename.endswith(".zip"): | 
					
						
							|  |  |  |             # Factorio mods need a specific name or they do not function | 
					
						
							| 
									
										
										
										
											2021-10-16 20:11:26 +02:00
										 |  |  |             _, seed_name, slot_id, slot_name = file.filename.rsplit("_", 1)[0].split("-", 3) | 
					
						
							| 
									
										
										
										
											2021-09-18 01:02:26 +02:00
										 |  |  |             slots.add(Slot(data=zfile.open(file, "r").read(), player_name=slot_name, | 
					
						
							|  |  |  |                            player_id=int(slot_id[1:]), game="Factorio")) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         elif file.filename.endswith(".apz5"): | 
					
						
							|  |  |  |             # .apz5 must be named specifically since they don't contain any metadata | 
					
						
							|  |  |  |             _, seed_name, slot_id, slot_name = file.filename.split('.')[0].split('_', 3) | 
					
						
							|  |  |  |             slots.add(Slot(data=zfile.open(file, "r").read(), player_name=slot_name, | 
					
						
							|  |  |  |                            player_id=int(slot_id[1:]), game="Ocarina of Time")) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-20 12:48:14 +02:00
										 |  |  |         elif file.filename.endswith(".json"): | 
					
						
							|  |  |  |             _, seed_name, slot_id, slot_name = file.filename.split('.')[0].split('-', 3) | 
					
						
							|  |  |  |             slots.add(Slot(data=zfile.open(file, "r").read(), player_name=slot_name, | 
					
						
							|  |  |  |                            player_id=int(slot_id[1:]), game="Dark Souls III")) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-18 01:02:26 +02:00
										 |  |  |         elif file.filename.endswith(".txt"): | 
					
						
							|  |  |  |             spoiler = zfile.open(file, "r").read().decode("utf-8-sig") | 
					
						
							| 
									
										
										
										
											2022-03-18 04:53:09 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-18 01:02:26 +02:00
										 |  |  |         elif file.filename.endswith(".archipelago"): | 
					
						
							|  |  |  |             try: | 
					
						
							|  |  |  |                 multidata = zfile.open(file).read() | 
					
						
							|  |  |  |             except: | 
					
						
							|  |  |  |                 flash("Could not load multidata. File may be corrupted or incompatible.") | 
					
						
							| 
									
										
										
										
											2021-11-22 17:57:23 +01:00
										 |  |  |                 multidata = None | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-18 01:02:26 +02:00
										 |  |  |     if multidata: | 
					
						
							| 
									
										
										
										
											2022-01-01 17:18:48 +01:00
										 |  |  |         decompressed_multidata = MultiServer.Context.decompress(multidata) | 
					
						
							| 
									
										
										
										
											2022-02-23 19:16:45 +01:00
										 |  |  |         if "slot_info" in decompressed_multidata: | 
					
						
							|  |  |  |             player_names = {slot.player_name for slot in slots} | 
					
						
							|  |  |  |             leftover_names: typing.Dict[int, NetworkSlot] = { | 
					
						
							|  |  |  |                 slot_id: slot_info for slot_id, slot_info in decompressed_multidata["slot_info"].items() | 
					
						
							|  |  |  |                 if slot_info.name not in player_names and slot_info.type != SlotType.group} | 
					
						
							|  |  |  |             newslots = [(Slot(data=None, player_name=slot_info.name, player_id=slot, game=slot_info.game)) | 
					
						
							|  |  |  |                         for slot, slot_info in leftover_names.items()] | 
					
						
							|  |  |  |             for slot in newslots: | 
					
						
							|  |  |  |                 slots.add(slot) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             flush()  # commit slots | 
					
						
							| 
									
										
										
										
											2021-12-22 20:15:56 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-18 01:02:26 +02:00
										 |  |  |         seed = Seed(multidata=multidata, spoiler=spoiler, slots=slots, owner=owner, meta=json.dumps(meta), | 
					
						
							|  |  |  |                     id=sid if sid else uuid.uuid4()) | 
					
						
							|  |  |  |         flush()  # create seed | 
					
						
							|  |  |  |         for slot in slots: | 
					
						
							|  |  |  |             slot.seed = seed | 
					
						
							|  |  |  |         return seed | 
					
						
							|  |  |  |     else: | 
					
						
							|  |  |  |         flash("No multidata was found in the zip file, which is required.") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-04 23:50:18 +02:00
										 |  |  | @app.route('/uploads', methods=['GET', 'POST']) | 
					
						
							|  |  |  | def uploads(): | 
					
						
							| 
									
										
										
										
											2020-06-26 19:29:33 +02:00
										 |  |  |     if request.method == 'POST': | 
					
						
							|  |  |  |         # check if the post request has the file part | 
					
						
							|  |  |  |         if 'file' not in request.files: | 
					
						
							|  |  |  |             flash('No file part') | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             file = request.files['file'] | 
					
						
							|  |  |  |             # if user does not select file, browser also | 
					
						
							|  |  |  |             # submit an empty part without filename | 
					
						
							|  |  |  |             if file.filename == '': | 
					
						
							|  |  |  |                 flash('No selected file') | 
					
						
							|  |  |  |             elif file and allowed_file(file.filename): | 
					
						
							| 
									
										
										
										
											2022-01-06 06:09:15 +01:00
										 |  |  |                 if zipfile.is_zipfile(file): | 
					
						
							| 
									
										
										
										
											2020-06-26 19:29:33 +02:00
										 |  |  |                     with zipfile.ZipFile(file, 'r') as zfile: | 
					
						
							| 
									
										
										
										
											2022-01-18 08:23:38 +01:00
										 |  |  |                         try: | 
					
						
							|  |  |  |                             res = upload_zip_to_db(zfile) | 
					
						
							|  |  |  |                         except VersionException: | 
					
						
							|  |  |  |                             flash(f"Could not load multidata. Wrong Version detected.") | 
					
						
							|  |  |  |                         else: | 
					
						
							|  |  |  |                             if type(res) == str: | 
					
						
							|  |  |  |                                 return res | 
					
						
							|  |  |  |                             elif res: | 
					
						
							|  |  |  |                                 return redirect(url_for("view_seed", seed=res.id)) | 
					
						
							| 
									
										
										
										
											2020-06-26 19:29:33 +02:00
										 |  |  |                 else: | 
					
						
							| 
									
										
										
										
											2022-01-08 21:21:29 +01:00
										 |  |  |                     file.seek(0)  # offset from is_zipfile check | 
					
						
							| 
									
										
										
										
											2022-01-01 17:18:48 +01:00
										 |  |  |                     # noinspection PyBroadException | 
					
						
							| 
									
										
										
										
											2020-06-26 19:29:33 +02:00
										 |  |  |                     try: | 
					
						
							| 
									
										
										
										
											2021-04-04 03:18:19 +02:00
										 |  |  |                         multidata = file.read() | 
					
						
							| 
									
										
										
										
											2022-01-01 17:18:48 +01:00
										 |  |  |                         MultiServer.Context.decompress(multidata) | 
					
						
							| 
									
										
										
										
											2022-01-08 21:21:29 +01:00
										 |  |  |                     except Exception as e: | 
					
						
							|  |  |  |                         flash(f"Could not load multidata. File may be corrupted or incompatible. ({e})") | 
					
						
							| 
									
										
										
										
											2020-06-26 19:29:33 +02:00
										 |  |  |                     else: | 
					
						
							| 
									
										
										
										
											2020-06-27 13:52:03 +02:00
										 |  |  |                         seed = Seed(multidata=multidata, owner=session["_id"]) | 
					
						
							| 
									
										
										
										
											2021-05-14 15:25:57 +02:00
										 |  |  |                         flush()  # place into DB and generate ids | 
					
						
							| 
									
										
										
										
											2021-11-25 20:48:58 +01:00
										 |  |  |                         return redirect(url_for("view_seed", seed=seed.id)) | 
					
						
							| 
									
										
										
										
											2020-06-26 19:29:33 +02:00
										 |  |  |             else: | 
					
						
							| 
									
										
										
										
											2021-10-16 20:11:26 +02:00
										 |  |  |                 flash("Not recognized file format. Awaiting a .archipelago file or .zip containing one.") | 
					
						
							| 
									
										
										
										
											2022-01-30 20:06:03 -05:00
										 |  |  |     return render_template("hostGame.html", version=__version__) | 
					
						
							| 
									
										
										
										
											2020-12-04 18:22:12 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | @app.route('/user-content', methods=['GET']) | 
					
						
							|  |  |  | def user_content(): | 
					
						
							| 
									
										
										
										
											2020-06-26 19:29:33 +02:00
										 |  |  |     rooms = select(room for room in Room if room.owner == session["_id"]) | 
					
						
							| 
									
										
										
										
											2020-12-04 23:25:49 +01:00
										 |  |  |     seeds = select(seed for seed in Seed if seed.owner == session["_id"]) | 
					
						
							| 
									
										
										
										
											2020-12-04 18:22:12 -05:00
										 |  |  |     return render_template("userContent.html", rooms=rooms, seeds=seeds) | 
					
						
							| 
									
										
										
										
											2020-07-27 04:05:42 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def allowed_file(filename): | 
					
						
							| 
									
										
										
										
											2021-01-03 14:32:32 +01:00
										 |  |  |     return filename.endswith(('.archipelago', ".zip")) |