Skip to content

Commit

Permalink
Merge pull request #7 from Webcampak/develop
Browse files Browse the repository at this point in the history
Implemented email alerts
  • Loading branch information
Fgerthoffert authored Dec 10, 2016
2 parents df4f1ba + 30abd62 commit c5727fd
Show file tree
Hide file tree
Showing 16 changed files with 1,079 additions and 136 deletions.
11 changes: 11 additions & 0 deletions config/plugins.d/alerts.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
### Reports Plugin Configuration for Webcampak

[alerts]

### If enabled, load a plugin named `example` either from the Python module
### `webcampak.cli.plugins.example` or from the file path
### `/var/lib/webcampak/plugins/example.py`
enable_plugin = true

### Additional plugin configuration settings
###foo = bar
63 changes: 63 additions & 0 deletions webcampak/cli/plugins/alerts.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
"""Example Plugin for Webcampak."""

from cement.core.controller import CementBaseController, expose
from cement.core import handler, hook

from webcampak.core.wpakAlertsCapture import alertsCapture

def alerts_plugin_hook(app):
# do something with the ``app`` object here.
pass

class ExamplePluginController(CementBaseController):
class Meta:
# name that the controller is displayed at command line
label = 'alerts'

# text displayed next to the label in ``--help`` output
description = 'Trigger some alerts based on specific events or checks'

# stack this controller on-top of ``base`` (or any other controller)
stacked_on = 'base'

# determines whether the controller is nested, or embedded
stacked_type = 'nested'

# these arguments are only going to display under
# ``$ webcampak alerts --help``
arguments = [
(
['-s', '--sourceid'],
dict(
help='Run the alert only for the specified source',
action='store',
)
)
]

@expose(hide=True)
def default(self):
self.app.log.info("Please indicate which command to run")

@expose(help="Alert if a capture is running late based on source schedule")
def capture(self):
self.app.log.info("Starting Capture Alert", __file__)
if self.app.pargs.config_dir != None:
config_dir = self.app.pargs.config_dir
else:
config_dir = self.app.config.get('webcampak', 'config_dir')

try:
start = alertsCapture(self.app.log, self.app.config, config_dir, self.app.pargs.sourceid)
start.run()
except Exception:
self.app.log.fatal("Ooops! Something went terribly wrong, stack trace below:", exc_info=True)
raise


def load(app):
# register the plugin class.. this only happens if the plugin is enabled
handler.register(ExamplePluginController)

# register a hook (function) to run after arguments are parsed.
hook.register('post_argument_parsing', alerts_plugin_hook)
11 changes: 1 addition & 10 deletions webcampak/cli/plugins/reports.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,23 +25,14 @@ class Meta:

# these arguments are only going to display under
# ``$ webcampak reports --help``
arguments = [
(
['-t', '--thread'],
dict(
help='Start/Stop a specific XFer job thread',
action='store',
)
)
]

@expose(hide=True)
def default(self):
self.app.log.info("Please indicate which command to run")

@expose(help="Daily reports for all sources")
def daily(self):
self.app.log.info("Starting XFer Dispatch", __file__)
self.app.log.info("Starting Daily report for all sources", __file__)
if self.app.pargs.config_dir != None:
config_dir = self.app.pargs.config_dir
else:
Expand Down
9 changes: 8 additions & 1 deletion webcampak/cli/plugins/stats.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,13 @@ class Meta:
action='store',
)
)
, (
['--full'],
dict(
help='Run consolidation on all system logs',
action='store_true',
)
)
]

@expose(hide=True)
Expand Down Expand Up @@ -65,7 +72,7 @@ def consolidate(self):

try:
consolidate = statsConsolidate(self.app.log, self.app.config, config_dir)
consolidate.run()
consolidate.run(self.app.pargs.full)
except Exception:
self.app.log.fatal("Ooops! Something went terribly wrong, stack trace below:", exc_info=True)
raise
Expand Down
488 changes: 488 additions & 0 deletions webcampak/core/wpakAlertsCapture.py

Large diffs are not rendered by default.

157 changes: 157 additions & 0 deletions webcampak/core/wpakAlertsEmails.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# Copyright 2010-2016 Eurotechnia ([email protected])
# This file is part of the Webcampak project.
# Webcampak is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License,
# or (at your option) any later version.

# Webcampak is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
# without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# See the GNU General Public License for more details.

# You should have received a copy of the GNU General Public License along with Webcampak.
# If not, see http://www.gnu.org/licenses/

import os
import time
import gettext
import json
from datetime import tzinfo, timedelta, datetime
import pytz
from dateutil import tz
import dateutil.parser
from tabulate import tabulate
import socket

from wpakConfigObj import Config
from wpakConfigCache import configCache
from wpakTimeUtils import timeUtils
from wpakSourcesUtils import sourcesUtils
from wpakFileUtils import fileUtils
from wpakDbUtils import dbUtils
from wpakEmailObj import emailObj
from wpakFTPUtils import FTPUtils
from wpakAlertsObj import alertObj

class alertsEmails(object):
""" This class contains functions used to send email to source users
Args:
parentClass: The parent class
Attributes:
tbc
"""

def __init__(self, parentClass):
self.log = parentClass.log

self.configPaths = parentClass.configPaths
self.dirSources = self.configPaths.getConfig('parameters')['dir_sources']
self.dirLocale = self.configPaths.getConfig('parameters')['dir_locale']
self.dirLocaleEmails = self.configPaths.getConfig('parameters')['dir_locale_emails']
self.dirEmails = self.configPaths.getConfig('parameters')['dir_emails']

self.configGeneral = parentClass.configGeneral
self.dbUtils = parentClass.dbUtils
self.configCache = parentClass.configCache
self.fileUtils = parentClass.fileUtils

def loadEmailTemplateFile(self, configSource, TemplateFilename):
"""Simple function to load an email template (either subject or content)"""
self.log.debug("alertsEmails.loadEmailTemplateFile(): " + _("Start"))

templateFile = self.dirLocale + configSource.getConfig('cfgsourcelanguage') + "/" + self.dirLocaleEmails + TemplateFilename
if os.path.isfile(templateFile) == False:
templateFile = self.dirLocale + "en_US.utf8/" + self.dirLocaleEmails + TemplateFilename
if os.path.isfile(templateFile):
self.log.info("alertsEmails.sendCaptureSuccess(): " + _("Using message subject file: %(templateFile)s") % {'templateFile': templateFile})
templateFileContent = open(templateFile, 'r')
templateContent = templateFileContent.read()
templateFileContent.close()
return templateContent
else:
return None


def sendCaptureError(self, currentAlert):
""" This function queue an email to inform the user that the capture is failing
The email's content and subject is store within the locale's directory corresponding to the language configured for the source.
Args:
currentAlert: a capture alert object
Returns:
None
"""
self.log.debug("alertsEmails.sendCaptureSuccess(): " + _("Start"))
configSource = self.configCache.getSourceConfig("source", currentAlert.getAlertValue("sourceid"))

emailContent = self.loadEmailTemplateFile(configSource, "alertErrorContent.txt")
if currentAlert.getAlertValue("emailType") == "REMINDER":
emailSubject = self.loadEmailTemplateFile(configSource, "alertErrorReminderSubject.txt")
else:
emailSubject = self.loadEmailTemplateFile(configSource, "alertErrorSubject.txt")

if emailContent != None and emailSubject != None:
currentSourceTime = dateutil.parser.parse(currentAlert.getAlertValue("currentTime"))
lastCatpureTime = dateutil.parser.parse(currentAlert.getAlertValue("lastCaptureTime"))
emailSubject = emailSubject.replace("#CURRENTHOSTNAME#", socket.gethostname())
emailSubject = emailSubject.replace("#CURRENTSOURCE#", str(currentAlert.getAlertValue("sourceid")))
emailSubject = emailSubject.replace("#CURRENTSOURCENAME#", self.dbUtils.getSourceName(currentAlert.getAlertValue("sourceid")))
emailSubject = emailSubject.replace("#LASTCAPTURETIME#", lastCatpureTime.strftime("%c"))
emailContent = emailContent.replace("#CURRENTSOURCETIME#", currentSourceTime.strftime("%c"))
emailContent = emailContent.replace("#LASTCAPTURETIME#", lastCatpureTime.strftime("%c"))
newEmail = emailObj(self.log, self.dirEmails, self.fileUtils)
newEmail.setFrom({'email': self.configGeneral.getConfig('cfgemailsendfrom')})
newEmail.setTo(self.dbUtils.getSourceEmailUsers(currentAlert.getAlertValue("sourceid")))
newEmail.setBody(emailContent)
newEmail.setSubject(emailSubject)
newEmail.writeEmailObjectFile()
else:
self.log.info("alertsEmails.sendCaptureSuccess(): " + _("Unable to find default translation files to be used"))

def sendCaptureSuccess(self, currentAlert):
""" This function queue an email to inform the user that the capture is successful.
The email's content and subject is store within the locale's directory corresponding to the language configured for the source.
If a filename is provided, a picture can be sent along the email.
Args:
currentAlert: a capture alert object
Returns:
None
"""
self.log.debug("alertsEmails.sendCaptureSuccess(): " + _("Start"))
configSource = self.configCache.getSourceConfig("source", currentAlert.getAlertValue("sourceid"))

emailContent = self.loadEmailTemplateFile(configSource, "alertWorkingContent.txt")
emailSubject = self.loadEmailTemplateFile(configSource, "alertWorkingSubject.txt")

if emailContent != None and emailSubject != None:
emailSubject = emailSubject.replace("#CURRENTHOSTNAME#", socket.gethostname())
emailSubject = emailSubject.replace("#CURRENTSOURCE#", str(currentAlert.getAlertValue("sourceid")))
emailSubject = emailSubject.replace("#CURRENTSOURCENAME#", self.dbUtils.getSourceName(currentAlert.getAlertValue("sourceid")))
currentSourceTime = dateutil.parser.parse( currentAlert.getAlertValue("currentTime"))
lastCatpureTime = dateutil.parser.parse( currentAlert.getAlertValue("lastCaptureTime"))
emailContent = emailContent.replace("#CURRENTSOURCETIME#", currentSourceTime.strftime("%c"))
emailContent = emailContent.replace("#LASTCAPTURETIME#", lastCatpureTime.strftime("%c"))
newEmail = emailObj(self.log, self.dirEmails, self.fileUtils)
newEmail.setFrom({'email': self.configGeneral.getConfig('cfgemailsendfrom')})
newEmail.setTo(self.dbUtils.getSourceEmailUsers(currentAlert.getAlertValue("sourceid")))
newEmail.setBody(emailContent)
newEmail.setSubject(emailSubject)
if currentAlert.getAlertValue("lastPicture") != None and int(configSource.getConfig('cfgemailsuccesspicturewidth')) > 0:
captureDirectory = currentAlert.getAlertValue("lastPicture")[:8]
dirCurrentSourcePictures = self.dirSources + 'source' + str(currentAlert.getAlertValue("sourceid")) + '/' + self.configPaths.getConfig('parameters')['dir_source_pictures']
if os.path.isfile(dirCurrentSourcePictures + captureDirectory + "/" + currentAlert.getAlertValue("lastPicture")):
captureFilename = dirCurrentSourcePictures + captureDirectory + "/" + currentAlert.getAlertValue("lastPicture")
newEmail.addAttachment({'PATH': captureFilename,
'WIDTH': int(configSource.getConfig('cfgemailsuccesspicturewidth')),
'NAME': 'last-capture.jpg'})
newEmail.writeEmailObjectFile()
else:
self.log.info("alertsEmails.sendCaptureSuccess(): " + _("Unable to find default translation files to be used"))

Loading

0 comments on commit c5727fd

Please sign in to comment.