Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add more improvements to Guidebook syncing #4442

Merged
merged 3 commits into from
Jan 16, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions uber/configspec.ini
Original file line number Diff line number Diff line change
Expand Up @@ -737,6 +737,10 @@ panels_confirm_deadline = integer(default=0)
# be ready, so we just set this to false whenever it is.
hide_schedule = boolean(default=True)

# Emails about changes to schedule items and other Guidebook items are sent TO this address.
# If the address is not set, these emails are disabled.
guidebook_updates_email = string(default="")

# These are the areas from which we'll show events to associated with panel
# applications on the schedule.
panel_rooms = string_list(default=list())
Expand Down
4 changes: 3 additions & 1 deletion uber/models/panels.py
Original file line number Diff line number Diff line change
Expand Up @@ -149,11 +149,13 @@ class PanelApplication(MagModel):

@presave_adjustment
def update_event_info(self):
if self.event:
if self.event and any([getattr(self.event, key, '') != getattr(self, key, '') for key in [
'name', 'description', 'public_description', 'track']]):
self.event.name = self.name
self.event.description = self.description
self.event.public_description = self.public_description
self.event.track = self.track
self.event.last_updated = self.last_updated

@presave_adjustment
def set_default_dept(self):
Expand Down
71 changes: 66 additions & 5 deletions uber/tasks/panels.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,47 @@
import json

from collections import defaultdict
from datetime import timedelta
from dateutil import parser as dateparser
from sqlalchemy import or_

from uber.config import c
from uber.decorators import render
from uber.models import Session
from uber.models import Email, Session, Tracking
from uber.tasks import celery
from uber.tasks.email import send_email
from uber.utils import GuidebookUtils, localized_now


__all__ = ['panels_waitlist_unaccepted_panels', 'sync_guidebook_models', 'check_stale_guidebook_models']
__all__ = ['panels_waitlist_unaccepted_panels', 'sync_guidebook_models',
'check_deleted_guidebook_models', 'check_stale_guidebook_models']


def _get_deleted_models(session, deleted_since=None):
deleted_synced = session.query(Tracking).filter(Tracking.action == c.DELETED,
Tracking.snapshot.contains('"last_synced": {"data": {"guidebook"'))
if deleted_since:
deleted_synced = deleted_synced.filter(Tracking.when > deleted_since)

deleted_models = defaultdict(list)
model_names = {}

for key, label in c.GUIDEBOOK_MODELS:
model_names[key] = label

for tracking_entry in deleted_synced:
snapshot = json.loads(tracking_entry.snapshot)

model = snapshot['_model']
if model == 'GuestGroup':
model += '_band' if snapshot['group_type'] == c.BAND else '_guest'
elif model == 'Group':
model += '_dealer'

model_name = 'Schedule Item' if model == 'Event' else model_names[model]

deleted_models[model_name].append(snapshot['last_synced']['data']['guidebook']['name'])
return deleted_models


@celery.task
Expand All @@ -31,21 +62,51 @@ def sync_guidebook_models(selected_model, sync_time, id_list):
session.commit()


@celery.schedule(timedelta(hours=12))
def check_deleted_guidebook_models():
if not c.PRE_CON or not c.GUIDEBOOK_UPDATES_EMAIL:
return

with Session() as session:
subject = f"Deleted Guidebook Items: {localized_now().strftime("%A %-I:%M %p")}"
last_email = session.query(Email).filter(Email.subject.contains("Deleted Guidebook Items")
).order_by(Email.when.desc()).first()

deleted_models = _get_deleted_models(session, deleted_since=last_email.when) if last_email else _get_deleted_models(session)

if deleted_models:
body = render('emails/guidebook_deletes.txt', {
'deleted_models': deleted_models,
}, encoding=None)
send_email.delay(c.REPORTS_EMAIL, c.GUIDEBOOK_UPDATES_EMAIL,
subject, body, ident="guidebook_deletes"
)


@celery.schedule(timedelta(minutes=15))
def check_stale_guidebook_models():
if not c.AT_THE_CON:
if not c.AT_THE_CON or not c.GUIDEBOOK_UPDATES_EMAIL:
return

with Session() as session:
cl_updates, schedule_updates = GuidebookUtils.get_changed_models(session)
stale_models = [key for key in cl_updates if cl_updates[key]]
if schedule_updates:
stale_models.append('Schedule')
if stale_models:

last_email = session.query(Email).filter(or_(
Email.subject.contains("Guidebook Updates"),
Email.subject.contains("Deleted Guidebook Items"))
).order_by(Email.when.desc()).first()

deleted_models = _get_deleted_models(session, deleted_since=last_email.when) if last_email else _get_deleted_models(session)

if stale_models or deleted_models:
body = render('emails/guidebook_updates.txt', {
'stale_models': stale_models,
'deleted_models': deleted_models,
}, encoding=None)
send_email.delay(c.REPORTS_EMAIL, "[email protected]",
send_email.delay(c.REPORTS_EMAIL, c.GUIDEBOOK_UPDATES_EMAIL,
f"Guidebook Updates: {localized_now().strftime("%A %-I:%M %p")}",
body, ident="guidebook_updates"
)
Expand Down
7 changes: 7 additions & 0 deletions uber/templates/emails/guidebook_deletes.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
Attention Guidebook admins! The items below have been deleted from the system.

{% for category in deleted_models %}{{ category }}(s):
{% for item in deleted_models[category] %} - {{ item }}
{% endfor %}{% endfor %}

This email will be the only record of these item deletions. Please keep it until you delete all the above items from Guidebook.
11 changes: 9 additions & 2 deletions uber/templates/emails/guidebook_updates.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
Attention Guidebook admins!
The following categories have stale items:

{% if stale_models %}The following categories have been updated in the system:
{% for label in stale_models %}- {{ label }}
{% endfor %}

You can review all pending items here: {{ c.URL_BASE }}/schedule_reports/index
{% endif %}{% if deleted_models %}The following items have been deleted:
{% for category in deleted_models %}{{ category }}(s):
{% for item in deleted_models[category] %} - {{ item }}
{% endfor %}
{% endfor %}

{% endif %}You can review all pending items here: {{ c.URL_BASE }}/schedule_reports/index
23 changes: 13 additions & 10 deletions uber/templates/schedule_reports/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,9 @@
});
}

let markItemSynced = function(event){
let form = $(this);
event.preventDefault();
let markItemSynced = function(){
let form = $(this).closest('form');

$.ajax({
method: 'POST',
url: 'mark_item_synced',
Expand Down Expand Up @@ -81,7 +81,10 @@
}

$().ready(function () {
$(".sync-item").submit(markItemSynced);
$('#schedule-table').on('click', '.sync-item', markItemSynced);
{% for model, label in c.GUIDEBOOK_MODELS %}
$('#{{ model }}-table').on('click', '.sync-item', markItemSynced);
{% endfor %}
});
</script>
{% set now = now() %}
Expand Down Expand Up @@ -158,7 +161,7 @@ <h2>Guidebook Exports and Updates -- {{ now|datetime_local("%m/%d/%Y, %-I:%M%p")
</form>
<p>Items in <em>italics</em> has been changed since the last sync.</p>
</div>
<table class="table table-hover datatable">
<table class="table table-hover datatable" id="schedule-table">
<thead>
<tr>
<th>Name</th>
Expand Down Expand Up @@ -203,13 +206,13 @@ <h2>Guidebook Exports and Updates -- {{ now|datetime_local("%m/%d/%Y, %-I:%M%p")
{% if c.HAS_SCHEDULE_ACCESS %}
<a href="../schedule/form?id={{ result.id }}" target="_blank" class="btn btn-primary">View</a>
{% endif %}
<form method="post" class="sync-item" action="mark_item_synced">
<form method="post" action="mark_item_synced">
{{ csrf_token() }}
<input type="hidden" name="selected_model" value="schedule" />
<input type="hidden" name="id" value="{{ result.id }}" />
<input type="hidden" name="sync_time" value="{{ now }}" />
<input type="hidden" name="sync_data" value='{{ current_data|tojson }}' />
<button type="submit" class="btn btn-success">Mark Synced</button>
<button type="button" class="btn btn-success sync-item">Mark Synced</button>
</form>
</div>
</td>
Expand All @@ -234,7 +237,7 @@ <h2>Guidebook Exports and Updates -- {{ now|datetime_local("%m/%d/%Y, %-I:%M%p")
</form>
<p>Items in <em>italics</em> has been changed since the last sync.</p>
</div>
<table class="table table-hover datatable">
<table class="table table-hover datatable" id="{{ model }}-table">
<thead>
<tr>
{% for key, label in c.GUIDEBOOK_PROPERTIES %}
Expand Down Expand Up @@ -275,13 +278,13 @@ <h2>Guidebook Exports and Updates -- {{ now|datetime_local("%m/%d/%Y, %-I:%M%p")
{% if result.guidebook_edit_link.split('/')[1] in (c.GETTABLE_SITE_PAGES[0] + c.ADMIN_ACCESS_SET|list) %}
<a href="{{ result.guidebook_edit_link }}" target="_blank" class="btn btn-primary">View</a>
{% endif %}
<form method="post" class="sync-item" action="mark_item_synced">
<form method="post" action="mark_item_synced">
{{ csrf_token() }}
<input type="hidden" name="selected_model" value="{{ model }}" />
<input type="hidden" name="id" value="{{ result.id }}" />
<input type="hidden" name="sync_time" value="{{ now }}" />
<input type="hidden" name="sync_data" value='{{ current_data|tojson }}' />
<button type="submit" class="btn btn-success">Mark Synced</button>
<button type="button" class="btn btn-success sync-item">Mark Synced</button>
</form>
</div>
</td>
Expand Down
Loading