def render(self, variables, content_template, pretty=False): """ Works like salmon.view.render, but uses apply_styles to modify the HTML with the configured CSS before returning it to you. If you set the pretty=True then it will prettyprint the results, which is a waste of bandwidth, but helps when debugging. Remember that content_template is run through the template system, and then processed with self.wiki (defaults to markdown). This let's you do template processing and write the HTML contents like you would an email. You could also attach the content_template as a text version of the message for people without HTML. Simply set the .Body attribute of the returned salmon.mail.MailResponse object. """ content = self.wiki(view.render(variables, content_template)) lvars = variables.copy() lvars['content'] = content html = view.render(lvars, self.template) styled = self.apply_styles(html) if pretty: return styled.prettify() else: return str(styled)
def ENROLL(message, nonce, host=None): server_name = server_name_config service_address = 'pm-enroll-%s' % (nonce,) # check if the email address is know, if it is, croak sender = c.place_sender(message) if sender == INTERNAL: logging.debug(u"INTERNAL ignoring %s@%s from %s" % (service_address, server_name, message['from'])) return # ignore if sender != UNKNOWN: msg = "Already playing" if type(sender) is tuple: msg = msg + " " + c.campaign_name(sender[0]) if silent: logging.debug(u"ALREADY ignoring %s@%s from %s - already playing" % (service_address, server_name, message['from'])) return raise SMTPError(550, msg) enrollment = c.find_enrollment(nonce) if enrollment is None: if silent: logging.debug(u"INVALID code, ignoring %s@%s from %s" % (service_address, server_name, message['from'])) return raise SMTPError(550, "Enrollment code invalid") (cid, short_form) = enrollment c.do_enrollment(cid, nonce, message['from'], short_form) lang = c.campaign_language(cid) campaign_name = c.campaign_name(cid) attribution = c.get_attribution(message['from']) msg = view.respond(locals(), "%s/enrolled_pc.msg" % (lang,), From="%s@%s" % (service_address, server_name), To=message['from'], Subject=view.render(locals(), "%s/enrolled_pc.subj" % (lang,))) logging.debug(u"ENROLLED short form %s, enrolled at %s, campaign %s" % (short_form, service_address, str(cid))) send_or_queue(msg, cid) (gm_address, gm_full, attribution) = c.campaign_gm(cid) msg = view.respond(locals(), "%s/enrolled_gm.msg" % (lang,), From="pm-enroll@%s" % (server_name,), To=gm_full, Subject=view.render(locals(), "%s/enrolled_gm.subj" % (lang,))) send_or_queue(msg, cid) return
def PC_END(message, nonce, host=None): # drop to NPC and inform the GM service_address = 'pm-unenroll-%s' % (nonce,) server_name = server_name_config sender = c.place_sender(message) if sender == INTERNAL: logging.debug(u"INTERNAL ignoring %s@%s from %s" % (service_address, server_name, message['from'])) return # ignore if sender == UNKNOWN: if silent: return raise SMTPError(550, "Unknown sender") unenrollment = c.find_unenrollment(nonce) if unenrollment is None: if silent: logging.debug(u"INVALID code, ignoring %s@%s from %s" % (service_address, server_name, message['from'])) return raise SMTPError(550, "Unenrollment code invalid") (cid, short_form) = unenrollment lang = c.campaign_language(cid) campaign_name = c.campaign_name(cid) attribution = c.get_attribution(message['from']) c.do_unenrollment(cid, nonce) logging.debug(u"UNENROLLED short form %s, unenrolled at %s, campaign %s" % (short_form, service_address, str(cid))) msg = view.respond(locals(), "%s/unenrolled_pc.msg" % (lang,), From="%s@%s" % (service_address, server_name), To=message['from'], Subject=view.render(locals(), "%s/unenrolled_pc.subj" % (lang,))) send_or_queue(msg, cid) # inform the GM (gm_address, gm_full, attribution) = c.campaign_gm(cid) msg = view.respond(locals(), "%s/unenrolled_gm.msg" % (lang,), From="pm-unenrolled@%s" % (server_name,), To=gm_full, Subject=view.render(locals(), "%s/unenrolled_gm.subj" % (lang,))) send_or_queue(msg, cid) return
def GAME_END(message, host=None): service_address = 'pm-end' server_name = server_name_config sender = c.place_sender(message) if sender == INTERNAL: return # ignore if sender == UNKNOWN: if silent: return raise SMTPError(550, "Unknown sender") cid = sender[0] lang = c.campaign_language(cid) campaign_name = c.campaign_name(cid) if sender[1]: # GM, pack and go logging.debug(u"END_GAME request from gm, campaign %s" % (str(cid),)) all_characters = c.all_characters(cid) emails = set() # save emails before the purge for character in all_characters: emails.add(character['controller']) report_id = end_campaign(cid) report_url = '%s/%s.zip' % (campaign_reports_url_config, report_id) for email in emails: msg = view.respond(locals(), "%s/end_game.msg" % (lang,), From="%s@%s" % (service_address, server_name,), To=email, Subject=view.render(locals(), "%s/end_game.subj" % (lang,))) send_or_queue(msg, cid) else: # PC, generate unenrollment address short_form = sender[2] unenrollment_address = t.start_unenrollment(cid, short_form) msg = view.respond(locals(), "%s/drop_pc.msg" % (lang,), From="%s@%s" % (service_address, server_name), To=message['from'], Subject=view.render(locals(), "%s/drop_pc.subj" % (lang,))) msg['Reply-To'] = "pm-unenroll-%s@%s" % (unenrollment_address, server_name) logging.debug(u"END_PC short form %s, unenroll at %s, campaign %s" % (short_form, unenrollment_address, str(cid))) send_or_queue(msg, cid) return
def POSTING(message, post_name=None, host=None): user, address = parseaddr(message['from']) user = user or address post_url = "posts/%s/%s.html" % (address, post_name) index_q = queue.Queue("run/indexed") post_keys = sorted(index_q.keys(), reverse=True) old_keys = post_keys[50:] del post_keys[50:] # find the old one and remove it posts = [] for key in post_keys: msg = index_q.get(key) if msg['x-post-url'] == post_url: # this is the old one, take it out index_q.remove(key) else: posts.append(msg) # update the index and our posts message['X-Post-URL'] = post_url index_q.push(message) posts.insert(0, message) # and generate the index with what we got now index = view.render(locals(), "web/index.html") f = open("app/data/index.html", "w") f.write(index.encode("utf-8")) f.close() # finally, zap all the old keys for old in old_keys: index_q.remove(old)
def respond(self, variables, content, **kwd): """ Works like salmon.view.respond letting you craft a salmon.mail.MailResponse immediately from the results of a salmon.html.HtmlMail.render call. Simply pass in the From, To, and Subject parameters you would normally pass in for MailResponse, and it'll craft the HTML mail for you and return it ready to deliver. A slight convenience in this function is that if the Body kw parameter equals the content parameter, then it's assumed you want the raw markdown content to be sent as the text version, and it will produce a nice dual HTML/text email. """ assert content, "You must give a contents template." if kwd.get('Body', None) == content: kwd['Body'] = view.render(variables, content) for key in kwd: kwd[key] = kwd[key] % variables msg = mail.MailResponse(**kwd) msg.Html = self.render(variables, content) return msg
def test_spelling(): message = {} original = {} for path in glob("app/templates/mail/*.msg"): template = "mail/" + os.path.basename(path) result = view.render(locals(), template) spelling(template, result)
def NEW_ATTRIBUTION(message, host=None): service_address = 'pm-new-attribution' server_name = server_name_config # check the sender is known sender = c.place_sender(message) if sender == INTERNAL: logging.debug(u"INTERNAL ignoring %s@%s from %s" % (service_address, server_name, message['from'])) return # ignore if sender == UNKNOWN: if silent: logging.debug(u"UNKNOWN ignoring %s@%s from %s" % (service_address, server_name, message['from'])) return raise SMTPError(550, "Unknown sender") cid = sender[0] lang = c.campaign_language(cid) campaign_name = c.campaign_name(cid) attribution = message['subject'] c.set_attribution(message['from'], attribution) msg = view.respond(locals(), "%s/new_attribution.msg" % (lang,), From="%s@%s" % (service_address, server_name), To=message['from'], Subject=view.render(locals(), "%s/new_attribution.subj" % (lang,))) logging.debug(u"New attribution: %s attribute to %s" % (message['from'],attribution)) send_or_queue(msg, cid) return
def test_HtmlMail_apply_styles(): hs = html.HtmlMail("style.css", "html_test.html") page = view.render(locals(), "html_test.html") styled = hs.apply_styles(page) assert "magenta" in str(styled) assert_not_equal(str(styled), str(page))
def load_css(self, css_template, variables): """ If you want to change the CSS, simply call this with the new CSS and variables. It will change internal state so that later calls to render or respond use the new CSS. """ self.css = view.render(variables, css_template) self.engine = clevercss.Engine(self.css) self.stylesheet = [] for selector, style in self.engine.evaluate(): attr = "; ".join("%s: %s" % (k,v) for k,v in style) selectors = selector[0].split() # root, path, attr self.stylesheet.append((selectors[0], selectors[1:], attr))
def post(post_name, user, host, message): user_dir = make_user_dir(user) user_id, domain = user.split("@") # make sure it's removed first if it existed delete(post_name, user) posting = open("%s/%s.html" % (user_dir, post_name), "w") content = markdown(message.body()) html = view.render(locals(), "web/post.html") posting.write(html.encode('utf-8')) post_q = get_user_post_queue(user_dir) post_q.push(message)
def COMMENTING(message, user_id=None, domain=None, post_name=None, host=None): address = user_id + '@' + domain user_dir = post.get_user_dir(address) if post.user_exists(address): # stuff it here for now, but we'll just build the file rolling comments = queue.Queue("%s/comments" % user_dir) comments.push(message) contents = markdown(message.body()) comment_file = "%s/%s-comments.html" % (user_dir, post_name) snippet = view.render(locals(), "web/comments.html") with open(comment_file, "a") as out: out.write(snippet) else: logging.warning("Attempt to post to user %r but user doesn't exist.", address)
def GAME_SUMMARY(message, host=None): service_address = 'pm-summary' server_name = server_name_config sender = c.place_sender(message) if sender == INTERNAL: return # ignore if sender == UNKNOWN: if silent: return raise SMTPError(550, "Unknown sender") cid = sender[0] lang = c.campaign_language(cid) campaign_name = c.campaign_name(cid) if not sender[1]: if silent: logging.debug(u"NOT_GM ignoring %s@%s from %s" % (service_address, server_name, message['from'])) return raise SMTPError(550, "Not a GM") logging.debug(u"GAME_SUMMARY request from gm, campaign %s" % (str(cid),)) all_characters = c.all_characters(cid) emails = set() # save emails before the purge for character in all_characters: emails.add(character['controller']) report_id = end_campaign(cid, purge=False) report_url = '%s/%s.zip' % (campaign_reports_url_config, report_id) msg = view.respond(locals(), "%s/game_summary.msg" % (lang,), From="%s@%s" % (service_address, server_name,), To=message['from'], Subject=view.render(locals(), "%s/game_summary.subj" % (lang,))) send_or_queue(msg, cid) return
def _new_campaign(message, lang, service_address): # check if the email address is know, if it is, croak sender = c.place_sender(message) if sender == INTERNAL: return # ignore server_name = server_name_config if sender != UNKNOWN: msg = "Already playing" if type(sender) is tuple: msg = msg + " " + c.campaign_name(sender[0]) if silent: logging.debug(u"MESSAGE to %s@%s from %s - already playing" % (service_address, server_name, message['from'])) return raise SMTPError(550, msg) # use subject for name of campaign campaign_name = message['subject'] # create campaign, set language to lang cid = c.new_campaign(campaign_name, message['from'], lang) # generate reply attribution = c.get_attribution(message['from']) msg = view.respond(locals(), "%s/new_campaign.msg" % (lang,), From="%s@%s" % (service_address, server_name), To=message['from'], Subject=view.render(locals(), "%s/new_campaign.subj" % (lang,))) logging.debug(u"MESSAGE to %s@%s from %s, new campaign %s - %s" % (service_address, server_name, safe_unicode(message['from']), str(cid), campaign_name)) send_or_queue(msg, cid) return
def test_render(): # try with some empty vars text = view.render({}, "template.txt") assert text
def DICE(message, rollid, host=None): service_address = 'pm-dice-' + rollid server_name = server_name_config # check the sender is known sender = c.place_sender(message) if sender == INTERNAL: logging.debug(u"INTERNAL ignoring %s@%s from %s" % (service_address, server_name, message['from'])) return # ignore if sender == UNKNOWN: if silent: logging.debug(u"UNKNOWN ignoring %s@%s from %s" % (service_address, server_name, message['from'])) return raise SMTPError(550, "Unknown sender") cid = sender[0] lang = c.campaign_language(cid) # verify the rollid exists and belongs to the sender roll_obj = find_roll(rollid) if roll_obj is None: # croak no roll msg = view.respond(locals(), "%s/roll/no_roll.msg" % (lang,), From="%s@%s" % (service_address, server_name), To=message['from'], Subject=view.render(locals(), "%s/roll/no_roll.subj" % (lang,))) send_or_queue(msg, cid) return if roll_obj is True: # croak already rolled, return result ( roll, check, roll_str ) = execute_roll(rollid) msg = view.respond(locals(), "%s/roll/already_rolled.msg" % (lang,), From="%s@%s" % (service_address, server_name), To=message['from'], Subject=view.render(locals(), "%s/roll/already_rolled.subj" % (lang,))) send_or_queue(msg, cid) return ( roll_cid, roll_character, roll_str ) = roll_obj if str(roll_cid) != str(cid): # croak spurious ID msg = view.respond(locals(), "%s/roll/no_roll.msg" % (lang,), From="%s@%s" % (service_address, server_name), To=message['from'], Subject=view.render(locals(), "%s/roll/no_roll.subj" % (lang,))) send_or_queue(msg, cid) return if not sender[1] and safe_unicode(roll_character).lower() != safe_unicode(sender[2]): # croak not the right person for this roll you_are = sender[2] intended_for = roll_character msg = view.respond(locals(), "%s/roll/wrong_person.msg" % (lang,), From="%s@%s" % (service_address, server_name), To=message['from'], Subject=view.render(locals(), "%s/roll/wrong_person.subj" % (lang,))) send_or_queue(msg, cid) return # perform the roll ( roll, check, roll_str ) = execute_roll(rollid) # report back to the sender and GM (if they are different) (gm_address, gm_full, attribution) = c.campaign_gm(cid) # GM email msg = view.respond(locals(), "%s/roll/rolled.msg" % (lang,), From="%s@%s" % (service_address, server_name,), To=gm_full, Subject=view.render(locals(), "%s/roll/rolled.subj" % (lang,))) if not sender[1]: msg['cc'] = '%s@%s' % (roll_character, server_name,) send_or_queue(msg, cid) if not sender[1]: character = c.get_character(cid, sender[2]) attribution = c.get_attribution(character['controller']) msg = view.respond(locals(), "%s/roll/rolled.msg" % (lang,), From="%s@%s" % (service_address, server_name,), To= formataddr( (attribution, character['controller']) ), Subject=view.render(locals(), "%s/roll/rolled.subj" % (lang,))) msg['cc'] = 'gm@%s' % (server_name,) send_or_queue(msg, cid) return
def ROLL(message, host=None): service_address = 'pm-roll' server_name = server_name_config sender = c.place_sender(message) if sender == INTERNAL: return # ignore if sender == UNKNOWN: if silent: return raise SMTPError(550, "Unknown sender") cid = sender[0] lang = c.campaign_language(cid) if not sender[1]: # croak only GMs can ask for rolls msg = view.respond(locals(), "%s/roll/not_gm.msg" % (lang,), From="%s@%s" % (service_address, server_name,), To=message['from'], Subject=view.render(locals(), "%s/roll/not_gm.subj" % (lang,))) send_or_queue(msg, cid) return (gm_address, gm_full, attribution) = c.campaign_gm(cid) # find the recipient that is a PC (if none, internal roll from the GM) recipients = c.get_recipients(message) character = None for recipient in recipients: if recipient == 'gm': continue if recipient == service_address: continue this_character = c.get_character(cid, recipient) if not int(this_character['is_npc']): if character is not None: # croak only one character per roll msg = view.respond(locals(), "%s/roll/too_many_characters.msg" % (lang,), From="%s@%s" % (service_address, server_name,), To=gm_full, Subject=view.render(locals(), "%s/roll/too_many_characters.subj" % (lang,))) send_or_queue(msg, cid) return character = recipient # find the roll commands rolls = [] full_content = message.body() text = safe_unicode(full_content) lines = text.split('\n') for line in lines: if line.startswith('ROLL:'): rolls.append(line[len('ROLL:'):]) if len(rolls) == 0: # croak no rolls msg = view.respond(locals(), "%s/roll/no_rolls.msg" % (lang,), From="%s@%s" % (service_address, server_name,), To=gm_full, Subject=view.render(locals(), "%s/roll/no_rolls.subj" % (lang,))) send_or_queue(msg, cid) return # for each roll command, register a roll-id and send a pm-dice-(rollid) email if character is not None: full_character = c.get_character(cid, character) character = full_character attribution = c.get_attribution(character['controller']) for roll in rolls: try: hashid = add_roll( cid, 'gm' if character is None else character['address'], roll ) return_service_address = 'pm-dice-' + hashid roll_address = "%s@%s" % (return_service_address, server_name,) msg = view.respond(locals(), "%s/roll/to_roll.msg" % (lang,), From="%s@%s" % (service_address, server_name,), To=gm_full if character is None else character['controller'], Subject=view.render(locals(), "%s/roll/to_roll.subj" % (lang,))) msg['Reply-To'] = roll_address except RollStrParseException as e: msg = view.respond(locals(), "%s/roll/syntax_error.msg" % (lang,), From="%s@%s" % (service_address, server_name,), To=gm_full, Subject=view.render(locals(), "%s/roll/syntax_error.subj" % (lang,))) send_or_queue(msg, cid) return
def START(message, address=None, host=None): server_name = server_name_config if(address.startswith("pm-")): return # ignore sender = c.place_sender(message) if sender == INTERNAL: return # ignore if sender == UNKNOWN: if silent: logging.debug(u"MESSAGE to %s@%s from %s - unknown" % (address, server_name, message['from'])) return raise SMTPError(550, "Unknown sender") cid = sender[0] # check the message haven't been processed already if tst_email_processed(message, cid): logging.debug(u"IGNORING processed email %s" % (message['message-id'],)) return # ignore # the message as been set as processed lang = c.campaign_language(cid) campaign_name = c.campaign_name(cid) server_name = server_name_config recipients = c.get_recipients(message) if sender[1]: # GM EMAIL # determine if the email is sent as somebody else (gm_address, gm_full, attribution) = c.campaign_gm(cid) send_as = None for recipient in recipients: if recipient.startswith('as-'): if send_as: other = send_as = recipient[3:].lower() msg = view.respond(locals(), "%s/repeated_as.msg" % (lang,), From="gm@%s" % (server_name,), To=gm_full, Subject=view.render(locals(), "%s/repeated_as.subj" % (lang,))) send_or_queue(msg, cid) return send_as = recipient[3:].lower() # validate the as-XYZ is valid or note, otherwise if send_as: original_send_as = send_as send_as = c.get_character(cid, send_as) if not send_as: # reply with error to the GM with list of valid send-as all_characters = c.all_characters(cid) send_as = original_send_as msg = view.respond(locals(), "%s/unknown_as.msg" % (lang,), From="gm@%s" % (server_name,), To=gm_full, Subject=view.render(locals(), "%s/unknown_as.subj" % (lang,))) send_or_queue(msg, cid) return if send_as: sender = formataddr( (send_as['name'], '%s@%s' % (send_as['address'], server_name)) ) else: sender = 'gm@%s' % (server_name,) # for each recipient that is not an NPC, generate an email # either from the gm or from whomever is send_as to them with # cc: to the other characters and send them # extract the text full_content = message.body() #TODO check message.base.parts for recipient in recipients: if recipient.startswith('as-'): continue if recipient.startswith('pm-'): continue character = c.get_character(cid, recipient) if int(character['is_npc']) : continue if character is None: #TODO localize full_content = "UNKNOWN: " + recipient msg = view.respond(locals(), "%s/base.msg" % (lang,), From="gm@%s" % (server_name,), To=gm_full, Subject=full_content) logging.debug(u"INVALID character %s" % (recipient,)) send_or_queue(msg, cid) return # ignore cc_list = [] for other in recipients: if other.startswith('as-'): cc_list.append('gm@%s' % (server_name,)) elif other.startswith('pm-') and not send_as: # this will be ignored by the server, but notifies # the users unless is a send-as which will # highlight the send-as to the players cc_list.append('%s@%s' % (other, server_name)) elif other != recipient: other_character = c.get_character(cid, other) if other_character is None: full_content = "UNKNOWN: " + other msg = view.respond(locals(), "%s/base.msg" % (lang,), From="gm@%s" % (server_name,), To=gm_full, Subject=full_content) logging.debug(u"INVALID character %s" % (othert,)) send_or_queue(msg, cid) return # ignore cc_list.append(formataddr( (other_character['name'], '%s@%s' % (other,server_name,)) )) # sort them cc_list = sorted(cc_list) attribution = c.get_attribution(character['controller']) msg = view.respond(locals(), "%s/base.msg" % (lang,), From=sender, To=formataddr( (attribution, character['controller']) ), Subject=campaign_name) if cc_list: msg['cc'] = ", ".join(cc_list) send_or_queue(msg, cid) else: short_form = sender[2] full_character = c.get_character(cid, short_form) # change the sender to their character email and send to GM (gm_address, gm_full, attribution) = c.campaign_gm(cid) # cc: for show cc_list = [] for recipient in recipients: if recipient == 'gm': continue character = c.get_character(cid, recipient) cc_list.append(formataddr( (character['name'], '%s@%s' % (recipient,server_name,)) )) # sort them cc_list = sorted(cc_list) # extract the text full_content = sanitize(message.body()) #TODO check message.base.parts msg = view.respond(locals(), "%s/base.msg" % (lang,), From=formataddr( (full_character['name'], "%s@%s" % (short_form, server_name)) ), To=gm_full, Subject="%s: %s" % (campaign_name, full_character['name'])) if cc_list: msg['cc'] = ", ".join(cc_list) send_or_queue(msg, cid) return
def end_campaign(cid, purge=True): """Ends a campaign, returns the list of email addresses to email, plus the code for downloading the log. It purges all emails and all information about the campaign. """ full_queue = Router.FULL_QUEUE messages = list() campaign_name_ = campaign_name(cid) lang = campaign_language(cid) emails_in_campaign = set() attribution_for_email = dict() ( gm_email, full_gm, gm_attribution ) = campaign_gm(cid) emails_in_campaign.add( gm_email ) campaign_characters = all_characters(cid) for character in campaign_characters: if not int(character['is_npc']): emails_in_campaign.add(character['controller']) for email in emails_in_campaign: attribution_for_email[email] = get_attribution(email) seen_ids = set() for key in full_queue.keys(): msg = full_queue.get(key) if msg is None: continue if not 'Message-ID' in msg: msg_id = key else: msg_id = get_message_id(msg) if msg_id in seen_ids: continue seen_ids.add(msg_id) name, sender = parseaddr(msg['from']) if sender in emails_in_campaign: msg_epoch = mktime_tz(parsedate_tz(msg['Date'])) messages.append( { 'epoch' : msg_epoch, 'msg' : msg, 'key' : key } ) # sort messages by date messages = sorted(messages, key=lambda t: t['epoch']) # create nonce while True: nonce = hashlib.sha256("%s-%d" % (cid, random.randint(0,9001))).hexdigest()[0:10] target_zip = "%s/%s.zip" % ( campaigns_report_folder, nonce ) if not os.path.exists(target_zip): break tmp_folder = "/tmp/" + nonce os.mkdir(tmp_folder) # First pass, compute statistics gm_emails = 0 gm_emails_as_npcs = 0 pc_emails = 0 dice_rolls = 0 for t in messages: msg = t['msg'] name, sender = parseaddr(msg['From']) recepients = get_recipients(msg) is_dice = False rcpts = list() if 'pm-dice' in sender or 'pm-roll' in sender: is_dice = True else: for rcpt in recepients: if 'pm-dice' in rcpt or 'pm-roll' in rcpt: is_dice = True elif not rcpt.startswith('as-'): rcpts.append(rcpt) if is_dice: dice_rolls += 1 t['flags'] = { 'dice' : True } else: if sender == gm_email: gm_emails += 1 t['flags'] = { 'gm' : True } for rcpt in recepients: if rcpt.startswith('as-'): gm_emails_as_npcs += 1 t['flags']['as'] = rcpt[3:] else: pc_emails += 1 placed = place_sender(msg) if len(placed) == 3: short_form = placed[2] t['flags'] = { 'pc' : short_form } else: t['flags'] = 'UNKNOWN' t['recipients'] = rcpts #### front matter tex = codecs.open(tmp_folder + "/campaign.tex", 'w', 'utf-8') md = codecs.open(tmp_folder + "/campaign.md", 'w', 'utf-8') tex.write(LOADER.get_template("%s/campaign.tex" % (lang,)).render(locals())) # GM, PC players, NPC players, attributions, licence all_mails = len(messages) print_characters = list() for character in campaign_characters: print_characters.append({ 'type' : ("NPC" if int(character['is_npc']) else "PC"), 'full_name': character['name'], 'short_form': character['address'], 'attribution' : (character['alt_attribution'] if 'alt_attribution' in character else attribution_for_email[character['controller']]) }) # TODO start date, end date md.write(view.render(locals(), "%s/campaign.md" % (lang,))) md.write('\n\n') for t in messages: msg = t['msg'] # header (includes who send it, potentially as-XYZ and to/cc) rcpts = ", ".join(t['recipients']) if 'dice' in t['flags']: md.write(view.render(locals(), "%s/dice_roll.md" % (lang,))) md.write(u"\n---------\n") elif 'gm' in t['flags']: if 'as' in t['flags']: md.write(u"%s (GM) → %s\n" % (t['flags']['as'], rcpts)) md.write(u'------------------------\n') else: md.write(u"GM → %s\n" % (rcpts,)) md.write(u'------------------------\n') else: md.write(u"%s (PC) → %s\n" % (t['flags']['pc'] , rcpts)) md.write(u'------------------------\n') # md.write(t['key'] + "\n\n") # if msg['subject']: # md.write(u"Subject: %s\n\n" % (msg['subject'],)) # content full_content = sanitize(msg.body()) md.write(full_content) md.write("\n") #TODO typeset email md.close() tex.close() # render to PDF if os.path.exists("/usr/bin/pdflatex") and os.path.exists("/usr/bin/pandoc"): call("cd %s; /usr/bin/pandoc campaign.md -o messages.tex" % (tmp_folder,), shell=True) call("cd %s; pdflatex campaign.tex; pdflatex campaign.tex; pdflatex campaign.tex" % (tmp_folder,), shell=True) # render to HTML if os.path.exists("/usr/bin/pandoc"): call("cd %s; /usr/bin/pandoc campaign.md -o campaign.html" % (tmp_folder,), shell=True) # zip source texts + PDF to target_zip call("cd /tmp; /usr/bin/zip -r %s %s" % (os.path.realpath(target_zip), nonce), shell=True) if purge: # delete messages from full queue for t in messages: full_queue.remove(t['key']) # purge campaign from redis delete_campaign(cid) return nonce
def NEW_CHARACTER(message, host=None, pc_or_npc="n"): service_address = 'pm-new-' + ("n" if pc_or_npc else "") + "pc" server_name = server_name_config # check the sender is an active GM, otherwise raise 550 sender = c.place_sender(message) if sender == INTERNAL: logging.debug(u"INTERNAL ignoring %s@%s from %s" % (service_address, server_name, message['from'])) return # ignore if sender == UNKNOWN: if silent: logging.debug(u"UNKNOWN ignoring %s@%s from %s" % (service_address, server_name, message['from'])) return raise SMTPError(550, "Unknown sender") if not sender[1]: if silent: logging.debug(u"NOT_GM ignoring %s@%s from %s" % (service_address, server_name, message['from'])) return raise SMTPError(550, "Not a GM") cid = sender[0] lang = c.campaign_language(cid) campaign_name = c.campaign_name(cid) attribution = c.get_attribution(message['from']) # get name of the character from subject, produce short form, # ensure short form doesn't collide with existing characters full_name = message['subject'] if '(' in full_name: ( full_name, short_form ) = full_name.split('(') full_name = full_name.strip() if ')' in short_form: short_form = short_form.split(')')[0].strip() else: short_form = full_name.split(' ')[0] full_name = full_name.strip() short_form = short_form.lower() if c.character_exists(cid, short_form): all_characters = c.all_characters(cid) msg = view.respond(locals(), "%s/repeated_short_form.msg" % (lang,), From="%s@%s" % (service_address, server_name), To=message['from'], Subject=view.render(locals(), "%s/repeated_short_form.subj" % (lang,))) logging.debug(u"DUPLICATE short form %s, campaign %s" % (short_form, str(cid))) send_or_queue(msg, cid) return if pc_or_npc: # create NPC, associate it with current campaign c.new_npc(cid, short_form, full_name) all_characters = c.all_characters(cid) # return template on the campaign language confirming its creation msg = view.respond(locals(), "%s/new_npc.msg" % (lang,), From="%s@%s" % (service_address, server_name), To=message['from'], Subject=view.render(locals(), "%s/new_npc.subj" % (lang,))) logging.debug(u"NEW_NPC short form %s, campaign %s" % (short_form, str(cid))) send_or_queue(msg, cid) return else: # create PC, associate it with current campaign and generate # enrollment email enrollment_address = c.new_pc(cid, short_form, full_name) all_characters = c.all_characters(cid) # return template on the campaign language with the enrollment email msg = view.respond(locals(), "%s/new_pc.msg" % (lang,), From="%s@%s" % (service_address, server_name), To=message['from'], Subject=view.render(locals(), "%s/new_pc.subj" % (lang,))) logging.debug(u"NEW_PC short form %s, enroll at %s, campaign %s" % (short_form, enrollment_address, str(cid))) send_or_queue(msg, cid) return