diff --git a/CHANGELOG.md b/CHANGELOG.md index 996acb40..44750a39 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,5 @@ # Changelog -## --- [4.3.1] - 2023/TBD +## --- [4.3.2] - 2024/TBD ### New features TBD ### Bug fixes @@ -10,7 +10,15 @@ TBD TBD

-## --- [4.3.0] - 2023/03/09 +## --- [4.3.1] - 2024/03/18 +### Bug fixes +- Fix Server ID Rework for backups, schedules, and roles (INT ID to UUID migration) ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/729)) +### Tweaks +- Remove http re-direct handler. Users should implement nginx configurations for port 80 redirects ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/730)) + +

+ +## --- [4.3.0] - 2024/03/09 ### Breaking Changes - This release includes database migrations that are not revertable. Once you update to this version you will not be able to rollback to a previous version. - In this release, we've implemented a breaking change to enhance server identification within Crafty: instead of relying on numerical integers (1, 2, 3, etc.), Servers are now uniquely identified by their UUIDs. Please adapt your API clients accordingly. @@ -34,7 +42,7 @@ TBD - Update `de_DE, en_EN, es_ES, fr_FR, he_IL, lol_EN, lv_LV, nl_BE pl_PL, th_TH, tr_TR, uk_UA, zh_CN` translations for `4.3.0` ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/715))

-## --- [4.2.3] - 2023/02/02 +## --- [4.2.3] - 2024/02/02 ### New features - Use Papermc Group's API for `paper` & `folia` builds in server builder ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/688)) - Allow omission of player count from Dashboard (e.g. for proxy servers) ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/692)) diff --git a/README.md b/README.md index bc621c7d..ae70bd0e 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ [![Crafty Logo](app/frontend/static/assets/images/logo_long.svg)](https://craftycontrol.com) -# Crafty Controller 4.3.1 +# Crafty Controller 4.3.2 > Python based Control Panel for your Minecraft Server ## What is Crafty Controller? diff --git a/app/classes/shared/helpers.py b/app/classes/shared/helpers.py index 6b821f9d..0427da11 100644 --- a/app/classes/shared/helpers.py +++ b/app/classes/shared/helpers.py @@ -496,7 +496,6 @@ class Helpers: # Config.json was removed from the repo to make it easier for users # To make non-breaking changes to the file. return { - "http_port": 8000, "https_port": 8443, "language": "en_EN", "cookie_expire": 30, diff --git a/app/classes/shared/migration.py b/app/classes/shared/migration.py index 1adea4c6..6a93802b 100644 --- a/app/classes/shared/migration.py +++ b/app/classes/shared/migration.py @@ -369,11 +369,14 @@ class MigrationManager(object): @cached_property def migrator(self) -> Migrator: """ - Create migrator and setup it with fake migrations. + Create migrator """ migrator = Migrator(self.database) - for name in self.done: - self.up_one(name, migrator, True) + # Removing the up_one to prevent running all + # migrations each time we got a new one. + # It's handled by migration.up() function. + # for name in self.done: + # self.up_one(name, migrator, True) return migrator def compile(self, name, migrate="", rollback=""): diff --git a/app/classes/web/http_handler.py b/app/classes/web/http_handler.py deleted file mode 100644 index 32676d59..00000000 --- a/app/classes/web/http_handler.py +++ /dev/null @@ -1,42 +0,0 @@ -import logging -import requests - -from app.classes.web.base_handler import BaseHandler - -logger = logging.getLogger(__name__) - - -class HTTPHandler(BaseHandler): - def get(self): - url = str(self.request.host) - port = 443 - url_list = url.split(":") - if url_list[0] != "": - url = "https://" + url_list[0] - else: - url = "https://" + url - db_port = self.helper.get_setting("https_port") - try: - resp = requests.head(url + ":" + str(port), timeout=(0.5, 5)) - resp.raise_for_status() - except Exception: - port = db_port - self.redirect(url + ":" + str(port)) - - -class HTTPHandlerPage(BaseHandler): - def get(self): - url = str(self.request.host) - port = 443 - url_list = url.split(":") - if url_list[0] != "": - url = "https://" + url_list[0] - else: - url = "https://" + url - db_port = self.helper.get_setting("https_port") - try: - resp = requests.head(url + ":" + str(port), timeout=(0.5, 5)) - resp.raise_for_status() - except Exception: - port = db_port - self.redirect(url + ":" + str(port)) diff --git a/app/classes/web/http_handler_page.py b/app/classes/web/http_handler_page.py deleted file mode 100644 index 77161577..00000000 --- a/app/classes/web/http_handler_page.py +++ /dev/null @@ -1,33 +0,0 @@ -import logging -import requests -from app.classes.web.base_handler import BaseHandler - -logger = logging.getLogger(__name__) - - -class HTTPHandlerPage(BaseHandler): - def get(self): - url = self.request.full_url - port = 443 - if url[len(url) - 1] == "/": - url = url.strip(url[len(url) - 1]) - url_list = url.split("/") - if url_list[0] != "": - primary_url = url_list[0] + ":" + str(port) + "/" - backup_url = ( - url_list[0] + ":" + str(self.helper.get_setting("https_port")) + "/" - ) - for i in range(len(url_list) - 1): - primary_url += url_list[i + 1] - backup_url += url_list[i + 1] - else: - primary_url = url + str(port) - backup_url = url + str(self.helper.get_setting("https_port")) - - try: - resp = requests.head(primary_url, timeout=(0.5, 5)) - resp.raise_for_status() - url = primary_url - except Exception: - url = backup_url - self.redirect("https://" + url + ":" + str(port)) diff --git a/app/classes/web/routes/api/roles/index.py b/app/classes/web/routes/api/roles/index.py index dce6f453..266afb23 100644 --- a/app/classes/web/routes/api/roles/index.py +++ b/app/classes/web/routes/api/roles/index.py @@ -17,7 +17,7 @@ create_role_schema = { "type": "object", "properties": { "server_id": { - "type": "integer", + "type": "string", "minimum": 1, }, "permissions": { @@ -47,7 +47,7 @@ basic_create_role_schema = { "type": "object", "properties": { "server_id": { - "type": "integer", + "type": "string", "minimum": 1, }, "permissions": { diff --git a/app/classes/web/routes/api/roles/role/index.py b/app/classes/web/routes/api/roles/role/index.py index 0dd7d6c8..5ed12d69 100644 --- a/app/classes/web/routes/api/roles/role/index.py +++ b/app/classes/web/routes/api/roles/role/index.py @@ -16,7 +16,7 @@ modify_role_schema = { "type": "object", "properties": { "server_id": { - "type": "integer", + "type": "string", "minimum": 1, }, "permissions": { @@ -46,7 +46,7 @@ basic_modify_role_schema = { "type": "object", "properties": { "server_id": { - "type": "integer", + "type": "string", "minimum": 1, }, "permissions": { diff --git a/app/classes/web/tornado_handler.py b/app/classes/web/tornado_handler.py index fbcf970f..f65f4fca 100644 --- a/app/classes/web/tornado_handler.py +++ b/app/classes/web/tornado_handler.py @@ -25,7 +25,6 @@ from app.classes.web.server_handler import ServerHandler from app.classes.web.websocket_handler import WebSocketHandler from app.classes.web.static_handler import CustomStaticHandler from app.classes.web.upload_handler import UploadHandler -from app.classes.web.http_handler import HTTPHandler, HTTPHandlerPage from app.classes.web.status_handler import StatusHandler @@ -44,7 +43,6 @@ class Webserver: file_helper: FileHelpers, ): self.ioloop = None - self.http_server = None self.https_server = None self.helper = helper self.controller = controller @@ -173,30 +171,6 @@ class Webserver: static_handler_class=CustomStaticHandler, serve_traceback=debug_errors, ) - http_handers = [ - (r"/", HTTPHandler, handler_args), - (r"/(.+)", HTTPHandlerPage, handler_args), - ] - http_app = tornado.web.Application( - http_handers, - template_path=os.path.join(self.helper.webroot, "templates"), - static_path=os.path.join(self.helper.webroot, "static"), - debug=debug_errors, - cookie_secret=cookie_secret, - xsrf_cookies=True, - autoreload=False, - log_function=self.log_function, - default_handler_class=HTTPHandler, - login_url="/login", - serve_traceback=debug_errors, - ) - - if http_port != 0: - self.http_server = tornado.httpserver.HTTPServer(http_app) - self.http_server.listen(http_port) - else: - logger.info("http port disabled by config") - self.https_server = tornado.httpserver.HTTPServer(app, ssl_options=cert_objects) self.https_server.listen(https_port) @@ -218,7 +192,6 @@ class Webserver: logger.info("Shutting Down Web Server") Console.info("Shutting Down Web Server") self.ioloop.stop() - self.http_server.stop() self.https_server.stop() logger.info("Web Server Stopped") Console.info("Web Server Stopped") diff --git a/app/config/version.json b/app/config/version.json index 9a8d1a7f..8dffa727 100644 --- a/app/config/version.json +++ b/app/config/version.json @@ -1,5 +1,5 @@ { "major": 4, "minor": 3, - "sub": 1 + "sub": 2 } diff --git a/app/migrations/20240310_fixing_rework_servers_uuid.py b/app/migrations/20240310_fixing_rework_servers_uuid.py new file mode 100644 index 00000000..3c613e52 --- /dev/null +++ b/app/migrations/20240310_fixing_rework_servers_uuid.py @@ -0,0 +1,132 @@ +import datetime +import uuid +import peewee +import logging + +from app.classes.shared.console import Console +from app.classes.shared.migration import Migrator, MigrateHistory +from app.classes.models.management import Schedules, Backups +from app.classes.models.server_permissions import RoleServers + +logger = logging.getLogger(__name__) + + +def migrate(migrator: Migrator, database, **kwargs): + """ + Write your migrations here. + """ + db = database + + # ********************************************************************************** + # Servers New Model from Old (easier to migrate without dunmping Database) + # ********************************************************************************** + class Servers(peewee.Model): + server_id = peewee.CharField(primary_key=True, default=str(uuid.uuid4())) + created = peewee.DateTimeField(default=datetime.datetime.now) + server_name = peewee.CharField(default="Server", index=True) + path = peewee.CharField(default="") + backup_path = peewee.CharField(default="") + executable = peewee.CharField(default="") + log_path = peewee.CharField(default="") + execution_command = peewee.CharField(default="") + auto_start = peewee.BooleanField(default=0) + auto_start_delay = peewee.IntegerField(default=10) + crash_detection = peewee.BooleanField(default=0) + stop_command = peewee.CharField(default="stop") + executable_update_url = peewee.CharField(default="") + server_ip = peewee.CharField(default="127.0.0.1") + server_port = peewee.IntegerField(default=25565) + logs_delete_after = peewee.IntegerField(default=0) + type = peewee.CharField(default="minecraft-java") + show_status = peewee.BooleanField(default=1) + created_by = peewee.IntegerField(default=-100) + shutdown_timeout = peewee.IntegerField(default=60) + ignored_exits = peewee.CharField(default="0") + + class Meta: + table_name = "servers" + database = db + + try: + logger.info("Migrating Data from Int to UUID (Fixing Issue)") + Console.info("Migrating Data from Int to UUID (Fixing Issue)") + + # Changes on Servers Roles Table + migrator.alter_column_type( + RoleServers, + "server_id", + peewee.ForeignKeyField( + Servers, + backref="role_server", + null=True, + field=peewee.CharField(primary_key=True, default=str(uuid.uuid4())), + ), + ) + + # Changes on Backups Table + migrator.alter_column_type( + Backups, + "server_id", + peewee.ForeignKeyField( + Servers, + backref="backup_server", + null=True, + field=peewee.CharField(primary_key=True, default=str(uuid.uuid4())), + ), + ) + + # Changes on SChedule Table + migrator.alter_column_type( + Schedules, + "server_id", + peewee.ForeignKeyField( + Servers, + backref="schedule_server", + null=True, + field=peewee.CharField(primary_key=True, default=str(uuid.uuid4())), + ), + ) + + migrator.run() + + logger.info("Migrating Data from Int to UUID (Fixing Issue) : SUCCESS") + Console.info("Migrating Data from Int to UUID (Fixing Issue) : SUCCESS") + + except Exception as ex: + logger.error("Error while migrating Data from Int to UUID (Fixing Issue)") + logger.error(ex) + Console.error("Error while migrating Data from Int to UUID (Fixing Issue)") + Console.error(ex) + last_migration = MigrateHistory.get_by_id(MigrateHistory.select().count()) + last_migration.delete() + return + + return + + +def rollback(migrator: Migrator, database, **kwargs): + """ + Write your rollback migrations here. + """ + db = database + + # Changes on Webhook Table + migrator.alter_column_type( + RoleServers, + "server_id", + peewee.IntegerField(null=True), + ) + + # Changes on Webhook Table + migrator.alter_column_type( + Backups, + "server_id", + peewee.IntegerField(null=True), + ) + + # Changes on Webhook Table + migrator.alter_column_type( + Schedules, + "server_id", + peewee.IntegerField(null=True), + ) diff --git a/sonar-project.properties b/sonar-project.properties index b6fa060c..a5f5e258 100644 --- a/sonar-project.properties +++ b/sonar-project.properties @@ -3,7 +3,7 @@ sonar.organization=crafty-controller # This is the name and version displayed in the SonarCloud UI. sonar.projectName=Crafty 4 -sonar.projectVersion=4.3.1 +sonar.projectVersion=4.3.2 sonar.python.version=3.9, 3.10, 3.11 sonar.exclusions=app/migrations/**, app/frontend/static/assets/vendors/**