summaryrefslogtreecommitdiff
path: root/django/archives/mailarchives/api.py
blob: a6b25365921169046b1719e0ebea8cb42ccbde49 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
from django.http import HttpResponse, HttpResponseForbidden
from django.shortcuts import get_object_or_404
from django.conf import settings
import ipaddress

from .views import cache
from .models import Message, List

import json


def is_host_allowed(request):
    for ip_range in settings.API_CLIENTS:
        if ipaddress.ip_address(request.META['REMOTE_ADDR']) in ipaddress.ip_network(ip_range):
            return True
    return False


@cache(hours=4)
def listinfo(request):
    if not settings.PUBLIC_ARCHIVES:
        return HttpResponseForbidden('No API access on private archives for now')

    if not is_host_allowed(request):
        return HttpResponseForbidden('Invalid host')

    resp = HttpResponse(content_type='application/json')
    json.dump([{
        'name': l.listname,
        'shortdesc': l.shortdesc,
        'description': l.description,
        'active': l.active,
        'group': l.group.groupname,
    } for l in List.objects.select_related('group').all()], resp)

    return resp


@cache(hours=4)
def latest(request, listname):
    if not settings.PUBLIC_ARCHIVES:
        return HttpResponseForbidden('No API access on private archives for now')

    if not is_host_allowed(request):
        return HttpResponseForbidden('Invalid host')

    # Return the latest <n> messages on this list.
    # If <n> is not specified, return 50. Max value for <n> is 100.
    if 'n' in request.GET:
        try:
            limit = int(request.GET['n'])
        except Exception:
            limit = 0
    else:
        limit = 50
    if limit <= 0 or limit > 100:
        limit = 50

    extrawhere = []
    extraparams = []

    # Return only messages that have attachments?
    if 'a' in request.GET:
        if request.GET['a'] == '1':
            extrawhere.append("has_attachment")

    # Restrict by full text search
    if 's' in request.GET and request.GET['s']:
        extrawhere.append("fti @@ plainto_tsquery('public.pg', %s)")
        extraparams.append(request.GET['s'])

    if listname != '*':
        list = get_object_or_404(List, listname=listname)
        extrawhere.append("threadid IN (SELECT threadid FROM list_threads WHERE listid=%s)" % list.listid)
    else:
        list = None
        extrawhere = ''

    mlist = Message.objects.defer('bodytxt', 'cc', 'to').select_related().extra(where=extrawhere, params=extraparams).order_by('-date')[:limit]
    allyearmonths = set([(m.date.year, m.date.month) for m in mlist])

    resp = HttpResponse(content_type='application/json')
    json.dump([
        {
            'msgid': m.messageid,
            'date': m.date.isoformat(),
            'from': m.mailfrom,
            'subj': m.subject,
        }
        for m in mlist], resp)

    # Make sure this expires from the varnish cache when new entries show
    # up in this month.
    # XXX: need to deal with the global view, but for now API callers come in directly
    if list and settings.PUBLIC_ARCHIVES:
        resp['xkey'] = ' '.join(['pgam_{0}/{1}/{2}'.format(list.listid, year, month) for year, month in allyearmonths])
    return resp


@cache(hours=4)
def thread(request, msgid):
    if not settings.PUBLIC_ARCHIVES:
        return HttpResponseForbidden('No API access on private archives for now')

    if not is_host_allowed(request):
        return HttpResponseForbidden('Invalid host')

    # Return metadata about a single thread. A list of all the emails
    # that are in the thread with their basic attributes are included.
    msg = get_object_or_404(Message, messageid=msgid)
    mlist = Message.objects.defer('bodytxt', 'cc', 'to').filter(threadid=msg.threadid)

    resp = HttpResponse(content_type='application/json')
    json.dump([
        {
            'msgid': m.messageid,
            'date': m.date.isoformat(),
            'from': m.mailfrom,
            'subj': m.subject,
            'atts': [{'id': a.id, 'name': a.filename} for a in m.attachment_set.all()],
        }
        for m in mlist], resp)
    if settings.PUBLIC_ARCHIVES:
        resp['xkey'] = 'pgat_{0}'.format(msg.threadid)
    return resp