Skip to content

Commit

Permalink
Merge pull request #142 from diggyk/sendmail
Browse files Browse the repository at this point in the history
Backend implementation for sending email to quest participants
  • Loading branch information
kelseyfix committed Feb 18, 2016
2 parents 4ed8672 + 22d6a0e commit 699d194
Show file tree
Hide file tree
Showing 6 changed files with 176 additions and 11 deletions.
166 changes: 164 additions & 2 deletions hermes/handlers/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@


from .util import ApiHandler
from ..util import id_generator, PluginHelper
from ..util import id_generator, PluginHelper, email_message
from .. import exc
from ..models import Host, EventType, Event, Labor, Fate, Quest
from ..settings import settings
Expand Down Expand Up @@ -2599,4 +2599,166 @@ def get(self):
"fullstoryId": settings.fullstory_id
}

self.success(result_json)
self.success(result_json)


class QuestMailHandler(ApiHandler):
def post(self, id):
"""**Send a message to all owners that are involved with a quest**
**Example Request:**
.. sourcecode:: http
POST /api/v1/quest/20/mail HTTP/1.1
Host: localhost
Content-Type: application/json
{
"serverOwners": true,
"laborOwners": false,
"from": "user@example.com",
"subject": "Hello!",
"message": "Work is about to commence."
}
**Example response:**
.. sourcecode:: http
HTTP/1.1 201 OK
Location: /api/v1/hosts/example
{
"status": "created",
}
**Note:**
Hermes will automatically append a link to the quest so users can go there directly from the email
:param id the ID of the quest we are working with when sending an email
:regjson boolean serverOwners: send to all owners of servers that have labors in this quest
:regjson boolean laborOwners: send to all labor owners (e.g. server owners if they own the active labor or the quest owner if they own the active labor)
:regjson string from: the sender email address
:regjson string subject: the subject line of the email
:regjson string message: the body of the message
:reqheader Content-Type: The server expects a json body specified with
this header.
:statuscode 201: Email was created and sent
"""

server_owners = self.jbody.get('serverOwners', False)
labor_owners = self.jbody.get('laborOwners', False)

if not server_owners and not labor_owners:
raise exc.BadRequest(
"Must specify serverOwners and/or laborOwners as true"
)

log.info(
"QUEST [{}]: sent email to {}{}{}".format(
id,
"server owners" if server_owners else "",
" and " if server_owners and labor_owners else "",
"labor owners" if labor_owners else ""
)
)

try:
from_address = self.jbody['from']
subject = self.jbody['subject']
message = self.jbody['message']
except KeyError as err:
raise exc.BadRequest(
"Missing Required Argument: {}".format(err.message)
)
except ValueError as err:
raise exc.BadRequest(err.message)

# Open the quest and grab the labors
quest = self.session.query(Quest).get(id)
if not quest:
raise exc.NotFound(
"Quest {} not found".format(id)
)

labors = quest.labors
# Grab the hostnames and look up the owners
hostnames = set()
for labor in labors:
hostnames.add(labor.host.hostname)

# get the owner information
try:
results = PluginHelper.request_post(
json_body={
"operation": "owners",
"hostnames": list(hostnames)
}
)
owners = results.json()['results']
except Exception as e:
logging.error("Failed to get host owners: " + e.message)
raise exc.BadRequest(
"Host owners not found"
)

# get contact information from strongpoc
strongpoc_contacts = None
if settings.strongpoc_server:
# get the contact information
try:
results = PluginHelper.request_get(
path = "/api/pocs/?expand=teams&expand=service_providers&expand=contact_types&service_provider__name=hermes&contact_type__name=email",
server = settings.strongpoc_server
)
strongpoc_results = results.json()
strongpoc_contacts = {}
for result in strongpoc_results:
strongpoc_contacts[result['team']['name']] = result['value']
except Exception as e:
logging.error("Failed to get strongpoc contacts: " + e.message)

recipients = set()

# If we want labor owners, loop through and see if who that should
# be and add them to recipients
if labor_owners:
for labor in labors:
if labor.for_creator:
# add quest creator to recipients
recipients.add(quest.creator)
if labor.for_owner:
# add machine owner to recipients
owner = owners[labor.host.hostname]
if owner in strongpoc_contacts:
recipients.add(strongpoc_contacts[owner])
else:
recipients.add("{}@{}".format(owner, settings.domain))

# If we want server owners, loop through hosts
# and add owners to the list
if server_owners:
for labor in labors:
# add machine owner to recipients
owner = owners[labor.host.hostname]
if owner in strongpoc_contacts:
recipients.add(strongpoc_contacts[owner])
else:
recipients.add("{}@{}".format(owner, settings.domain))

# Send email
email_message(recipients, subject, message, sender=from_address)

self.created()

log.info(
"QUEST [{}]: sent email to {}{}{}".format(
id,
"server owners" if server_owners else "",
" and " if server_owners and labor_owners else "",
"labor owners" if labor_owners else ""
)
)
2 changes: 1 addition & 1 deletion hermes/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -1484,7 +1484,7 @@ class Labor(Model):
quest: the Quest to this this Labor belongs
host: the Host to which this Labor pertains
for_creator: if true, the labor will be designated for the quest creator
for_labor: if true, the labor is designate for the server owner
for_owner: if true, the labor is designate for the server owner
creation_time: when this Labor was created
ack_time: when this Labor was acknowledged
ack_user: the user who acknowledged the Labor
Expand Down
1 change: 1 addition & 0 deletions hermes/routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
# Quests
(r"/api/v1/quests\/?", api.QuestsHandler),
(r"/api/v1/quests/(?P<id>\d+)\/?", api.QuestHandler),
(r"/api/v1/quests/(?P<id>\d+)/mail\/?", api.QuestMailHandler),

# Queries to 3rd party tools
(r"/api/v1/extquery\/?", api.ExtQueryHandler),
Expand Down
7 changes: 5 additions & 2 deletions hermes/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,13 +61,16 @@ def slack_message(message):
log.warn("Error writing to Slack: {}".format(exc.message))


def email_message(recipients, subject, message, html_message=None, cc=None):
def email_message(recipients, subject, message, html_message=None, cc=None, sender=None):
"""Email a message to a user.
Args:
subject: the subject of the email we wish to send
message: the content of the email we wish to send
recipients: the email address to whom we wish to send the email
html_message: optional html formatted message we wish to send
cc: optional list of email addresses to carbon copy
sender: optional sender email address
"""

if not settings.email_notifications:
Expand Down Expand Up @@ -126,7 +129,7 @@ def email_message(recipients, subject, message, html_message=None, cc=None):
msg = part1

msg["Subject"] = subject
msg["From"] = settings.email_sender_address
msg["From"] = settings.email_sender_address if not sender else sender
msg["To"] = ", ".join(recipients)
msg["Cc"] = ", ".join(extra_recipients)

Expand Down
1 change: 1 addition & 0 deletions hermes/webapp/src/css/main.less
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,7 @@ a {
font-size: 1.5em;
font-weight: bold;
width: @width2;
vertical-align: middle;
.bib-icon {
float: left;
text-align: left;
Expand Down
10 changes: 4 additions & 6 deletions hermes/webapp/src/templates/questCreation.html
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@
<!-- ROW TWO -->
<div class="row panel-row">
<div class="col-md-6 create-panel">
<div><label>Start with fate:
<div><label>Quest type:
<select ng-model="qc.fateSelection"
ng-model-options="qc.selectOptions"
ng-options="optValue.description for optValue in qc.startingFates">
Expand All @@ -76,11 +76,9 @@
</div>
<div class="col-md-4 helper-panel">
<div>
<strong>Need help picking a starting fate?</strong>
<p>Use the explorer to
see all the possible fates and the chain of labors that
will satisfy them.</p>
<button type="button" ng-click="qc.showFatesModal = true">Fates Explorer</button>
<strong>Need help picking a quest type?</strong>
<p>Use the explorer to see the quest types and what kind of workflow each implies..</p>
<button type="button" ng-click="qc.showFatesModal = true">Quest Type Explorer</button>
</div>
</div>
</div>
Expand Down

0 comments on commit 699d194

Please sign in to comment.