mcmanager 0.1.2__tar.gz → 0.1.4__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (80) hide show
  1. {mcmanager-0.1.2 → mcmanager-0.1.4}/PKG-INFO +5 -2
  2. {mcmanager-0.1.2 → mcmanager-0.1.4}/mcmanager/cli.py +135 -115
  3. mcmanager-0.1.4/mcmanager/console/admin.py +54 -0
  4. mcmanager-0.1.4/mcmanager/console/apps.py +10 -0
  5. mcmanager-0.1.4/mcmanager/console/compat.py +31 -0
  6. mcmanager-0.1.4/mcmanager/console/forms.py +15 -0
  7. mcmanager-0.1.4/mcmanager/console/json_utils.py +8 -0
  8. mcmanager-0.1.4/mcmanager/console/management/__init__.py +0 -0
  9. mcmanager-0.1.4/mcmanager/console/management/commands/__init__.py +0 -0
  10. mcmanager-0.1.4/mcmanager/console/management/commands/format_code.py +43 -0
  11. mcmanager-0.1.4/mcmanager/console/management/commands/generate_secret_key.py +23 -0
  12. mcmanager-0.1.4/mcmanager/console/migrations/0001_initial.py +45 -0
  13. mcmanager-0.1.4/mcmanager/console/migrations/0002_alter_server_ip_alter_server_port.py +23 -0
  14. mcmanager-0.1.4/mcmanager/console/migrations/0003_remove_server_ip_server_status.py +22 -0
  15. mcmanager-0.1.4/mcmanager/console/migrations/0004_server_server_properties.py +18 -0
  16. mcmanager-0.1.4/mcmanager/console/migrations/0005_alter_server_jar_template_and_more.py +23 -0
  17. mcmanager-0.1.4/mcmanager/console/migrations/0006_server_rcon_password_server_rcon_port.py +68 -0
  18. mcmanager-0.1.4/mcmanager/console/migrations/0007_remove_server_status.py +17 -0
  19. mcmanager-0.1.4/mcmanager/console/migrations/0008_jardownload.py +26 -0
  20. mcmanager-0.1.4/mcmanager/console/migrations/0009_backup.py +26 -0
  21. mcmanager-0.1.4/mcmanager/console/migrations/0010_server_auto_restart_enabled_and_more.py +38 -0
  22. mcmanager-0.1.4/mcmanager/console/migrations/__init__.py +0 -0
  23. mcmanager-0.1.4/mcmanager/console/models.py +118 -0
  24. mcmanager-0.1.4/mcmanager/console/services/__init__.py +0 -0
  25. mcmanager-0.1.4/mcmanager/console/services/backups.py +137 -0
  26. mcmanager-0.1.4/mcmanager/console/services/dashboard.py +49 -0
  27. mcmanager-0.1.4/mcmanager/console/services/doctor.py +82 -0
  28. mcmanager-0.1.4/mcmanager/console/services/jar_providers/__init__.py +0 -0
  29. mcmanager-0.1.4/mcmanager/console/services/jar_providers/base.py +18 -0
  30. mcmanager-0.1.4/mcmanager/console/services/jar_providers/mojang.py +36 -0
  31. mcmanager-0.1.4/mcmanager/console/services/jar_providers/paper.py +32 -0
  32. mcmanager-0.1.4/mcmanager/console/services/jars.py +72 -0
  33. mcmanager-0.1.4/mcmanager/console/services/process.py +214 -0
  34. mcmanager-0.1.4/mcmanager/console/services/provisioning.py +77 -0
  35. mcmanager-0.1.4/mcmanager/console/services/rcon.py +86 -0
  36. mcmanager-0.1.4/mcmanager/console/services/supervisor.py +93 -0
  37. {mcmanager-0.1.2 → mcmanager-0.1.4}/mcmanager/console/static/css/tailwind.css +813 -742
  38. {mcmanager-0.1.2 → mcmanager-0.1.4}/mcmanager/console/templates/console/index.html +149 -13
  39. mcmanager-0.1.4/mcmanager/console/templates/console/jars.html +122 -0
  40. mcmanager-0.1.4/mcmanager/console/templates/index.html +152 -0
  41. mcmanager-0.1.4/mcmanager/console/urls.py +23 -0
  42. mcmanager-0.1.4/mcmanager/console/views.py +149 -0
  43. mcmanager-0.1.4/mcmanager/console/views_backups.py +63 -0
  44. mcmanager-0.1.4/mcmanager/console/views_jars.py +54 -0
  45. {mcmanager-0.1.2 → mcmanager-0.1.4}/mcmanager/settings.py +8 -0
  46. {mcmanager-0.1.2 → mcmanager-0.1.4}/mcmanager.egg-info/PKG-INFO +5 -2
  47. mcmanager-0.1.4/mcmanager.egg-info/SOURCES.txt +70 -0
  48. {mcmanager-0.1.2 → mcmanager-0.1.4}/mcmanager.egg-info/requires.txt +4 -0
  49. {mcmanager-0.1.2 → mcmanager-0.1.4}/pyproject.toml +46 -36
  50. {mcmanager-0.1.2 → mcmanager-0.1.4}/requirements.txt +2 -2
  51. mcmanager-0.1.2/mcmanager/console/admin.py +0 -29
  52. mcmanager-0.1.2/mcmanager/console/apps.py +0 -22
  53. mcmanager-0.1.2/mcmanager/console/models.py +0 -112
  54. mcmanager-0.1.2/mcmanager/console/templates/index.html +0 -42
  55. mcmanager-0.1.2/mcmanager/console/tests.py +0 -3
  56. mcmanager-0.1.2/mcmanager/console/urls.py +0 -14
  57. mcmanager-0.1.2/mcmanager/console/views.py +0 -175
  58. mcmanager-0.1.2/mcmanager.egg-info/SOURCES.txt +0 -37
  59. {mcmanager-0.1.2 → mcmanager-0.1.4}/MANIFEST.in +0 -0
  60. {mcmanager-0.1.2 → mcmanager-0.1.4}/README.md +0 -0
  61. {mcmanager-0.1.2 → mcmanager-0.1.4}/mcmanager/__init__.py +0 -0
  62. {mcmanager-0.1.2 → mcmanager-0.1.4}/mcmanager/__main__.py +0 -0
  63. {mcmanager-0.1.2 → mcmanager-0.1.4}/mcmanager/asgi.py +0 -0
  64. {mcmanager-0.1.2 → mcmanager-0.1.4}/mcmanager/configs/server.properties +0 -0
  65. {mcmanager-0.1.2 → mcmanager-0.1.4}/mcmanager/console/__init__.py +0 -0
  66. {mcmanager-0.1.2 → mcmanager-0.1.4}/mcmanager/console/static/css/font-awesome.css +0 -0
  67. {mcmanager-0.1.2 → mcmanager-0.1.4}/mcmanager/console/static/css/font-awesome.min.css +0 -0
  68. {mcmanager-0.1.2 → mcmanager-0.1.4}/mcmanager/console/static/css/styles.css +0 -0
  69. {mcmanager-0.1.2 → mcmanager-0.1.4}/mcmanager/console/static/css/toastify.min.css +0 -0
  70. {mcmanager-0.1.2 → mcmanager-0.1.4}/mcmanager/console/static/fonts/fontawesome-webfont.ttf +0 -0
  71. {mcmanager-0.1.2 → mcmanager-0.1.4}/mcmanager/console/static/fonts/fontawesome-webfont.woff +0 -0
  72. {mcmanager-0.1.2 → mcmanager-0.1.4}/mcmanager/console/static/fonts/fontawesome-webfont.woff2 +0 -0
  73. {mcmanager-0.1.2 → mcmanager-0.1.4}/mcmanager/console/static/img/favicon.ico +0 -0
  74. {mcmanager-0.1.2 → mcmanager-0.1.4}/mcmanager/console/static/js/toastify-js.js +0 -0
  75. {mcmanager-0.1.2 → mcmanager-0.1.4}/mcmanager/urls.py +0 -0
  76. {mcmanager-0.1.2 → mcmanager-0.1.4}/mcmanager/wsgi.py +0 -0
  77. {mcmanager-0.1.2 → mcmanager-0.1.4}/mcmanager.egg-info/dependency_links.txt +0 -0
  78. {mcmanager-0.1.2 → mcmanager-0.1.4}/mcmanager.egg-info/entry_points.txt +0 -0
  79. {mcmanager-0.1.2 → mcmanager-0.1.4}/mcmanager.egg-info/top_level.txt +0 -0
  80. {mcmanager-0.1.2 → mcmanager-0.1.4}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mcmanager
3
- Version: 0.1.2
3
+ Version: 0.1.4
4
4
  Summary: A Django-based web interface to manage Minecraft servers on a VPS
5
5
  License: MIT
6
6
  Classifier: Programming Language :: Python :: 3
@@ -8,11 +8,14 @@ Classifier: Framework :: Django
8
8
  Classifier: License :: OSI Approved :: MIT License
9
9
  Classifier: Operating System :: POSIX :: Linux
10
10
  Classifier: Topic :: Games/Entertainment
11
- Requires-Python: >=3.8
11
+ Requires-Python: >=3.10
12
12
  Description-Content-Type: text/markdown
13
13
  Requires-Dist: Django<5.2.0,>=4.2.0
14
14
  Requires-Dist: psutil>=5.8.0
15
15
  Requires-Dist: whitenoise>=6.0.0
16
+ Provides-Extra: dev
17
+ Requires-Dist: pytest>=7.4.0; extra == "dev"
18
+ Requires-Dist: pytest-django>=4.7.0; extra == "dev"
16
19
 
17
20
  # mcmanager (BETA)
18
21
 
@@ -1,115 +1,135 @@
1
- import os
2
- import sys
3
- import argparse
4
- import shutil
5
- from pathlib import Path
6
-
7
- def get_data_dir():
8
- """Determina o diretório de dados com base na variável de ambiente ou home"""
9
- if os.environ.get("MCMANAGER_DATA_DIR"):
10
- return Path(os.environ["MCMANAGER_DATA_DIR"]).resolve()
11
-
12
- debug_mode = os.environ.get("MCMANAGER_DEBUG", "False").lower() in ("true", "1", "yes")
13
- if debug_mode:
14
- # Se estiver em modo debug local, usa a pasta do próprio projeto
15
- return Path(__file__).resolve().parent.parent
16
- else:
17
- return Path.home() / ".mcmanager"
18
-
19
- def main():
20
- parser = argparse.ArgumentParser(
21
- description="mcmanager - Painel de Controle de Servidores Minecraft"
22
- )
23
- subparsers = parser.add_subparsers(dest="command", required=True, help="Subcomando a executar")
24
-
25
- # Comando init
26
- init_parser = subparsers.add_parser("init", help="Inicializa o diretório de dados, banco e arquivos padrões")
27
-
28
- # Comando run
29
- run_parser = subparsers.add_parser("run", help="Inicia o servidor web do painel")
30
- run_parser.add_argument("--host", default="0.0.0.0", help="Endereço IP para escutar (padrão: 0.0.0.0)")
31
- run_parser.add_argument("--port", type=int, default=8000, help="Porta para escutar (padrão: 8000)")
32
-
33
- # Comando createsuperuser
34
- createsuperuser_parser = subparsers.add_parser(
35
- "createsuperuser", help="Cria um usuário administrador para o painel"
36
- )
37
-
38
- # Comando shell
39
- shell_parser = subparsers.add_parser("shell", help="Inicia o console interativo do Django")
40
-
41
- args = parser.parse_args()
42
-
43
- # 1. Obter e criar estrutura de dados do usuário
44
- data_dir = get_data_dir()
45
- data_dir.mkdir(parents=True, exist_ok=True)
46
- (data_dir / "servers").mkdir(exist_ok=True)
47
- (data_dir / "jar").mkdir(exist_ok=True)
48
- (data_dir / "configs").mkdir(exist_ok=True)
49
-
50
- # 2. Copiar server.properties padrão se não existir
51
- properties_dest = data_dir / "configs" / "server.properties"
52
- if not properties_dest.exists():
53
- # Tenta carregar usando importlib.resources (PEP 517)
54
- copied = False
55
- try:
56
- from importlib import resources
57
- # Python 3.9+
58
- source_path = resources.files("mcmanager").joinpath("configs/server.properties")
59
- with source_path.open("rb") as fsrc:
60
- with open(properties_dest, "wb") as fdst:
61
- shutil.copyfileobj(fsrc, fdst)
62
- copied = True
63
- except Exception:
64
- pass
65
-
66
- if not copied:
67
- # Fallback para caminho relativo
68
- source_path = Path(__file__).resolve().parent / "configs" / "server.properties"
69
- if source_path.exists():
70
- shutil.copy(source_path, properties_dest)
71
- copied = True
72
-
73
- if copied:
74
- print(f"[*] Arquivo server.properties padrão copiado para: {properties_dest}")
75
- else:
76
- print("[!] Aviso: Não foi possível copiar o arquivo server.properties padrão.")
77
-
78
- # 3. Configurar variáveis de ambiente do Django
79
- os.environ.setdefault("MCMANAGER_DATA_DIR", str(data_dir))
80
- os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mcmanager.settings")
81
-
82
- # 4. Inicializar Django
83
- import django
84
- django.setup()
85
-
86
- from django.core.management import call_command
87
-
88
- # 5. Executar os subcomandos
89
- if args.command == "init":
90
- print("[*] Executando migrações do banco de dados...")
91
- call_command("migrate", interactive=False)
92
- print("[*] Coletando arquivos estáticos...")
93
- call_command("collectstatic", "--noinput", "--clear")
94
- print("\n[+] Inicialização concluída com sucesso!")
95
- print(f"[+] Seus dados estão em: {data_dir}")
96
- print("[+] Agora você pode rodar: mcmanager createsuperuser")
97
-
98
- elif args.command == "run":
99
- bind_address = f"{args.host}:{args.port}"
100
- print(f"[*] Iniciando servidor mcmanager em http://{bind_address}/")
101
- print("[*] Pressione CTRL+C para encerrar.")
102
- # Em produção, rodamos sem autoreload
103
- call_command("runserver", "--noreload", "--nostatic", bind_address)
104
-
105
- elif args.command == "createsuperuser":
106
- try:
107
- call_command("createsuperuser")
108
- except KeyboardInterrupt:
109
- print("\n[!] Operação cancelada.")
110
-
111
- elif args.command == "shell":
112
- call_command("shell")
113
-
114
- if __name__ == "__main__":
115
- main()
1
+ import os
2
+ import sys
3
+ import argparse
4
+ import shutil
5
+ from pathlib import Path
6
+
7
+ def get_data_dir():
8
+ """Determina o diretório de dados com base na variável de ambiente ou home"""
9
+ if os.environ.get("MCMANAGER_DATA_DIR"):
10
+ return Path(os.environ["MCMANAGER_DATA_DIR"]).resolve()
11
+
12
+ debug_mode = os.environ.get("MCMANAGER_DEBUG", "False").lower() in ("true", "1", "yes")
13
+ if debug_mode:
14
+ # Se estiver em modo debug local, usa a pasta do próprio projeto
15
+ return Path(__file__).resolve().parent.parent
16
+ else:
17
+ return Path.home() / ".mcmanager"
18
+
19
+ def main():
20
+ parser = argparse.ArgumentParser(
21
+ description="mcmanager - Painel de Controle de Servidores Minecraft"
22
+ )
23
+ subparsers = parser.add_subparsers(dest="command", required=True, help="Subcomando a executar")
24
+
25
+ # Comando init
26
+ subparsers.add_parser("init", help="Inicializa o diretório de dados, banco e arquivos padrões")
27
+
28
+ # Comando run
29
+ run_parser = subparsers.add_parser("run", help="Inicia o servidor web do painel")
30
+ run_parser.add_argument("--host", default="0.0.0.0", help="Endereço IP para escutar (padrão: 0.0.0.0)")
31
+ run_parser.add_argument("--port", type=int, default=8000, help="Porta para escutar (padrão: 8000)")
32
+
33
+ # Comando createsuperuser
34
+ subparsers.add_parser(
35
+ "createsuperuser", help="Cria um usuário administrador para o painel"
36
+ )
37
+
38
+ # Comando shell
39
+ subparsers.add_parser("shell", help="Inicia o console interativo do Django")
40
+
41
+ # Comando doctor
42
+ subparsers.add_parser(
43
+ "doctor", help="Diagnostica o ambiente (Java, diretórios, banco de dados)"
44
+ )
45
+
46
+ args = parser.parse_args()
47
+
48
+ # 1. Obter e criar estrutura de dados do usuário
49
+ data_dir = get_data_dir()
50
+ data_dir.mkdir(parents=True, exist_ok=True)
51
+ (data_dir / "servers").mkdir(exist_ok=True)
52
+ (data_dir / "jar").mkdir(exist_ok=True)
53
+ (data_dir / "configs").mkdir(exist_ok=True)
54
+ (data_dir / "run").mkdir(exist_ok=True)
55
+ (data_dir / "backups").mkdir(exist_ok=True)
56
+
57
+ # 2. Copiar server.properties padrão se não existir
58
+ properties_dest = data_dir / "configs" / "server.properties"
59
+ if not properties_dest.exists():
60
+ # Tenta carregar usando importlib.resources (PEP 517)
61
+ copied = False
62
+ try:
63
+ from importlib import resources
64
+ # Python 3.9+
65
+ source_path = resources.files("mcmanager").joinpath("configs/server.properties")
66
+ with source_path.open("rb") as fsrc:
67
+ with open(properties_dest, "wb") as fdst:
68
+ shutil.copyfileobj(fsrc, fdst)
69
+ copied = True
70
+ except Exception:
71
+ pass
72
+
73
+ if not copied:
74
+ # Fallback para caminho relativo
75
+ source_path = Path(__file__).resolve().parent / "configs" / "server.properties"
76
+ if source_path.exists():
77
+ shutil.copy(source_path, properties_dest)
78
+ copied = True
79
+
80
+ if copied:
81
+ print(f"[*] Arquivo server.properties padrão copiado para: {properties_dest}")
82
+ else:
83
+ print("[!] Aviso: Não foi possível copiar o arquivo server.properties padrão.")
84
+
85
+ # 3. Configurar variáveis de ambiente do Django
86
+ os.environ.setdefault("MCMANAGER_DATA_DIR", str(data_dir))
87
+ os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mcmanager.settings")
88
+
89
+ # 4. Inicializar Django
90
+ import django
91
+ django.setup()
92
+
93
+ from django.core.management import call_command
94
+
95
+ # 5. Executar os subcomandos
96
+ if args.command == "init":
97
+ print("[*] Executando migrações do banco de dados...")
98
+ call_command("migrate", interactive=False)
99
+ print("[*] Coletando arquivos estáticos...")
100
+ call_command("collectstatic", "--noinput", "--clear")
101
+ print("\n[+] Inicialização concluída com sucesso!")
102
+ print(f"[+] Seus dados estão em: {data_dir}")
103
+ print("[+] Agora você pode rodar: mcmanager createsuperuser")
104
+
105
+ elif args.command == "run":
106
+ from mcmanager.console.services import supervisor
107
+ supervisor.start()
108
+ bind_address = f"{args.host}:{args.port}"
109
+ print(f"[*] Iniciando servidor mcmanager em http://{bind_address}/")
110
+ print("[*] Pressione CTRL+C para encerrar.")
111
+ # Em produção, rodamos sem autoreload
112
+ call_command("runserver", "--noreload", "--nostatic", bind_address)
113
+
114
+ elif args.command == "createsuperuser":
115
+ try:
116
+ call_command("createsuperuser")
117
+ except KeyboardInterrupt:
118
+ print("\n[!] Operação cancelada.")
119
+
120
+ elif args.command == "shell":
121
+ call_command("shell")
122
+
123
+ elif args.command == "doctor":
124
+ from mcmanager.console.services import doctor
125
+ results = doctor.run_checks()
126
+ all_passed = True
127
+ for result in results:
128
+ symbol = "OK" if result['passed'] else "FAIL"
129
+ print(f"[{symbol}] {result['name']}: {result['message']}")
130
+ if not result['passed']:
131
+ all_passed = False
132
+ sys.exit(0 if all_passed else 1)
133
+
134
+ if __name__ == "__main__":
135
+ main()
@@ -0,0 +1,54 @@
1
+ from typing import Any
2
+
3
+ from django.contrib import admin
4
+
5
+ from .forms import ServerForm
6
+ from .models import Server, Type
7
+ from .services import process, provisioning
8
+
9
+
10
+ @admin.register(Server)
11
+ class ServerAdmin(admin.ModelAdmin):
12
+ form = ServerForm
13
+ list_display = ('name', 'port', 'type', 'is_running')
14
+ exclude = ('jar', 'server_properties', 'desired_running', 'consecutive_restart_failures', 'last_scheduled_backup_date')
15
+ search_fields = ('name', 'port', 'type')
16
+ list_filter = ('type',)
17
+ readonly_fields = ()
18
+
19
+ def is_running(self, obj):
20
+ return process.is_running(obj)
21
+ is_running.boolean = True
22
+ is_running.short_description = 'Running'
23
+
24
+ def get_form(self, request, obj=..., change=..., **kwargs) -> Any:
25
+ internal_fields = ('desired_running', 'consecutive_restart_failures', 'last_scheduled_backup_date')
26
+ if obj is None:
27
+ self.exclude = ('jar', 'server_properties') + internal_fields
28
+ self.readonly_fields = ()
29
+ else:
30
+ self.exclude = internal_fields
31
+ self.readonly_fields = ('jar',)
32
+ return super().get_form(request, obj, change, **kwargs)
33
+
34
+ def save_model(self, request, obj, form, change):
35
+ super().save_model(request, obj, form, change)
36
+ if not obj.jar:
37
+ provisioning.create_server_files(obj)
38
+ else:
39
+ provisioning.sync_server_properties_file(obj)
40
+
41
+ def delete_model(self, request, obj):
42
+ provisioning.delete_server_files(obj)
43
+ super().delete_model(request, obj)
44
+
45
+ def delete_queryset(self, request, queryset):
46
+ for obj in queryset:
47
+ provisioning.delete_server_files(obj)
48
+ super().delete_queryset(request, queryset)
49
+
50
+
51
+ @admin.register(Type)
52
+ class TypeAdmin(admin.ModelAdmin):
53
+ list_display = ('name',)
54
+ search_fields = ('name',)
@@ -0,0 +1,10 @@
1
+ from django.apps import AppConfig
2
+
3
+
4
+ class ConsoleConfig(AppConfig):
5
+ default_auto_field = 'django.db.models.BigAutoField'
6
+ name = 'mcmanager.console'
7
+
8
+ def ready(self):
9
+ from .compat import patch_context_copy_for_python314
10
+ patch_context_copy_for_python314()
@@ -0,0 +1,31 @@
1
+ """Runtime compatibility shims for this project's supported environments."""
2
+ from django.template.context import BaseContext
3
+
4
+
5
+ def patch_context_copy_for_python314():
6
+ """Python 3.14 changed copy.copy()'s handling of `super` proxy objects,
7
+ breaking Django 5.1's BaseContext.__copy__ (which does
8
+ `duplicate = copy(super())` to get a shallow copy of self while bypassing
9
+ dict's own __copy__ -- BaseContext isn't a dict subclass, but relies on
10
+ this idiom to allocate a bare instance). This now raises
11
+ `AttributeError: 'super' object has no attribute 'dicts' and no __dict__
12
+ for setting new attributes` any time Django copies a template Context --
13
+ which happens on every Django admin change-list page render (via the
14
+ `{% change_list_object_tools %}` templatetag), and more generally
15
+ whenever `Context.new()` is called. Reproduced independently of Django
16
+ with a minimal `copy(super())` snippet, so this is an upstream Python
17
+ 3.14 regression, not an application bug. Django 5.1.15 (latest 5.1.x as
18
+ of writing) does not include a fix.
19
+
20
+ TODO: remove once either (a) Django ships a fix for the copy(super())
21
+ idiom under Python 3.14+, or (b) this project's supported Python floor
22
+ is raised past whatever version fixes it -- check `python --version`
23
+ and retest by removing this call before deleting it.
24
+ """
25
+ def _base_context_copy(self):
26
+ duplicate = object.__new__(self.__class__)
27
+ duplicate.__dict__.update(self.__dict__)
28
+ duplicate.dicts = self.dicts[:]
29
+ return duplicate
30
+
31
+ BaseContext.__copy__ = _base_context_copy
@@ -0,0 +1,15 @@
1
+ from django import forms
2
+
3
+ from .models import Server, get_jar_files
4
+
5
+
6
+ class ServerForm(forms.ModelForm):
7
+ jar_template = forms.ChoiceField(choices=[])
8
+
9
+ class Meta:
10
+ model = Server
11
+ fields = '__all__'
12
+
13
+ def __init__(self, *args, **kwargs):
14
+ super().__init__(*args, **kwargs)
15
+ self.fields['jar_template'].choices = get_jar_files()
@@ -0,0 +1,8 @@
1
+ """Shared JSON error-response helper. Success responses keep their existing,
2
+ per-view flat shape unchanged — only error responses use this, so they get a
3
+ real HTTP status code instead of always returning 200."""
4
+ from django.http import JsonResponse
5
+
6
+
7
+ def json_error(message, status=400):
8
+ return JsonResponse({'status': 'error', 'message': message}, status=status)
@@ -0,0 +1,43 @@
1
+ import subprocess
2
+ from django.core.management.base import BaseCommand
3
+
4
+
5
+ class Command(BaseCommand):
6
+ """
7
+ Formatar o código do projeto
8
+ """
9
+ help = 'Formatar o código do projeto'
10
+
11
+ def handle(self, *args, **kwargs):
12
+ # Executa o comando de formatação para *.py
13
+ result1 = subprocess.getstatusoutput(
14
+ "autopep8 --recursive --in-place --exclude venv,.git,node_modules ./")
15
+ if result1[0] == 0:
16
+ self.stdout.write(self.style.SUCCESS(
17
+ 'Código Python formatado com sucesso!'))
18
+ if kwargs.get('verbosity', 1) > 1:
19
+ self.stdout.write(self.style.SUCCESS(result1[1]))
20
+ else:
21
+ self.stdout.write(self.style.ERROR(
22
+ 'Erro ao formatar o código Python!'))
23
+ if kwargs.get('verbosity', 1) > 1:
24
+ self.stdout.write(self.style.ERROR(result1[1]))
25
+ # Executa o comando de formatação para *.html, *.css e *.js
26
+ result2 = subprocess.getstatusoutput(
27
+ """find . -type d \\( -name 'venv' -o -name 'node_modules' -o -name '.git' \\) -prune -false -o -type d -name 'templates' | while read -r dir; do
28
+ echo "Formating $dir"
29
+ djlint "$dir" --reformat --format-css --format-js --use-gitignore
30
+ done""")
31
+ if result2[0] == 0:
32
+ self.stdout.write(self.style.SUCCESS(
33
+ 'Não foi necessário formatar o código HTML, CSS e JavaScript!'))
34
+ if kwargs.get('verbosity', 1) > 1:
35
+ self.stdout.write(self.style.SUCCESS(result2[1]))
36
+ else:
37
+ if kwargs.get('verbosity', 1) > 1:
38
+ self.stdout.write(self.style.WARNING(
39
+ 'Foram realizadas alterações no código HTML, CSS e JavaScript!'))
40
+ self.stdout.write(self.style.WARNING(result2[1]))
41
+ else:
42
+ self.stdout.write(self.style.WARNING(
43
+ 'Foram realizadas alterações no código HTML, CSS e JavaScript!\nUse "python manage.py format_code --verbosity 2" para mais detalhes.'))
@@ -0,0 +1,23 @@
1
+ from django.core.management.base import BaseCommand
2
+ from django.core.management.utils import get_random_secret_key
3
+ from django.conf import settings
4
+
5
+
6
+ class Command(BaseCommand):
7
+ """
8
+ Gerar uma nova SECRET_KEY e atualizá-la no arquivo .secret_key do diretório de dados
9
+ """
10
+ help = 'Gerar uma nova SECRET_KEY e atualizá-la no arquivo .secret_key do diretório de dados'
11
+
12
+ def handle(self, *args, **kwargs):
13
+ secret_key = get_random_secret_key()
14
+ user_data_dir = getattr(settings, 'USER_DATA_DIR', settings.BASE_DIR)
15
+ secret_key_file = user_data_dir / '.secret_key'
16
+
17
+ user_data_dir.mkdir(parents=True, exist_ok=True)
18
+ secret_key_file.write_text(secret_key, encoding='utf-8')
19
+
20
+ self.stdout.write(self.style.SUCCESS(
21
+ f'Nova SECRET_KEY gerada e salva com sucesso em: {secret_key_file}'
22
+ ))
23
+
@@ -0,0 +1,45 @@
1
+ # Generated by Django 4.0.5 on 2024-07-09 23:19
2
+
3
+ from django.db import migrations, models
4
+ import django.db.models.deletion
5
+
6
+
7
+ class Migration(migrations.Migration):
8
+
9
+ initial = True
10
+
11
+ dependencies = [
12
+ ]
13
+
14
+ operations = [
15
+ migrations.CreateModel(
16
+ name='Type',
17
+ fields=[
18
+ ('id', models.BigAutoField(auto_created=True,
19
+ primary_key=True, serialize=False, verbose_name='ID')),
20
+ ('name', models.CharField(max_length=100)),
21
+ ('dependencies', models.JSONField(blank=True, null=True)),
22
+ ('created_at', models.DateTimeField(auto_now_add=True)),
23
+ ('updated_at', models.DateTimeField(auto_now=True)),
24
+ ],
25
+ ),
26
+ migrations.CreateModel(
27
+ name='Server',
28
+ fields=[
29
+ ('id', models.BigAutoField(auto_created=True,
30
+ primary_key=True, serialize=False, verbose_name='ID')),
31
+ ('name', models.CharField(max_length=100)),
32
+ ('jar_template', models.CharField(choices=[('custom.jar', 'custom.jar'), (
33
+ 'minecraft_server.1.7.10.jar', 'minecraft_server.1.7.10.jar')], max_length=100)),
34
+ ('jar', models.CharField(blank=True, max_length=100, null=True)),
35
+ ('ip', models.GenericIPAddressField()),
36
+ ('port', models.IntegerField()),
37
+ ('memory_limit', models.IntegerField(
38
+ default=1024, verbose_name='Memory Limit (MB)')),
39
+ ('created_at', models.DateTimeField(auto_now_add=True)),
40
+ ('updated_at', models.DateTimeField(auto_now=True)),
41
+ ('type', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE,
42
+ related_name='servers', to='console.type')),
43
+ ],
44
+ ),
45
+ ]
@@ -0,0 +1,23 @@
1
+ # Generated by Django 4.0.5 on 2024-07-09 23:49
2
+
3
+ from django.db import migrations, models
4
+
5
+
6
+ class Migration(migrations.Migration):
7
+
8
+ dependencies = [
9
+ ('console', '0001_initial'),
10
+ ]
11
+
12
+ operations = [
13
+ migrations.AlterField(
14
+ model_name='server',
15
+ name='ip',
16
+ field=models.GenericIPAddressField(blank=True, null=True),
17
+ ),
18
+ migrations.AlterField(
19
+ model_name='server',
20
+ name='port',
21
+ field=models.IntegerField(default=25565),
22
+ ),
23
+ ]
@@ -0,0 +1,22 @@
1
+ # Generated by Django 4.0.5 on 2024-07-10 00:44
2
+
3
+ from django.db import migrations, models
4
+
5
+
6
+ class Migration(migrations.Migration):
7
+
8
+ dependencies = [
9
+ ('console', '0002_alter_server_ip_alter_server_port'),
10
+ ]
11
+
12
+ operations = [
13
+ migrations.RemoveField(
14
+ model_name='server',
15
+ name='ip',
16
+ ),
17
+ migrations.AddField(
18
+ model_name='server',
19
+ name='status',
20
+ field=models.BooleanField(default=False),
21
+ ),
22
+ ]
@@ -0,0 +1,18 @@
1
+ # Generated by Django 4.0.5 on 2024-07-10 20:29
2
+
3
+ from django.db import migrations, models
4
+
5
+
6
+ class Migration(migrations.Migration):
7
+
8
+ dependencies = [
9
+ ('console', '0003_remove_server_ip_server_status'),
10
+ ]
11
+
12
+ operations = [
13
+ migrations.AddField(
14
+ model_name='server',
15
+ name='server_properties',
16
+ field=models.TextField(blank=True, default='#Minecraft server properties\n#Wed Jul 10 19:30:06 UTC 2024\ngenerator-settings=\nop-permission-level=4\nallow-nether=true\nlevel-name=world\nenable-query=false\nallow-flight=true\nannounce-player-achievements=true\nserver-port=25566\nlevel-type=DEFAULT\nenable-rcon=false\nforce-gamemode=false\nlevel-seed=\nserver-ip=\nmax-build-height=256\nspawn-npcs=true\nwhite-list=false\nspawn-animals=true\nhardcore=false\nsnooper-enabled=true\nonline-mode=false\nresource-pack=\npvp=true\ndifficulty=1\nenable-command-block=false\ngamemode=0\nplayer-idle-timeout=0\nmax-players=5\nspawn-monsters=true\ngenerate-structures=true\nview-distance=10\nmotd=A Minecraft Server\n', null=True),
17
+ ),
18
+ ]
@@ -0,0 +1,23 @@
1
+ # Generated by Django 5.1.15 on 2026-07-17 13:23
2
+
3
+ from django.db import migrations, models
4
+
5
+
6
+ class Migration(migrations.Migration):
7
+
8
+ dependencies = [
9
+ ('console', '0004_server_server_properties'),
10
+ ]
11
+
12
+ operations = [
13
+ migrations.AlterField(
14
+ model_name='server',
15
+ name='jar_template',
16
+ field=models.CharField(max_length=100),
17
+ ),
18
+ migrations.AlterField(
19
+ model_name='server',
20
+ name='server_properties',
21
+ field=models.TextField(blank=True, null=True),
22
+ ),
23
+ ]