mirror of
https://gitlab.com/crafty-controller/crafty-4.git
synced 2024-08-30 18:23:09 +00:00
Merge branch 'dev' into dev_websocket_server_status
This commit is contained in:
commit
bae08d05d9
@ -40,13 +40,11 @@ class Management_Controller:
|
||||
|
||||
@staticmethod
|
||||
def send_command(user_id, server_id, remote_ip, command):
|
||||
|
||||
server_name = servers_helper.get_server_friendly_name(server_id)
|
||||
|
||||
# Example: Admin issued command start_server for server Survival
|
||||
management_helper.add_to_audit_log(user_id, "issued command {} for server {}".format(command, server_name),
|
||||
server_id, remote_ip)
|
||||
|
||||
management_helper.add_command(server_id, user_id, remote_ip, command)
|
||||
|
||||
@staticmethod
|
||||
|
@ -100,9 +100,7 @@ class Servers_Controller:
|
||||
@staticmethod
|
||||
def get_authorized_servers_stats(user_id):
|
||||
server_data = []
|
||||
print('test 1')
|
||||
authorized_servers = Servers_Controller.get_authorized_servers(user_id)
|
||||
print('test 2')
|
||||
|
||||
for s in authorized_servers:
|
||||
latest = servers_helper.get_latest_server_stats(s.get('server_id'))
|
||||
@ -137,11 +135,10 @@ class Servers_Controller:
|
||||
|
||||
@staticmethod
|
||||
def server_id_authorized(server_id_a, user_id):
|
||||
print("Server id authorized: ")
|
||||
user_roles = users_helper.user_role_query(user_id)
|
||||
for role in user_roles:
|
||||
for server_id_b in server_permissions.get_role_servers_from_role_id(role.role_id):
|
||||
if server_id_a == server_id_b:
|
||||
if str(server_id_a) == str(server_id_b.server_id):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
@ -12,6 +12,7 @@ from app.classes.shared.console import console
|
||||
from app.classes.models.servers import Servers
|
||||
from app.classes.minecraft.server_props import ServerProps
|
||||
from app.classes.web.websocket_helper import websocket_helper
|
||||
from app.classes.models.server_permissions import server_permissions
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@ -190,7 +191,6 @@ class ServerJars:
|
||||
except Exception as e:
|
||||
logger.error("Unable to save jar to {path} due to error:{error}".format(path=path, error=e))
|
||||
pass
|
||||
websocket_helper.broadcast('notification', "Executable download finished for server named: " + name)
|
||||
|
||||
|
||||
return False
|
||||
|
@ -9,6 +9,8 @@ from app.classes.shared.main_models import db_helper
|
||||
from app.classes.models.users import Users, users_helper
|
||||
from app.classes.models.servers import Servers, servers_helper
|
||||
from app.classes.web.websocket_helper import websocket_helper
|
||||
from app.classes.models.server_permissions import server_permissions
|
||||
import time
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@ -156,7 +158,7 @@ class helpers_management:
|
||||
@staticmethod
|
||||
def get_unactioned_commands():
|
||||
query = Commands.select().where(Commands.executed == 0)
|
||||
return db_helper.return_rows(query)
|
||||
return query
|
||||
|
||||
@staticmethod
|
||||
def mark_command_complete(command_id=None):
|
||||
@ -181,7 +183,9 @@ class helpers_management:
|
||||
|
||||
audit_msg = "{} {}".format(str(user_data['username']).capitalize(), log_msg)
|
||||
|
||||
websocket_helper.broadcast('notification', audit_msg)
|
||||
server_users = server_permissions.get_server_user_list(server_id)
|
||||
for user in server_users:
|
||||
websocket_helper.broadcast_user(user,'notification', audit_msg)
|
||||
|
||||
Audit_Log.insert({
|
||||
Audit_Log.user_name: user_data['username'],
|
||||
|
@ -7,7 +7,7 @@ from app.classes.shared.helpers import helper
|
||||
from app.classes.shared.console import console
|
||||
from app.classes.models.servers import Servers
|
||||
from app.classes.models.roles import Roles
|
||||
from app.classes.models.users import users_helper, ApiKeys, Users
|
||||
from app.classes.models.users import User_Roles, users_helper, ApiKeys, Users
|
||||
from app.classes.shared.permission_helper import permission_helper
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@ -172,11 +172,26 @@ class Permissions_Servers:
|
||||
if user.superuser:
|
||||
permissions_mask = '1' * len(server_permissions.get_permissions_list())
|
||||
else:
|
||||
roles_list = users_helper.get_user_roles_id(user['user_id'])
|
||||
roles_list = users_helper.get_user_roles_id(user.user_id)
|
||||
role_server = Role_Servers.select().where(Role_Servers.role_id.in_(roles_list)).where(Role_Servers.server_id == server_id).execute()
|
||||
permissions_mask = role_server[0].permissions
|
||||
return permissions_mask
|
||||
|
||||
@staticmethod
|
||||
def get_server_user_list(server_id):
|
||||
final_users = []
|
||||
server_roles = Role_Servers.select().where(Role_Servers.server_id == server_id)
|
||||
super_users = Users.select().where(Users.superuser == True)
|
||||
for role in server_roles:
|
||||
users = User_Roles.select().where(User_Roles.role_id == role.role_id)
|
||||
for user in users:
|
||||
if user.user_id.user_id not in final_users:
|
||||
final_users.append(user.user_id.user_id)
|
||||
for suser in super_users:
|
||||
if suser.user_id not in final_users:
|
||||
final_users.append(suser.user_id)
|
||||
return final_users
|
||||
|
||||
@staticmethod
|
||||
def get_user_id_permissions_list(user_id, server_id: str):
|
||||
user = users_helper.get_user_model(user_id)
|
||||
|
@ -174,6 +174,15 @@ class helper_users:
|
||||
if up_data:
|
||||
Users.update(up_data).where(Users.user_id == user_id).execute()
|
||||
|
||||
@staticmethod
|
||||
def get_super_user_list():
|
||||
final_users = []
|
||||
super_users = Users.select().where(Users.superuser == True)
|
||||
for suser in super_users:
|
||||
if suser.user_id not in final_users:
|
||||
final_users.append(suser.user_id)
|
||||
return final_users
|
||||
|
||||
@staticmethod
|
||||
def remove_user(user_id):
|
||||
with database.atomic():
|
||||
|
@ -137,6 +137,8 @@ class Controller:
|
||||
|
||||
|
||||
def package_support_logs(self, exec_user):
|
||||
#pausing so on screen notifications can run for user
|
||||
time.sleep(7)
|
||||
websocket_helper.broadcast_user(exec_user['user_id'], 'notification', 'Preparing your support logs')
|
||||
tempDir = tempfile.mkdtemp()
|
||||
tempZipStorage = tempfile.mkdtemp()
|
||||
@ -161,7 +163,10 @@ class Controller:
|
||||
for server in auth_servers:
|
||||
final_path = os.path.join(server_path, str(server['server_name']))
|
||||
os.mkdir(final_path)
|
||||
shutil.copy(server['log_path'], final_path)
|
||||
try:
|
||||
shutil.copy(server['log_path'], final_path)
|
||||
except Exception as e:
|
||||
logger.warning("Failed to copy file with error: {}".format(e))
|
||||
#Copy crafty logs to archive dir
|
||||
full_log_name = os.path.join(crafty_path, 'logs')
|
||||
shutil.copytree(os.path.join(self.project_root, 'logs'), full_log_name)
|
||||
@ -195,7 +200,7 @@ class Controller:
|
||||
|
||||
def get_server_data(self, server_id: str):
|
||||
for s in self.servers_list:
|
||||
if s['server_id'] == server_id:
|
||||
if str(s['server_id']) == str(server_id):
|
||||
return s['server_data_obj']
|
||||
|
||||
logger.warning("Unable to find server object for server id {}".format(server_id))
|
||||
@ -281,7 +286,12 @@ class Controller:
|
||||
logger.error("Unable to create required server files due to :{}".format(e))
|
||||
return False
|
||||
|
||||
server_command = 'java -Xms{}M -Xmx{}M -jar "{}" nogui'.format(helper.float_to_string(min_mem),
|
||||
if helper.is_os_windows():
|
||||
server_command = 'java -Xms{}M -Xmx{}M -jar "{}" nogui'.format(helper.float_to_string(min_mem),
|
||||
helper.float_to_string(max_mem),
|
||||
full_jar_path)
|
||||
else:
|
||||
server_command = 'java -Xms{}M -Xmx{}M -jar {} nogui'.format(helper.float_to_string(min_mem),
|
||||
helper.float_to_string(max_mem),
|
||||
full_jar_path)
|
||||
server_log_file = "{}/logs/latest.log".format(server_dir)
|
||||
@ -315,7 +325,7 @@ class Controller:
|
||||
new_server_dir = os.path.join(helper.servers_dir, server_id)
|
||||
backup_path = os.path.join(helper.backup_path, server_id)
|
||||
if helper.is_os_windows():
|
||||
server_dir = helper.wtol_path(new_server_dir)
|
||||
new_server_dir = helper.wtol_path(new_server_dir)
|
||||
backup_path = helper.wtol_path(backup_path)
|
||||
new_server_dir.replace(' ', '^ ')
|
||||
backup_path.replace(' ', '^ ')
|
||||
@ -337,9 +347,14 @@ class Controller:
|
||||
|
||||
full_jar_path = os.path.join(new_server_dir, server_jar)
|
||||
|
||||
server_command = 'java -Xms{}M -Xmx{}M -jar {} nogui'.format(helper.float_to_string(min_mem),
|
||||
if helper.is_os_windows():
|
||||
server_command = 'java -Xms{}M -Xmx{}M -jar {} nogui'.format(helper.float_to_string(min_mem),
|
||||
helper.float_to_string(max_mem),
|
||||
+'"'+full_jar_path+'"')
|
||||
'"'+full_jar_path+'"')
|
||||
else:
|
||||
server_command = 'java -Xms{}M -Xmx{}M -jar {} nogui'.format(helper.float_to_string(min_mem),
|
||||
helper.float_to_string(max_mem),
|
||||
full_jar_path)
|
||||
server_log_file = "{}/logs/latest.log".format(new_server_dir)
|
||||
server_stop = "stop"
|
||||
|
||||
@ -377,9 +392,14 @@ class Controller:
|
||||
|
||||
full_jar_path = os.path.join(new_server_dir, server_jar)
|
||||
|
||||
server_command = 'java -Xms{}M -Xmx{}M -jar {} nogui'.format(helper.float_to_string(min_mem),
|
||||
if helper.is_os_windows():
|
||||
server_command = 'java -Xms{}M -Xmx{}M -jar {} nogui'.format(helper.float_to_string(min_mem),
|
||||
helper.float_to_string(max_mem),
|
||||
+'"'+full_jar_path+'"')
|
||||
'"'+full_jar_path+'"')
|
||||
else:
|
||||
server_command = 'java -Xms{}M -Xmx{}M -jar {} nogui'.format(helper.float_to_string(min_mem),
|
||||
helper.float_to_string(max_mem),
|
||||
full_jar_path)
|
||||
logger.debug('command: ' + server_command)
|
||||
server_log_file = "{}/logs/latest.log".format(new_server_dir)
|
||||
server_stop = "stop"
|
||||
@ -430,7 +450,7 @@ class Controller:
|
||||
for s in self.servers_list:
|
||||
|
||||
# if this is the droid... im mean server we are looking for...
|
||||
if s['server_id'] == server_id:
|
||||
if str(s['server_id']) == str(server_id):
|
||||
server_data = self.get_server_data(server_id)
|
||||
server_name = server_data['server_name']
|
||||
backup_dir = self.servers.get_server_data_by_id(server_id)['backup_path']
|
||||
|
@ -25,6 +25,7 @@ from app.classes.models.management import management_helper
|
||||
from app.classes.web.websocket_helper import websocket_helper
|
||||
from app.classes.shared.translation import translation
|
||||
from app.classes.models.users import users_helper
|
||||
from app.classes.models.server_permissions import server_permissions
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@ -383,11 +384,10 @@ class Server:
|
||||
return False
|
||||
|
||||
def send_command(self, command):
|
||||
console.info("COMMAND TIME: {}".format(command))
|
||||
if not self.check_running() and command.lower() != 'start':
|
||||
logger.warning("Server not running, unable to send command \"{}\"".format(command))
|
||||
return False
|
||||
|
||||
console.info("COMMAND TIME: {}".format(command))
|
||||
logger.debug("Sending command {} to server".format(command))
|
||||
|
||||
# send it
|
||||
@ -477,7 +477,7 @@ class Server:
|
||||
def remove_watcher_thread(self):
|
||||
logger.info("Removing old crash detection watcher thread")
|
||||
console.info("Removing old crash detection watcher thread")
|
||||
schedule.clear(self.name)
|
||||
self.crash_watcher_schedule.remove(self.server_name)
|
||||
|
||||
def agree_eula(self, user_id):
|
||||
file = os.path.join(self.server_path, 'eula.txt')
|
||||
@ -610,7 +610,9 @@ class Server:
|
||||
if len(websocket_helper.clients) > 0:
|
||||
# There are clients
|
||||
self.check_update()
|
||||
websocket_helper.broadcast('notification', "Executable update finished for " + self.name)
|
||||
server_users = server_permissions.get_server_user_list(self.server_id)
|
||||
for user in server_users:
|
||||
websocket_helper.broadcast_user(user, 'notification', "Executable update finished for " + self.name)
|
||||
time.sleep(3)
|
||||
websocket_helper.broadcast_page('/panel/server_detail', 'update_button_status', {
|
||||
'isUpdating': self.check_update(),
|
||||
@ -619,15 +621,18 @@ class Server:
|
||||
})
|
||||
websocket_helper.broadcast_page('/panel/dashboard', 'send_start_reload', {
|
||||
})
|
||||
websocket_helper.broadcast('notification', "Executable update finished for "+self.name)
|
||||
server_users = server_permissions.get_server_user_list(self.server_id)
|
||||
for user in server_users:
|
||||
websocket_helper.broadcast_user(user, 'notification', "Executable update finished for "+self.name)
|
||||
|
||||
management_helper.add_to_audit_log_raw('Alert', '-1', self.server_id, "Executable update finished for "+self.name, self.settings['server_ip'])
|
||||
if wasStarted:
|
||||
self.start_server()
|
||||
elif not downloaded and not self.is_backingup:
|
||||
time.sleep(5)
|
||||
servers_helper.set_update(self.server_id, False)
|
||||
websocket_helper.broadcast('notification',
|
||||
server_users = server_permissions.get_server_user_list(self.server_id)
|
||||
for user in server_users:
|
||||
websocket_helper.broadcast_user(user,'notification',
|
||||
"Executable update failed for " + self.name + ". Check log file for details.")
|
||||
logger.error("Executable download failed.")
|
||||
pass
|
||||
|
@ -26,6 +26,7 @@ logger = logging.getLogger('apscheduler')
|
||||
|
||||
try:
|
||||
from apscheduler.schedulers.background import BackgroundScheduler
|
||||
from apscheduler.triggers.cron import CronTrigger
|
||||
|
||||
except ModuleNotFoundError as e:
|
||||
logger.critical("Import Error: Unable to load {} module".format(e.name), exc_info=True)
|
||||
@ -52,8 +53,8 @@ class TasksManager:
|
||||
self.controller = controller
|
||||
self.tornado = Webserver(controller, self)
|
||||
|
||||
tz = get_localzone()
|
||||
self.scheduler = BackgroundScheduler(timezone=str(tz))
|
||||
self.tz = get_localzone()
|
||||
self.scheduler = BackgroundScheduler(timezone=str(self.tz))
|
||||
|
||||
self.users_controller = Users_Controller()
|
||||
|
||||
@ -86,10 +87,14 @@ class TasksManager:
|
||||
# select any commands waiting to be processed
|
||||
commands = management_helper.get_unactioned_commands()
|
||||
for c in commands:
|
||||
|
||||
svr = self.controller.get_server_obj(c['server_id']['server_id'])
|
||||
user_id = c.get('user')['user_id']
|
||||
command = c.get('command', None)
|
||||
try:
|
||||
svr = self.controller.get_server_obj(c.server_id)
|
||||
except:
|
||||
logger.error("Server value requested does note exist purging item from waiting commands.")
|
||||
management_helper.mark_command_complete(c.command_id)
|
||||
|
||||
user_id = c.user_id
|
||||
command = c.command
|
||||
|
||||
if command == 'start_server':
|
||||
svr.run_threaded_server(user_id)
|
||||
@ -107,7 +112,7 @@ class TasksManager:
|
||||
svr.jar_update()
|
||||
else:
|
||||
svr.send_command(command)
|
||||
management_helper.mark_command_complete(c.get('command_id', None))
|
||||
management_helper.mark_command_complete(c.command_id)
|
||||
|
||||
time.sleep(1)
|
||||
|
||||
@ -154,11 +159,19 @@ class TasksManager:
|
||||
schedules = management_helper.get_schedules_enabled()
|
||||
self.scheduler.add_listener(self.schedule_watcher, mask=EVENT_JOB_EXECUTED)
|
||||
#self.scheduler.add_job(self.scheduler.print_jobs, 'interval', seconds=10, id='-1')
|
||||
|
||||
#load schedules from DB
|
||||
for schedule in schedules:
|
||||
if schedule.cron_string != "":
|
||||
cron = schedule.cron_string.split(' ')
|
||||
self.scheduler.add_job(management_helper.add_command, 'cron', minute = cron[0], hour = cron[1], day = cron[2], month = cron[3], day_of_week = cron[4], id=str(schedule.schedule_id), args=[schedule.server_id, self.users_controller.get_id_by_name('system'), '127.0.0.1', schedule.command])
|
||||
try:
|
||||
self.scheduler.add_job(management_helper.add_command, CronTrigger.from_crontab(schedule.cron_string, timezone=str(self.tz)), id=str(schedule.schedule_id), args=[schedule.server_id, self.users_controller.get_id_by_name('system'), '127.0.0.1', schedule.command])
|
||||
except Exception as e:
|
||||
console.error("Failed to schedule task with error: {}.".format(e))
|
||||
console.warning("Removing failed task from DB.")
|
||||
logger.error("Failed to schedule task with error: {}.".format(e))
|
||||
logger.warning("Removing failed task from DB.")
|
||||
#remove items from DB if task fails to add to apscheduler
|
||||
management_helper.delete_scheduled_task(schedule.schedule_id)
|
||||
else:
|
||||
if schedule.interval_type == 'hours':
|
||||
self.scheduler.add_job(management_helper.add_command, 'cron', minute = 0, hour = '*/'+str(schedule.interval), id=str(schedule.schedule_id), args=[schedule.server_id, self.users_controller.get_id_by_name('system'), '127.0.0.1', schedule.command])
|
||||
@ -178,12 +191,14 @@ class TasksManager:
|
||||
sch_id = management_helper.create_scheduled_task(job_data['server_id'], job_data['action'], job_data['interval'], job_data['interval_type'], job_data['start_time'], job_data['command'], "None", job_data['enabled'], job_data['one_time'], job_data['cron_string'])
|
||||
if job_data['enabled']:
|
||||
if job_data['cron_string'] != "":
|
||||
cron = job_data['cron_string'].split(' ')
|
||||
try:
|
||||
self.scheduler.add_job(management_helper.add_command, 'cron', minute = cron[0], hour = cron[1], day = cron[2], month = cron[3], day_of_week = cron[4], id=str(sch_id), args=[job_data['server_id'], self.users_controller.get_id_by_name('system'), '127.0.0.1', job_data['command']])
|
||||
self.scheduler.add_job(management_helper.add_command, CronTrigger.from_crontab(job_data['cron_string'], timezone=str(self.tz)), id=str(sch_id), args=[job_data['server_id'], self.users_controller.get_id_by_name('system'), '127.0.0.1', job_data['command']])
|
||||
except Exception as e:
|
||||
console.error("Failed to schedule task with error: {}.".format(e))
|
||||
console.info("Removing failed task from DB.")
|
||||
console.warning("Removing failed task from DB.")
|
||||
logger.error("Failed to schedule task with error: {}.".format(e))
|
||||
logger.warning("Removing failed task from DB.")
|
||||
#remove items from DB if task fails to add to apscheduler
|
||||
management_helper.delete_scheduled_task(sch_id)
|
||||
else:
|
||||
if job_data['interval_type'] == 'hours':
|
||||
|
@ -199,6 +199,14 @@ class AjaxHandler(BaseHandler):
|
||||
|
||||
srv_obj = self.controller.get_server_obj(server_id)
|
||||
|
||||
if command == srv_obj.settings['stop_command']:
|
||||
logger.info("Stop command detected as terminal input - intercepting. Starting Crafty's stop process for server with id: {}.".format(server_id))
|
||||
self.controller.management.send_command(exec_user['user_id'], server_id, self.get_remote_ip(), 'stop_server')
|
||||
command = None
|
||||
elif command == 'restart':
|
||||
logger.info("Restart command detected as terminal input - intercepting. Starting Crafty's stop process for server with id: {}.".format(server_id))
|
||||
self.controller.management.send_command(exec_user['user_id'], server_id, self.get_remote_ip(), 'restart_server')
|
||||
command = None
|
||||
if command:
|
||||
if srv_obj.check_running():
|
||||
srv_obj.send_command(command)
|
||||
@ -419,7 +427,7 @@ class AjaxHandler(BaseHandler):
|
||||
server_data = self.controller.get_server_data(server_id)
|
||||
server_name = server_data['server_name']
|
||||
|
||||
self.controller.management.add_to_audit_log(exec_user_id,
|
||||
self.controller.management.add_to_audit_log(exec_user['user_id'],
|
||||
"Deleted server {} named {}".format(server_id, server_name),
|
||||
server_id,
|
||||
self.get_remote_ip())
|
||||
@ -439,7 +447,7 @@ class AjaxHandler(BaseHandler):
|
||||
server_data = self.controller.get_server_data(server_id)
|
||||
server_name = server_data['server_name']
|
||||
|
||||
self.controller.management.add_to_audit_log(exec_user_id,
|
||||
self.controller.management.add_to_audit_log(exec_user['user_id'],
|
||||
"Deleted server {} named {}".format(server_id, server_name),
|
||||
server_id,
|
||||
self.get_remote_ip())
|
||||
|
@ -17,6 +17,8 @@ import threading
|
||||
from cron_validator import CronValidator
|
||||
#TZLocal is set as a hidden import on win pipeline
|
||||
from tzlocal import get_localzone
|
||||
import libgravatar
|
||||
import requests
|
||||
|
||||
from tornado import locale, iostream
|
||||
from tornado.ioloop import IOLoop
|
||||
@ -128,7 +130,7 @@ class PanelHandler(BaseHandler):
|
||||
# increasing and will eat up the RAM
|
||||
del chunk
|
||||
|
||||
def check_server_id(self) -> Optional[str]:
|
||||
def check_server_id(self):
|
||||
server_id = self.get_argument('id', None)
|
||||
|
||||
api_key, _, exec_user = self.current_user
|
||||
@ -244,6 +246,24 @@ class PanelHandler(BaseHandler):
|
||||
} if api_key is not None else None,
|
||||
'superuser': superuser
|
||||
}
|
||||
if helper.get_setting("allow_nsfw_profile_pictures"):
|
||||
rating = "x"
|
||||
else:
|
||||
rating = "g"
|
||||
|
||||
|
||||
#Get grvatar hash for profile pictures
|
||||
if exec_user['email'] != 'default@example.com' or "":
|
||||
g = libgravatar.Gravatar(libgravatar.sanitize_email(exec_user['email']))
|
||||
url = g.get_image(size=80, default="404", force_default=False, rating=rating, filetype_extension=False, use_ssl=True) # + "?d=404"
|
||||
if requests.head(url).status_code != 404:
|
||||
profile_url = url
|
||||
else:
|
||||
profile_url = "/static/assets/images/faces-clipart/pic-3.png"
|
||||
else:
|
||||
profile_url = "/static/assets/images/faces-clipart/pic-3.png"
|
||||
|
||||
page_data['user_image'] = profile_url
|
||||
|
||||
if page == 'unauthorized':
|
||||
template = "panel/denied.html"
|
||||
@ -539,7 +559,6 @@ class PanelHandler(BaseHandler):
|
||||
'Players': Enum_Permissions_Server.Players,
|
||||
}
|
||||
page_data['user_permissions'] = self.controller.server_perms.get_user_id_permissions_list(exec_user["user_id"], server_id)
|
||||
exec_user_server_permissions = self.controller.server_perms.get_user_permissions_list(exec_user["user_id"], server_id)
|
||||
page_data['server_data'] = self.controller.servers.get_server_data_by_id(server_id)
|
||||
page_data['server_stats'] = self.controller.servers.get_server_stats_by_id(server_id)
|
||||
page_data['new_schedule'] = True
|
||||
@ -557,7 +576,7 @@ class PanelHandler(BaseHandler):
|
||||
page_data['schedule']['difficulty'] = "basic"
|
||||
page_data['schedule']['interval_type'] = 'days'
|
||||
|
||||
if not Enum_Permissions_Server.Schedule in exec_user_server_permissions:
|
||||
if not Enum_Permissions_Server.Schedule in page_data['user_permissions']:
|
||||
if not superuser:
|
||||
self.redirect("/panel/error?error=Unauthorized access To Scheduled Tasks")
|
||||
return
|
||||
@ -581,7 +600,6 @@ class PanelHandler(BaseHandler):
|
||||
'Players': Enum_Permissions_Server.Players,
|
||||
}
|
||||
page_data['user_permissions'] = self.controller.server_perms.get_user_id_permissions_list(exec_user["user_id"], server_id)
|
||||
exec_user_server_permissions = self.controller.server_perms.get_user_permissions_list(exec_user["user_id"], server_id)
|
||||
page_data['server_data'] = self.controller.servers.get_server_data_by_id(server_id)
|
||||
page_data['server_stats'] = self.controller.servers.get_server_stats_by_id(server_id)
|
||||
page_data['new_schedule'] = False
|
||||
@ -609,7 +627,7 @@ class PanelHandler(BaseHandler):
|
||||
if sch_id == None or server_id == None:
|
||||
self.redirect("/panel/error?error=Invalid server ID or Schedule ID")
|
||||
|
||||
if not Enum_Permissions_Server.Schedule in exec_user_server_permissions:
|
||||
if not Enum_Permissions_Server.Schedule in page_data['user_permissions']:
|
||||
if not superuser:
|
||||
self.redirect("/panel/error?error=Unauthorized access To Scheduled Tasks")
|
||||
return
|
||||
@ -864,7 +882,6 @@ class PanelHandler(BaseHandler):
|
||||
'Config': Enum_Permissions_Server.Config,
|
||||
'Players': Enum_Permissions_Server.Players,
|
||||
}
|
||||
user_perms = self.controller.server_perms.get_user_id_permissions_list(exec_user["user_id"], server_id)
|
||||
exec_user_role = set()
|
||||
if superuser:
|
||||
# defined_servers = self.controller.list_defined_servers()
|
||||
@ -878,7 +895,7 @@ class PanelHandler(BaseHandler):
|
||||
exec_user_role.add(role['role_name'])
|
||||
|
||||
if page == 'server_detail':
|
||||
if not permissions['Config'] in user_perms:
|
||||
if not permissions['Config'] in self.controller.server_perms.get_user_id_permissions_list(exec_user["user_id"], server_id):
|
||||
if not superuser:
|
||||
self.redirect("/panel/error?error=Unauthorized access to Config")
|
||||
return
|
||||
@ -886,7 +903,13 @@ class PanelHandler(BaseHandler):
|
||||
server_obj = self.controller.servers.get_server_obj(server_id)
|
||||
if superuser:
|
||||
server_path = self.get_argument('server_path', None)
|
||||
if helper.is_os_windows():
|
||||
server_path.replace(' ', '^ ')
|
||||
server_path = helper.wtol_path(server_path)
|
||||
log_path = self.get_argument('log_path', None)
|
||||
if helper.is_os_windows():
|
||||
log_path.replace(' ', '^ ')
|
||||
log_path = helper.wtol_path(log_path)
|
||||
executable = self.get_argument('executable', None)
|
||||
execution_command = self.get_argument('execution_command', None)
|
||||
server_ip = self.get_argument('server_ip', None)
|
||||
@ -955,11 +978,14 @@ class PanelHandler(BaseHandler):
|
||||
server_obj = self.controller.servers.get_server_obj(server_id)
|
||||
if superuser:
|
||||
backup_path = bleach.clean(self.get_argument('backup_path', None))
|
||||
if helper.is_os_windows():
|
||||
backup_path.replace(' ', '^ ')
|
||||
backup_path = helper.wtol_path(backup_path)
|
||||
else:
|
||||
backup_path = server_obj.backup_path
|
||||
max_backups = bleach.clean(self.get_argument('max_backups', None))
|
||||
|
||||
if not permissions['Backup'] in user_perms:
|
||||
if not permissions['Backup'] in self.controller.server_perms.get_user_id_permissions_list(exec_user["user_id"], server_id):
|
||||
if not superuser:
|
||||
self.redirect("/panel/error?error=Unauthorized access: User not authorized")
|
||||
return
|
||||
@ -1035,7 +1061,7 @@ class PanelHandler(BaseHandler):
|
||||
else:
|
||||
one_time = False
|
||||
|
||||
if not superuser and not permissions['Backup'] in user_perms:
|
||||
if not superuser and not permissions['Backup'] in self.controller.server_perms.get_user_id_permissions_list(exec_user["user_id"], server_id):
|
||||
self.redirect("/panel/error?error=Unauthorized access: User not authorized")
|
||||
return
|
||||
elif server_id is None:
|
||||
@ -1155,7 +1181,7 @@ class PanelHandler(BaseHandler):
|
||||
else:
|
||||
one_time = False
|
||||
|
||||
if not superuser and not permissions['Backup'] in user_perms:
|
||||
if not superuser and not permissions['Backup'] in self.controller.server_perms.get_user_id_permissions_list(exec_user["user_id"], server_id):
|
||||
self.redirect("/panel/error?error=Unauthorized access: User not authorized")
|
||||
return
|
||||
elif server_id is None:
|
||||
|
@ -120,23 +120,6 @@ class PublicHandler(BaseHandler):
|
||||
# log this login
|
||||
self.controller.management.add_to_audit_log(user_data.user_id, "Logged in", 0, self.get_remote_ip())
|
||||
|
||||
if helper.get_setting("allow_nsfw_profile_pictures"):
|
||||
rating = "x"
|
||||
else:
|
||||
rating = "g"
|
||||
|
||||
|
||||
#Get grvatar hash for profile pictures
|
||||
if user_data.email != 'default@example.com' or "":
|
||||
g = libgravatar.Gravatar(libgravatar.sanitize_email(user_data.email))
|
||||
url = g.get_image(size=80, default="404", force_default=False, rating=rating, filetype_extension=False, use_ssl=True) # + "?d=404"
|
||||
if requests.head(url).status_code != 404:
|
||||
profile_url = url
|
||||
else:
|
||||
profile_url = "/static/assets/images/faces-clipart/pic-3.png"
|
||||
else:
|
||||
profile_url = "/static/assets/images/faces-clipart/pic-3.png"
|
||||
|
||||
next_page = "/panel/dashboard"
|
||||
self.redirect(next_page)
|
||||
else:
|
||||
|
@ -9,6 +9,8 @@ from app.classes.web.base_handler import BaseHandler
|
||||
from app.classes.models.crafty_permissions import Enum_Permissions_Crafty
|
||||
from app.classes.minecraft.serverjars import server_jar_obj
|
||||
from app.classes.shared.helpers import helper
|
||||
import libgravatar
|
||||
import requests
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@ -81,6 +83,23 @@ class ServerHandler(BaseHandler):
|
||||
} if api_key is not None else None,
|
||||
'superuser': superuser
|
||||
}
|
||||
if helper.get_setting("allow_nsfw_profile_pictures"):
|
||||
rating = "x"
|
||||
else:
|
||||
rating = "g"
|
||||
|
||||
|
||||
if exec_user['email'] != 'default@example.com' or "":
|
||||
g = libgravatar.Gravatar(libgravatar.sanitize_email(exec_user['email']))
|
||||
url = g.get_image(size=80, default="404", force_default=False, rating=rating, filetype_extension=False, use_ssl=True) # + "?d=404"
|
||||
if requests.head(url).status_code != 404:
|
||||
profile_url = url
|
||||
else:
|
||||
profile_url = "/static/assets/images/faces-clipart/pic-3.png"
|
||||
else:
|
||||
profile_url = "/static/assets/images/faces-clipart/pic-3.png"
|
||||
|
||||
page_data['user_image'] = profile_url
|
||||
if superuser:
|
||||
page_data['roles'] = list_roles
|
||||
|
||||
|
@ -18,10 +18,10 @@
|
||||
|
||||
<li class="nav-item dropdown user-dropdown">
|
||||
<a class="nav-link dropdown-toggle" id="UserDropdown" href="#" data-toggle="dropdown" aria-expanded="false">
|
||||
<img class="img-xs rounded-circle profile-picture" src="{{ data['user_data'].get('profile_url') }}" alt="Profile image"> </a>
|
||||
<img class="img-xs rounded-circle profile-picture" src="{{ data['user_image'] }}" alt="Profile image"> </a>
|
||||
<div class="dropdown-menu dropdown-menu-right navbar-dropdown" aria-labelledby="UserDropdown">
|
||||
<div class="dropdown-header text-center">
|
||||
<img class="img-md rounded-circle profile-picture" src="{{ data['user_data'].get('profile_url') }}" alt="Profile image">
|
||||
<img class="img-md rounded-circle profile-picture" src="{{ data['user_image'] }}" alt="Profile image">
|
||||
<p class="mb-1 mt-3 font-weight-semibold">{{ data['user_data']['username'] }}</p>
|
||||
<p class="font-weight-light text-muted mb-0">Roles: </p>
|
||||
{% for r in data['user_role'] %}
|
||||
|
@ -3,7 +3,7 @@
|
||||
{% block meta %}
|
||||
{% end %}
|
||||
|
||||
{% block title %}Crafty Controller - Panel Config{% end %}
|
||||
{% block title %}Crafty Controller - {{ translate('panelConfig', 'pageTitle', data['lang']) }}{% end %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
@ -14,7 +14,7 @@
|
||||
<div class="col-12">
|
||||
<div class="page-header">
|
||||
<!-- TODO: Translate the following -->
|
||||
<h4 class="page-title">Panel Config</h4>
|
||||
<h4 class="page-title">{{ translate('panelConfig', 'pageTitle', data['lang']) }}</h4>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -30,11 +30,11 @@
|
||||
<div class="col-md-12 col-lg-12 grid-margin stretch-card">
|
||||
<div class="card">
|
||||
<div class="card-header header-sm d-flex justify-content-between align-items-center">
|
||||
<h4 class="card-title"><i class="fas fa-users"></i> Users</h4>
|
||||
<h4 class="card-title"><i class="fas fa-users"></i> {{ translate('panelConfig', 'users', data['lang']) }}</h4>
|
||||
<span class="too_small" title="{{ translate('dashboard', 'cannotSee', data['lang']) }}", data-content="{{ translate('dashboard', 'cannotSeeOnMobile2', data['lang']) }}", data-placement="top"></span>
|
||||
|
||||
<!-- TODO: Translate the following -->
|
||||
<div><a class="nav-link" href="/panel/add_user"><i class="fas fa-plus-circle"></i> Add New User</a></div>
|
||||
<div><a class="nav-link" href="/panel/add_user"><i class="fas fa-plus-circle"></i> {{ translate('panelConfig', 'newUser', data['lang']) }}</a></div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="table-responsive">
|
||||
@ -42,11 +42,11 @@
|
||||
<thead>
|
||||
<!-- TODO: Translate the following -->
|
||||
<tr class="rounded">
|
||||
<th>User</th>
|
||||
<th>Enabled</th>
|
||||
<th>Allowed Servers</th>
|
||||
<th>Assigned Roles</th>
|
||||
<th>Edit</th>
|
||||
<th>{{ translate('panelConfig', 'user', data['lang']) }}</th>
|
||||
<th>{{ translate('panelConfig', 'enabled', data['lang']) }}</th>
|
||||
<th>{{ translate('panelConfig', 'allowedServers', data['lang']) }}</th>
|
||||
<th>{{ translate('panelConfig', 'assignedRoles', data['lang']) }}</th>
|
||||
<th>{{ translate('panelConfig', 'edit', data['lang']) }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@ -93,9 +93,9 @@
|
||||
<div class="col-md-12 col-lg-12 grid-margin stretch-card">
|
||||
<div class="card">
|
||||
<div class="card-header header-sm d-flex justify-content-between align-items-center">
|
||||
<h4 class="card-title"><i class="fas fa-user-tag"></i> Roles</h4>
|
||||
<h4 class="card-title"><i class="fas fa-user-tag"></i> {{ translate('panelConfig', 'roles', data['lang']) }}</h4>
|
||||
<span class="too_small2" title="{{ translate('dashboard', 'cannotSee', data['lang']) }}", data-content="{{ translate('dashboard', 'cannotSeeOnMobile2', data['lang']) }}", data-placement="top"></span>
|
||||
<div><a class="nav-link" href="/panel/add_role"><i class="fas fa-plus-circle"></i> Add New Role</a></div>
|
||||
<div><a class="nav-link" href="/panel/add_role"><i class="fas fa-plus-circle"></i> {{ translate('panelConfig', 'newRole', data['lang']) }}</a></div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="table-responsive">
|
||||
@ -103,10 +103,10 @@
|
||||
<thead>
|
||||
<!-- TODO: Translate the following -->
|
||||
<tr class="rounded">
|
||||
<th>Role</th>
|
||||
<th>Allowed Servers</th>
|
||||
<th>Role Users</th>
|
||||
<th>Edit</th>
|
||||
<th>{{ translate('panelConfig', 'role', data['lang']) }}</th>
|
||||
<th>{{ translate('panelConfig', 'allowedServers', data['lang']) }}</th>
|
||||
<th>{{ translate('panelConfig', 'roleUsers', data['lang']) }}</th>
|
||||
<th>{{ translate('panelConfig', 'edit', data['lang']) }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
|
@ -3,7 +3,7 @@
|
||||
{% block meta %}
|
||||
{% end %}
|
||||
|
||||
{% block title %}Crafty Controller - Edit Role{% end %}
|
||||
{% block title %}Crafty Controller - {{ translate('rolesConfig', 'pageTitle', data['lang']) }}{% end %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
@ -15,13 +15,13 @@
|
||||
<div class="page-header">
|
||||
{% if data['new_role'] %}
|
||||
<h4 class="page-title">
|
||||
New Role
|
||||
{{ translate('rolesConfig', 'pageTitleNew', data['lang']) }}
|
||||
<br />
|
||||
<small>RID: N/A</small>
|
||||
</h4>
|
||||
{% else %}
|
||||
<h4 class="page-title">
|
||||
Edit Role - {{ data['role']['role_name'] }}
|
||||
{{ translate('rolesConfig', 'pageTitle', data['lang']) }} - {{ data['role']['role_name'] }}
|
||||
<br />
|
||||
<small>RID: {{ data['role']['role_id'] }}</small>
|
||||
</h4>
|
||||
@ -40,7 +40,7 @@
|
||||
<ul class="nav nav-tabs col-md-12 tab-simple-styled " role="tablist">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link active" href="/panel/edit_role?id={{ data['role']['role_id'] }}&subpage=config" role="tab" aria-selected="true">
|
||||
<i class="fas fa-cogs"></i>Config</a>
|
||||
<i class="fas fa-cogs"></i>{{ translate('rolesConfig', 'config', data['lang']) }}</a>
|
||||
</li>
|
||||
<!-- <li class="nav-item">
|
||||
<a class="nav-link" href="/panel/edit_role?id={{ data['role']['role_id'] }}&subpage=other" role="tab" aria-selected="false">
|
||||
@ -60,11 +60,11 @@
|
||||
|
||||
<div class="card">
|
||||
<div class="card-header header-sm d-flex justify-content-between align-items-center">
|
||||
<h4 class="card-title"><i class="fas fa-user-tag"></i> Role Settings</h4>
|
||||
<h4 class="card-title"><i class="fas fa-user-tag"></i> {{ translate('rolesConfig', 'roleTitle', data['lang']) }}</h4>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="form-group">
|
||||
<label for="role_name">Role Name <small class="text-muted ml-1"> - What you wish to call this role</small> </label>
|
||||
<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>
|
||||
</div>
|
||||
@ -72,7 +72,7 @@
|
||||
|
||||
<div class="card">
|
||||
<div class="card-header header-sm d-flex justify-content-between align-items-center">
|
||||
<h4 class="card-title"><i class="fas fa-server"></i> Allowed Servers <small class="text-muted ml-1"> - servers this role is allowed to access </small> </h4>
|
||||
<h4 class="card-title"><i class="fas fa-server"></i> {{ translate('rolesConfig', 'roleServers', data['lang']) }} <small class="text-muted ml-1"> {{ translate('rolesConfig', 'serversDesc', data['lang']) }}</small> </h4>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="form-group">
|
||||
@ -80,8 +80,8 @@
|
||||
<table class="table table-hover">
|
||||
<thead>
|
||||
<tr class="rounded">
|
||||
<th>Server Name</th>
|
||||
<th>Access?</th>
|
||||
<th>{{ translate('rolesConfig', 'serverName', data['lang']) }}</th>
|
||||
<th>{{ translate('rolesConfig', 'serverAccess', data['lang']) }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@ -107,7 +107,7 @@
|
||||
|
||||
<div class="card">
|
||||
<div class="card-header header-sm d-flex justify-content-between align-items-center">
|
||||
<h4 class="card-title"><i class="fas fa-user-lock"></i> Roles Permissions <small class="text-muted ml-1"> - permissions this role has on this/these servers </small></h4>
|
||||
<h4 class="card-title"><i class="fas fa-user-lock"></i> {{ translate('rolesConfig', 'rolePerms', data['lang']) }}<small class="text-muted ml-1"> - {{ translate('rolesConfig', 'permsServer', data['lang']) }} </small></h4>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="form-group">
|
||||
@ -115,8 +115,8 @@
|
||||
<table class="table table-hover">
|
||||
<thead>
|
||||
<tr class="rounded">
|
||||
<th>Permission Name</th>
|
||||
<th>Authorized ?</th>
|
||||
<th>{{ translate('rolesConfig', 'permName', data['lang']) }}</th>
|
||||
<th>{{ translate('rolesConfig', 'permAccess', data['lang']) }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@ -148,14 +148,14 @@
|
||||
<div class="col-md-3 col-sm-12">
|
||||
<div class="card">
|
||||
<div class="card-header header-sm d-flex justify-content-between align-items-center">
|
||||
<h4 class="card-title"><i class="fas fa-users"></i> Users Assigned to Role:</h4>
|
||||
<h4 class="card-title"><i class="fas fa-users"></i> {{ translate('rolesConfig', 'roleUsers', data['lang']) }}</h4>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-hover">
|
||||
<thead>
|
||||
<tr class="rounded">
|
||||
<th>User Name</th>
|
||||
<th>{{ translate('rolesConfig', 'roleUserName', data['lang']) }}</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
@ -182,22 +182,22 @@
|
||||
<div class="col-md-3 col-sm-12">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<h4 class="card-title">Role Config Area</h4>
|
||||
<p class="card-description"> Here is where you can change the configuration of your role</p>
|
||||
<h4 class="card-title">{{ translate('rolesConfig', 'roleConfigArea', data['lang']) }}</h4>
|
||||
<p class="card-description"> {{ translate('rolesConfig', 'configDesc', data['lang']) }}</p>
|
||||
<blockquote class="blockquote">
|
||||
<p class="mb-0">
|
||||
Created: {{ str(data['role']['created']) }}
|
||||
{{ translate('rolesConfig', 'created', data['lang']) }} {{ str(data['role']['created']) }}
|
||||
<br />
|
||||
Last updated: {{ str(data['role']['last_update']) }}
|
||||
{{ translate('rolesConfig', 'configUpdate', data['lang']) }} {{ str(data['role']['last_update']) }}
|
||||
<br />
|
||||
</p>
|
||||
</blockquote>
|
||||
<div class="text-center">
|
||||
{% if data['new_role'] %}
|
||||
<a class="btn btn-sm btn-danger disabled"><i class="fas fa-trash"></i> Delete Role</a><br />
|
||||
<small>You cannot delete something that does not yet exist</small>
|
||||
<a class="btn btn-sm btn-danger disabled"><i class="fas fa-trash"></i>{{ translate('rolesConfig', 'delRole', data['lang']) }}</a><br />
|
||||
<small>{{ translate('rolesConfig', 'doesNotExist', data['lang']) }}</small>
|
||||
{% else %}
|
||||
<a href="/panel/remove_role?id={{ data['role']['role_id'] }}" class="btn btn-sm btn-danger"><i class="fas fa-trash"></i> Delete Role</a>
|
||||
<a href="/panel/remove_role?id={{ data['role']['role_id'] }}" class="btn btn-sm btn-danger"><i class="fas fa-trash"></i>{{ translate('rolesConfig', 'delRole', data['lang']) }}</a>
|
||||
{% end %}
|
||||
</div>
|
||||
</div>
|
||||
|
@ -15,13 +15,13 @@
|
||||
<div class="page-header">
|
||||
{% if data['new_user'] %}
|
||||
<h4 class="page-title">
|
||||
New User
|
||||
{{ translate('userConfig', 'pageTitleNew', data['lang']) }}
|
||||
<br />
|
||||
<small>UID: N/A</small>
|
||||
</h4>
|
||||
{% else %}
|
||||
<h4 class="page-title">
|
||||
Edit User - {{ data['user']['user_id'] }}
|
||||
{{ translate('userConfig', 'pageTitle', data['lang']) }} - {{ data['user']['user_id'] }}
|
||||
<br />
|
||||
<small>UID: {{ data['user']['user_id'] }}</small>
|
||||
</h4>
|
||||
@ -40,16 +40,12 @@
|
||||
<ul class="nav nav-tabs col-md-12 tab-simple-styled " role="tablist">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link active" href="/panel/{{ 'add_user' if data['new_user'] else 'edit_user' }}?id={{ data['user']['user_id'] }}&subpage=config" role="tab" aria-selected="true">
|
||||
<i class="fas fa-cogs"></i>Config</a>
|
||||
<i class="fas fa-cogs"></i> {{ translate('userConfig', 'config', data['lang']) }} - {{ data['user']['user_id'] }}</a>
|
||||
</li>
|
||||
{% if not data['new_user'] %}
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/panel/edit_user_apikeys?id={{ data['user']['user_id'] }}" role="tab" aria-selected="false">
|
||||
<i class="fas fa-key"></i>API Keys</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/panel/add_user?id={{ data['user']['user_id'] }}&subpage=other" role="tab" aria-selected="false">
|
||||
<i class="fas fa-folder-tree"></i>Other</a>
|
||||
<i class="fas fa-key"></i>{{ translate('userConfig', 'apiKey', data['lang']) }} - {{ data['user']['user_id'] }}</a>
|
||||
</li>
|
||||
{% end %}
|
||||
</ul>
|
||||
@ -68,27 +64,27 @@
|
||||
|
||||
<div class="card">
|
||||
<div class="card-header header-sm d-flex justify-content-between align-items-center">
|
||||
<h4 class="card-title"><i class="fas fa-user"></i> User Settings</h4>
|
||||
<h4 class="card-title"><i class="fas fa-user"></i> {{ translate('userConfig', 'userSettings', data['lang']) }} - {{ data['user']['user_id'] }}</h4>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="form-group">
|
||||
<label class="form-label" for="username">User Name <small class="text-muted ml-1"> - What you wish to call this user</small> </label>
|
||||
<label class="form-label" for="username">{{ translate('userConfig', 'userName', data['lang']) }} - {{ data['user']['user_id'] }}<small class="text-muted ml-1"> - {{ translate('userConfig', 'userNameDesc', data['lang']) }} - {{ data['user']['user_id'] }}</small> </label>
|
||||
<input type="text" class="form-control" name="username" id="username" value="{{ data['user']['username'] }}" placeholder="User Name" >
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="form-label" for="password0">Password <small class="text-muted ml-1"> - leave blank to don't change</small> </label>
|
||||
<label class="form-label" for="password0">{{ translate('userConfig', 'password', data['lang']) }} - {{ data['user']['user_id'] }}<small class="text-muted ml-1"> - {{ translate('userConfig', 'leaveBlank', data['lang']) }} - {{ data['user']['user_id'] }}</small> </label>
|
||||
<input type="password" class="form-control" name="password0" id="password0" value="" placeholder="Password" >
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="form-label" for="password1">Repeat Password <small class="text-muted ml-1"> - leave blank to don't change</small> </label>
|
||||
<label class="form-label" for="password1">{{ translate('userConfig', 'repeat', data['lang']) }} - {{ data['user']['user_id'] }} <small class="text-muted ml-1"> - {{ translate('userConfig', 'leaveBlank', data['lang']) }} - {{ data['user']['user_id'] }}</small> </label>
|
||||
<input type="password" class="form-control" name="password1" id="password1" value="" placeholder="Repeat Password" >
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="form-label" for="email">Gravatar Email <small class="text-muted ml-1"> - for the profile picture. this is not required. crafty will never make use of user emails. User emails are strictly for Gravatar</small> </label>
|
||||
<label class="form-label" for="email">{{ translate('userConfig', 'gravEmail', data['lang']) }} - {{ data['user']['user_id'] }}<small class="text-muted ml-1"> - {{ translate('userConfig', 'gravDesc', data['lang']) }} - {{ data['user']['user_id'] }}</small> </label>
|
||||
<input type="email" class="form-control" name="email" id="email" value="{{ data['user']['email'] }}" placeholder="Gravatar Email" >
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="form-label" for="language">User Language:</label>
|
||||
<label class="form-label" for="language">{{ translate('userConfig', 'userLang', data['lang']) }}</label>
|
||||
<select class="form-select form-control form-control-lg select-css" id="language" name="language" form="user_form">
|
||||
{% for lang in data['languages'] %}
|
||||
<option value="{{lang}}">{{lang}}</option>
|
||||
@ -100,7 +96,7 @@
|
||||
|
||||
<div class="card">
|
||||
<div class="card-header header-sm d-flex justify-content-between align-items-center">
|
||||
<h4 class="card-title"><i class="fas fa-user-tag"></i> Roles <small class="text-muted ml-1"> - the roles this user is a member of</small></h4>
|
||||
<h4 class="card-title"><i class="fas fa-user-tag"></i> {{ translate('userConfig', 'userRoles', data['lang']) }} <small class="text-muted ml-1"> - {{ translate('userConfig', 'userRolesDesc', data['lang']) }}</small></h4>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="form-group">
|
||||
@ -108,8 +104,8 @@
|
||||
<table class="table table-hover">
|
||||
<thead>
|
||||
<tr class="rounded">
|
||||
<th>Role Name</th>
|
||||
<th>Member?</th>
|
||||
<th>{{ translate('userConfig', 'roleName', data['lang']) }}</th>
|
||||
<th>{{ translate('userConfig', 'member', data['lang']) }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@ -137,7 +133,7 @@
|
||||
|
||||
<div class="card">
|
||||
<div class="card-header header-sm d-flex justify-content-between align-items-center">
|
||||
<h4 class="card-title"><i class="fas fa-user-lock"></i> Crafty Permissions <small class="text-muted ml-1"> - permissions this user has on Crafty Controller </small></h4>
|
||||
<h4 class="card-title"><i class="fas fa-user-lock"></i> {{ translate('userConfig', 'craftyPerms', data['lang']) }} <small class="text-muted ml-1"> - {{ translate('userConfig', 'craftyPermDesc', data['lang']) }}permissions this user has on Crafty Controller </small></h4>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="form-group">
|
||||
@ -145,9 +141,9 @@
|
||||
<table class="table table-hover">
|
||||
<thead>
|
||||
<tr class="rounded">
|
||||
<th>Permission Name</th>
|
||||
<th>Authorized ?</th>
|
||||
<th>Number of Uses Allowed (-1=No Limit)</th>
|
||||
<th>{{ translate('userConfig', 'permName', data['lang']) }}</th>
|
||||
<th>{{ translate('userConfig', 'auth', data['lang']) }}</th>
|
||||
<th>{{ translate('userConfig', 'uses', data['lang']) }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@ -174,17 +170,17 @@
|
||||
<div class="form-check-flat">
|
||||
<label for="enabled" class="form-check-label ml-4 mb-4">
|
||||
{% if data['user']['enabled'] %}
|
||||
<input type="checkbox" class="form-check-input" id="enabled" name="enabled" checked="" value="1">Enabled
|
||||
<input type="checkbox" class="form-check-input" id="enabled" name="enabled" checked="" value="1">{{ translate('userConfig', 'enabled', data['lang']) }}
|
||||
{% else %}
|
||||
<input type="checkbox" class="form-check-input" id="enabled" name="enabled" value="1">Enabled
|
||||
<input type="checkbox" class="form-check-input" id="enabled" name="enabled" value="1">{{ translate('userConfig', 'enabled', data['lang']) }}
|
||||
{% end %}
|
||||
</label>
|
||||
|
||||
<label for="superuser" class="form-check-label ml-4 mb-4">
|
||||
{% if data['user']['superuser'] %}
|
||||
<input type="checkbox" onclick="superConfirm()" class="form-check-input" id="superuser" name="superuser" checked="" value="1" {{ data['super-disabled'] }} >Super User
|
||||
<input type="checkbox" onclick="superConfirm()" class="form-check-input" id="superuser" name="superuser" checked="" value="1" {{ data['super-disabled'] }} >{{ translate('userConfig', 'super', data['lang']) }}
|
||||
{% else %}
|
||||
<input type="checkbox" onclick="superConfirm()" class="form-check-input" id="superuser" name="superuser" {{ data['super-disabled'] }} value="1" >Super User
|
||||
<input type="checkbox" onclick="superConfirm()" class="form-check-input" id="superuser" name="superuser" {{ data['super-disabled'] }} value="1" >{{ translate('userConfig', 'super', data['lang']) }}
|
||||
{% end %}
|
||||
</label>
|
||||
|
||||
@ -198,19 +194,17 @@
|
||||
<div class="col-md-6 col-sm-12">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<h4 class="card-title"><i class="fas fa-user-cog"></i> User Config Area</h4>
|
||||
<p class="card-description"> Here is where you can change the configuration of your user</p>
|
||||
<h4 class="card-title"><i class="fas fa-user-cog"></i> {{ translate('userConfig', 'configArea', data['lang']) }}</h4>
|
||||
<p class="card-description"> {{ translate('userConfig', 'configAreaDesc', data['lang']) }}</p>
|
||||
<blockquote class="blockquote">
|
||||
<p class="mb-0">
|
||||
Created: {{ str(data['user']['created']) }}
|
||||
{{ translate('userConfig', 'created', data['lang']) }} {{ str(data['user']['created']) }}
|
||||
<br />
|
||||
Last login: {{ str(data['user']['last_login']) }}
|
||||
{{ translate('userConfig', 'lastLogin', data['lang']) }} {{ str(data['user']['last_login']) }}
|
||||
<br />
|
||||
Last update: {{ str(data['user']['last_update']) }}
|
||||
{{ translate('userConfig', 'lastUpdate', data['lang']) }} {{ str(data['user']['last_update']) }}
|
||||
<br />
|
||||
Last IP: {{ data['user']['last_ip'] }}
|
||||
<br />
|
||||
API Key: TODO! <!-- TODO -->
|
||||
{{ translate('userConfig', 'lastIP', data['lang']) }} {{ data['user']['last_ip'] }}
|
||||
<br />
|
||||
</p>
|
||||
</blockquote>
|
||||
@ -218,13 +212,13 @@
|
||||
</div>
|
||||
<div class="text-center">
|
||||
{% if data['new_user'] %}
|
||||
<a class="btn btn-sm btn-danger disabled"><i class="fas fa-trash"></i> Delete User</a><br />
|
||||
<small>You cannot delete something that does not yet exist</small>
|
||||
<a class="btn btn-sm btn-danger disabled"><i class="fas fa-trash"></i>{{ translate('userConfig', 'deleteUserB', data['lang']) }}</a><br />
|
||||
<small>{{ translate('userConfig', 'notExist', data['lang']) }}</small>
|
||||
{% elif data['user']['superuser'] %}
|
||||
<a class="btn btn-sm btn-danger disabled"><i class="fas fa-trash"></i> Delete User</a><br />
|
||||
<small>You cannot delete a superuser</small>
|
||||
<a class="btn btn-sm btn-danger disabled"><i class="fas fa-trash"></i> {{ translate('userConfig', 'deleteUserB', data['lang']) }}</a><br />
|
||||
<small>{{ translate('userConfig', 'delSuper', data['lang']) }}</small>
|
||||
{% else %}
|
||||
<button class="btn btn-sm btn-danger delete-user"><i class="fas fa-trash"></i> Delete User</a>
|
||||
<button class="btn btn-sm btn-danger delete-user"><i class="fas fa-trash"></i> {{ translate('userConfig', 'deleteUserB', data['lang']) }}</a>
|
||||
{% end %}
|
||||
|
||||
</div>
|
||||
@ -251,8 +245,8 @@
|
||||
console.log("User to delete is {{ data['user']['username'] }}");
|
||||
|
||||
bootbox.confirm({
|
||||
title: "{% raw translate('usersConfig', 'deleteUser', data['lang']) %}"+"{{ data['user']['username'] }}",
|
||||
message: "{{ translate('usersConfig', 'confirmDelete', data['lang']) }}",
|
||||
title: "{% raw translate('userConfig', 'deleteUser', data['lang']) %}"+"{{ data['user']['username'] }}",
|
||||
message: "{{ translate('userConfig', 'confirmDelete', data['lang']) }}",
|
||||
buttons: {
|
||||
cancel: {
|
||||
label: '<i class="fas fa-times"></i> {{ translate("serverBackups", "cancel", data['lang']) }}'
|
||||
|
@ -14,7 +14,7 @@
|
||||
<div class="col-12">
|
||||
<div class="page-header">
|
||||
<h4 class="page-title">
|
||||
Edit User API Keys - {{ data['user']['user_id'] }}
|
||||
{{ translate('apiKeys', 'pageTitle', data['lang']) }} - {{ data['user']['user_id'] }}
|
||||
<br/>
|
||||
<small>UID: {{ data['user']['user_id'] }}</small>
|
||||
</h4>
|
||||
@ -34,13 +34,13 @@
|
||||
<a class="nav-link" href="/panel/edit_user?id={{ data['user']['user_id'] }}&subpage=config"
|
||||
role="tab"
|
||||
aria-selected="false">
|
||||
<i class="fas fa-cogs"></i>Config</a>
|
||||
<i class="fas fa-cogs"></i>{{ translate('apiKeys', 'config', data['lang']) }}</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link active" href="/panel/edit_user_apikeys?id={{ data['user']['user_id'] }}"
|
||||
role="tab"
|
||||
aria-selected="true">
|
||||
<i class="fas fa-key"></i>API Keys</a>
|
||||
<i class="fas fa-key"></i>{{ translate('apiKeys', 'apiKeys', data['lang']) }}</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
@ -48,7 +48,7 @@
|
||||
<div class="col-md-7 col-sm-12">
|
||||
<div class="card">
|
||||
<div class="card-header header-sm d-flex justify-content-between align-items-center">
|
||||
<h4 class="card-title"><i class="fas fa-key"></i> API Keys</h4>
|
||||
<h4 class="card-title"><i class="fas fa-key"></i>{{ translate('apiKeys', 'apiKeys', data['lang']) }}</h4>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="form-group">
|
||||
@ -57,11 +57,11 @@
|
||||
<thead>
|
||||
<tr class="rounded">
|
||||
<!--<th>ID</th>-->
|
||||
<th>Name</th>
|
||||
<th>Created</th>
|
||||
<th>Superuser</th>
|
||||
<th>Permissions</th>
|
||||
<th>Buttons</th>
|
||||
<th>{{ translate('apiKeys', 'name', data['lang']) }}</th>
|
||||
<th>{{ translate('apiKeys', 'created', data['lang']) }}</th>
|
||||
<th>{{ translate('apiKeys', 'superUser', data['lang']) }}</th>
|
||||
<th>{{ translate('apiKeys', 'perms', data['lang']) }}</th>
|
||||
<th>{{ translate('apiKeys', 'buttons', data['lang']) }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@ -73,16 +73,16 @@
|
||||
<td>
|
||||
{% if apikey.superuser %}
|
||||
<span class="text-success">
|
||||
<i class="fas fa-check-square"></i> Yes
|
||||
<i class="fas fa-check-square"></i> {{ translate('apiKeys', 'yes', data['lang']) }}
|
||||
</span>
|
||||
{% else %}
|
||||
<span class="text-danger">
|
||||
<i class="far fa-times-square"></i> No
|
||||
<i class="far fa-times-square"></i> {{ translate('apiKeys', 'no', data['lang']) }}
|
||||
</span>
|
||||
{% end %}
|
||||
</td>
|
||||
<td>Server: {{ apikey.server_permissions }}
|
||||
Crafty: {{ apikey.crafty_permissions }}</td>
|
||||
<td>{{ translate('apiKeys', 'server', data['lang']) }} {{ apikey.server_permissions }}
|
||||
{{ translate('apiKeys', 'crafty', data['lang']) }} {{ apikey.crafty_permissions }}</td>
|
||||
<td>
|
||||
<button
|
||||
class="btn btn-danger delete-api-key"
|
||||
@ -93,7 +93,7 @@
|
||||
class="btn btn-outline-primary get-a-token"
|
||||
data-key-id="{{ apikey.token_id }}"
|
||||
data-key-name="{{ apikey.name }}"
|
||||
>Get a token
|
||||
>{{ translate('apiKeys', 'getToken', data['lang']) }}
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
@ -109,7 +109,7 @@
|
||||
<div class="col-md-5 col-sm-12">
|
||||
<div class="card">
|
||||
<div class="card-header header-sm d-flex justify-content-between align-items-center">
|
||||
<h4 class="card-title"><i class="fas fa-plus"></i> Create new API key</h4>
|
||||
<h4 class="card-title"><i class="fas fa-plus"></i> {{ translate('apiKeys', 'createNew', data['lang']) }}</h4>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<form id="user_form" class="forms-sample" method="post"
|
||||
@ -118,9 +118,8 @@
|
||||
<input type="hidden" name="id" value="{{ data['user']['user_id'] }}">
|
||||
|
||||
<div class="form-group">
|
||||
<label class="form-label" for="username">Name <small
|
||||
class="text-muted ml-1"> - What you wish to
|
||||
call this API key</small> </label>
|
||||
<label class="form-label" for="username">{{ translate('apiKeys', 'name', data['lang']) }}<small
|
||||
class="text-muted ml-1"> - {{ translate('apiKeys', 'nameDesc', data['lang']) }}</small> </label>
|
||||
<input type="text" class="form-control" name="name" id="name"
|
||||
placeholder="API Key">
|
||||
</div>
|
||||
@ -128,8 +127,8 @@
|
||||
<table class="table table-hover mb-3">
|
||||
<thead>
|
||||
<tr class="rounded">
|
||||
<th>Permission Name</th>
|
||||
<th>Authorized ?</th>
|
||||
<th>{{ translate('apiKeys', 'permName', data['lang']) }}</th>
|
||||
<th>{{ translate('apiKeys', 'auth', data['lang']) }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
|
@ -202,9 +202,9 @@ try{
|
||||
}catch{
|
||||
console.log("no element named {{ data['schedule']['action'] }}")
|
||||
}
|
||||
ifDays();
|
||||
yesnoCheck();
|
||||
basicAdvanced();
|
||||
ifDays();
|
||||
if("{{ data['schedule']['enabled'] }}" == 'True'){
|
||||
document.getElementById('enabled').checked = true;
|
||||
}else{
|
||||
|
@ -76,10 +76,6 @@
|
||||
"clickRoot": "Click here to select Root Dir",
|
||||
"explainRoot": "Please click the button below to select your server's root dir inside of the archive"
|
||||
},
|
||||
"usersConfig":{
|
||||
"deleteUser": "Delete user: ",
|
||||
"confirmDelete": "Are you sure you want to delete this user? This action is irreversible."
|
||||
},
|
||||
"dashboard": {
|
||||
"dashboard": "Dashboard",
|
||||
"memUsage": "Memory Usage",
|
||||
@ -305,12 +301,85 @@
|
||||
]
|
||||
},
|
||||
"panelConfig": {
|
||||
"pageTitle": "Panel Config",
|
||||
"users": "Users",
|
||||
"roles": "Roles",
|
||||
"newUser": "Add New User",
|
||||
"newRole": "Add New Role",
|
||||
"user": "User",
|
||||
"enabled": "Enabled",
|
||||
"allowedServers": "Allowed Servers",
|
||||
"assignedRoles": "Assigned Roles",
|
||||
"edit": "Edit",
|
||||
"role": "Role",
|
||||
"roleUsers": "Role Users",
|
||||
"save": "Save",
|
||||
"cancel": "Cancel",
|
||||
"delete": "Delete",
|
||||
"superConfirmTitle": "Enable superuser? Are you sure?",
|
||||
"superConfirm": "Proceed only if you want this user to have access to EVERYTHING (all user accounts, servers, panel settings, etc.). They can even revoke your superuser rights."
|
||||
},
|
||||
"userConfig": {
|
||||
"pageTitle": "Edit User",
|
||||
"pageTitleNew": "Create User",
|
||||
"config": "Config",
|
||||
"apiKey": "API Keys",
|
||||
"userSettings": "User Settings",
|
||||
"userName": "User Name",
|
||||
"userNameDesc": "What do you want to call this user?",
|
||||
"password": "Password",
|
||||
"repeat": "Repeat Password",
|
||||
"leaveBlank": "To edit user without changing password leave it blank.",
|
||||
"craftyPermDesc": "Crafty permissions this user has ",
|
||||
"gravEmail": "Gravatar™ Email",
|
||||
"gravDesc": "This email is strictly for use with Gravatar™. Crafty will not, under any circumstance make use of this email for anything other than looking up your Gravatar™",
|
||||
"userLang": "User Language",
|
||||
"userRoles": "User Roles",
|
||||
"userRolesDesc": "Roles this user is a member of.",
|
||||
"roleName": "Role Name",
|
||||
"member": "Member?",
|
||||
"craftyPerms": "Crafty Permissons: ",
|
||||
"permName":"Permission Name",
|
||||
"auth": "Authorized? ",
|
||||
"uses": "Number of uses allowed (-1==No Limit)",
|
||||
"super": "Super User",
|
||||
"enabled": "Enabled",
|
||||
"configArea": "User Config Area",
|
||||
"configAreaDesc": "Here is where you change all of your user settings",
|
||||
"created": "Created: ",
|
||||
"lastLogin": "Last Login: ",
|
||||
"lastUpdate": "Last Update: ",
|
||||
"lastIP": "Last IP: ",
|
||||
"deleteUserB": "Delete User",
|
||||
"notExist": "You cannot delete something that doesn't exist!",
|
||||
"delSuper": "You cannot delete a super user",
|
||||
"deleteUser": "Delete user: ",
|
||||
"confirmDelete": "Are you sure you want to delete this user? This action is irreversible."
|
||||
},
|
||||
"rolesConfig": {
|
||||
"pageTitle": "Edit Role",
|
||||
"pageTitleNew": "New Role",
|
||||
"config": "Role Config",
|
||||
"roleTitle": "Roles Settings",
|
||||
"roleName": "Role Name: ",
|
||||
"roleDesc": "What would you like to call this role?",
|
||||
"roleServers": "Allowed Servers",
|
||||
"serversDesc": "servers this role is allowed to access",
|
||||
"serverName": "Server Name",
|
||||
"serverAccess": "Access?",
|
||||
"rolePerms": "Role Permissions",
|
||||
"permsServer": "Permissions this role has for these specified servers",
|
||||
"permName": "Permission Name",
|
||||
"permAccess": "Access?",
|
||||
"roleUsers": "Role Users: ",
|
||||
"roleUserName": "User Name",
|
||||
"roleConfigArea": "Role Config Area",
|
||||
"configDesc": "Here is where you can change the configuration of your role",
|
||||
"created": "Created: ",
|
||||
"configUpdate": "Last Updated: ",
|
||||
"delRole": "Delete Role",
|
||||
"doesNotExist": "You cannot delete something that does not exist yet"
|
||||
},
|
||||
"datatables": {
|
||||
"i18n": {
|
||||
"decimal": "",
|
||||
@ -379,6 +448,23 @@
|
||||
"doesNotWorkWithoutJavascript": "<strong>Warning: </strong>Crafty doesn't work properly when JavaScript isn't enabled!"
|
||||
},
|
||||
"apiKeys": {
|
||||
"pageTitle": "Edit User API Keys",
|
||||
"config": "Config",
|
||||
"apiKeys": "API Keys",
|
||||
"name": "Name",
|
||||
"created": "Created",
|
||||
"perms": "Permissions",
|
||||
"buttons": "Buttons",
|
||||
"yes": "Yes",
|
||||
"no": "No",
|
||||
"server": "Server: ",
|
||||
"crafty": "Crafty: ",
|
||||
"getToken": "Get A Token",
|
||||
"createNew": "Create new API Token",
|
||||
"nameDesc": "What would you like to call this API token? ",
|
||||
"permName": "Permission Name",
|
||||
"auth":"Authorized? ",
|
||||
"superUser": "Super User",
|
||||
"deleteKeyConfirmation": "Do you want to delete this API key? This cannot be undone.",
|
||||
"deleteKeyConfirmationTitle": "Remove API key ${keyId}?"
|
||||
}
|
||||
|
@ -6,13 +6,20 @@ upstream crafty {
|
||||
}
|
||||
|
||||
server {
|
||||
listen 80 default_server;
|
||||
listen 80;
|
||||
server_name <DOMAIN>;
|
||||
if ($host !~* ^<SUBDOMAIN>\.<EXAMPLE>\.com$ ) {
|
||||
return 444;
|
||||
}
|
||||
rewrite ^(.*) https://$host$1 permanent;
|
||||
}
|
||||
|
||||
server {
|
||||
listen 443 ssl;
|
||||
server_name <DOMAIN>;
|
||||
if ($host !~* ^<SUBDOMAIN>\.<EXAMPLE>\.com$ ) {
|
||||
return 444;
|
||||
}
|
||||
ssl_certificate <CERIFICATE_LOCATION>;
|
||||
ssl_certificate_key <KEYFILE_LOCATION>;
|
||||
location / {
|
||||
|
Loading…
Reference in New Issue
Block a user