Skip to content
Draft
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 cuegui/cuegui/Constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,10 @@ def __get_version_from_cmd(command):
SHOW_SUPPORT_CC_TEMPLATE = [val.strip()
for val
in __config.get('email.show_support_cc_template', '').split(',')]
SUBSCRIPTION_CHANGE_CC_TEMPLATE = [val.strip()
for val
in __config.get('email.subscription_change_cc', '').split(',')
if val.strip()]

GITHUB_CREATE_ISSUE_URL = __config.get('links.issue.create')
URL_USERGUIDE = __config.get('links.user_guide')
Expand Down
100 changes: 100 additions & 0 deletions cuegui/cuegui/MenuActions.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,18 @@
from builtins import filter
from builtins import str
from builtins import object
import datetime
import getpass
import glob
import smtplib
import subprocess
import time
try:
from email.MIMEText import MIMEText
from email.Header import Header
except ImportError:
from email.mime.text import MIMEText
from email.header import Header

from qtpy import QtGui
from qtpy import QtWidgets
Expand Down Expand Up @@ -1663,6 +1671,82 @@ class SubscriptionActions(AbstractActions):
def __init__(self, *args):
AbstractActions.__init__(self, *args)

def _sendSubscriptionChangeEmail(self, subscription, change_type, old_value, new_value):
"""Sends an email notification when a subscription is changed.
@param subscription: The subscription object that was changed
@param change_type: Type of change ('size' or 'burst')
@param old_value: The previous value (in cores)
@param new_value: The new value (in cores)
"""
try:
username = getpass.getuser()
timestamp = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")

# Extract show name from subscription
show_name = subscription.data.show_name
subscription_name = subscription.data.name
allocation_name = subscription.data.allocation_name

# Construct email
subject = "Subscription {} Changed: {}".format(change_type.title(), subscription_name)

body = """A subscription {} has been modified.
Subscription: {}
Show: {}
Allocation: {}
Change Details:
{}: {} -> {}
Modified by: {}
Timestamp: {}
This is an automated notification from CueCommander.
""".format(change_type, subscription_name, show_name, allocation_name,
change_type.title(), old_value, new_value, username, timestamp)

# Email addresses
email_domain = cuegui.Constants.EMAIL_DOMAIN
if not email_domain:
logger.warning("EMAIL_DOMAIN not configured, skipping email notification")
return

from_addr = "cuecommander@{}".format(email_domain)

# Build CC list from configuration template
cc_list = []
for template in cuegui.Constants.SUBSCRIPTION_CHANGE_CC_TEMPLATE:
if template:
cc_addr = template.format(show=show_name, domain=email_domain)
cc_list.append(cc_addr)

# Skip sending email if no CC recipients are configured
if not cc_list:
logger.info(
"No CC recipients configured for subscription change notifications, "
"skipping email")
return

# Create email message
msg = MIMEText(body, 'plain', 'utf-8')
msg["Subject"] = Header(subject, 'utf-8', continuation_ws=' ')
msg["From"] = from_addr
msg["To"] = from_addr
msg["Cc"] = ", ".join(cc_list)

# Send email
recipient_list = [from_addr] + cc_list
server = smtplib.SMTP('smtp')
server.sendmail(from_addr, recipient_list, msg.as_string())
server.quit()

logger.info("Sent subscription change notification email for %s", subscription_name)
except Exception as e:
# Log error but don't fail the operation if email fails
logger.warning("Failed to send subscription change notification email: %s", e)

editSize_info = ["Edit Subscription Size...", None, "configure"]
def editSize(self, rpcObjects=None):
subs = self._getSelected(rpcObjects)
Expand All @@ -1688,9 +1772,17 @@ def editSize(self, rpcObjects=None):
return

for sub in subs:
# Capture old value before change
old_size = sub.data.size / 100.0
new_size = value

self.cuebotCall(sub.setSize,
"Set Size on Subscription %s Failed" % sub.data.name,
int(value*100.0))

# Send email notification
self._sendSubscriptionChangeEmail(sub, "size", old_size, new_size)

self._update()

editBurst_info = ["Edit Subscription Burst...", None, "configure"]
Expand All @@ -1708,9 +1800,17 @@ def editBurst(self, rpcObjects=None):
decimalPlaces)
if choice:
for sub in subs:
# Capture old value before change
old_burst = sub.data.burst / 100.0
new_burst = value

self.cuebotCall(sub.setBurst,
"Set Burst on Subscription %s Failed" % sub.data.name,
int(value*100.0))

# Send email notification
self._sendSubscriptionChangeEmail(sub, "burst", old_burst, new_burst)

self._update()

delete_info = ["Delete Subscription", None, "configure"]
Expand Down
8 changes: 8 additions & 0 deletions cuegui/cuegui/config/cuegui.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,14 @@ email.domain: 'your.domain.com'
# - {show} is not required and will be replaced by the job show
# - Multiple addresses might be provided in a comma-separated list
email.show_support_cc_template: "{show}-support@{domain}"
# CC list for subscription change notifications (size/burst changes)
# - {domain} will be replaced by email.domain
# - {show} will be replaced by the subscription show name
# - Multiple addresses might be provided in a comma-separated list
# - Set to empty string ("") to disable email notifications for subscription changes
# - Example: "{show}-admin@{domain},resource-team@{domain}"
# - Example: "[email protected],[email protected]"
email.subscription_change_cc: ""

# Unix epoch timestamp. If the user last viewed the startup notice before this time, the
# notice will be shown.
Expand Down
Loading