From 91e4481c450eb7eb928debc1cb7fa59bdb63dd7b Mon Sep 17 00:00:00 2001 From: Kali Kaneko Date: Tue, 25 Jul 2017 11:40:11 -0400 Subject: [pkg] packaging and path changes - move all the pixelated python package under src/ - move the pixelated_www package under the leap namespace - allow to set globally the static folder - add hours and minutes to the timestamp in package version, to allow for several releases a day. --- service/pixelated/adapter/services/__init__.py | 15 -- .../pixelated/adapter/services/draft_service.py | 40 ----- .../pixelated/adapter/services/feedback_service.py | 36 ----- service/pixelated/adapter/services/mail_sender.py | 106 ------------- service/pixelated/adapter/services/mail_service.py | 172 --------------------- service/pixelated/adapter/services/tag_service.py | 23 --- 6 files changed, 392 deletions(-) delete mode 100644 service/pixelated/adapter/services/__init__.py delete mode 100644 service/pixelated/adapter/services/draft_service.py delete mode 100644 service/pixelated/adapter/services/feedback_service.py delete mode 100644 service/pixelated/adapter/services/mail_sender.py delete mode 100644 service/pixelated/adapter/services/mail_service.py delete mode 100644 service/pixelated/adapter/services/tag_service.py (limited to 'service/pixelated/adapter/services') diff --git a/service/pixelated/adapter/services/__init__.py b/service/pixelated/adapter/services/__init__.py deleted file mode 100644 index 2756a319..00000000 --- a/service/pixelated/adapter/services/__init__.py +++ /dev/null @@ -1,15 +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 . diff --git a/service/pixelated/adapter/services/draft_service.py b/service/pixelated/adapter/services/draft_service.py deleted file mode 100644 index 504d92db..00000000 --- a/service/pixelated/adapter/services/draft_service.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 . -from twisted.internet import defer - - -class DraftService(object): - __slots__ = '_mail_store' - - def __init__(self, mail_store): - self._mail_store = mail_store - - @defer.inlineCallbacks - def create_draft(self, input_mail): - mail = yield self._mail_store.add_mail('DRAFTS', input_mail.raw) - defer.returnValue(mail) - - @defer.inlineCallbacks - def update_draft(self, ident, input_mail): - removed = yield self._mail_store.delete_mail(ident) - if removed: - new_draft = yield self.create_draft(input_mail) - defer.returnValue(new_draft) - - def process_draft(self, ident, input_mail): - if ident: - return self.update_draft(ident, input_mail) - return self.create_draft(input_mail) diff --git a/service/pixelated/adapter/services/feedback_service.py b/service/pixelated/adapter/services/feedback_service.py deleted file mode 100644 index 0cc595eb..00000000 --- a/service/pixelated/adapter/services/feedback_service.py +++ /dev/null @@ -1,36 +0,0 @@ -# -# Copyright (c) 2015 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 . - -import os -import requests - - -class FeedbackService(object): - FEEDBACK_URL = os.environ.get('FEEDBACK_URL') - - def __init__(self, leap_session): - self.leap_session = leap_session - - def open_ticket(self, feedback): - account_mail = self.leap_session.account_email() - data = { - "ticket[comments_attributes][0][body]": feedback, - "ticket[subject]": "Feedback user-agent from {0}".format(account_mail), - "ticket[email]": account_mail, - "ticket[regarding_user]": account_mail - } - - return requests.post(self.FEEDBACK_URL, data=data, verify=False) diff --git a/service/pixelated/adapter/services/mail_sender.py b/service/pixelated/adapter/services/mail_sender.py deleted file mode 100644 index 063ea156..00000000 --- a/service/pixelated/adapter/services/mail_sender.py +++ /dev/null @@ -1,106 +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 . -from StringIO import StringIO -from email.utils import parseaddr -from copy import deepcopy -from leap.bitmask.mail.outgoing.service import OutgoingMail - -from twisted.internet.defer import Deferred, fail -from twisted.mail.smtp import SMTPSenderFactory -from twisted.internet import reactor, defer -from pixelated.support.functional import flatten -from twisted.mail.smtp import User - -from twisted.logger import Logger - - -logger = Logger() - - -class SMTPDownException(Exception): - def __init__(self): - Exception.__init__(self, "Couldn't send mail now, try again later.") - - -NOT_NEEDED = None - - -class MailSenderException(Exception): - - def __init__(self, message, email_error_map): - super(MailSenderException, self).__init__(message, email_error_map) - self.email_error_map = email_error_map - - -class MailSender(object): - - def __init__(self, smtp_config, keymanager): - self._smtp_config = smtp_config - self._keymanager = keymanager - - @defer.inlineCallbacks - def sendmail(self, mail): - # message is changed in sending, but should be saved unaltered - mail = deepcopy(mail) - - recipients = flatten([mail.to, mail.cc, mail.bcc]) - - results = yield self._send_mail_to_all_recipients(mail, recipients) - all_succeeded = reduce(lambda a, b: a and b, [r[0] for r in results]) - - if not all_succeeded: - error_map = self._build_error_map(recipients, results) - raise MailSenderException('Failed to send mail to all recipients', error_map) - - defer.returnValue(all_succeeded) - - def _send_mail_to_all_recipients(self, mail, recipients): - outgoing_mail = self._create_outgoing_mail() - bccs = mail.bcc - deferreds = [] - - for recipient in recipients: - logger.info('_send_mail_to_all_recipients: Sending mail to recipient %s' % recipient) - self._define_bcc_field(mail, recipient, bccs) - smtp_recipient = self._create_twisted_smtp_recipient(recipient) - logger.info('_send_mail_to_all_recipients: Sending mail to smtp_recipient %s' % smtp_recipient) - deferreds.append(outgoing_mail.send_message(mail.to_smtp_format(), smtp_recipient)) - - return defer.DeferredList(deferreds, fireOnOneErrback=False, consumeErrors=True) - - def _define_bcc_field(self, mail, recipient, bccs): - if recipient in bccs: - mail.headers['Bcc'] = [recipient] - else: - mail.headers['Bcc'] = [] - - def _build_error_map(self, recipients, results): - error_map = {} - for email, error in [(recipients[idx], r[1]) for idx, r in enumerate(results)]: - error_map[email] = error - return error_map - - def _create_outgoing_mail(self): - return OutgoingMail(str(self._smtp_config.account_email), - self._keymanager, - self._smtp_config.cert_path, - self._smtp_config.cert_path, - str(self._smtp_config.remote_smtp_host), - int(self._smtp_config.remote_smtp_port)) - - def _create_twisted_smtp_recipient(self, recipient): - # TODO: Better is fix Twisted instead - return User(str(recipient), NOT_NEEDED, NOT_NEEDED, NOT_NEEDED) diff --git a/service/pixelated/adapter/services/mail_service.py b/service/pixelated/adapter/services/mail_service.py deleted file mode 100644 index e5343997..00000000 --- a/service/pixelated/adapter/services/mail_service.py +++ /dev/null @@ -1,172 +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 . -from email import encoders -from email.mime.nonmultipart import MIMENonMultipart -from email.mime.multipart import MIMEMultipart -from leap.bitmask.mail.mail import Message - -from twisted.internet import defer - -from pixelated.adapter.model.mail import InputMail -from pixelated.adapter.model.status import Status -from pixelated.adapter.services.tag_service import extract_reserved_tags -from leap.bitmask.mail.adaptors.soledad import SoledadMailAdaptor - - -class MailService(object): - - def __init__(self, mail_sender, mail_store, search_engine, account_email, attachment_store): - self.mail_store = mail_store - self.search_engine = search_engine - self.mail_sender = mail_sender - self.account_email = account_email - self.attachment_store = attachment_store - - @defer.inlineCallbacks - def all_mails(self): - mails = yield self.mail_store.all_mails(gracefully_ignore_errors=True) - defer.returnValue(mails) - - def save_attachment(self, content, content_type): - return self.attachment_store.add_attachment(content, content_type) - - @defer.inlineCallbacks - def mails(self, query, window_size, page): - mail_ids, total = self.search_engine.search(query, window_size, page) - - try: - mails = yield self.mail_store.get_mails(mail_ids) - defer.returnValue((mails, total)) - except Exception, e: - import traceback - traceback.print_exc() - raise - - @defer.inlineCallbacks - def update_tags(self, mail_id, new_tags): - new_tags = self._filter_white_space_tags(new_tags) - reserved_words = extract_reserved_tags(new_tags) - if len(reserved_words): - raise ValueError('None of the following words can be used as tags: ' + ' '.join(reserved_words)) - new_tags = self._favor_existing_tags_casing(new_tags) - mail = yield self.mail(mail_id) - mail.tags = set(new_tags) - yield self.mail_store.update_mail(mail) - - defer.returnValue(mail) - - def _filter_white_space_tags(self, tags): - return [tag.strip() for tag in tags if not tag.isspace()] - - def _favor_existing_tags_casing(self, new_tags): - current_tags = [tag['name'] for tag in self.search_engine.tags(query='', skip_default_tags=True)] - current_tags_lower = [tag.lower() for tag in current_tags] - - def _use_current_casing(new_tag_lower): - return current_tags[current_tags_lower.index(new_tag_lower)] - - return [_use_current_casing(new_tag.lower()) if new_tag.lower() in current_tags_lower else new_tag for new_tag in new_tags] - - def mail(self, mail_id): - return self.mail_store.get_mail(mail_id, include_body=True) - - def attachment(self, attachment_id): - return self.attachment_store.get_mail_attachment(attachment_id) - - @defer.inlineCallbacks - def mail_exists(self, mail_id): - try: - mail = yield self.mail_store.get_mail(mail_id, include_body=False) - defer.returnValue(mail is not None) - except Exception, e: - defer.returnValue(False) - - @defer.inlineCallbacks - def send_mail(self, content_dict): - mail = InputMail.from_dict(content_dict, self.account_email) - draft_id = content_dict.get('ident') - self._deduplicate_recipients(mail) - yield self.mail_sender.sendmail(mail) - - sent_mail = yield self.move_to_sent(draft_id, mail) - defer.returnValue(sent_mail) - - def _deduplicate_recipients(self, mail): - self._remove_canonical(mail) - self._remove_duplicates_form_cc_and_to(mail) - - def _remove_canonical(self, mail): - mail.headers['To'] = map(self._remove_canonical_recipient, mail.to) - mail.headers['Cc'] = map(self._remove_canonical_recipient, mail.cc) - mail.headers['Bcc'] = map(self._remove_canonical_recipient, mail.bcc) - - def _remove_duplicates_form_cc_and_to(self, mail): - mail.headers['To'] = list(set(self._remove_duplicates(mail.to)).difference(set(mail.bcc))) - mail.headers['Cc'] = list((set(self._remove_duplicates(mail.cc)).difference(set(mail.bcc)).difference(set(mail.to)))) - mail.headers['Bcc'] = self._remove_duplicates(mail.bcc) - - def _remove_duplicates(self, recipient): - return list(set(recipient)) - - # TODO removing canocical should, be added back later - def _remove_canonical_recipient(self, recipient): - return recipient.split('<')[1][0:-1] if '<' in recipient else recipient - - @defer.inlineCallbacks - def move_to_sent(self, last_draft_ident, mail): - if last_draft_ident: - try: - yield self.mail_store.delete_mail(last_draft_ident) - except Exception as error: - pass - sent_mail = yield self.mail_store.add_mail('SENT', mail.raw) - sent_mail.flags.add(Status.SEEN) - yield self.mail_store.update_mail(sent_mail) - defer.returnValue(sent_mail) - - @defer.inlineCallbacks - def mark_as_read(self, mail_id): - mail = yield self.mail(mail_id) - mail.flags.add(Status.SEEN) - yield self.mail_store.update_mail(mail) - - @defer.inlineCallbacks - def mark_as_unread(self, mail_id): - mail = yield self.mail(mail_id) - mail.flags.remove(Status.SEEN) - yield self.mail_store.update_mail(mail) - - @defer.inlineCallbacks - def delete_mail(self, mail_id): - mail = yield self.mail(mail_id) - if mail is not None: - if mail.mailbox_name.upper() in (u'TRASH', u'DRAFTS'): - yield self.mail_store.delete_mail(mail_id) - else: - yield self.mail_store.move_mail_to_mailbox(mail_id, 'TRASH') - - @defer.inlineCallbacks - def recover_mail(self, mail_id): - yield self.mail_store.move_mail_to_mailbox(mail_id, 'INBOX') - - @defer.inlineCallbacks - def archive_mail(self, mail_id): - yield self.mail_store.add_mailbox('ARCHIVE') - yield self.mail_store.move_mail_to_mailbox(mail_id, 'ARCHIVE') - - @defer.inlineCallbacks - def delete_permanent(self, mail_id): - yield self.mail_store.delete_mail(mail_id) diff --git a/service/pixelated/adapter/services/tag_service.py b/service/pixelated/adapter/services/tag_service.py deleted file mode 100644 index c51da625..00000000 --- a/service/pixelated/adapter/services/tag_service.py +++ /dev/null @@ -1,23 +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 . -from pixelated.adapter.model.tag import Tag - -SPECIAL_TAGS = {Tag('inbox', True), Tag('sent', True), Tag('drafts', True), Tag('trash', True), Tag('ALL', True)} - - -def extract_reserved_tags(tags): - tags = [tag.lower() for tag in tags] - return {tag.name for tag in SPECIAL_TAGS if tag.name in tags} -- cgit v1.2.3