Source code for mailmanapi.api

import os
import uuid
import logging

from bottle import route, request, template, default_app

try:
    from Mailman import Utils, Errors, Post, mm_cfg
except ImportError:
    logging.error('Could not import Mailman module')

from .members import Member
from .utils import parse_boolean, jsonify, get_mailinglist, get_timestamp


CWD = os.path.abspath(os.path.dirname(__file__))
EMAIL_TEMPLATE = os.path.join(CWD, 'templates', 'message.tpl')


@route('/', method='GET')
def list_lists():
[docs] """Lists existing mailing lists on the server. **Method**: GET **URI**: / Returns a list of the mailing lists that exist on this server.""" all_lists = Utils.list_names() lists = [] include_description = request.query.get('description') address = request.query.get('address') for listname in all_lists: mlist = get_mailinglist(listname, lock=False) members = mlist.getMembers() if not address or address in members: if include_description: lists.append((listname, mlist.description.decode('latin1'))) else: lists.append(listname) return jsonify(lists) @route('/<listname>', method='PUT')
def subscribe(listname):
[docs] """Adds a new subscriber to the list called `<listname>` **Method**: PUT **URI**: /<listname> **Parameters**: * `address`: email address that is to be subscribed to the list. * `fullname`: full name of the person being subscribed to the list. * `digest`: if this equals `true`, the new subscriber will receive digests instead of every mail sent to the list. """ address = request.forms.get('address') fullname = request.forms.get('fullname') digest = parse_boolean(request.forms.get('digest')) mlist = get_mailinglist(listname) userdesc = Member(fullname, address, digest) try: mlist.ApprovedAddMember(userdesc, ack=True, admin_notif=True) except Errors.MMAlreadyAMember: return jsonify("Address already a member.", 409) except Errors.MembershipIsBanned: return jsonify("Banned address.", 403) except (Errors.MMBadEmailError, Errors.MMHostileAddress): return jsonify("Invalid address.", 400) else: mlist.Save() finally: mlist.Unlock() return jsonify(True) @route('/<listname>', method='DELETE')
def unsubscribe(listname):
[docs] """Unsubsribe an email address from the mailing list. **Method**: DELETE **URI**: /<listname> **Parameters**: * `address`: email address that is to be unsubscribed from the list """ address = request.forms.get('address') mlist = get_mailinglist(listname) try: mlist.ApprovedDeleteMember(address, admin_notif=False, userack=True) mlist.Save() except Errors.NotAMemberError: return jsonify("Not a member.", 404) finally: mlist.Unlock() return jsonify(True) @route('/<listname>', method='GET')
def members(listname):
[docs] """Lists subscribers for the `listname` list. **Method**: GET **URI**: /<listname> Returns an array of email addresses.""" mlist = get_mailinglist(listname, lock=False) return jsonify(mlist.getMembers()) @route('/<listname>/sendmail', method='POST')
def sendmail(listname):
[docs] """Posts an email to the mailing list. **Method**: POST **URI**: /<listname>/sendmail **Parameters**: * `name_from`: name of the poster * `email_from`: email address of the poster * `subject`: the subject of the message * `body`: the body of the message. * `in_reply_to` (optional): Message-ID of the message that is being replied to, if any.""" mlist = get_mailinglist(listname, lock=False) context = {} context['email_to'] = mlist.GetListEmail() context['message_id'] = uuid.uuid1() context['ip_from'] = request.environ.get('REMOTE_ADDR') context['timestamp'] = get_timestamp() context['name_from'] = request.forms.get('name_from') context['email_from'] = request.forms.get('email_from') context['subject'] = request.forms.get('subject') context['body'] = request.forms.get('body') in_reply_to = request.forms.get('in_reply_to') if in_reply_to: context['in_reply_to'] = in_reply_to if None in context.values(): return jsonify('Missing information. `email_from`, `subject` and ' '`body` are mandatory', 400) email = template(EMAIL_TEMPLATE, context) Post.inject(listname, email.encode('utf8'), qdir=mm_cfg.INQUEUE_DIR) return jsonify(True) def get_application(allowed_ips):
bottle_app = default_app() def application(environ, start_response): if environ['REMOTE_ADDR'] not in allowed_ips: status = '403 FORBIDDEN' headers = [('Content-type', 'text/plain')] start_response(status, headers) return 'FORBIDDEN' return bottle_app(environ, start_response) return application