From f4d15c5eaf89c61ac5391a2fac7262ae57ea7180 Mon Sep 17 00:00:00 2001
From: Radiquum <kentai.waah@gmail.com>
Date: Wed, 14 May 2025 23:49:01 +0500
Subject: [PATCH] add types and decouple packs functions from flask

---
 src/api/packs.py       | 63 ++++++++++--------------------------------
 src/shared/__init__.py |  0
 src/shared/packs.py    | 61 ++++++++++++++++++++++++++++++++++++++++
 src/type/__init__.py   |  0
 src/type/file.py       | 21 ++++++++++++++
 src/type/mod.py        | 39 ++++++++++++++++++++++++++
 src/type/pack.py       | 38 +++++++++++++++++++++++++
 7 files changed, 174 insertions(+), 48 deletions(-)
 create mode 100644 src/shared/__init__.py
 create mode 100644 src/shared/packs.py
 create mode 100644 src/type/__init__.py
 create mode 100644 src/type/file.py
 create mode 100644 src/type/mod.py
 create mode 100644 src/type/pack.py

diff --git a/src/api/packs.py b/src/api/packs.py
index cc2f5df..611d8a6 100644
--- a/src/api/packs.py
+++ b/src/api/packs.py
@@ -1,70 +1,37 @@
-import os
 from . import apiPacks
 from flask import request, jsonify
-from config import PACKS_FOLDER
-import json
-import shutil
+from shared.packs import getPacks, createPack, deletePack
 
 
 @apiPacks.route("/all", methods=["GET"])
-def getPacks():
-    packs = []
-
-    if not os.path.exists(f"{PACKS_FOLDER}"):
-        os.makedirs(f"{PACKS_FOLDER}", exist_ok=True)
-        return jsonify(packs)
-
-    pack_folders = [f.name for f in os.scandir(PACKS_FOLDER) if f.is_dir()]
-    for pack_folder in pack_folders:
-        if not os.path.exists(f"{PACKS_FOLDER}/{pack_folder}/packfile.json"):
-            continue
-        with open(f"{PACKS_FOLDER}/{pack_folder}/packfile.json") as fp:
-            pack = json.load(fp)
-            pack["_id"] = pack_folder
-            packs.append(pack)
-            fp.close()
-    return jsonify(packs)
+def getPacksEndpoint():
+    return jsonify(getPacks())
 
 
 @apiPacks.route("/new", methods=["POST"])
-def createPack():
-    pack = {
-        "formatVersion": 0,
-        "modpackVersion": 0,
-        "title": request.json.get("title"),
-        "author": request.json.get("author"),
-        "version": request.json.get("version"),
-        "modloader": request.json.get("modloader"),
-        "updateURL": "",
-        "mods": [],
-    }
-    title = pack.get("title").replace(" ", "_")
+def createPackEndpoint():
+    pack, is_exists = createPack(
+        request.json.get("title"),
+        request.json.get("author"),
+        request.json.get("version"),
+        request.json.get("modloader"),
+    )
 
-    if os.path.exists(f"{PACKS_FOLDER}/{title}"):
+    if is_exists:
         return jsonify({"status": "error", "message": "pack already exists"})
 
-    os.makedirs(f"{PACKS_FOLDER}/{title}", exist_ok=True)
-
-    with open(
-        os.path.abspath(f"{PACKS_FOLDER}/{title}/packfile.json"),
-        mode="w",
-        encoding="utf-8",
-    ) as fp:
-        json.dump(pack, fp)
-        fp.close()
-
     return jsonify(
         {
             "status": "ok",
-            "message": f"pack {pack.get('title')} created",
-            "id": title,
+            "message": f"pack {pack.title} created",
+            "id": pack._id,
         }
     )
 
 
 @apiPacks.route("/<id>/delete", methods=["GET"])
-def deletePack(id):
-    shutil.rmtree(f"{PACKS_FOLDER}/{id}")
+def deletePackEndpoint(id):
+    deletePack(id)
     return jsonify(
         {
             "status": "ok",
diff --git a/src/shared/__init__.py b/src/shared/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/src/shared/packs.py b/src/shared/packs.py
new file mode 100644
index 0000000..385106f
--- /dev/null
+++ b/src/shared/packs.py
@@ -0,0 +1,61 @@
+import os
+from config import PACKS_FOLDER
+import json
+import shutil
+
+from type.pack import Pack
+
+
+def getPacks() -> list[Pack]:
+    """
+    Lists and returns all available packs from PACKS_FOLDER directory defined in config.py
+    """
+    packs: list[Pack] = []
+
+    if not os.path.exists(f"{PACKS_FOLDER}"):
+        os.makedirs(f"{PACKS_FOLDER}", exist_ok=True)
+        return packs
+
+    pack_folders = [f.name for f in os.scandir(PACKS_FOLDER) if f.is_dir()]
+    for pack_folder in pack_folders:
+        if not os.path.exists(f"{PACKS_FOLDER}/{pack_folder}/packfile.json"):
+            continue
+        with open(f"{PACKS_FOLDER}/{pack_folder}/packfile.json") as fp:
+            pack = json.load(fp)
+            pack["_id"] = pack_folder
+            packs.append(pack)
+            fp.close()
+
+    return packs
+
+
+def createPack(
+    title: str, author: str, game_version: str, mod_loader: str
+) -> Pack | bool:
+    """
+    Creates a new pack.
+    If pack exists returns tuple[Pack, True], if pack was created returns tuple[Pack, False]
+    """
+    pack = Pack(
+        title.replace(" ", "_"), title, author, game_version, mod_loader, "", [], 0, 0
+    )
+
+    if os.path.exists(f"{PACKS_FOLDER}/{pack._id}"):
+        return pack, True
+
+    os.makedirs(f"{PACKS_FOLDER}/{pack._id}", exist_ok=True)
+
+    with open(
+        os.path.abspath(f"{PACKS_FOLDER}/{pack._id}/packfile.json"),
+        mode="w",
+        encoding="utf-8",
+    ) as fp:
+        json.dump(pack.json(), fp)
+        fp.close()
+
+    return pack, False
+
+
+def deletePack(id):
+    shutil.rmtree(f"{PACKS_FOLDER}/{id}")
+    return True
diff --git a/src/type/__init__.py b/src/type/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/src/type/file.py b/src/type/file.py
new file mode 100644
index 0000000..02b9ab6
--- /dev/null
+++ b/src/type/file.py
@@ -0,0 +1,21 @@
+import json
+
+
+class ModFile:
+    def __init__(
+        self, version: str, hashes: dict[str, str], url: str, filename: str, size: int
+    ):
+        self.version = version
+        self.hashes = hashes
+        self.url = url
+        self.filename = filename
+        self.size = size
+
+    def json(self):
+        return {
+            "version": self.version,
+            "hashes": self.hashes,
+            "url": self.url,
+            "filename": self.filename,
+            "size": self.size,
+        }
diff --git a/src/type/mod.py b/src/type/mod.py
new file mode 100644
index 0000000..63ec543
--- /dev/null
+++ b/src/type/mod.py
@@ -0,0 +1,39 @@
+import json
+from .file import ModFile
+
+
+class Mod:
+    def __init__(
+        self,
+        slug: str,
+        project_id: str,
+        icon: str,
+        title: str,
+        developers: list[str],
+        source: str,
+        environment: dict[str, bool],
+        dependencies: list,
+        file: ModFile,
+    ):
+        self.slug = slug
+        self.project_id = project_id
+        self.icon = icon
+        self.title = title
+        self.developers = developers
+        self.source = source
+        self.environment = environment
+        self.dependencies = dependencies
+        self.file = file
+
+    def json(self):
+        return {
+            "slug": self.slug,
+            "project_id": self.project_id,
+            "icon": self.icon,
+            "title": self.title,
+            "developers": self.developers,
+            "source": self.source,
+            "environment": self.environment,
+            "dependencies": self.dependencies,
+            "file": self.file,
+        }
diff --git a/src/type/pack.py b/src/type/pack.py
new file mode 100644
index 0000000..d0c1262
--- /dev/null
+++ b/src/type/pack.py
@@ -0,0 +1,38 @@
+import json
+from .mod import Mod
+
+
+class Pack:
+    def __init__(
+        self,
+        _id: str,
+        title: str,
+        author: str,
+        version: str,
+        modloader: str,
+        updateURL: str,
+        mods: list[Mod],
+        modpackVersion: int = 0,
+        formatVersion: int = 0,
+    ):
+        self._id = _id
+        self.title = title
+        self.author = author
+        self.version = version
+        self.modloader = modloader
+        self.updateURL = updateURL
+        self.mods = mods
+        self.modpackVersion = modpackVersion
+        self.formatVersion = formatVersion
+
+    def json(self):
+        return {
+            "title": self.title,
+            "author": self.author,
+            "version": self.version,
+            "modloader": self.modloader,
+            "updateURL": self.updateURL,
+            "mods": self.mods,
+            "modpackVersion": self.modpackVersion,
+            "formatVersion": self.formatVersion,
+        }