Merge branch 'feature/pretzel-users-roles-manager' into 'dev'

Add manager field to users/roles. Add created by field to servers - fixes bug with quotas.

See merge request crafty-controller/crafty-4!434
This commit is contained in:
Iain Powrie 2022-08-27 16:39:59 +00:00
commit ffd0f3d55d
28 changed files with 486 additions and 112 deletions

View File

@ -2,10 +2,12 @@
## --- [4.0.11] - 2022/TBD
### New features
- Add server import status indicators ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/433))
- Users can now be assigned as manager of other users/roles ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/434))
### Bug fixes
TBD
- Fix creation quota not refilling after server delete ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/434))
### Tweaks
- Make imports threaded ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/433))
- Add 'Created By' Field to servers ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/434))
### Lang
TBD
<br><br>

View File

@ -60,26 +60,6 @@ class CraftyPermsController:
permissions_list = PermissionsCrafty.get_permissions(permissions_mask)
return permissions_list
@staticmethod
def add_server_creation(user_id):
"""Increase the "Server Creation" counter for this user
Args:
user_id (int): The modifiable user's ID
Returns:
int: The new count of servers created by this user
"""
return PermissionsCrafty.add_server_creation(user_id)
@staticmethod
def add_user_creation(user_id):
return PermissionsCrafty.add_user_creation(user_id)
@staticmethod
def add_role_creation(user_id):
return PermissionsCrafty.add_role_creation(user_id)
@staticmethod
def get_api_key_permissions_list(key: ApiKeys):
return PermissionsCrafty.get_api_key_permissions_list(key)

View File

@ -64,8 +64,8 @@ class RolesController:
HelperRoles.update_role(role_id, up_data)
@staticmethod
def add_role(role_name):
return HelperRoles.add_role(role_name)
def add_role(role_name, manager):
return HelperRoles.add_role(role_name, manager)
class RoleServerJsonType(t.TypedDict):
server_id: t.Union[str, int]
@ -92,6 +92,7 @@ class RolesController:
def add_role_advanced(
name: str,
servers: t.Iterable[RoleServerJsonType],
manager: int,
) -> int:
"""Add a role with a name and a list of servers
@ -102,7 +103,7 @@ class RolesController:
Returns:
int: The new role's ID
"""
role_id: t.Final[int] = HelperRoles.add_role(name)
role_id: t.Final[int] = HelperRoles.add_role(name, manager)
for server in servers:
PermissionsServers.get_or_create(
role_id, server["server_id"], server["permissions"]
@ -114,6 +115,7 @@ class RolesController:
role_id: t.Union[str, int],
role_name: t.Optional[str],
servers: t.Optional[t.Iterable[RoleServerJsonType]],
manager: int,
) -> None:
"""Update a role with a name and a list of servers
@ -152,6 +154,7 @@ class RolesController:
up_data = {
"role_name": role_name,
"last_update": Helpers.get_time_as_string(),
"manager": manager,
}
# TODO: do the last_update on the db side
HelperRoles.update_role(role_id, up_data)

View File

@ -51,6 +51,7 @@ class ServersController(metaclass=Singleton):
server_log_file: str,
server_stop: str,
server_type: str,
created_by: int,
server_port: int = 25565,
server_host: str = "127.0.0.1",
) -> int:
@ -85,6 +86,7 @@ class ServersController(metaclass=Singleton):
server_log_file,
server_stop,
server_type,
created_by,
server_port,
server_host,
)

View File

@ -1,7 +1,9 @@
import logging
import typing as t
from app.classes.models.servers import HelperServers
from app.classes.models.users import HelperUsers
from app.classes.models.roles import HelperRoles
from app.classes.models.crafty_permissions import (
PermissionsCrafty,
EnumPermissionsCrafty,
@ -132,6 +134,18 @@ class UsersController:
def set_support_path(user_id, support_path):
HelperUsers.set_support_path(user_id, support_path)
@staticmethod
def get_managed_users(exec_user_id):
return HelperUsers.get_managed_users(exec_user_id)
@staticmethod
def get_managed_roles(exec_user_id):
return HelperUsers.get_managed_roles(exec_user_id)
@staticmethod
def get_created_servers(exec_user_id):
return HelperServers.get_total_owned_servers(exec_user_id)
def update_user(self, user_id: str, user_data=None, user_crafty_data=None):
if user_crafty_data is None:
user_crafty_data = {}
@ -206,6 +220,7 @@ class UsersController:
def add_user(
self,
username,
manager,
password,
email="default@example.com",
enabled: bool = True,
@ -213,6 +228,7 @@ class UsersController:
):
return self.users_helper.add_user(
username,
manager,
password=password,
email=email,
enabled=enabled,
@ -236,6 +252,10 @@ class UsersController:
)
def remove_user(self, user_id):
for user in self.get_managed_users(user_id):
self.update_user(user.user_id, {"manager": None})
for role in HelperUsers.get_managed_roles(user_id):
HelperRoles.update_role(role.role_id, {"manager": None})
return self.users_helper.remove_user(user_id)
@staticmethod

View File

@ -9,6 +9,7 @@ from peewee import (
)
from app.classes.models.base_model import BaseModel
from app.classes.models.servers import HelperServers
from app.classes.models.users import Users, ApiKeys, HelperUsers
from app.classes.shared.permission_helper import PermissionHelper
@ -23,9 +24,6 @@ class UserCrafty(BaseModel):
limit_server_creation = IntegerField(default=-1)
limit_user_creation = IntegerField(default=0)
limit_role_creation = IntegerField(default=0)
created_server = IntegerField(default=0)
created_user = IntegerField(default=0)
created_role = IntegerField(default=0)
class Meta:
table_name = "user_crafty"
@ -107,9 +105,6 @@ class PermissionsCrafty:
UserCrafty.limit_server_creation: 0,
UserCrafty.limit_user_creation: 0,
UserCrafty.limit_role_creation: 0,
UserCrafty.created_server: 0,
UserCrafty.created_user: 0,
UserCrafty.created_role: 0,
}
).execute()
user_crafty = PermissionsCrafty.get_user_crafty(user_id)
@ -159,11 +154,16 @@ class PermissionsCrafty:
@staticmethod
def get_created_quantity_list(user_id):
user_crafty = PermissionsCrafty.get_user_crafty(user_id)
quantity_list = {
EnumPermissionsCrafty.SERVER_CREATION.name: user_crafty.created_server,
EnumPermissionsCrafty.USER_CONFIG.name: user_crafty.created_user,
EnumPermissionsCrafty.ROLES_CONFIG.name: user_crafty.created_role,
EnumPermissionsCrafty.SERVER_CREATION.name: HelperServers.get_total_owned_servers( # pylint: disable=line-too-long
user_id
),
EnumPermissionsCrafty.USER_CONFIG.name: HelperUsers.get_managed_users(
user_id
).count(),
EnumPermissionsCrafty.ROLES_CONFIG.name: HelperUsers.get_managed_roles(
user_id
).count(),
}
return quantity_list
@ -183,31 +183,6 @@ class PermissionsCrafty:
or limit_list[permission.name] == -1
)
@staticmethod
def add_server_creation(user_id: int):
"""Increase the "Server Creation" counter for this user
Args:
user_id (int): The modifiable user's ID
"""
UserCrafty.update(created_server=UserCrafty.created_server + 1).where(
UserCrafty.user_id == user_id
).execute()
@staticmethod
def add_user_creation(user_id):
user_crafty = PermissionsCrafty.get_user_crafty(user_id)
user_crafty.created_user += 1
UserCrafty.save(user_crafty)
return user_crafty.created_user
@staticmethod
def add_role_creation(user_id):
user_crafty = PermissionsCrafty.get_user_crafty(user_id)
user_crafty.created_role += 1
UserCrafty.save(user_crafty)
return user_crafty.created_role
@staticmethod
def get_api_key_permissions_list(key: ApiKeys):
user = HelperUsers.get_user(key.user_id)

View File

@ -6,6 +6,7 @@ from peewee import (
DoesNotExist,
AutoField,
DateTimeField,
IntegerField,
)
from playhouse.shortcuts import model_to_dict
@ -22,6 +23,7 @@ class Roles(BaseModel):
created = DateTimeField(default=datetime.datetime.now)
last_update = DateTimeField(default=datetime.datetime.now)
role_name = CharField(default="", unique=True, index=True)
manager = IntegerField(null=True)
class Meta:
table_name = "roles"
@ -71,11 +73,12 @@ class HelperRoles:
)
@staticmethod
def add_role(role_name):
def add_role(role_name, manager):
role_id = Roles.insert(
{
Roles.role_name: role_name.lower(),
Roles.created: Helpers.get_time_as_string(),
Roles.manager: manager,
}
).execute()
return role_id

View File

@ -38,6 +38,7 @@ class Servers(BaseModel):
logs_delete_after = IntegerField(default=0)
type = CharField(default="minecraft-java")
show_status = BooleanField(default=1)
created_by = IntegerField(default=-100)
class Meta:
table_name = "servers"
@ -64,6 +65,7 @@ class HelperServers:
server_log_file: str,
server_stop: str,
server_type: str,
created_by: int,
server_port: int = 25565,
server_host: str = "127.0.0.1",
) -> int:
@ -105,6 +107,7 @@ class HelperServers:
Servers.stop_command: server_stop,
Servers.backup_path: backup_path,
Servers.type: server_type,
Servers.created_by: created_by,
}
).execute()
@ -112,6 +115,10 @@ class HelperServers:
def get_server_obj(server_id):
return Servers.get_by_id(server_id)
@staticmethod
def get_total_owned_servers(user_id):
return Servers.select().where(Servers.created_by == user_id).count()
@staticmethod
def get_server_type_by_id(server_id):
server_type = Servers.select().where(Servers.server_id == server_id).get()

View File

@ -6,6 +6,7 @@ from peewee import (
ForeignKeyField,
CharField,
AutoField,
IntegerField,
DateTimeField,
BooleanField,
CompositeKey,
@ -40,6 +41,7 @@ class Users(BaseModel):
server_order = CharField(default="")
preparing = BooleanField(default=False)
hints = BooleanField(default=True)
manager = IntegerField(default=None, null=True)
class Meta:
table_name = "users"
@ -138,6 +140,16 @@ class HelperUsers:
user_query = Users.select().where(Users.user_id == user_id)
return user_query
@staticmethod
def get_managed_users(exec_user_id):
user_query = Users.select().where(Users.manager == exec_user_id)
return user_query
@staticmethod
def get_managed_roles(exec_user_id):
roles_query = Roles.select().where(Roles.manager == exec_user_id)
return roles_query
@staticmethod
def get_user(user_id):
if user_id == 0:
@ -192,6 +204,7 @@ class HelperUsers:
def add_user(
self,
username: str,
manager: str,
password: str = None,
email: t.Optional[str] = None,
enabled: bool = True,
@ -209,6 +222,7 @@ class HelperUsers:
Users.enabled: enabled,
Users.superuser: superuser,
Users.created: Helpers.get_time_as_string(),
Users.manager: manager,
}
).execute()
return user_id
@ -229,6 +243,7 @@ class HelperUsers:
Users.enabled: enabled,
Users.superuser: superuser,
Users.created: Helpers.get_time_as_string(),
Users.manager: None,
}
).execute()
return user_id

View File

@ -246,7 +246,7 @@ class Controller:
except:
return {"percent": 0, "total_files": 0}
def create_api_server(self, data: dict):
def create_api_server(self, data: dict, user_id):
server_fs_uuid = Helpers.create_uuid()
new_server_path = os.path.join(self.helper.servers_dir, server_fs_uuid)
backup_path = os.path.join(self.helper.backup_path, server_fs_uuid)
@ -309,7 +309,9 @@ class Controller:
# TODO: Copy files from the zip file to the new server directory
server_file = create_data["jarfile"]
raise Exception("Not yet implemented")
_create_server_properties_if_needed(create_data["server_properties_port"])
_create_server_properties_if_needed(
create_data["server_properties_port"],
)
min_mem = create_data["mem_min"]
max_mem = create_data["mem_max"]
@ -405,6 +407,7 @@ class Controller:
server_log_file=log_location,
server_stop=stop_command,
server_port=monitoring_port,
created_by=user_id,
server_host=monitoring_host,
server_type=monitoring_type,
)
@ -431,6 +434,7 @@ class Controller:
min_mem: int,
max_mem: int,
port: int,
user_id: int,
):
server_id = Helpers.create_uuid()
server_dir = os.path.join(self.helper.servers_dir, server_id)
@ -491,6 +495,7 @@ class Controller:
server_log_file,
server_stop,
port,
user_id,
server_type="minecraft-java",
)
@ -526,6 +531,7 @@ class Controller:
min_mem: int,
max_mem: int,
port: int,
user_id: int,
):
server_id = Helpers.create_uuid()
new_server_dir = os.path.join(self.helper.servers_dir, server_id)
@ -567,6 +573,7 @@ class Controller:
server_log_file,
server_stop,
port,
user_id,
server_type="minecraft-java",
)
ServersController.set_import(new_id)
@ -581,6 +588,7 @@ class Controller:
min_mem: int,
max_mem: int,
port: int,
user_id: int,
):
server_id = Helpers.create_uuid()
new_server_dir = os.path.join(self.helper.servers_dir, server_id)
@ -623,6 +631,7 @@ class Controller:
server_log_file,
server_stop,
port,
user_id,
server_type="minecraft-java",
)
ServersController.set_import(new_id)
@ -636,7 +645,12 @@ class Controller:
# **********************************************************************************
def import_bedrock_server(
self, server_name: str, server_path: str, server_exe: str, port: int
self,
server_name: str,
server_path: str,
server_exe: str,
port: int,
user_id: int,
):
server_id = Helpers.create_uuid()
new_server_dir = os.path.join(self.helper.servers_dir, server_id)
@ -671,6 +685,7 @@ class Controller:
server_log_file,
server_stop,
port,
user_id,
server_type="minecraft-bedrock",
)
ServersController.set_import(new_id)
@ -680,7 +695,12 @@ class Controller:
return new_id
def import_bedrock_zip_server(
self, server_name: str, zip_path: str, server_exe: str, port: int
self,
server_name: str,
zip_path: str,
server_exe: str,
port: int,
user_id: int,
):
server_id = Helpers.create_uuid()
new_server_dir = os.path.join(self.helper.servers_dir, server_id)
@ -715,6 +735,7 @@ class Controller:
server_log_file,
server_stop,
port,
user_id,
server_type="minecraft-bedrock",
)
self.import_helper.import_bedrock_zip_server(
@ -760,6 +781,7 @@ class Controller:
server_log_file: str,
server_stop: str,
server_port: int,
created_by: int,
server_type: str,
server_host: str = "127.0.0.1",
):
@ -774,6 +796,7 @@ class Controller:
server_log_file,
server_stop,
server_type,
created_by,
server_port,
server_host,
)

View File

@ -26,6 +26,7 @@ class DatabaseBuilder:
password=password,
email="default@example.com",
superuser=True,
manager=None,
)
def is_fresh_install(self):

View File

@ -394,6 +394,7 @@ class AjaxHandler(BaseHandler):
"1",
"2",
server_data["server_port"],
server_data["created_by"],
)
new_server_id = new_server
new_server = self.controller.servers.get_server_data(new_server)
@ -416,6 +417,7 @@ class AjaxHandler(BaseHandler):
temp_dir,
server_data["executable"],
server_data["server_port"],
server_data["created_by"],
)
new_server_id = new_server
new_server = self.controller.servers.get_server_data(new_server)

View File

@ -340,10 +340,11 @@ class CreateUser(ApiHandler):
new_username = self.get_argument("username").lower()
new_pass = self.get_argument("password")
manager = int(user_obj["user_id"])
if new_username:
self.controller.users.add_user(
new_username, new_pass, "default@example.com", True, False
new_username, manager, new_pass, "default@example.com", True, False
)
self.return_response(

View File

@ -860,6 +860,18 @@ class PanelHandler(BaseHandler):
page_data["users"] = self.controller.users.get_all_users()
page_data["roles"] = self.controller.roles.get_all_roles()
page_data["auth-servers"][user.user_id] = super_auth_servers
page_data["managed_users"] = []
else:
page_data["managed_users"] = self.controller.users.get_managed_users(
exec_user["user_id"]
)
page_data["assigned_roles"] = []
for item in page_data["roles"]:
page_data["assigned_roles"].append(item.role_id)
page_data["managed_roles"] = self.controller.users.get_managed_roles(
exec_user["user_id"]
)
template = "panel/panel_config.html"
@ -885,7 +897,7 @@ class PanelHandler(BaseHandler):
)
return
page_data["roles_all"] = self.controller.roles.get_all_roles()
page_data["roles"] = self.controller.roles.get_all_roles()
page_data["servers"] = []
page_data["servers_all"] = self.controller.servers.get_all_defined_servers()
page_data["role-servers"] = []
@ -904,8 +916,16 @@ class PanelHandler(BaseHandler):
)
if superuser:
page_data["super-disabled"] = ""
page_data["users"] = self.controller.users.get_all_users()
else:
page_data["super-disabled"] = "disabled"
page_data["exec_user"] = exec_user["user_id"]
page_data["manager"] = {
"user_id": -100,
"username": "None",
}
for file in sorted(
os.listdir(os.path.join(self.helper.root_dir, "app", "translations"))
):
@ -1074,9 +1094,21 @@ class PanelHandler(BaseHandler):
page_data["user"] = self.controller.users.get_user_by_id(user_id)
page_data["servers"] = set()
page_data["role-servers"] = page_role_servers
page_data["roles_all"] = self.controller.roles.get_all_roles()
page_data["roles"] = self.controller.roles.get_all_roles()
page_data["exec_user"] = exec_user["user_id"]
page_data["servers_all"] = self.controller.servers.get_all_defined_servers()
page_data["superuser"] = superuser
if page_data["user"]["manager"] is not None:
page_data["manager"] = self.controller.users.get_user_by_id(
page_data["user"]["manager"]
)
else:
page_data["manager"] = {
"user_id": -100,
"username": "None",
}
if exec_user["superuser"]:
page_data["users"] = self.controller.users.get_all_users()
page_data[
"permissions_all"
] = self.controller.crafty_perms.list_defined_crafty_permissions()
@ -1115,6 +1147,17 @@ class PanelHandler(BaseHandler):
"/panel/error?error=Unauthorized access: not a user editor"
)
return
if (
(
self.controller.users.get_user_by_id(user_id)["manager"]
!= exec_user["user_id"]
)
and not exec_user["superuser"]
and str(exec_user["user_id"]) != str(user_id)
):
self.redirect(
"/panel/error?error=Unauthorized access: you cannot edit this user"
)
page_data["servers"] = []
page_data["role-servers"] = []
@ -1212,6 +1255,11 @@ class PanelHandler(BaseHandler):
defined_servers = self.controller.servers.get_authorized_servers(
exec_user["user_id"]
)
page_data["role_manager"] = {
"user_id": -100,
"username": "None",
}
page_servers = []
for server in defined_servers:
if server not in page_servers:
@ -1229,6 +1277,7 @@ class PanelHandler(BaseHandler):
user_roles = self.get_user_roles()
page_data["new_role"] = False
role_id = self.get_argument("id", None)
role = self.controller.roles.get_role(role_id)
page_data["role"] = self.controller.roles.get_role_with_servers(role_id)
if exec_user["superuser"]:
defined_servers = self.controller.servers.list_defined_servers()
@ -1252,7 +1301,21 @@ class PanelHandler(BaseHandler):
page_data["user-roles"] = user_roles
page_data["users"] = self.controller.users.get_all_users()
if EnumPermissionsCrafty.ROLES_CONFIG not in exec_user_crafty_permissions:
if page_data["role"]["manager"] is not None:
page_data["role_manager"] = self.controller.users.get_user_by_id(
page_data["role"]["manager"]
)
else:
page_data["role_manager"] = {
"user_id": -100,
"username": "None",
}
if (
EnumPermissionsCrafty.ROLES_CONFIG not in exec_user_crafty_permissions
or exec_user["user_id"] != role["manager"]
and not exec_user["superuser"]
):
self.redirect(
"/panel/error?error=Unauthorized access: not a role editor"
)
@ -1266,8 +1329,15 @@ class PanelHandler(BaseHandler):
elif page == "remove_role":
role_id = bleach.clean(self.get_argument("id", None))
if not superuser:
self.redirect("/panel/error?error=Unauthorized access: not superuser")
if (
not superuser
and self.controller.roles.get_role(role_id)["manager"]
!= exec_user["user_id"]
):
self.redirect(
"/panel/error?error=Unauthorized access: not superuser not"
" role manager"
)
return
if role_id is None:
self.redirect("/panel/error?error=Invalid Role ID")
@ -1930,6 +2000,7 @@ class PanelHandler(BaseHandler):
"system user is not editable"
)
user_id = bleach.clean(self.get_argument("id", None))
user = self.controller.users.get_user_by_id(user_id)
username = bleach.clean(self.get_argument("username", None).lower())
if (
username != self.controller.users.get_user_by_id(user_id)["username"]
@ -1962,7 +2033,19 @@ class PanelHandler(BaseHandler):
else:
superuser = 0
if not exec_user["superuser"]:
if exec_user["superuser"]:
manager = self.get_argument("manager")
if manager == "":
manager = None
else:
manager = int(manager)
else:
manager = user["manager"]
if (
not exec_user["superuser"]
and int(exec_user["user_id"]) != user["manager"]
):
if username is None or username == "":
self.redirect("/panel/error?error=Invalid username")
return
@ -2013,6 +2096,7 @@ class PanelHandler(BaseHandler):
user_data = {
"username": username,
"manager": manager,
"password": password0,
"email": email,
"enabled": enabled,
@ -2158,6 +2242,15 @@ class PanelHandler(BaseHandler):
if username is None or username == "":
self.redirect("/panel/error?error=Invalid username")
return
if exec_user["superuser"]:
manager = self.get_argument("manager")
if manager == "":
manager = None
else:
manager = int(manager)
else:
manager = int(exec_user["user_id"])
# does this user id exist?
if self.controller.users.get_id_by_name(username) is not None:
self.redirect("/panel/error?error=User exists")
@ -2172,6 +2265,7 @@ class PanelHandler(BaseHandler):
user_id = self.controller.users.add_user(
username,
manager=manager,
password=password0,
email=email,
enabled=enabled,
@ -2198,14 +2292,19 @@ class PanelHandler(BaseHandler):
server_id=0,
source_ip=self.get_remote_ip(),
)
self.controller.crafty_perms.add_user_creation(exec_user["user_id"])
self.redirect("/panel/panel_config")
elif page == "edit_role":
role_id = bleach.clean(self.get_argument("id", None))
role_name = bleach.clean(self.get_argument("role_name", None))
if EnumPermissionsCrafty.ROLES_CONFIG not in exec_user_crafty_permissions:
role = self.controller.roles.get_role(role_id)
if (
EnumPermissionsCrafty.ROLES_CONFIG not in exec_user_crafty_permissions
and exec_user["user_id"] != role["manager"]
and not exec_user["superuser"]
):
self.redirect(
"/panel/error?error=Unauthorized access: not a role editor"
)
@ -2221,9 +2320,18 @@ class PanelHandler(BaseHandler):
self.redirect("/panel/error?error=Invalid Role ID")
return
if exec_user["superuser"]:
manager = self.get_argument("manager", None)
if manager == "":
manager = None
else:
manager = role["manager"]
servers = self.get_role_servers()
self.controller.roles.update_role_advanced(role_id, role_name, servers)
self.controller.roles.update_role_advanced(
role_id, role_name, servers, manager
)
self.controller.management.add_to_audit_log(
exec_user["user_id"],
@ -2235,6 +2343,12 @@ class PanelHandler(BaseHandler):
elif page == "add_role":
role_name = bleach.clean(self.get_argument("role_name", None))
if exec_user["superuser"]:
manager = self.get_argument("manager", None)
if manager == "":
manager = None
else:
manager = exec_user["user_id"]
if EnumPermissionsCrafty.ROLES_CONFIG not in exec_user_crafty_permissions:
self.redirect(
@ -2259,7 +2373,9 @@ class PanelHandler(BaseHandler):
servers = self.get_role_servers()
role_id = self.controller.roles.add_role_advanced(role_name, servers)
role_id = self.controller.roles.add_role_advanced(
role_name, servers, manager
)
self.controller.management.add_to_audit_log(
exec_user["user_id"],
@ -2267,7 +2383,6 @@ class PanelHandler(BaseHandler):
server_id=0,
source_ip=self.get_remote_ip(),
)
self.controller.crafty_perms.add_role_creation(exec_user["user_id"])
self.redirect("/panel/panel_config")
else:

View File

@ -116,7 +116,9 @@ class ApiRolesIndexHandler(BaseApiHandler):
400, {"status": "error", "error": "ROLE_NAME_ALREADY_EXISTS"}
)
role_id = self.controller.roles.add_role_advanced(role_name, servers)
role_id = self.controller.roles.add_role_advanced(
role_name, servers, user["user_id"]
)
self.controller.management.add_to_audit_log(
user["user_id"],

View File

@ -665,10 +665,9 @@ class ApiServersIndexHandler(BaseApiHandler):
},
)
new_server_id, new_server_uuid = self.controller.create_api_server(data)
# Increase the server creation counter
self.controller.crafty_perms.add_server_creation(user["user_id"])
new_server_id, new_server_uuid = self.controller.create_api_server(
data, user["user_id"]
)
self.controller.servers.stats.record_stats()

View File

@ -84,6 +84,7 @@ class ApiServersServerActionHandler(BaseApiHandler):
new_server_log_file,
server_data.get("stop_command"),
server_data.get("type"),
user_id,
server_data.get("server_port"),
)

View File

@ -96,6 +96,7 @@ class ApiUsersIndexHandler(BaseApiHandler):
username = data["username"]
username = str(username).lower()
manager = int(user["user_id"])
password = data["password"]
email = data.get("email", "default@example.com")
enabled = data.get("enabled", True)
@ -149,6 +150,7 @@ class ApiUsersIndexHandler(BaseApiHandler):
# TODO: do this in the most efficient way
user_id = self.controller.users.add_user(
username,
manager,
password,
email,
enabled,

View File

@ -1,6 +1,7 @@
import json
import logging
import os
import time
import tornado.web
import tornado.escape
import bleach
@ -224,6 +225,23 @@ class ServerHandler(BaseHandler):
if server_id is not None:
if command == "clone_server":
if (
not superuser
and not self.controller.crafty_perms.can_create_server(
exec_user["user_id"]
)
):
time.sleep(3)
self.helper.websocket_helper.broadcast_user(
exec_user["user_id"],
"send_start_error",
{
"error": "<i class='fas fa-exclamation-triangle'"
" style='font-size:48px;color:red'>"
"</i> Not a server creator or server limit reached."
},
)
return
def is_name_used(name):
for server in self.controller.servers.get_all_defined_servers():
@ -231,6 +249,7 @@ class ServerHandler(BaseHandler):
return True
return
template = "/panel/dashboard"
server_data = self.controller.servers.get_server_data_by_id(
server_id
)
@ -265,6 +284,7 @@ class ServerHandler(BaseHandler):
backup_path = os.path.join(self.helper.backup_path, new_server_uuid)
server_port = server_data.get("server_port")
server_type = server_data.get("type")
created_by = exec_user["user_id"]
new_server_id = self.controller.servers.create_server(
new_server_name,
@ -276,6 +296,7 @@ class ServerHandler(BaseHandler):
new_server_log_file,
stop_command,
server_type,
created_by,
server_port,
)
if not exec_user["superuser"]:
@ -283,7 +304,8 @@ class ServerHandler(BaseHandler):
new_server_id
).get("server_uuid")
role_id = self.controller.roles.add_role(
f"Creator of Server with uuid={new_server_uuid}"
f"Creator of Server with uuid={new_server_uuid}",
exec_user["user_id"],
)
self.controller.server_perms.add_role_server(
new_server_id, role_id, "11111111"
@ -291,9 +313,6 @@ class ServerHandler(BaseHandler):
self.controller.users.add_role_to_user(
exec_user["user_id"], role_id
)
self.controller.crafty_perms.add_server_creation(
exec_user["user_id"]
)
self.controller.servers.init_all_servers()
@ -353,6 +372,7 @@ class ServerHandler(BaseHandler):
min_mem,
max_mem,
port,
exec_user["user_id"],
)
self.controller.management.add_to_audit_log(
exec_user["user_id"],
@ -369,7 +389,13 @@ class ServerHandler(BaseHandler):
return
new_server_id = self.controller.import_zip_server(
server_name, zip_path, import_server_jar, min_mem, max_mem, port
server_name,
zip_path,
import_server_jar,
min_mem,
max_mem,
port,
exec_user["user_id"],
)
if new_server_id == "false":
self.redirect(
@ -400,6 +426,7 @@ class ServerHandler(BaseHandler):
min_mem,
max_mem,
port,
exec_user["user_id"],
)
self.controller.management.add_to_audit_log(
exec_user["user_id"],
@ -418,7 +445,8 @@ class ServerHandler(BaseHandler):
new_server_id
).get("server_uuid")
role_id = self.controller.roles.add_role(
f"Creator of Server with uuid={new_server_uuid}"
f"Creator of Server with uuid={new_server_uuid}",
exec_user["user_id"],
)
self.controller.server_perms.add_role_server(
new_server_id, role_id, "11111111"
@ -426,9 +454,6 @@ class ServerHandler(BaseHandler):
self.controller.users.add_role_to_user(
exec_user["user_id"], role_id
)
self.controller.crafty_perms.add_server_creation(
exec_user["user_id"]
)
else:
for role in captured_roles:
@ -481,7 +506,11 @@ class ServerHandler(BaseHandler):
return
new_server_id = self.controller.import_bedrock_server(
server_name, import_server_path, import_server_exe, port
server_name,
import_server_path,
import_server_exe,
port,
exec_user["user_id"],
)
self.controller.management.add_to_audit_log(
exec_user["user_id"],
@ -498,7 +527,11 @@ class ServerHandler(BaseHandler):
return
new_server_id = self.controller.import_bedrock_zip_server(
server_name, zip_path, import_server_exe, port
server_name,
zip_path,
import_server_exe,
port,
exec_user["user_id"],
)
if new_server_id == "false":
self.redirect(
@ -522,7 +555,13 @@ class ServerHandler(BaseHandler):
# TODO: add server type check here and call the correct server
# add functions if not a jar
new_server_id = self.controller.create_jar_server(
server_type, server_version, server_name, min_mem, max_mem, port
server_type,
server_version,
server_name,
min_mem,
max_mem,
port,
exec_user["user_id"],
)
self.controller.management.add_to_audit_log(
exec_user["user_id"],
@ -541,7 +580,8 @@ class ServerHandler(BaseHandler):
new_server_id
).get("server_uuid")
role_id = self.controller.roles.add_role(
f"Creator of Server with uuid={new_server_uuid}"
f"Creator of Server with uuid={new_server_uuid}",
exec_user["user_id"],
)
self.controller.server_perms.add_role_server(
new_server_id, role_id, "11111111"
@ -549,9 +589,6 @@ class ServerHandler(BaseHandler):
self.controller.users.add_role_to_user(
exec_user["user_id"], role_id
)
self.controller.crafty_perms.add_server_creation(
exec_user["user_id"]
)
else:
for role in captured_roles:

View File

@ -893,9 +893,6 @@
message: '<div align="center"><i class="fas fa-spin fa-spinner"></i> &nbsp; {% raw translate("dashboard", "bePatientClone", data["lang"]) %} </div>',
closeButton: false,
});
setTimeout(function () {
location.reload();
}, 5000)
}
</script>
<script src="/static/assets/vendors/js/jquery-ui.js"></script>

View File

@ -87,6 +87,38 @@
<td><a href="/panel/edit_user?id={{user.user_id}}"><i class="fas fa-pencil-alt"></i></a></td>
</tr>
{% end %}
{% for user in data['managed_users'] %}
<tr>
<td><i class="fas fa-user"></i> {{ user.username }}</td>
<td>
{% if user.enabled %}
<span class="text-success">
<i class="fas fa-check-square"></i> Yes
</span>
{% else %}
<span class="text-danger">
<i class="far fa-times-square"></i> No
</span>
{% end %}
</td>
<td id="server_list_{{user.user_id}}">
<ul id="{{user.user_id}}">
{% for item in data['auth-servers'][user.user_id] %}
<li>{{item}}</li>
{% end %}
</ul>
</td>
<td id="role_list_{{user.user_id}}">
<ul>
{% for item in data['user-roles'][user.user_id] %}
<li data-toggle="tooltip" title="{{ item }}">{{item}}</li>
{% end %}
</ul>
</td>
<td><a href="/panel/edit_user?id={{user.user_id}}"><i class="fas fa-pencil-alt"></i></a></td>
</tr>
{% end %}
</tbody>
</table>
</div>
@ -146,6 +178,34 @@
</tr>
{% end %}
{% if not data['superuser'] %}
{% for role in data['managed_roles'] %}
{% if role.role_id not in data['assigned_roles'] %}
<tr>
<td>{{ role.role_name }}</td>
<td id="role_list_{{role.role_id}}">
<ul id="{{role.role_id}}">
{% for item in data['role-servers'][role.role_id] %}
<li>{{item}}</li>
{% end %}
</ul>
</td>
<td>
<ul>
{% for user in data['users'] %}
{% for ruser in data['user-roles'][user.user_id] %}
{% if ruser == role.role_name %}
<li>{{ user.username }}</li>
{% end %}
{% end %}
{% end %}
</ul>
</td>
<td><a href="/panel/edit_role?id={{role.role_id}}"><i class="fas fa-pencil-alt"></i></a></td>
</tr>
{% end %}
{% end %}
{% end %}
</tbody>
</table>
</div>

View File

@ -49,7 +49,7 @@
</ul>
<div class="">
<div class="">
<form class="forms-sample" method="post" action="{{ '/panel/add_role' if data['new_role'] else '/panel/edit_role' }}">
<form id="role_form" class="forms-sample" method="post" action="{{ '/panel/add_role' if data['new_role'] else '/panel/edit_role' }}">
{% raw xsrf_form_html() %}
<input type="hidden" name="id" value="{{ data['role']['role_id'] }}">
<input type="hidden" name="subpage" value="config">
@ -63,6 +63,29 @@
<label for="role_name">{{ translate('rolesConfig', 'roleName', data['lang']) }} <small class="text-muted ml-1"> - {{ translate('rolesConfig', 'roleDesc', data['lang']) }}</small> </label>
<input type="text" class="form-control" name="role_name" id="role_name" value="{{ data['role']['role_name'] }}" placeholder="Role Name" >
</div>
<br />
{% if data['superuser'] %}
<div class="form-group">
<label class="form-label" for="manager">{{ translate('rolesConfig', 'selectManager',
data['lang']) }}
</label>
<select class="form-select form-control form-control-lg select-css" id="manager" name="manager"
form="role_form">
{% if data["role_manager"]["username"] != "None" %}
<option value='{{data["role_manager"]["user_id"]}}'>{{ data["role_manager"]["username"]
}}</option>
{% end %}
<option value="">None</option>
{% for user in data['users'] %}
{% if user.user_id != data['role_manager']['user_id']
%}
<option value="{{user.user_id}}">{{user.username}}</option>
{% end %}
{% end %}
</select>
</div>
{% end %}
</div>
</div>
@ -252,6 +275,8 @@
<br />
{{ translate('rolesConfig', 'configUpdate', data['lang']) }} {{ str(data['role']['last_update']) }}
<br />
{{ translate('userConfig', 'manager', data['lang']) }}: {{ data['role_manager']['username'] }}
<br />
</p>
</blockquote>
<div class="text-center">

View File

@ -121,6 +121,27 @@ data['lang']) }}{% end %}
{% end %}
</select>
</div>
{% if data['superuser'] %}
<div class="form-group">
<label class="form-label" for="manager">{{ translate('userConfig', 'selectManager',
data['lang']) }}
</label>
<select class="form-select form-control form-control-lg select-css" id="manager" name="manager"
form="user_form">
{% if data["manager"]["username"] != "None" %}
<option value='{{data["manager"]["user_id"]}}'>{{ data["manager"]["username"]
}}</option>
{% end %}
<option value="">None</option>
{% for user in data['users'] %}
{% if user.username != data['user']['username'] and user.user_id != data['manager']['user_id']
%}
<option value="{{user.user_id}}">{{user.username}}</option>
{% end %}
{% end %}
</select>
</div>
{% end %}
</div>
</div>
@ -141,21 +162,29 @@ data['lang']) }}{% end %}
</tr>
</thead>
<tbody>
{% for role in data['roles_all'] %}
{% for role in data['roles'] %}
<tr>
{% if data['superuser'] or role.role_id in data['user']['roles'] or role.manager == data['exec_user'] %}
<td>{{ role.role_name }}</td>
<td>
{% if role.role_id in data['user']['roles'] %}
{% if role.manager == data['exec_user'] or data['superuser'] %}
<input type="checkbox" class="form-check-input"
id="role_{{ role.role_id }}_membership" name="role_{{ role.role_id }}_membership"
checked="" value="1">
{% else %}
<input type="checkbox" class="form-check-input"
id="role_{{ role.role_id }}_membership" name="role_{{ role.role_id }}_membership"
checked="" value="1" disabled>
{% end %}
{% elif data['superuser'] or role.manager == data['exec_user'] %}
<input type="checkbox" class="form-check-input"
id="role_{{ role.role_id }}_membership" name="role_{{ role.role_id }}_membership"
value="1">
{% end %}
</td>
{% end %}
</tr>
{% end %}
</tbody>
@ -268,6 +297,8 @@ data['lang']) }}{% end %}
<br />
{{ translate('userConfig', 'lastIP', data['lang']) }} {{ data['user']['last_ip'] }}
<br />
{{ translate('userConfig', 'manager', data['lang'])}}: {{data['manager']['username'] }}
<br />
</p>
</blockquote>
</div>
@ -284,7 +315,7 @@ data['lang']) }}{% end %}
{% else %}
<button class="btn btn-sm btn-danger delete-user"><i class="fas fa-trash"></i> {{
translate('userConfig', 'deleteUserB', data['lang']) }}</a>
{% end %}
{% end %}</button>
</div>
</div>

View File

@ -0,0 +1,16 @@
# Generated by database migrator
import peewee
def migrate(migrator, database, **kwargs):
migrator.add_columns("roles", manager=peewee.IntegerField(null=True))
"""
Write your migrations here.
"""
def rollback(migrator, database, **kwargs):
migrator.drop_columns("roles", ["manager"])
"""
Write your rollback migrations here.
"""

View File

@ -0,0 +1,16 @@
# Generated by database migrator
import peewee
def migrate(migrator, database, **kwargs):
migrator.add_columns("users", manager=peewee.IntegerField(null=True))
"""
Write your migrations here.
"""
def rollback(migrator, database, **kwargs):
migrator.drop_columns("users", ["manager"])
"""
Write your rollback migrations here.
"""

View File

@ -0,0 +1,16 @@
# Generated by database migrator
import peewee
def migrate(migrator, database, **kwargs):
migrator.add_columns("servers", created_by=peewee.IntegerField(default=-100))
"""
Write your migrations here.
"""
def rollback(migrator, database, **kwargs):
migrator.drop_columns("servers", ["created_by"])
"""
Write your rollback migrations here.
"""

View File

@ -0,0 +1,20 @@
# Generated by database migrator
import peewee
def migrate(migrator, database, **kwargs):
migrator.drop_columns("user_crafty", ["created_server"])
migrator.drop_columns("user_crafty", ["created_user"])
migrator.drop_columns("user_crafty", ["created_role"])
"""
Write your migrations here.
"""
def rollback(migrator, database, **kwargs):
migrator.add_columns("user_crafty", created_server=peewee.IntegerField(default=0))
migrator.add_columns("user_crafty", created_user=peewee.IntegerField(default=0))
migrator.add_columns("user_crafty", created_role=peewee.IntegerField(default=0))
"""
Write your rollback migrations here.
"""

View File

@ -245,7 +245,8 @@
"roleUsers": "Role Users: ",
"serverAccess": "Access?",
"serverName": "Server Name",
"serversDesc": "servers this role is allowed to access"
"serversDesc": "servers this role is allowed to access",
"selectManager": "Select a manager for this Role"
},
"serverBackups": {
"backupAtMidnight": "Auto-backup at midnight?",
@ -556,6 +557,8 @@
"userRoles": "User Roles",
"userRolesDesc": "Roles this user is a member of.",
"userSettings": "User Settings",
"uses": "Number of uses allowed (-1==No Limit)"
"uses": "Number of uses allowed (-1==No Limit)",
"manager": "Manager",
"selectManager": "Select Manager for User"
}
}