Merge branch 'enhancement/pretzel-next-run' into 'dev'

Add next run to schedule info

See merge request crafty-controller/crafty-4!417
This commit is contained in:
Iain Powrie 2022-08-05 00:46:45 +00:00
commit bc8ec179a1
5 changed files with 109 additions and 36 deletions

View File

@ -10,7 +10,7 @@ TBD
- Fix server creation with serverjars API ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/415))
- Fix API Key delete confirmations ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/416))
### Tweaks
TBD
- Add next run to schedule info ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/417))
### Lang
- Updated `es_ES` ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/412))
- Added `pl_PL` ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/412))

View File

@ -115,6 +115,7 @@ class Schedules(BaseModel):
cron_string = CharField(default="")
parent = IntegerField(null=True)
delay = IntegerField(default=0)
next_run = CharField(default="")
class Meta:
table_name = "schedules"
@ -285,6 +286,7 @@ class HelpersManagement:
Schedules.cron_string: cron_string,
Schedules.parent: parent,
Schedules.delay: delay,
Schedules.next_run: "",
}
).execute()
return sch_id

View File

@ -192,6 +192,7 @@ class TasksManager:
def scheduler_thread(self):
schedules = HelpersManagement.get_schedules_enabled()
self.scheduler.add_listener(self.schedule_watcher, mask=EVENT_JOB_EXECUTED)
self.scheduler.start()
# self.scheduler.add_job(
# self.scheduler.print_jobs, "interval", seconds=10, id="-1"
# )
@ -201,7 +202,7 @@ class TasksManager:
if schedule.interval != "reaction":
if schedule.cron_string != "":
try:
self.scheduler.add_job(
new_job = self.scheduler.add_job(
HelpersManagement.add_command,
CronTrigger.from_crontab(
schedule.cron_string, timezone=str(self.tz)
@ -215,6 +216,7 @@ class TasksManager:
],
)
except Exception as e:
new_job = "error"
Console.error(f"Failed to schedule task with error: {e}.")
Console.warning("Removing failed task from DB.")
logger.error(f"Failed to schedule task with error: {e}.")
@ -225,7 +227,7 @@ class TasksManager:
)
else:
if schedule.interval_type == "hours":
self.scheduler.add_job(
new_job = self.scheduler.add_job(
HelpersManagement.add_command,
"cron",
minute=0,
@ -239,7 +241,7 @@ class TasksManager:
],
)
elif schedule.interval_type == "minutes":
self.scheduler.add_job(
new_job = self.scheduler.add_job(
HelpersManagement.add_command,
"cron",
minute="*/" + str(schedule.interval),
@ -253,7 +255,7 @@ class TasksManager:
)
elif schedule.interval_type == "days":
curr_time = schedule.start_time.split(":")
self.scheduler.add_job(
new_job = self.scheduler.add_job(
HelpersManagement.add_command,
"cron",
day="*/" + str(schedule.interval),
@ -267,7 +269,18 @@ class TasksManager:
schedule.command,
],
)
self.scheduler.start()
if new_job != "error":
task = self.controller.management.get_scheduled_task_model(
int(new_job.id)
)
self.controller.management.update_scheduled_task(
task.schedule_id,
{
"next_run": str(
new_job.next_run_time.strftime("%m/%d/%Y, %H:%M:%S")
)
},
)
jobs = self.scheduler.get_jobs()
logger.info("Loaded schedules. Current enabled schedules: ")
for item in jobs:
@ -298,7 +311,7 @@ class TasksManager:
if job_data["enabled"] and job_data["interval_type"] != "reaction":
if job_data["cron_string"] != "":
try:
self.scheduler.add_job(
new_job = self.scheduler.add_job(
HelpersManagement.add_command,
CronTrigger.from_crontab(
job_data["cron_string"], timezone=str(self.tz)
@ -312,6 +325,7 @@ class TasksManager:
],
)
except Exception as e:
new_job = "error"
Console.error(f"Failed to schedule task with error: {e}.")
Console.warning("Removing failed task from DB.")
logger.error(f"Failed to schedule task with error: {e}.")
@ -320,7 +334,7 @@ class TasksManager:
self.controller.management_helper.delete_scheduled_task(sch_id)
else:
if job_data["interval_type"] == "hours":
self.scheduler.add_job(
new_job = self.scheduler.add_job(
HelpersManagement.add_command,
"cron",
minute=0,
@ -334,7 +348,7 @@ class TasksManager:
],
)
elif job_data["interval_type"] == "minutes":
self.scheduler.add_job(
new_job = self.scheduler.add_job(
HelpersManagement.add_command,
"cron",
minute="*/" + str(job_data["interval"]),
@ -348,7 +362,7 @@ class TasksManager:
)
elif job_data["interval_type"] == "days":
curr_time = job_data["start_time"].split(":")
self.scheduler.add_job(
new_job = self.scheduler.add_job(
HelpersManagement.add_command,
"cron",
day="*/" + str(job_data["interval"]),
@ -364,6 +378,14 @@ class TasksManager:
)
logger.info("Added job. Current enabled schedules: ")
jobs = self.scheduler.get_jobs()
if new_job != "error":
task = self.controller.management.get_scheduled_task_model(
int(new_job.id)
)
self.controller.management.update_scheduled_task(
task.schedule_id,
{"next_run": new_job.next_run_time.strftime("%m/%d/%Y, %H:%M:%S")},
)
for item in jobs:
logger.info(f"JOB: {item}")
@ -418,7 +440,7 @@ class TasksManager:
if job_data["enabled"] and job_data["interval"] != "reaction":
if job_data["cron_string"] != "":
try:
self.scheduler.add_job(
new_job = self.scheduler.add_job(
HelpersManagement.add_command,
CronTrigger.from_crontab(
job_data["cron_string"], timezone=str(self.tz)
@ -432,12 +454,13 @@ class TasksManager:
],
)
except Exception as e:
new_job = "error"
Console.error(f"Failed to schedule task with error: {e}.")
Console.info("Removing failed task from DB.")
self.controller.management_helper.delete_scheduled_task(sch_id)
else:
if job_data["interval_type"] == "hours":
self.scheduler.add_job(
new_job = self.scheduler.add_job(
HelpersManagement.add_command,
"cron",
minute=0,
@ -451,7 +474,7 @@ class TasksManager:
],
)
elif job_data["interval_type"] == "minutes":
self.scheduler.add_job(
new_job = self.scheduler.add_job(
HelpersManagement.add_command,
"cron",
minute="*/" + str(job_data["interval"]),
@ -465,7 +488,7 @@ class TasksManager:
)
elif job_data["interval_type"] == "days":
curr_time = job_data["start_time"].split(":")
self.scheduler.add_job(
new_job = self.scheduler.add_job(
HelpersManagement.add_command,
"cron",
day="*/" + str(job_data["interval"]),
@ -479,6 +502,14 @@ class TasksManager:
job_data["command"],
],
)
if new_job != "error":
task = self.controller.management.get_scheduled_task_model(
int(new_job.id)
)
self.controller.management.update_scheduled_task(
task.schedule_id,
{"next_run": new_job.next_run_time.strftime("%m/%d/%Y, %H:%M:%S")},
)
else:
try:
self.scheduler.get_job(str(sch_id))
@ -506,6 +537,15 @@ class TasksManager:
if task.one_time:
self.remove_job(task.schedule_id)
logger.info("one time task detected. Deleting...")
else:
self.controller.management.update_scheduled_task(
task.schedule_id,
{
"next_run": self.scheduler.get_job(
event.job_id
).next_run_time.strftime("%m/%d/%Y, %H:%M:%S")
},
)
# check for any child tasks for this. It's kind of backward,
# but this makes DB management a lot easier. One to one
# instead of one to many.

View File

@ -14,7 +14,8 @@
<div class="col-12">
<div class="page-header">
<h4 class="page-title">
{{ translate('serverDetails', 'serverDetails', data['lang']) }} - {{ data['server_stats']['server_id']['server_name'] }}
{{ translate('serverDetails', 'serverDetails', data['lang']) }} - {{
data['server_stats']['server_id']['server_name'] }}
<br />
<small>UUID: {{ data['server_stats']['server_id']['server_uuid'] }}</small>
</h4>
@ -46,23 +47,23 @@
<h4 class="card-title"><i class="fas fa-calendar"></i> Scheduled Tasks</h4>
{% if data['user_data']['hints'] %}
<span class="too_small" title="{{ translate('serverSchedules', 'cannotSee', data['lang']) }}" ,
data-content="{{ translate('serverSchedules', 'cannotSeeOnMobile', data['lang']) }}" ,
data-placement="bottom"></span>
data-content="{{ translate('serverSchedules', 'cannotSeeOnMobile', data['lang']) }}" ,
data-placement="bottom"></span>
{% end %}
<div><button
onclick="location.href=`/panel/add_schedule?id={{ data['server_stats']['server_id']['server_id'] }}`"
class="btn btn-info">Create New Schedule <i class="fas fa-pencil-alt"></i></button></div>
onclick="location.href=`/panel/add_schedule?id={{ data['server_stats']['server_id']['server_id'] }}`"
class="btn btn-info">Create New Schedule <i class="fas fa-pencil-alt"></i></button></div>
</div>
<div class="card-body">
<table class="table table-hover d-none d-lg-block responsive-table" id="schedule_table" width="100%"
style="table-layout:fixed;">
style="table-layout:fixed;">
<thead>
<tr class="rounded">
<th style="width: 2%; min-width: 10px;">ID</th>
<th style="width: 23%; min-width: 50px;">Action</th>
<th style="width: 40%; min-width: 50px;">Command</th>
<th style="width: 10%; min-width: 50px;">Interval</th>
<th style="width: 10%; min-width: 50px;">Start Time</th>
<th style="width: 10%; min-width: 50px;">Next Run</th>
<th style="width: 10%; min-width: 50px;">Enabled</th>
<th style="width: 10%; min-width: 50px;">Edit</th>
</tr>
@ -91,13 +92,17 @@
{% end %}
</td>
<td id="{{schedule.start_time}}" class="action">
<p>{{schedule.start_time}}</p>
<p>{{schedule.next_run}}</p>
</td>
<td id="{{schedule.enabled}}" class="action">
<input style="width: 10px !important;" type="checkbox" class="schedule-enabled-toggle" data-schedule-id="{{schedule.schedule_id}}" data-schedule-enabled="{{ 'true' if schedule.enabled else 'false' }}">
<input style="width: 10px !important;" type="checkbox" class="schedule-enabled-toggle"
data-schedule-id="{{schedule.schedule_id}}"
data-schedule-enabled="{{ 'true' if schedule.enabled else 'false' }}">
</td>
<td id="{{schedule.action}}" class="action">
<button onclick="window.location.href='/panel/edit_schedule?id={{ data['server_stats']['server_id']['server_id'] }}&sch_id={{schedule.schedule_id}}'" class="btn btn-info">
<button
onclick="window.location.href='/panel/edit_schedule?id={{ data['server_stats']['server_id']['server_id'] }}&sch_id={{schedule.schedule_id}}'"
class="btn btn-info">
<i class="fas fa-pencil-alt"></i>
</button>
<br>
@ -111,7 +116,8 @@
</tbody>
</table>
<hr />
<table class="table table-hover d-block d-lg-none" id="mini_schedule_table" width="100%" style="table-layout:fixed;">
<table class="table table-hover d-block d-lg-none" id="mini_schedule_table" width="100%"
style="table-layout:fixed;">
<thead>
<tr class="rounded">
<th style="width: 25%; min-width: 50px;">Action</th>
@ -141,7 +147,8 @@
</td>
</tr>
<!-- Modal -->
<div class="modal fade" id="task_details_{{schedule.schedule_id}}" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
<div class="modal fade" id="task_details_{{schedule.schedule_id}}" tabindex="-1" role="dialog"
aria-labelledby="exampleModalLabel" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
@ -177,17 +184,22 @@
{% end %}
</li>
<li id="{{schedule.start_time}}" class="action" style="border-top: .1em solid gray;">
<h4>Start Time</h4>
<p>{{schedule.start_time}}</p>
<h4>Next Run</h4>
<p>{{schedule.next_run}}</p>
</li>
<li id="{{schedule.enabled}}" class="action" style="border-top: .1em solid gray; border-bottom: .1em solid gray">
<li id="{{schedule.enabled}}" class="action"
style="border-top: .1em solid gray; border-bottom: .1em solid gray">
<h4>Enabled</h4>
<input type="checkbox" class="schedule-enabled-toggle" data-schedule-id="{{schedule.schedule_id}}" data-schedule-enabled="{{ 'true' if schedule.enabled else 'false' }}">
<input type="checkbox" class="schedule-enabled-toggle"
data-schedule-id="{{schedule.schedule_id}}"
data-schedule-enabled="{{ 'true' if schedule.enabled else 'false' }}">
</li>
</ul>
</div>
<div class="modal-footer">
<button onclick="window.location.href='/panel/edit_schedule?id={{ data['server_stats']['server_id']['server_id'] }}&sch_id={{schedule.schedule_id}}'" class="btn btn-info">
<button
onclick="window.location.href='/panel/edit_schedule?id={{ data['server_stats']['server_id']['server_id'] }}&sch_id={{schedule.schedule_id}}'"
class="btn btn-info">
<i class="fas fa-pencil-alt"></i> Edit
</button>
<button data-sch={{ schedule.schedule_id }} class="btn btn-danger del_button">
@ -215,12 +227,15 @@
color: white !important;
;
}
.toggle-handle {
background-color: white !important;
}
.toggle-on {
color: black !important;
}
.toggle {
height: 0px !important;
}
@ -250,7 +265,7 @@
{% block js %}
<script>
function debounce(func, timeout = 300){
function debounce(func, timeout = 300) {
let timer;
return (...args) => {
clearTimeout(timer);
@ -265,17 +280,17 @@
onstyle: 'success',
offstyle: 'danger',
})
$('.schedule-enabled-toggle').each(function() {
$('.schedule-enabled-toggle').each(function () {
const enabled = JSON.parse(this.getAttribute('data-schedule-enabled'));
$(this).bootstrapToggle(enabled ? 'on' : 'off')
})
$('.schedule-enabled-toggle').change(function() {
$('.schedule-enabled-toggle').change(function () {
const id = this.getAttribute('data-schedule-id');
const enabled = this.checked;
fetch(`/api/v2/servers/{{data['server_id']}}/tasks/${id}`, {
method: 'PATCH',
body: JSON.stringify({enabled}),
body: JSON.stringify({ enabled }),
headers: {
'Content-Type': 'application/json',
},
@ -420,4 +435,4 @@
</script>
{% end %}
{% end %}

View File

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