diff options
Diffstat (limited to 'py-fake-service/app')
-rw-r--r-- | py-fake-service/app/__init__.py | 0 | ||||
-rw-r--r-- | py-fake-service/app/adapter/__init__.py | 16 | ||||
-rw-r--r-- | py-fake-service/app/adapter/contacts.py | 41 | ||||
-rw-r--r-- | py-fake-service/app/adapter/mail.py | 91 | ||||
-rw-r--r-- | py-fake-service/app/adapter/mail_service.py | 128 | ||||
-rw-r--r-- | py-fake-service/app/adapter/mailset.py | 69 | ||||
-rw-r--r-- | py-fake-service/app/adapter/tag.py | 40 | ||||
-rw-r--r-- | py-fake-service/app/adapter/tagsset.py | 57 | ||||
-rw-r--r-- | py-fake-service/app/pixelated_user_agent.py | 196 | ||||
-rw-r--r-- | py-fake-service/app/search/__init__.py | 16 | ||||
-rw-r--r-- | py-fake-service/app/search/search_query.py | 86 |
11 files changed, 0 insertions, 740 deletions
diff --git a/py-fake-service/app/__init__.py b/py-fake-service/app/__init__.py deleted file mode 100644 index e69de29b..00000000 --- a/py-fake-service/app/__init__.py +++ /dev/null diff --git a/py-fake-service/app/adapter/__init__.py b/py-fake-service/app/adapter/__init__.py deleted file mode 100644 index 55f91e08..00000000 --- a/py-fake-service/app/adapter/__init__.py +++ /dev/null @@ -1,16 +0,0 @@ -# -# Copyright (c) 2014 ThoughtWorks, Inc. -# -# Pixelated is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# Pixelated is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with Pixelated. If not, see <http://www.gnu.org/licenses/>. -from mail_service import MailService diff --git a/py-fake-service/app/adapter/contacts.py b/py-fake-service/app/adapter/contacts.py deleted file mode 100644 index 30ff1253..00000000 --- a/py-fake-service/app/adapter/contacts.py +++ /dev/null @@ -1,41 +0,0 @@ -# -# Copyright (c) 2014 ThoughtWorks, Inc. -# -# Pixelated is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# Pixelated is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with Pixelated. If not, see <http://www.gnu.org/licenses/>. -import re - - -class Contacts: - - def __init__(self): - self.contacts = [] - - def add(self, mbox_mail): - contact = mbox_mail.get('From') or mbox_mail.from_addr - self.contacts.append(Contact(contact)) - - def search(self, query): - contacts_query = re.compile(query) - return [ - contact.__dict__ - for contact in self.contacts - if contacts_query.match(contact.addresses[0]) - ] - - -class Contact: - - def __init__(self, contact): - self.addresses = [contact] - self.name = '' diff --git a/py-fake-service/app/adapter/mail.py b/py-fake-service/app/adapter/mail.py deleted file mode 100644 index 26c00277..00000000 --- a/py-fake-service/app/adapter/mail.py +++ /dev/null @@ -1,91 +0,0 @@ -# -# Copyright (c) 2014 ThoughtWorks, Inc. -# -# Pixelated is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# Pixelated is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with Pixelated. If not, see <http://www.gnu.org/licenses/>. -from datetime import datetime -import random -import calendar -from dateutil import parser - -class Mail: - - NOW = calendar.timegm( - datetime.strptime( - datetime.now().isoformat(), - "%Y-%m-%dT%H:%M:%S.%f").timetuple()) - - @staticmethod - def from_json(mail_json): - mail = Mail() - mail.header = mail_json['header'] - mail.header['date'] = datetime.now().isoformat() - mail.ident = mail_json.get('ident', 0) - mail.body = mail_json['body'] - mail.tags = mail_json['tags'] - mail.security_casing = {} - mail.status = [] - mail.draft_reply_for = mail_json.get('draft_reply_for', 0) - return mail - - def __init__(self, mbox_mail=None, ident=None): - if mbox_mail: - self.header = self._get_headers(mbox_mail) - self.ident = ident - self.body = self._get_body(mbox_mail) - self.tags = self._get_tags(mbox_mail) - self.security_casing = {} - self.status = self._get_status() - self.draft_reply_for = -1 - - def _get_body(self, message): - if message.is_multipart(): - boundary = '--{boundary}'.format( - boundary=message.get_boundary().strip()) - body_parts = [x.as_string() for x in message.get_payload()] - - body = boundary + '\n' - body += '{boundary}\n'.format(boundary=boundary).join(body_parts) - body += '{boundary}--\n'.format(boundary=boundary) - - return body - else: - return message.get_payload() - - def _get_status(self): - status = [] - if 'sent' in self.tags: - status.append('read') - - return status - - def _get_headers(self, mbox_mail): - headers = {} - headers['from'] = mbox_mail.get('From') or mbox_mail.from_addr - headers['to'] = [mbox_mail.get('To')] - headers['subject'] = mbox_mail.get('Subject') - headers['date'] = parser.parse(mbox_mail['Date']).isoformat() - headers['content_type'] = mbox_mail.get('Content-Type') - - return headers - - def _get_tags(self, mbox_mail): - return filter(len, mbox_mail.get('X-TW-Pixelated-Tags').split(', ')) - - @property - def subject(self): - return self.header['subject'] - - @property - def date(self): - return self.header['date'] diff --git a/py-fake-service/app/adapter/mail_service.py b/py-fake-service/app/adapter/mail_service.py deleted file mode 100644 index 2825af9d..00000000 --- a/py-fake-service/app/adapter/mail_service.py +++ /dev/null @@ -1,128 +0,0 @@ -# -# Copyright (c) 2014 ThoughtWorks, Inc. -# -# Pixelated is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# Pixelated is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with Pixelated. If not, see <http://www.gnu.org/licenses/>. -import os -import re -import mailbox - -from tagsset import TagsSet -from mailset import MailSet -from contacts import Contacts -from mail import Mail - - -class MailService: - MAILSET_PATH = os.path.join(os.environ['HOME'], 'mailsets', 'mediumtagged') - - def __init__(self): - self.mailset = MailSet() - self.tagsset = TagsSet() - self.contacts = Contacts() - - def reset(self): - self.mailset = MailSet() - self.tagsset = TagsSet() - self.contacts = Contacts() - - def _read_file(self, filename): - with open(filename, 'r') as fd: - return fd.read() - - def _create_message_from_file(self, filename): - data = self._read_file(filename) - return self.create_message_from_string(data, filename) - - def create_message_from_string(self, data, filename=None): - if data.startswith('From '): - msg = mailbox.mboxMessage(data) - from_addr = re.sub(r"^From ", "", msg.get_unixfrom()) - msg.from_addr = from_addr - msg.set_from(from_addr) - else: - msg = mailbox.Message(data) - msg.from_addr = msg.get('From') - return msg - - def _create_message_from_string(self, data): - return mailbox.Message(data) - - def load_mailset(self): - mbox_filenames = [ - filename - for filename in os.listdir - (self.MAILSET_PATH) if filename.startswith('mbox')] - messages = (self._create_message_from_file(os.path.join(self.MAILSET_PATH, mbox)) - for mbox in mbox_filenames) - - self.index_messages(messages) - - def index_messages(self, messages): - for message in messages: - self.mailset.add(message) - self.tagsset.add(message) - self.contacts.add(message) - - def mails(self, query, page, window_size): - mails = self.mailset.values() - mails = [mail for mail in mails if query.test(mail)] - return sorted(mails, key=lambda mail: mail.date, reverse=True) - - def mail(self, mail_id): - return self.mailset.get(mail_id) - - def search_contacts(self, query): - return self.contacts.search(query) - - def mark_as_read(self, mail_id): - self.mailset.mark_as_read(mail_id) - self.tagsset.mark_as_read(self.mail(mail_id).tags) - - def delete_mail(self, mail_id): - purged = self.mailset.delete(mail_id) - if not purged: - self.tagsset.increment_tag_total_count('trash') - - def update_tags_for(self, mail_id, new_tags): - mail = self.mail(mail_id) - - new_tags_set = set(new_tags) - old_tags_set = set(mail.tags) - - increment_set = new_tags_set - old_tags_set - decrement_set = old_tags_set - new_tags_set - - map(lambda x: self.tagsset.increment_tag_total_count(x), increment_set) - map(lambda x: self.tagsset.decrement_tag_total_count(x), decrement_set) - - mail.tags = new_tags - - def send(self, mail): - mail = Mail.from_json(mail) - self.mailset.update(mail) - self.tagsset.increment_tag_total_count('sent') - self.tagsset.decrement_tag_total_count('drafts') - return mail.ident - - def save_draft(self, mail): - mail = self.mailset.add_draft(Mail.from_json(mail)) - return mail.ident - - def update_draft(self, mail): - mail = Mail.from_json(mail) - self.mailset.update(mail) - return mail.ident - - def draft_reply_for(self, mail_id): - return self.mailset.find(draft_reply_for=mail_id) diff --git a/py-fake-service/app/adapter/mailset.py b/py-fake-service/app/adapter/mailset.py deleted file mode 100644 index bf7e8c67..00000000 --- a/py-fake-service/app/adapter/mailset.py +++ /dev/null @@ -1,69 +0,0 @@ -# -# Copyright (c) 2014 ThoughtWorks, Inc. -# -# Pixelated is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# Pixelated is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with Pixelated. If not, see <http://www.gnu.org/licenses/>. -from mail import Mail - - -class MailSet: - - def __init__(self): - self.ident = 0 - self.mails = {} - - def add(self, mbox_mail): - self.mails[self.ident] = Mail(mbox_mail, self.ident) - self.ident += 1 - - def values(self): - return self.mails.values() - - def get(self, mail_id): - return self.mails.get(mail_id) - - def mark_as_read(self, mail_id): - mail = self.get(mail_id) - mail.status.append('read') - - def delete(self, mail_id): - """ - Returns True if the email got purged, - else returns False meaning the email got moved to trash - """ - - mail = self.get(mail_id) - if 'trash' in mail.tags: - del self.mails[mail_id] - return True - mail.tags.append('trash') - return False - - def update(self, mail): - self.mails[mail.ident] = mail - - def add_draft(self, mail): - mail.ident = self.ident - self.mails[mail.ident] = mail - self.ident += 1 - return mail - - def find(self, draft_reply_for): - match = [ - mail - for mail in self.mails.values - () if mail.draft_reply_for == draft_reply_for] - if len(match) == 0: - return None - else: - return match[0] diff --git a/py-fake-service/app/adapter/tag.py b/py-fake-service/app/adapter/tag.py deleted file mode 100644 index b866d789..00000000 --- a/py-fake-service/app/adapter/tag.py +++ /dev/null @@ -1,40 +0,0 @@ -# -# Copyright (c) 2014 ThoughtWorks, Inc. -# -# Pixelated is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# Pixelated is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with Pixelated. If not, see <http://www.gnu.org/licenses/>. - - -class Tag: - DEFAULT_TAGS = ["inbox", "sent", "trash", "drafts"] - - def __init__(self, name, ident): - self.counts = { - 'total': 0, - 'read': 0, - 'starred': 0, - 'reply': 0 - } - - self.ident = ident - self.name = name.lower() - self.default = name in self.DEFAULT_TAGS - - def increment_count(self): - self.counts['total'] += 1 - - def increment_read(self): - self.counts['read'] += 1 - - def decrement_count(self): - self.counts['total'] -= 1 diff --git a/py-fake-service/app/adapter/tagsset.py b/py-fake-service/app/adapter/tagsset.py deleted file mode 100644 index 8e0d7ca3..00000000 --- a/py-fake-service/app/adapter/tagsset.py +++ /dev/null @@ -1,57 +0,0 @@ -# -# Copyright (c) 2014 ThoughtWorks, Inc. -# -# Pixelated is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# Pixelated is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with Pixelated. If not, see <http://www.gnu.org/licenses/>. -from tag import Tag - - -class TagsSet: - - DEFAULT_TAGS = ["inbox", "sent", "trash", "drafts"] - - def __init__(self): - self.ident = 0 - self.tags = {} - self.tags = {tag: self._create_new_tag(tag) for tag in self.DEFAULT_TAGS} - - def add(self, mbox_mail): - tags = filter(len, mbox_mail.get('X-TW-Pixelated-Tags').split(', ')) - for tag in tags: - tag = self._create_new_tag(tag) - tag.increment_count() - - def all_tags(self): - return self.tags.values() - - def mark_as_read(self, tags): - for tag in tags: - tag = tag.lower() - tag = self.tags.get(tag) - tag.increment_read() - - def increment_tag_total_count(self, tagname): - tag = self.tags.get(tagname) - if tag: - tag.increment_count() - else: - self._create_new_tag(tagname) - - def decrement_tag_total_count(self, tag): - self.tags.get(tag).decrement_count() - - def _create_new_tag(self, tag): - tag = Tag(tag, self.ident) - tag = self.tags.setdefault(tag.name, tag) - self.ident += 1 - return tag diff --git a/py-fake-service/app/pixelated_user_agent.py b/py-fake-service/app/pixelated_user_agent.py deleted file mode 100644 index 5931bce5..00000000 --- a/py-fake-service/app/pixelated_user_agent.py +++ /dev/null @@ -1,196 +0,0 @@ -# # Copyright (c) 2014 ThoughtWorks, Inc. -# -# Pixelated is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# Pixelated is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with Pixelated. If not, see <http://www.gnu.org/licenses/>. -from flask import Flask, request, Response, redirect -import os -import csv -import json -import datetime -import mailbox -import StringIO -import requests -from adapter import MailService -from search import SearchQuery - -app = Flask(__name__, static_url_path='', static_folder='../../web-ui/app') -MEDIUM_TAGGED_URL = 'https://static.wazokazi.is/py-mediumtagged.tar.gz' -client = None -converter = None -account = None -autoload = os.environ.get('AUTOLOAD', False) -mail_service = MailService() - - -def respond_json(entity): - response = json.dumps(entity) - return Response(response=response, mimetype="application/json") - - -@app.route('/disabled_features') -def disabled_features(): - return respond_json([]) - - -@app.route('/mails', methods=['POST']) -def save_draft_or_send(): - mail = request.json - if mail['ident']: - ident = mail_service.send(mail) - else: - ident = mail_service.save_draft(mail) - - return respond_json({'ident': ident}) - - -@app.route('/mails', methods=['PUT']) -def update_draft(): - mail = request.json - ident = mail_service.update_draft(mail) - return respond_json({'ident': ident}) - - -@app.route('/mails') -def mails(): - query = SearchQuery.compile(request.args.get('q', '')) - page = request.args.get('p', '') - window_size = request.args.get('w', '') - fetched_mails = mail_service.mails(query, page, window_size) - - mails = [mail.__dict__ for mail in fetched_mails] - response = { - "stats": { - "total": len(mails), - "read": 0, - "starred": 0, - "replied": 0 - }, - "mails": mails - } - - return respond_json(response) - - -@app.route('/mail/<int:mail_id>', methods=['DELETE']) -def delete_mails(mail_id): - mail_service.delete_mail(mail_id) - return respond_json(None) - - -@app.route('/tags') -def tags(): - tags = mail_service.tagsset.all_tags() - return respond_json([tag.__dict__ for tag in tags]) - - -@app.route('/mail/<int:mail_id>') -def mail(mail_id): - return respond_json(mail_service.mail(mail_id).__dict__) - - -@app.route('/mail/<int:mail_id>/tags', methods=['POST']) -def mail_tags(mail_id): - new_tags = request.json['newtags'] - mail_service.update_tags_for(mail_id, new_tags) - return respond_json(request.json['newtags']) - - -@app.route('/mail/<int:mail_id>/read', methods=['POST']) -def mark_mail_as_read(mail_id): - mail_service.mark_as_read(mail_id) - return "" - - -@app.route('/contacts') -def contacts(): - contacts_query = request.args.get('q') - return respond_json( - {'contacts': mail_service.search_contacts(contacts_query)}) - - -@app.route('/draft_reply_for/<int:mail_id>') -def draft_reply_for(mail_id): - mail = mail_service.draft_reply_for(mail_id) - if mail: - return respond_json(mail.__dict__) - else: - return respond_json(None) - - -def utf_8_encoder(unicode_csv_data): - for line in unicode_csv_data: - yield line.encode('utf-8') - - -@app.route('/control/mailset/csv/load', methods=['POST']) -def load_mailset_from_csv(): - csv_data = request.form.keys()[0] - csv_string = StringIO.StringIO(csv_data) - csv_reader = csv.reader(utf_8_encoder(csv_string)) - headers = csv_reader.next() - messages = [] - for row in csv_reader: - mail = "" - row[3] = ', '.join(filter(len, row[3].split(' '))) - for header, value in zip(headers, row): - if header == 'Body': - mail += "\n" - else: - mail += header + ": " - mail += value + "\n" - messages.append(mailbox.mboxMessage(mail)) - mail_service.index_messages(messages) - return respond_json(None) - - -@app.route('/control/mailset/<mailset>/load', methods=['POST']) -def load_mailset(mailset): - import os - from tarfile import TarFile - from gzip import GzipFile - mbox_root = os.path.join(os.environ['HOME'], 'mailsets') - if not os.path.isdir(os.path.join(mbox_root)): - os.mkdir(mbox_root) - - if len(os.listdir(mbox_root)) == 0: - response = requests.get(MEDIUM_TAGGED_URL, verify=False) - mbox_archive_path = os.path.join(mbox_root, 'py-mediumtagged.tar.gz') - mbox_archive = open(mbox_archive_path, 'w') - mbox_archive.write(response.content) - mbox_archive.close() - gzippedfile = GzipFile(filename=mbox_archive_path) - tarfile = TarFile(fileobj=gzippedfile) - tarfile.extractall(path=mbox_root) - - mail_service.reset() - mail_service.load_mailset() - - return respond_json(None) - - -@app.route('/') -def index(): - global autoload - if autoload: - load_mailset('mediumtagged') - autoload = False - - return app.send_static_file('index.html') - - -def setup(): - app.run(host="0.0.0.0", debug=True, port=4567) - - -if __name__ == '__main__': - setup() diff --git a/py-fake-service/app/search/__init__.py b/py-fake-service/app/search/__init__.py deleted file mode 100644 index d6d7b07c..00000000 --- a/py-fake-service/app/search/__init__.py +++ /dev/null @@ -1,16 +0,0 @@ -# -# Copyright (c) 2014 ThoughtWorks, Inc. -# -# Pixelated is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# Pixelated is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with Pixelated. If not, see <http://www.gnu.org/licenses/>. -from search_query import SearchQuery diff --git a/py-fake-service/app/search/search_query.py b/py-fake-service/app/search/search_query.py deleted file mode 100644 index 34e68601..00000000 --- a/py-fake-service/app/search/search_query.py +++ /dev/null @@ -1,86 +0,0 @@ -# -# Copyright (c) 2014 ThoughtWorks, Inc. -# -# Pixelated is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# Pixelated is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with Pixelated. If not, see <http://www.gnu.org/licenses/>. -from scanner import StringScanner, StringRegexp -import re - - -def _next_token(): - return StringRegexp('[^\s]+') - - -def _separators(): - return StringRegexp('[\s&]+') - - -def _compile_tag(compiled, token): - tag = token.split(":").pop() - if token[0] == "-": - compiled["not_tags"].append(tag) - else: - compiled["tags"].append(tag) - return compiled - - -class SearchQuery: - - @staticmethod - def compile(query): - compiled = {"tags": [], "not_tags": [], "general": []} - - scanner = StringScanner(query.encode('utf8').replace("\"", "")) - first_token = True - while not scanner.is_eos: - token = scanner.scan(_next_token()) - - if not token: - scanner.skip(_separators()) - continue - - if ":" in token: - compiled = _compile_tag(compiled, token) - elif first_token: - compiled["general"].append(token) - - if not first_token: - first_token = True - - compiled["general"] = ' '.join(compiled["general"]) - return SearchQuery(compiled) - - def __init__(self, compiled): - self.compiled = compiled - - def test(self, mail): - if 'all' in self.compiled.get('tags'): - return True - - if set(self.compiled.get('not_tags')).intersection(set(mail.tags)): - return False - - if set(self.compiled.get('tags')).intersection(set(mail.tags)): - return True - - if self.compiled.get('general'): - search_terms = re.compile( - self.compiled['general'], - flags=re.IGNORECASE) - if search_terms.search(mail.subject+' '+mail.body): - return True - - if not [v for v in self.compiled.values() if v]: - return True - - return False |