06c2cd0c90889d0d876292969e703c5f7e54502f
[nmhive.git] / nmhive.py
1 #!/usr/bin/env python
2
3 import json
4 import mailbox
5 import os
6 import tempfile
7 import urllib.request
8
9 import flask
10 import flask_cors
11 import nmbug
12 import notmuch
13
14
15 app = flask.Flask(__name__)
16 app.config['CORS_HEADERS'] = 'Content-Type'
17 flask_cors.CORS(app)
18
19 TAG_PREFIX = os.getenv('NMBPREFIX', 'notmuch::')
20 NOTMUCH_PATH = None
21
22
23 @app.route('/tags', methods=['GET'])
24 def tags():
25     tags = set()
26     database = notmuch.Database(path=NOTMUCH_PATH)
27     try:
28         for t in database.get_all_tags():
29             if t.startswith(TAG_PREFIX):
30                 tags.add(t[len(TAG_PREFIX):])
31     finally:
32         database.close()
33     return flask.Response(
34         response=json.dumps(sorted(tags)),
35         mimetype='application/json')
36
37
38 def _message_tags(message):
39     return sorted(
40         tag[len(TAG_PREFIX):] for tag in message.get_tags()
41         if tag.startswith(TAG_PREFIX))
42
43
44 @app.route('/mid/<message_id>', methods=['GET', 'POST'])
45 def message_id_tags(message_id):
46     if flask.request.method == 'POST':
47         changes = flask.request.get_json()
48         database = notmuch.Database(
49             path=NOTMUCH_PATH,
50             mode=notmuch.Database.MODE.READ_WRITE)
51         try:
52             message = database.find_message(message_id)
53             if not(message):
54                 return flask.Response(status=404)
55             database.begin_atomic()
56             message.freeze()
57             for change in changes:
58                 if change.startswith('+'):
59                     message.add_tag(TAG_PREFIX + change[1:])
60                 elif change.startswith('-'):
61                     message.remove_tag(TAG_PREFIX + change[1:])
62                 else:
63                     return flask.Response(status=400)
64             message.thaw()
65             database.end_atomic()
66             tags = _message_tags(message=message)
67         finally:
68             database.close()
69         nmbug.commit(message='nmhive: {} {}'.format(
70             message_id, ' '.join(changes)))
71     elif flask.request.method == 'GET':
72         database = notmuch.Database(path=NOTMUCH_PATH)
73         try:
74             message = database.find_message(message_id)
75             if not(message):
76                 return flask.Response(status=404)
77             tags = _message_tags(message=message)
78         finally:
79             database.close()
80     return flask.Response(
81         response=json.dumps(tags),
82         mimetype='application/json')
83
84
85 @app.route('/gmane/<group>/<int:article>', methods=['GET'])
86 def gmane_message_id(group, article):
87     url = 'http://download.gmane.org/{}/{}/{}'.format(
88         group, article, article + 1)
89     response = urllib.request.urlopen(url=url, timeout=3)
90     mbox_bytes = response.read()
91     with tempfile.NamedTemporaryFile(prefix='nmbug-', suffix='.mbox') as f:
92         f.write(mbox_bytes)
93         mbox = mailbox.mbox(path=f.name)
94         _, message = mbox.popitem()
95         message_id = message['message-id']
96     return flask.Response(
97         response=message_id.lstrip('<').rstrip('>'),
98         mimetype='text/plain')
99
100
101 if __name__ == '__main__':
102     app.run(host='0.0.0.0')