Merge branch 'dev' into dev_websocket_server_status

This commit is contained in:
Silversthorn
2022-01-21 23:54:59 +01:00
21 changed files with 357 additions and 172 deletions

View File

@ -40,13 +40,11 @@ class Management_Controller:
@staticmethod @staticmethod
def send_command(user_id, server_id, remote_ip, command): def send_command(user_id, server_id, remote_ip, command):
server_name = servers_helper.get_server_friendly_name(server_id) server_name = servers_helper.get_server_friendly_name(server_id)
# Example: Admin issued command start_server for server Survival # 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), management_helper.add_to_audit_log(user_id, "issued command {} for server {}".format(command, server_name),
server_id, remote_ip) server_id, remote_ip)
management_helper.add_command(server_id, user_id, remote_ip, command) management_helper.add_command(server_id, user_id, remote_ip, command)
@staticmethod @staticmethod

View File

@ -100,9 +100,7 @@ class Servers_Controller:
@staticmethod @staticmethod
def get_authorized_servers_stats(user_id): def get_authorized_servers_stats(user_id):
server_data = [] server_data = []
print('test 1')
authorized_servers = Servers_Controller.get_authorized_servers(user_id) authorized_servers = Servers_Controller.get_authorized_servers(user_id)
print('test 2')
for s in authorized_servers: for s in authorized_servers:
latest = servers_helper.get_latest_server_stats(s.get('server_id')) latest = servers_helper.get_latest_server_stats(s.get('server_id'))
@ -137,11 +135,10 @@ class Servers_Controller:
@staticmethod @staticmethod
def server_id_authorized(server_id_a, user_id): def server_id_authorized(server_id_a, user_id):
print("Server id authorized: ")
user_roles = users_helper.user_role_query(user_id) user_roles = users_helper.user_role_query(user_id)
for role in user_roles: for role in user_roles:
for server_id_b in server_permissions.get_role_servers_from_role_id(role.role_id): 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 True
return False return False

View File

@ -12,6 +12,7 @@ from app.classes.shared.console import console
from app.classes.models.servers import Servers from app.classes.models.servers import Servers
from app.classes.minecraft.server_props import ServerProps from app.classes.minecraft.server_props import ServerProps
from app.classes.web.websocket_helper import websocket_helper from app.classes.web.websocket_helper import websocket_helper
from app.classes.models.server_permissions import server_permissions
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -190,7 +191,6 @@ class ServerJars:
except Exception as e: except Exception as e:
logger.error("Unable to save jar to {path} due to error:{error}".format(path=path, error=e)) logger.error("Unable to save jar to {path} due to error:{error}".format(path=path, error=e))
pass pass
websocket_helper.broadcast('notification', "Executable download finished for server named: " + name)
return False return False

View File

@ -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.users import Users, users_helper
from app.classes.models.servers import Servers, servers_helper from app.classes.models.servers import Servers, servers_helper
from app.classes.web.websocket_helper import websocket_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__) logger = logging.getLogger(__name__)
@ -156,7 +158,7 @@ class helpers_management:
@staticmethod @staticmethod
def get_unactioned_commands(): def get_unactioned_commands():
query = Commands.select().where(Commands.executed == 0) query = Commands.select().where(Commands.executed == 0)
return db_helper.return_rows(query) return query
@staticmethod @staticmethod
def mark_command_complete(command_id=None): def mark_command_complete(command_id=None):
@ -181,7 +183,9 @@ class helpers_management:
audit_msg = "{} {}".format(str(user_data['username']).capitalize(), log_msg) 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.insert({
Audit_Log.user_name: user_data['username'], Audit_Log.user_name: user_data['username'],

View File

@ -7,7 +7,7 @@ from app.classes.shared.helpers import helper
from app.classes.shared.console import console from app.classes.shared.console import console
from app.classes.models.servers import Servers from app.classes.models.servers import Servers
from app.classes.models.roles import Roles 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 from app.classes.shared.permission_helper import permission_helper
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -172,11 +172,26 @@ class Permissions_Servers:
if user.superuser: if user.superuser:
permissions_mask = '1' * len(server_permissions.get_permissions_list()) permissions_mask = '1' * len(server_permissions.get_permissions_list())
else: 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() 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 permissions_mask = role_server[0].permissions
return permissions_mask 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 @staticmethod
def get_user_id_permissions_list(user_id, server_id: str): def get_user_id_permissions_list(user_id, server_id: str):
user = users_helper.get_user_model(user_id) user = users_helper.get_user_model(user_id)

View File

@ -174,6 +174,15 @@ class helper_users:
if up_data: if up_data:
Users.update(up_data).where(Users.user_id == user_id).execute() 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 @staticmethod
def remove_user(user_id): def remove_user(user_id):
with database.atomic(): with database.atomic():

View File

@ -137,6 +137,8 @@ class Controller:
def package_support_logs(self, exec_user): 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') websocket_helper.broadcast_user(exec_user['user_id'], 'notification', 'Preparing your support logs')
tempDir = tempfile.mkdtemp() tempDir = tempfile.mkdtemp()
tempZipStorage = tempfile.mkdtemp() tempZipStorage = tempfile.mkdtemp()
@ -161,7 +163,10 @@ class Controller:
for server in auth_servers: for server in auth_servers:
final_path = os.path.join(server_path, str(server['server_name'])) final_path = os.path.join(server_path, str(server['server_name']))
os.mkdir(final_path) 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 #Copy crafty logs to archive dir
full_log_name = os.path.join(crafty_path, 'logs') full_log_name = os.path.join(crafty_path, 'logs')
shutil.copytree(os.path.join(self.project_root, 'logs'), full_log_name) 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): def get_server_data(self, server_id: str):
for s in self.servers_list: 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'] return s['server_data_obj']
logger.warning("Unable to find server object for server id {}".format(server_id)) 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)) logger.error("Unable to create required server files due to :{}".format(e))
return False 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), helper.float_to_string(max_mem),
full_jar_path) full_jar_path)
server_log_file = "{}/logs/latest.log".format(server_dir) 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) new_server_dir = os.path.join(helper.servers_dir, server_id)
backup_path = os.path.join(helper.backup_path, server_id) backup_path = os.path.join(helper.backup_path, server_id)
if helper.is_os_windows(): 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) backup_path = helper.wtol_path(backup_path)
new_server_dir.replace(' ', '^ ') new_server_dir.replace(' ', '^ ')
backup_path.replace(' ', '^ ') backup_path.replace(' ', '^ ')
@ -337,9 +347,14 @@ class Controller:
full_jar_path = os.path.join(new_server_dir, server_jar) 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), 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_log_file = "{}/logs/latest.log".format(new_server_dir)
server_stop = "stop" server_stop = "stop"
@ -377,9 +392,14 @@ class Controller:
full_jar_path = os.path.join(new_server_dir, server_jar) 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), 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) logger.debug('command: ' + server_command)
server_log_file = "{}/logs/latest.log".format(new_server_dir) server_log_file = "{}/logs/latest.log".format(new_server_dir)
server_stop = "stop" server_stop = "stop"
@ -430,7 +450,7 @@ class Controller:
for s in self.servers_list: for s in self.servers_list:
# if this is the droid... im mean server we are looking for... # 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_data = self.get_server_data(server_id)
server_name = server_data['server_name'] server_name = server_data['server_name']
backup_dir = self.servers.get_server_data_by_id(server_id)['backup_path'] backup_dir = self.servers.get_server_data_by_id(server_id)['backup_path']

View File

@ -25,6 +25,7 @@ from app.classes.models.management import management_helper
from app.classes.web.websocket_helper import websocket_helper from app.classes.web.websocket_helper import websocket_helper
from app.classes.shared.translation import translation from app.classes.shared.translation import translation
from app.classes.models.users import users_helper from app.classes.models.users import users_helper
from app.classes.models.server_permissions import server_permissions
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -383,11 +384,10 @@ class Server:
return False return False
def send_command(self, command): def send_command(self, command):
console.info("COMMAND TIME: {}".format(command))
if not self.check_running() and command.lower() != 'start': if not self.check_running() and command.lower() != 'start':
logger.warning("Server not running, unable to send command \"{}\"".format(command)) logger.warning("Server not running, unable to send command \"{}\"".format(command))
return False return False
console.info("COMMAND TIME: {}".format(command))
logger.debug("Sending command {} to server".format(command)) logger.debug("Sending command {} to server".format(command))
# send it # send it
@ -477,7 +477,7 @@ class Server:
def remove_watcher_thread(self): def remove_watcher_thread(self):
logger.info("Removing old crash detection watcher thread") logger.info("Removing old crash detection watcher thread")
console.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): def agree_eula(self, user_id):
file = os.path.join(self.server_path, 'eula.txt') file = os.path.join(self.server_path, 'eula.txt')
@ -610,7 +610,9 @@ class Server:
if len(websocket_helper.clients) > 0: if len(websocket_helper.clients) > 0:
# There are clients # There are clients
self.check_update() 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) time.sleep(3)
websocket_helper.broadcast_page('/panel/server_detail', 'update_button_status', { websocket_helper.broadcast_page('/panel/server_detail', 'update_button_status', {
'isUpdating': self.check_update(), 'isUpdating': self.check_update(),
@ -619,15 +621,18 @@ class Server:
}) })
websocket_helper.broadcast_page('/panel/dashboard', 'send_start_reload', { 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']) management_helper.add_to_audit_log_raw('Alert', '-1', self.server_id, "Executable update finished for "+self.name, self.settings['server_ip'])
if wasStarted: if wasStarted:
self.start_server() self.start_server()
elif not downloaded and not self.is_backingup: elif not downloaded and not self.is_backingup:
time.sleep(5) time.sleep(5)
servers_helper.set_update(self.server_id, False) server_users = server_permissions.get_server_user_list(self.server_id)
websocket_helper.broadcast('notification', for user in server_users:
websocket_helper.broadcast_user(user,'notification',
"Executable update failed for " + self.name + ". Check log file for details.") "Executable update failed for " + self.name + ". Check log file for details.")
logger.error("Executable download failed.") logger.error("Executable download failed.")
pass pass

View File

@ -26,6 +26,7 @@ logger = logging.getLogger('apscheduler')
try: try:
from apscheduler.schedulers.background import BackgroundScheduler from apscheduler.schedulers.background import BackgroundScheduler
from apscheduler.triggers.cron import CronTrigger
except ModuleNotFoundError as e: except ModuleNotFoundError as e:
logger.critical("Import Error: Unable to load {} module".format(e.name), exc_info=True) logger.critical("Import Error: Unable to load {} module".format(e.name), exc_info=True)
@ -52,8 +53,8 @@ class TasksManager:
self.controller = controller self.controller = controller
self.tornado = Webserver(controller, self) self.tornado = Webserver(controller, self)
tz = get_localzone() self.tz = get_localzone()
self.scheduler = BackgroundScheduler(timezone=str(tz)) self.scheduler = BackgroundScheduler(timezone=str(self.tz))
self.users_controller = Users_Controller() self.users_controller = Users_Controller()
@ -86,10 +87,14 @@ class TasksManager:
# select any commands waiting to be processed # select any commands waiting to be processed
commands = management_helper.get_unactioned_commands() commands = management_helper.get_unactioned_commands()
for c in commands: for c in commands:
try:
svr = self.controller.get_server_obj(c['server_id']['server_id']) svr = self.controller.get_server_obj(c.server_id)
user_id = c.get('user')['user_id'] except:
command = c.get('command', None) 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': if command == 'start_server':
svr.run_threaded_server(user_id) svr.run_threaded_server(user_id)
@ -107,7 +112,7 @@ class TasksManager:
svr.jar_update() svr.jar_update()
else: else:
svr.send_command(command) 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) time.sleep(1)
@ -154,11 +159,19 @@ class TasksManager:
schedules = management_helper.get_schedules_enabled() schedules = management_helper.get_schedules_enabled()
self.scheduler.add_listener(self.schedule_watcher, mask=EVENT_JOB_EXECUTED) self.scheduler.add_listener(self.schedule_watcher, mask=EVENT_JOB_EXECUTED)
#self.scheduler.add_job(self.scheduler.print_jobs, 'interval', seconds=10, id='-1') #self.scheduler.add_job(self.scheduler.print_jobs, 'interval', seconds=10, id='-1')
#load schedules from DB #load schedules from DB
for schedule in schedules: for schedule in schedules:
if schedule.cron_string != "": if schedule.cron_string != "":
cron = schedule.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(schedule.schedule_id), args=[schedule.server_id, self.users_controller.get_id_by_name('system'), '127.0.0.1', schedule.command]) 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: else:
if schedule.interval_type == 'hours': 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]) 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']) 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['enabled']:
if job_data['cron_string'] != "": if job_data['cron_string'] != "":
cron = job_data['cron_string'].split(' ')
try: 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: except Exception as e:
console.error("Failed to schedule task with error: {}.".format(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) management_helper.delete_scheduled_task(sch_id)
else: else:
if job_data['interval_type'] == 'hours': if job_data['interval_type'] == 'hours':

View File

@ -199,6 +199,14 @@ class AjaxHandler(BaseHandler):
srv_obj = self.controller.get_server_obj(server_id) 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 command:
if srv_obj.check_running(): if srv_obj.check_running():
srv_obj.send_command(command) srv_obj.send_command(command)
@ -419,7 +427,7 @@ class AjaxHandler(BaseHandler):
server_data = self.controller.get_server_data(server_id) server_data = self.controller.get_server_data(server_id)
server_name = server_data['server_name'] 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), "Deleted server {} named {}".format(server_id, server_name),
server_id, server_id,
self.get_remote_ip()) self.get_remote_ip())
@ -439,7 +447,7 @@ class AjaxHandler(BaseHandler):
server_data = self.controller.get_server_data(server_id) server_data = self.controller.get_server_data(server_id)
server_name = server_data['server_name'] 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), "Deleted server {} named {}".format(server_id, server_name),
server_id, server_id,
self.get_remote_ip()) self.get_remote_ip())

View File

@ -17,6 +17,8 @@ import threading
from cron_validator import CronValidator from cron_validator import CronValidator
#TZLocal is set as a hidden import on win pipeline #TZLocal is set as a hidden import on win pipeline
from tzlocal import get_localzone from tzlocal import get_localzone
import libgravatar
import requests
from tornado import locale, iostream from tornado import locale, iostream
from tornado.ioloop import IOLoop from tornado.ioloop import IOLoop
@ -128,7 +130,7 @@ class PanelHandler(BaseHandler):
# increasing and will eat up the RAM # increasing and will eat up the RAM
del chunk del chunk
def check_server_id(self) -> Optional[str]: def check_server_id(self):
server_id = self.get_argument('id', None) server_id = self.get_argument('id', None)
api_key, _, exec_user = self.current_user api_key, _, exec_user = self.current_user
@ -244,6 +246,24 @@ class PanelHandler(BaseHandler):
} if api_key is not None else None, } if api_key is not None else None,
'superuser': superuser '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': if page == 'unauthorized':
template = "panel/denied.html" template = "panel/denied.html"
@ -539,7 +559,6 @@ class PanelHandler(BaseHandler):
'Players': Enum_Permissions_Server.Players, 'Players': Enum_Permissions_Server.Players,
} }
page_data['user_permissions'] = self.controller.server_perms.get_user_id_permissions_list(exec_user["user_id"], server_id) 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_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['server_stats'] = self.controller.servers.get_server_stats_by_id(server_id)
page_data['new_schedule'] = True page_data['new_schedule'] = True
@ -557,7 +576,7 @@ class PanelHandler(BaseHandler):
page_data['schedule']['difficulty'] = "basic" page_data['schedule']['difficulty'] = "basic"
page_data['schedule']['interval_type'] = 'days' 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: if not superuser:
self.redirect("/panel/error?error=Unauthorized access To Scheduled Tasks") self.redirect("/panel/error?error=Unauthorized access To Scheduled Tasks")
return return
@ -581,7 +600,6 @@ class PanelHandler(BaseHandler):
'Players': Enum_Permissions_Server.Players, 'Players': Enum_Permissions_Server.Players,
} }
page_data['user_permissions'] = self.controller.server_perms.get_user_id_permissions_list(exec_user["user_id"], server_id) 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_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['server_stats'] = self.controller.servers.get_server_stats_by_id(server_id)
page_data['new_schedule'] = False page_data['new_schedule'] = False
@ -609,7 +627,7 @@ class PanelHandler(BaseHandler):
if sch_id == None or server_id == None: if sch_id == None or server_id == None:
self.redirect("/panel/error?error=Invalid server ID or Schedule ID") 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: if not superuser:
self.redirect("/panel/error?error=Unauthorized access To Scheduled Tasks") self.redirect("/panel/error?error=Unauthorized access To Scheduled Tasks")
return return
@ -864,7 +882,6 @@ class PanelHandler(BaseHandler):
'Config': Enum_Permissions_Server.Config, 'Config': Enum_Permissions_Server.Config,
'Players': Enum_Permissions_Server.Players, '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() exec_user_role = set()
if superuser: if superuser:
# defined_servers = self.controller.list_defined_servers() # defined_servers = self.controller.list_defined_servers()
@ -878,7 +895,7 @@ class PanelHandler(BaseHandler):
exec_user_role.add(role['role_name']) exec_user_role.add(role['role_name'])
if page == 'server_detail': 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: if not superuser:
self.redirect("/panel/error?error=Unauthorized access to Config") self.redirect("/panel/error?error=Unauthorized access to Config")
return return
@ -886,7 +903,13 @@ class PanelHandler(BaseHandler):
server_obj = self.controller.servers.get_server_obj(server_id) server_obj = self.controller.servers.get_server_obj(server_id)
if superuser: if superuser:
server_path = self.get_argument('server_path', None) 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) 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) executable = self.get_argument('executable', None)
execution_command = self.get_argument('execution_command', None) execution_command = self.get_argument('execution_command', None)
server_ip = self.get_argument('server_ip', 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) server_obj = self.controller.servers.get_server_obj(server_id)
if superuser: if superuser:
backup_path = bleach.clean(self.get_argument('backup_path', None)) 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: else:
backup_path = server_obj.backup_path backup_path = server_obj.backup_path
max_backups = bleach.clean(self.get_argument('max_backups', None)) 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: if not superuser:
self.redirect("/panel/error?error=Unauthorized access: User not authorized") self.redirect("/panel/error?error=Unauthorized access: User not authorized")
return return
@ -1035,7 +1061,7 @@ class PanelHandler(BaseHandler):
else: else:
one_time = False 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") self.redirect("/panel/error?error=Unauthorized access: User not authorized")
return return
elif server_id is None: elif server_id is None:
@ -1155,7 +1181,7 @@ class PanelHandler(BaseHandler):
else: else:
one_time = False 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") self.redirect("/panel/error?error=Unauthorized access: User not authorized")
return return
elif server_id is None: elif server_id is None:

View File

@ -120,23 +120,6 @@ class PublicHandler(BaseHandler):
# log this login # log this login
self.controller.management.add_to_audit_log(user_data.user_id, "Logged in", 0, self.get_remote_ip()) 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" next_page = "/panel/dashboard"
self.redirect(next_page) self.redirect(next_page)
else: else:

View File

@ -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.models.crafty_permissions import Enum_Permissions_Crafty
from app.classes.minecraft.serverjars import server_jar_obj from app.classes.minecraft.serverjars import server_jar_obj
from app.classes.shared.helpers import helper from app.classes.shared.helpers import helper
import libgravatar
import requests
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -81,6 +83,23 @@ class ServerHandler(BaseHandler):
} if api_key is not None else None, } if api_key is not None else None,
'superuser': superuser '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: if superuser:
page_data['roles'] = list_roles page_data['roles'] = list_roles

View File

@ -18,10 +18,10 @@
<li class="nav-item dropdown user-dropdown"> <li class="nav-item dropdown user-dropdown">
<a class="nav-link dropdown-toggle" id="UserDropdown" href="#" data-toggle="dropdown" aria-expanded="false"> <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-menu dropdown-menu-right navbar-dropdown" aria-labelledby="UserDropdown">
<div class="dropdown-header text-center"> <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="mb-1 mt-3 font-weight-semibold">{{ data['user_data']['username'] }}</p>
<p class="font-weight-light text-muted mb-0">Roles: </p> <p class="font-weight-light text-muted mb-0">Roles: </p>
{% for r in data['user_role'] %} {% for r in data['user_role'] %}

View File

@ -3,7 +3,7 @@
{% block meta %} {% block meta %}
{% end %} {% end %}
{% block title %}Crafty Controller - Panel Config{% end %} {% block title %}Crafty Controller - {{ translate('panelConfig', 'pageTitle', data['lang']) }}{% end %}
{% block content %} {% block content %}
@ -14,7 +14,7 @@
<div class="col-12"> <div class="col-12">
<div class="page-header"> <div class="page-header">
<!-- TODO: Translate the following --> <!-- TODO: Translate the following -->
<h4 class="page-title">Panel Config</h4> <h4 class="page-title">{{ translate('panelConfig', 'pageTitle', data['lang']) }}</h4>
</div> </div>
</div> </div>
@ -30,11 +30,11 @@
<div class="col-md-12 col-lg-12 grid-margin stretch-card"> <div class="col-md-12 col-lg-12 grid-margin stretch-card">
<div class="card"> <div class="card">
<div class="card-header header-sm d-flex justify-content-between align-items-center"> <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> <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 --> <!-- TODO: Translate the following -->
<div><a class="nav-link" href="/panel/add_user"><i class="fas fa-plus-circle"></i> &nbsp; Add New User</a></div> <div><a class="nav-link" href="/panel/add_user"><i class="fas fa-plus-circle"></i> &nbsp; {{ translate('panelConfig', 'newUser', data['lang']) }}</a></div>
</div> </div>
<div class="card-body"> <div class="card-body">
<div class="table-responsive"> <div class="table-responsive">
@ -42,11 +42,11 @@
<thead> <thead>
<!-- TODO: Translate the following --> <!-- TODO: Translate the following -->
<tr class="rounded"> <tr class="rounded">
<th>User</th> <th>{{ translate('panelConfig', 'user', data['lang']) }}</th>
<th>Enabled</th> <th>{{ translate('panelConfig', 'enabled', data['lang']) }}</th>
<th>Allowed Servers</th> <th>{{ translate('panelConfig', 'allowedServers', data['lang']) }}</th>
<th>Assigned Roles</th> <th>{{ translate('panelConfig', 'assignedRoles', data['lang']) }}</th>
<th>Edit</th> <th>{{ translate('panelConfig', 'edit', data['lang']) }}</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
@ -93,9 +93,9 @@
<div class="col-md-12 col-lg-12 grid-margin stretch-card"> <div class="col-md-12 col-lg-12 grid-margin stretch-card">
<div class="card"> <div class="card">
<div class="card-header header-sm d-flex justify-content-between align-items-center"> <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> <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> &nbsp; Add New Role</a></div> <div><a class="nav-link" href="/panel/add_role"><i class="fas fa-plus-circle"></i> &nbsp; {{ translate('panelConfig', 'newRole', data['lang']) }}</a></div>
</div> </div>
<div class="card-body"> <div class="card-body">
<div class="table-responsive"> <div class="table-responsive">
@ -103,10 +103,10 @@
<thead> <thead>
<!-- TODO: Translate the following --> <!-- TODO: Translate the following -->
<tr class="rounded"> <tr class="rounded">
<th>Role</th> <th>{{ translate('panelConfig', 'role', data['lang']) }}</th>
<th>Allowed Servers</th> <th>{{ translate('panelConfig', 'allowedServers', data['lang']) }}</th>
<th>Role Users</th> <th>{{ translate('panelConfig', 'roleUsers', data['lang']) }}</th>
<th>Edit</th> <th>{{ translate('panelConfig', 'edit', data['lang']) }}</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>

View File

@ -3,7 +3,7 @@
{% block meta %} {% block meta %}
{% end %} {% end %}
{% block title %}Crafty Controller - Edit Role{% end %} {% block title %}Crafty Controller - {{ translate('rolesConfig', 'pageTitle', data['lang']) }}{% end %}
{% block content %} {% block content %}
@ -15,13 +15,13 @@
<div class="page-header"> <div class="page-header">
{% if data['new_role'] %} {% if data['new_role'] %}
<h4 class="page-title"> <h4 class="page-title">
New Role {{ translate('rolesConfig', 'pageTitleNew', data['lang']) }}
<br /> <br />
<small>RID: N/A</small> <small>RID: N/A</small>
</h4> </h4>
{% else %} {% else %}
<h4 class="page-title"> <h4 class="page-title">
Edit Role - {{ data['role']['role_name'] }} {{ translate('rolesConfig', 'pageTitle', data['lang']) }} - {{ data['role']['role_name'] }}
<br /> <br />
<small>RID: {{ data['role']['role_id'] }}</small> <small>RID: {{ data['role']['role_id'] }}</small>
</h4> </h4>
@ -40,7 +40,7 @@
<ul class="nav nav-tabs col-md-12 tab-simple-styled " role="tablist"> <ul class="nav nav-tabs col-md-12 tab-simple-styled " role="tablist">
<li class="nav-item"> <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"> <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>
<!-- <li class="nav-item"> <!-- <li class="nav-item">
<a class="nav-link" href="/panel/edit_role?id={{ data['role']['role_id'] }}&subpage=other" role="tab" aria-selected="false"> <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">
<div class="card-header header-sm d-flex justify-content-between align-items-center"> <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>
<div class="card-body"> <div class="card-body">
<div class="form-group"> <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" > <input type="text" class="form-control" name="role_name" id="role_name" value="{{ data['role']['role_name'] }}" placeholder="Role Name" >
</div> </div>
</div> </div>
@ -72,7 +72,7 @@
<div class="card"> <div class="card">
<div class="card-header header-sm d-flex justify-content-between align-items-center"> <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>
<div class="card-body"> <div class="card-body">
<div class="form-group"> <div class="form-group">
@ -80,8 +80,8 @@
<table class="table table-hover"> <table class="table table-hover">
<thead> <thead>
<tr class="rounded"> <tr class="rounded">
<th>Server Name</th> <th>{{ translate('rolesConfig', 'serverName', data['lang']) }}</th>
<th>Access?</th> <th>{{ translate('rolesConfig', 'serverAccess', data['lang']) }}</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
@ -107,7 +107,7 @@
<div class="card"> <div class="card">
<div class="card-header header-sm d-flex justify-content-between align-items-center"> <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>
<div class="card-body"> <div class="card-body">
<div class="form-group"> <div class="form-group">
@ -115,8 +115,8 @@
<table class="table table-hover"> <table class="table table-hover">
<thead> <thead>
<tr class="rounded"> <tr class="rounded">
<th>Permission Name</th> <th>{{ translate('rolesConfig', 'permName', data['lang']) }}</th>
<th>Authorized ?</th> <th>{{ translate('rolesConfig', 'permAccess', data['lang']) }}</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
@ -148,14 +148,14 @@
<div class="col-md-3 col-sm-12"> <div class="col-md-3 col-sm-12">
<div class="card"> <div class="card">
<div class="card-header header-sm d-flex justify-content-between align-items-center"> <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>
<div class="card-body"> <div class="card-body">
<div class="table-responsive"> <div class="table-responsive">
<table class="table table-hover"> <table class="table table-hover">
<thead> <thead>
<tr class="rounded"> <tr class="rounded">
<th>User Name</th> <th>{{ translate('rolesConfig', 'roleUserName', data['lang']) }}</th>
<th></th> <th></th>
</tr> </tr>
</thead> </thead>
@ -182,22 +182,22 @@
<div class="col-md-3 col-sm-12"> <div class="col-md-3 col-sm-12">
<div class="card"> <div class="card">
<div class="card-body"> <div class="card-body">
<h4 class="card-title">Role Config Area</h4> <h4 class="card-title">{{ translate('rolesConfig', 'roleConfigArea', data['lang']) }}</h4>
<p class="card-description"> Here is where you can change the configuration of your role</p> <p class="card-description"> {{ translate('rolesConfig', 'configDesc', data['lang']) }}</p>
<blockquote class="blockquote"> <blockquote class="blockquote">
<p class="mb-0"> <p class="mb-0">
Created: {{ str(data['role']['created']) }} {{ translate('rolesConfig', 'created', data['lang']) }} {{ str(data['role']['created']) }}
<br /> <br />
Last updated: {{ str(data['role']['last_update']) }} {{ translate('rolesConfig', 'configUpdate', data['lang']) }} {{ str(data['role']['last_update']) }}
<br /> <br />
</p> </p>
</blockquote> </blockquote>
<div class="text-center"> <div class="text-center">
{% if data['new_role'] %} {% if data['new_role'] %}
<a class="btn btn-sm btn-danger disabled"><i class="fas fa-trash"></i> Delete Role</a><br /> <a class="btn btn-sm btn-danger disabled"><i class="fas fa-trash"></i>{{ translate('rolesConfig', 'delRole', data['lang']) }}</a><br />
<small>You cannot delete something that does not yet exist</small> <small>{{ translate('rolesConfig', 'doesNotExist', data['lang']) }}</small>
{% else %} {% 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 %} {% end %}
</div> </div>
</div> </div>

View File

@ -15,13 +15,13 @@
<div class="page-header"> <div class="page-header">
{% if data['new_user'] %} {% if data['new_user'] %}
<h4 class="page-title"> <h4 class="page-title">
New User {{ translate('userConfig', 'pageTitleNew', data['lang']) }}
<br /> <br />
<small>UID: N/A</small> <small>UID: N/A</small>
</h4> </h4>
{% else %} {% else %}
<h4 class="page-title"> <h4 class="page-title">
Edit User - {{ data['user']['user_id'] }} {{ translate('userConfig', 'pageTitle', data['lang']) }} - {{ data['user']['user_id'] }}
<br /> <br />
<small>UID: {{ data['user']['user_id'] }}</small> <small>UID: {{ data['user']['user_id'] }}</small>
</h4> </h4>
@ -40,16 +40,12 @@
<ul class="nav nav-tabs col-md-12 tab-simple-styled " role="tablist"> <ul class="nav nav-tabs col-md-12 tab-simple-styled " role="tablist">
<li class="nav-item"> <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"> <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> </li>
{% if not data['new_user'] %} {% if not data['new_user'] %}
<li class="nav-item"> <li class="nav-item">
<a class="nav-link" href="/panel/edit_user_apikeys?id={{ data['user']['user_id'] }}" role="tab" aria-selected="false"> <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> <i class="fas fa-key"></i>{{ translate('userConfig', 'apiKey', data['lang']) }} - {{ data['user']['user_id'] }}</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>
</li> </li>
{% end %} {% end %}
</ul> </ul>
@ -68,27 +64,27 @@
<div class="card"> <div class="card">
<div class="card-header header-sm d-flex justify-content-between align-items-center"> <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>
<div class="card-body"> <div class="card-body">
<div class="form-group"> <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" > <input type="text" class="form-control" name="username" id="username" value="{{ data['user']['username'] }}" placeholder="User Name" >
</div> </div>
<div class="form-group"> <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" > <input type="password" class="form-control" name="password0" id="password0" value="" placeholder="Password" >
</div> </div>
<div class="form-group"> <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" > <input type="password" class="form-control" name="password1" id="password1" value="" placeholder="Repeat Password" >
</div> </div>
<div class="form-group"> <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" > <input type="email" class="form-control" name="email" id="email" value="{{ data['user']['email'] }}" placeholder="Gravatar Email" >
</div> </div>
<div class="form-group"> <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"> <select class="form-select form-control form-control-lg select-css" id="language" name="language" form="user_form">
{% for lang in data['languages'] %} {% for lang in data['languages'] %}
<option value="{{lang}}">{{lang}}</option> <option value="{{lang}}">{{lang}}</option>
@ -100,7 +96,7 @@
<div class="card"> <div class="card">
<div class="card-header header-sm d-flex justify-content-between align-items-center"> <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>
<div class="card-body"> <div class="card-body">
<div class="form-group"> <div class="form-group">
@ -108,8 +104,8 @@
<table class="table table-hover"> <table class="table table-hover">
<thead> <thead>
<tr class="rounded"> <tr class="rounded">
<th>Role Name</th> <th>{{ translate('userConfig', 'roleName', data['lang']) }}</th>
<th>Member?</th> <th>{{ translate('userConfig', 'member', data['lang']) }}</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
@ -137,7 +133,7 @@
<div class="card"> <div class="card">
<div class="card-header header-sm d-flex justify-content-between align-items-center"> <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>
<div class="card-body"> <div class="card-body">
<div class="form-group"> <div class="form-group">
@ -145,9 +141,9 @@
<table class="table table-hover"> <table class="table table-hover">
<thead> <thead>
<tr class="rounded"> <tr class="rounded">
<th>Permission Name</th> <th>{{ translate('userConfig', 'permName', data['lang']) }}</th>
<th>Authorized ?</th> <th>{{ translate('userConfig', 'auth', data['lang']) }}</th>
<th>Number of Uses Allowed (-1=No Limit)</th> <th>{{ translate('userConfig', 'uses', data['lang']) }}</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
@ -174,17 +170,17 @@
<div class="form-check-flat"> <div class="form-check-flat">
<label for="enabled" class="form-check-label ml-4 mb-4"> <label for="enabled" class="form-check-label ml-4 mb-4">
{% if data['user']['enabled'] %} {% 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 %} {% 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 %} {% end %}
</label> </label>
<label for="superuser" class="form-check-label ml-4 mb-4"> <label for="superuser" class="form-check-label ml-4 mb-4">
{% if data['user']['superuser'] %} {% 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 %} {% 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 %} {% end %}
</label> </label>
@ -198,19 +194,17 @@
<div class="col-md-6 col-sm-12"> <div class="col-md-6 col-sm-12">
<div class="card"> <div class="card">
<div class="card-body"> <div class="card-body">
<h4 class="card-title"><i class="fas fa-user-cog"></i> User Config Area</h4> <h4 class="card-title"><i class="fas fa-user-cog"></i> {{ translate('userConfig', 'configArea', data['lang']) }}</h4>
<p class="card-description"> Here is where you can change the configuration of your user</p> <p class="card-description"> {{ translate('userConfig', 'configAreaDesc', data['lang']) }}</p>
<blockquote class="blockquote"> <blockquote class="blockquote">
<p class="mb-0"> <p class="mb-0">
Created: {{ str(data['user']['created']) }} {{ translate('userConfig', 'created', data['lang']) }} {{ str(data['user']['created']) }}
<br /> <br />
Last login: {{ str(data['user']['last_login']) }} {{ translate('userConfig', 'lastLogin', data['lang']) }} {{ str(data['user']['last_login']) }}
<br /> <br />
Last update: {{ str(data['user']['last_update']) }} {{ translate('userConfig', 'lastUpdate', data['lang']) }} {{ str(data['user']['last_update']) }}
<br /> <br />
Last IP: {{ data['user']['last_ip'] }} {{ translate('userConfig', 'lastIP', data['lang']) }} {{ data['user']['last_ip'] }}
<br />
API Key: TODO! <!-- TODO -->
<br /> <br />
</p> </p>
</blockquote> </blockquote>
@ -218,13 +212,13 @@
</div> </div>
<div class="text-center"> <div class="text-center">
{% if data['new_user'] %} {% if data['new_user'] %}
<a class="btn btn-sm btn-danger disabled"><i class="fas fa-trash"></i> Delete User</a><br /> <a class="btn btn-sm btn-danger disabled"><i class="fas fa-trash"></i>{{ translate('userConfig', 'deleteUserB', data['lang']) }}</a><br />
<small>You cannot delete something that does not yet exist</small> <small>{{ translate('userConfig', 'notExist', data['lang']) }}</small>
{% elif data['user']['superuser'] %} {% elif data['user']['superuser'] %}
<a class="btn btn-sm btn-danger disabled"><i class="fas fa-trash"></i> Delete User</a><br /> <a class="btn btn-sm btn-danger disabled"><i class="fas fa-trash"></i> {{ translate('userConfig', 'deleteUserB', data['lang']) }}</a><br />
<small>You cannot delete a superuser</small> <small>{{ translate('userConfig', 'delSuper', data['lang']) }}</small>
{% else %} {% 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 %} {% end %}
</div> </div>
@ -251,8 +245,8 @@
console.log("User to delete is {{ data['user']['username'] }}"); console.log("User to delete is {{ data['user']['username'] }}");
bootbox.confirm({ bootbox.confirm({
title: "{% raw translate('usersConfig', 'deleteUser', data['lang']) %}"+"{{ data['user']['username'] }}", title: "{% raw translate('userConfig', 'deleteUser', data['lang']) %}"+"{{ data['user']['username'] }}",
message: "{{ translate('usersConfig', 'confirmDelete', data['lang']) }}", message: "{{ translate('userConfig', 'confirmDelete', data['lang']) }}",
buttons: { buttons: {
cancel: { cancel: {
label: '<i class="fas fa-times"></i> {{ translate("serverBackups", "cancel", data['lang']) }}' label: '<i class="fas fa-times"></i> {{ translate("serverBackups", "cancel", data['lang']) }}'

View File

@ -14,7 +14,7 @@
<div class="col-12"> <div class="col-12">
<div class="page-header"> <div class="page-header">
<h4 class="page-title"> <h4 class="page-title">
Edit User API Keys - {{ data['user']['user_id'] }} {{ translate('apiKeys', 'pageTitle', data['lang']) }} - {{ data['user']['user_id'] }}
<br/> <br/>
<small>UID: {{ data['user']['user_id'] }}</small> <small>UID: {{ data['user']['user_id'] }}</small>
</h4> </h4>
@ -34,13 +34,13 @@
<a class="nav-link" href="/panel/edit_user?id={{ data['user']['user_id'] }}&subpage=config" <a class="nav-link" href="/panel/edit_user?id={{ data['user']['user_id'] }}&subpage=config"
role="tab" role="tab"
aria-selected="false"> 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>
<li class="nav-item"> <li class="nav-item">
<a class="nav-link active" href="/panel/edit_user_apikeys?id={{ data['user']['user_id'] }}" <a class="nav-link active" href="/panel/edit_user_apikeys?id={{ data['user']['user_id'] }}"
role="tab" role="tab"
aria-selected="true"> 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> </li>
</ul> </ul>
@ -48,7 +48,7 @@
<div class="col-md-7 col-sm-12"> <div class="col-md-7 col-sm-12">
<div class="card"> <div class="card">
<div class="card-header header-sm d-flex justify-content-between align-items-center"> <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>
<div class="card-body"> <div class="card-body">
<div class="form-group"> <div class="form-group">
@ -57,11 +57,11 @@
<thead> <thead>
<tr class="rounded"> <tr class="rounded">
<!--<th>ID</th>--> <!--<th>ID</th>-->
<th>Name</th> <th>{{ translate('apiKeys', 'name', data['lang']) }}</th>
<th>Created</th> <th>{{ translate('apiKeys', 'created', data['lang']) }}</th>
<th>Superuser</th> <th>{{ translate('apiKeys', 'superUser', data['lang']) }}</th>
<th>Permissions</th> <th>{{ translate('apiKeys', 'perms', data['lang']) }}</th>
<th>Buttons</th> <th>{{ translate('apiKeys', 'buttons', data['lang']) }}</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
@ -73,16 +73,16 @@
<td> <td>
{% if apikey.superuser %} {% if apikey.superuser %}
<span class="text-success"> <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> </span>
{% else %} {% else %}
<span class="text-danger"> <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> </span>
{% end %} {% end %}
</td> </td>
<td>Server: {{ apikey.server_permissions }} <td>{{ translate('apiKeys', 'server', data['lang']) }} {{ apikey.server_permissions }}
Crafty: {{ apikey.crafty_permissions }}</td> {{ translate('apiKeys', 'crafty', data['lang']) }} {{ apikey.crafty_permissions }}</td>
<td> <td>
<button <button
class="btn btn-danger delete-api-key" class="btn btn-danger delete-api-key"
@ -93,7 +93,7 @@
class="btn btn-outline-primary get-a-token" class="btn btn-outline-primary get-a-token"
data-key-id="{{ apikey.token_id }}" data-key-id="{{ apikey.token_id }}"
data-key-name="{{ apikey.name }}" data-key-name="{{ apikey.name }}"
>Get a token >{{ translate('apiKeys', 'getToken', data['lang']) }}
</button> </button>
</td> </td>
</tr> </tr>
@ -109,7 +109,7 @@
<div class="col-md-5 col-sm-12"> <div class="col-md-5 col-sm-12">
<div class="card"> <div class="card">
<div class="card-header header-sm d-flex justify-content-between align-items-center"> <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>
<div class="card-body"> <div class="card-body">
<form id="user_form" class="forms-sample" method="post" <form id="user_form" class="forms-sample" method="post"
@ -118,9 +118,8 @@
<input type="hidden" name="id" value="{{ data['user']['user_id'] }}"> <input type="hidden" name="id" value="{{ data['user']['user_id'] }}">
<div class="form-group"> <div class="form-group">
<label class="form-label" for="username">Name <small <label class="form-label" for="username">{{ translate('apiKeys', 'name', data['lang']) }}<small
class="text-muted ml-1"> - What you wish to class="text-muted ml-1"> - {{ translate('apiKeys', 'nameDesc', data['lang']) }}</small> </label>
call this API key</small> </label>
<input type="text" class="form-control" name="name" id="name" <input type="text" class="form-control" name="name" id="name"
placeholder="API Key"> placeholder="API Key">
</div> </div>
@ -128,8 +127,8 @@
<table class="table table-hover mb-3"> <table class="table table-hover mb-3">
<thead> <thead>
<tr class="rounded"> <tr class="rounded">
<th>Permission Name</th> <th>{{ translate('apiKeys', 'permName', data['lang']) }}</th>
<th>Authorized ?</th> <th>{{ translate('apiKeys', 'auth', data['lang']) }}</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>

View File

@ -202,9 +202,9 @@ try{
}catch{ }catch{
console.log("no element named {{ data['schedule']['action'] }}") console.log("no element named {{ data['schedule']['action'] }}")
} }
ifDays();
yesnoCheck(); yesnoCheck();
basicAdvanced(); basicAdvanced();
ifDays();
if("{{ data['schedule']['enabled'] }}" == 'True'){ if("{{ data['schedule']['enabled'] }}" == 'True'){
document.getElementById('enabled').checked = true; document.getElementById('enabled').checked = true;
}else{ }else{

View File

@ -76,10 +76,6 @@
"clickRoot": "Click here to select Root Dir", "clickRoot": "Click here to select Root Dir",
"explainRoot": "Please click the button below to select your server's root dir inside of the archive" "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": "Dashboard", "dashboard": "Dashboard",
"memUsage": "Memory Usage", "memUsage": "Memory Usage",
@ -305,12 +301,85 @@
] ]
}, },
"panelConfig": { "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", "save": "Save",
"cancel": "Cancel", "cancel": "Cancel",
"delete": "Delete", "delete": "Delete",
"superConfirmTitle": "Enable superuser? Are you sure?", "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." "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": { "datatables": {
"i18n": { "i18n": {
"decimal": "", "decimal": "",
@ -379,6 +448,23 @@
"doesNotWorkWithoutJavascript": "<strong>Warning: </strong>Crafty doesn't work properly when JavaScript isn't enabled!" "doesNotWorkWithoutJavascript": "<strong>Warning: </strong>Crafty doesn't work properly when JavaScript isn't enabled!"
}, },
"apiKeys": { "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.", "deleteKeyConfirmation": "Do you want to delete this API key? This cannot be undone.",
"deleteKeyConfirmationTitle": "Remove API key ${keyId}?" "deleteKeyConfirmationTitle": "Remove API key ${keyId}?"
} }

View File

@ -6,13 +6,20 @@ upstream crafty {
} }
server { server {
listen 80 default_server; listen 80;
server_name <DOMAIN>;
if ($host !~* ^<SUBDOMAIN>\.<EXAMPLE>\.com$ ) {
return 444;
}
rewrite ^(.*) https://$host$1 permanent; rewrite ^(.*) https://$host$1 permanent;
} }
server { server {
listen 443 ssl; listen 443 ssl;
server_name <DOMAIN>; server_name <DOMAIN>;
if ($host !~* ^<SUBDOMAIN>\.<EXAMPLE>\.com$ ) {
return 444;
}
ssl_certificate <CERIFICATE_LOCATION>; ssl_certificate <CERIFICATE_LOCATION>;
ssl_certificate_key <KEYFILE_LOCATION>; ssl_certificate_key <KEYFILE_LOCATION>;
location / { location / {