From 6ac2e7a4c23ef2798ca5b4ad0aa84a5fb7b371f8 Mon Sep 17 00:00:00 2001 From: Duda Dornelles Date: Wed, 15 Oct 2014 16:03:17 +0200 Subject: moving things out of user_agent. now it is called runserver and only does basic app setup and delegates to other "classes". --- service/pixelated/bitmask_libraries/register.py | 18 +++ service/pixelated/config/app_factory.py | 86 +++++++++++++++ service/pixelated/config/args.py | 31 ++++++ service/pixelated/config/reactor_manager.py | 65 +++++++++++ service/pixelated/controllers/__init__.py | 1 - service/pixelated/reactor_manager.py | 65 ----------- service/pixelated/runserver.py | 49 +++++++++ service/pixelated/user_agent.py | 139 ------------------------ service/setup.py | 4 +- service/test/functional/features/environment.py | 6 +- service/test/support/integration_helper.py | 10 +- service/test/unit/user_agent_test.py | 2 +- 12 files changed, 261 insertions(+), 215 deletions(-) create mode 100644 service/pixelated/bitmask_libraries/register.py create mode 100644 service/pixelated/config/app_factory.py create mode 100644 service/pixelated/config/args.py create mode 100644 service/pixelated/config/reactor_manager.py delete mode 100644 service/pixelated/reactor_manager.py create mode 100644 service/pixelated/runserver.py delete mode 100644 service/pixelated/user_agent.py diff --git a/service/pixelated/bitmask_libraries/register.py b/service/pixelated/bitmask_libraries/register.py new file mode 100644 index 00000000..79c9069a --- /dev/null +++ b/service/pixelated/bitmask_libraries/register.py @@ -0,0 +1,18 @@ +import getpass + +import os +import os.path +import pixelated.bitmask_libraries.session as LeapSession +from pixelated.bitmask_libraries.config import LeapConfig +from pixelated.bitmask_libraries.provider import LeapProvider +from pixelated.bitmask_libraries.auth import LeapAuthenticator, LeapCredentials + + +def register_new_user(username, server_name): + certs_home = os.path.abspath(os.path.join(os.path.abspath(__file__), "..", "certificates")) + config = LeapConfig(certs_home=certs_home) + provider = LeapProvider(server_name, config) + password = getpass.getpass('Please enter password for %s: ' % username) + LeapAuthenticator(provider).register(LeapCredentials(username, password)) + session = LeapSession.open(username, password, server_name) + session.nicknym.generate_openpgp_key() diff --git a/service/pixelated/config/app_factory.py b/service/pixelated/config/app_factory.py new file mode 100644 index 00000000..f4aa06d7 --- /dev/null +++ b/service/pixelated/config/app_factory.py @@ -0,0 +1,86 @@ +# +# 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.mail_service import MailService +from pixelated.adapter.mail import InputMail +from pixelated.adapter.soledad_querier import SoledadQuerier +from pixelated.adapter.search import SearchEngine +from pixelated.adapter.draft_service import DraftService +from pixelated.adapter.listener import MailboxListener +import pixelated.bitmask_libraries.session as LeapSession +from pixelated.controllers import * +from pixelated.adapter.tag_service import TagService +import os + + +def _setup_routes(app, home_controller, mails_controller, tags_controller, features_controller): + # home + app.add_url_rule('/', methods=['GET'], view_func=home_controller.home) + # mails + app.add_url_rule('/mails', methods=['GET'], view_func=mails_controller.mails) + app.add_url_rule('/mail//read', methods=['POST'], view_func=mails_controller.mark_mail_as_read) + app.add_url_rule('/mail//unread', methods=['POST'], view_func=mails_controller.mark_mail_as_unread) + app.add_url_rule('/mails/unread', methods=['POST'], view_func=mails_controller.mark_many_mail_unread) + app.add_url_rule('/mail/', methods=['GET'], view_func=mails_controller.mail) + app.add_url_rule('/mail/', methods=['DELETE'], view_func=mails_controller.delete_mail) + app.add_url_rule('/mails', methods=['DELETE'], view_func=mails_controller.delete_mails) + app.add_url_rule('/mails', methods=['POST'], view_func=mails_controller.send_mail) + app.add_url_rule('/mail//tags', methods=['POST'], view_func=mails_controller.mail_tags) + app.add_url_rule('/mails', methods=['PUT'], view_func=mails_controller.update_draft) + # tags + app.add_url_rule('/tags', methods=['GET'], view_func=tags_controller.tags) + # features + app.add_url_rule('/features', methods=['GET'], view_func=features_controller.features) + + +def create_app(debug_enabled, app): + + with app.app_context(): + leap_session = LeapSession.open(app.config['LEAP_USERNAME'], app.config['LEAP_PASSWORD'], + app.config['LEAP_SERVER_NAME']) + tag_service = TagService() + soledad_querier = SoledadQuerier(soledad=leap_session.account._soledad) + pixelated_mailboxes = PixelatedMailBoxes(leap_session.account, soledad_querier) + pixelated_mail_sender = PixelatedMailSender(leap_session.account_email()) + mail_service = MailService(pixelated_mailboxes, pixelated_mail_sender, tag_service, soledad_querier) + search_engine = SearchEngine() + search_engine.index_mails(mail_service.all_mails()) + draft_service = DraftService(pixelated_mailboxes) + + MailboxListener.SEARCH_ENGINE = search_engine + InputMail.FROM_EMAIL_ADDRESS = leap_session.account_email() + + home_controller = HomeController() + features_controller = FeaturesController() + mails_controller = MailsController(mail_service=mail_service, + draft_service=draft_service, + search_engine=search_engine) + tags_controller = TagsController(search_engine=search_engine) + + _setup_routes(app, home_controller, mails_controller, tags_controller, features_controller) + + app.run(host=app.config['HOST'], debug=debug_enabled, + port=app.config['PORT'], use_reloader=False) + + +def get_static_folder(): + static_folder = os.path.abspath(os.path.join(os.path.abspath(__file__), "..", "..", "..", "web-ui", "app")) + # this is a workaround for packaging + if not os.path.exists(static_folder): + static_folder = os.path.abspath(os.path.join(os.path.abspath(__file__), "..", "..", "..", "..", "web-ui", "app")) + if not os.path.exists(static_folder): + static_folder = os.path.join('/', 'usr', 'share', 'pixelated-user-agent') + return static_folder diff --git a/service/pixelated/config/args.py b/service/pixelated/config/args.py new file mode 100644 index 00000000..0e830e0a --- /dev/null +++ b/service/pixelated/config/args.py @@ -0,0 +1,31 @@ +# +# 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 . + +import argparse + +import os + + +def parse(): + default_config_path = os.path.join(os.environ['HOME'], '.pixelated') + parser = argparse.ArgumentParser(description='Pixelated user agent.') + parser.add_argument('--debug', action='store_true', + help='DEBUG mode.') + parser.add_argument('--register', metavar='username', help='register user with name.') + parser.add_argument('-c', '--config', metavar='configfile', default=default_config_path, + help='use specified config file. Default is ~/.pixelated.') + args = parser.parse_args() + return args diff --git a/service/pixelated/config/reactor_manager.py b/service/pixelated/config/reactor_manager.py new file mode 100644 index 00000000..c9473400 --- /dev/null +++ b/service/pixelated/config/reactor_manager.py @@ -0,0 +1,65 @@ +# +# 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 . +import signal +import sys +from threading import Thread +import logging + +from twisted.internet import reactor + + +def signal_handler(signal, frame): + stop_reactor_on_exit() + sys.exit(0) + + +def start_reactor(logging=False): + if logging: + enable_logging() + + def start_reactor_run(): + reactor.run(False) + + global REACTOR_THREAD + REACTOR_THREAD = Thread(target=start_reactor_run) + daemon = True + REACTOR_THREAD.start() + + +def stop_reactor_on_exit(): + reactor.callFromThread(reactor.stop) + global REACTOR_THREAD + REACTOR_THREAD = None + +signal.signal(signal.SIGINT, signal_handler) + + +def enable_logging(): + logging.basicConfig(level=logging.DEBUG, + format='%(asctime)s %(name)-12s %(levelname)-8s %(message)s', + datefmt='%m-%d %H:%M', + filename='/tmp/leap.log', + filemode='w') + + # define a Handler which writes INFO messages or higher to the sys.stderr + console = logging.StreamHandler() + console.setLevel(logging.DEBUG) + # set a format which is simpler for console use + formatter = logging.Formatter('%(name)-12s: %(levelname)-8s %(message)s') + # tell the handler to use this format + console.setFormatter(formatter) + # add the handler to the root logger + logging.getLogger('').addHandler(console) diff --git a/service/pixelated/controllers/__init__.py b/service/pixelated/controllers/__init__.py index 66502b83..969e8e6f 100644 --- a/service/pixelated/controllers/__init__.py +++ b/service/pixelated/controllers/__init__.py @@ -29,4 +29,3 @@ from home_controller import HomeController from mails_controller import MailsController from tags_controller import TagsController from features_controller import FeaturesController - diff --git a/service/pixelated/reactor_manager.py b/service/pixelated/reactor_manager.py deleted file mode 100644 index c9473400..00000000 --- a/service/pixelated/reactor_manager.py +++ /dev/null @@ -1,65 +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 . -import signal -import sys -from threading import Thread -import logging - -from twisted.internet import reactor - - -def signal_handler(signal, frame): - stop_reactor_on_exit() - sys.exit(0) - - -def start_reactor(logging=False): - if logging: - enable_logging() - - def start_reactor_run(): - reactor.run(False) - - global REACTOR_THREAD - REACTOR_THREAD = Thread(target=start_reactor_run) - daemon = True - REACTOR_THREAD.start() - - -def stop_reactor_on_exit(): - reactor.callFromThread(reactor.stop) - global REACTOR_THREAD - REACTOR_THREAD = None - -signal.signal(signal.SIGINT, signal_handler) - - -def enable_logging(): - logging.basicConfig(level=logging.DEBUG, - format='%(asctime)s %(name)-12s %(levelname)-8s %(message)s', - datefmt='%m-%d %H:%M', - filename='/tmp/leap.log', - filemode='w') - - # define a Handler which writes INFO messages or higher to the sys.stderr - console = logging.StreamHandler() - console.setLevel(logging.DEBUG) - # set a format which is simpler for console use - formatter = logging.Formatter('%(name)-12s: %(levelname)-8s %(message)s') - # tell the handler to use this format - console.setFormatter(formatter) - # add the handler to the root logger - logging.getLogger('').addHandler(console) diff --git a/service/pixelated/runserver.py b/service/pixelated/runserver.py new file mode 100644 index 00000000..840d6621 --- /dev/null +++ b/service/pixelated/runserver.py @@ -0,0 +1,49 @@ +# +# 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 . + +import os +import os.path +import crochet +from flask import Flask +from pixelated.config import app_factory +import pixelated.config.args as input_args +import pixelated.bitmask_libraries.register as leap_register +import pixelated.config.reactor_manager as reactor_manager + + +app = Flask(__name__, static_url_path='', static_folder=app_factory.get_static_folder()) + + +def setup(): + try: + args = input_args.parse() + debug_enabled = args.debug or os.environ.get('DEBUG', False) + reactor_manager.start_reactor(logging=debug_enabled) + crochet.setup() + + app.config.from_pyfile(args.config) + + if args.register: + server_name = app.config['LEAP_SERVER_NAME'] + leap_register.register_new_user(args.register, server_name) + else: + app_factory.create_app(debug_enabled, app) + finally: + reactor_manager.stop_reactor_on_exit() + + +if __name__ == '__main__': + setup() diff --git a/service/pixelated/user_agent.py b/service/pixelated/user_agent.py deleted file mode 100644 index d8c3d4a6..00000000 --- a/service/pixelated/user_agent.py +++ /dev/null @@ -1,139 +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 . -import argparse -import getpass - -import os -import os.path -import crochet -from flask import Flask -from pixelated.adapter.pixelated_mail_sender import PixelatedMailSender -from pixelated.adapter.pixelated_mailboxes import PixelatedMailBoxes -import pixelated.reactor_manager as reactor_manager -import pixelated.bitmask_libraries.session as LeapSession -from pixelated.bitmask_libraries.config import LeapConfig -from pixelated.bitmask_libraries.provider import LeapProvider -from pixelated.bitmask_libraries.auth import LeapAuthenticator, LeapCredentials -from pixelated.adapter.mail_service import MailService -from pixelated.adapter.mail import InputMail -from pixelated.adapter.soledad_querier import SoledadQuerier -from pixelated.adapter.search import SearchEngine -from pixelated.adapter.draft_service import DraftService -from pixelated.adapter.listener import MailboxListener -from pixelated.controllers import * -from pixelated.adapter.tag_service import TagService - - -static_folder = os.path.abspath(os.path.join(os.path.abspath(__file__), "..", "..", "web-ui", "app")) -# this is a workaround for packaging -if not os.path.exists(static_folder): - static_folder = os.path.abspath(os.path.join(os.path.abspath(__file__), "..", "..", "..", "web-ui", "app")) -if not os.path.exists(static_folder): - static_folder = os.path.join('/', 'usr', 'share', 'pixelated-user-agent') - -app = Flask(__name__, static_url_path='', static_folder=static_folder) - - -def register_new_user(username, server_name): - certs_home = os.path.abspath(os.path.join(os.path.abspath(__file__), "..", "certificates")) - config = LeapConfig(certs_home=certs_home) - provider = LeapProvider(server_name, config) - password = getpass.getpass('Please enter password for %s: ' % username) - LeapAuthenticator(provider).register(LeapCredentials(username, password)) - session = LeapSession.open(username, password, server_name) - session.nicknym.generate_openpgp_key() - - -def _setup_routes(app, home_controller, mails_controller, tags_controller, features_controller): - # home - app.add_url_rule('/', methods=['GET'], view_func=home_controller.home) - # mails - app.add_url_rule('/mails', methods=['GET'], view_func=mails_controller.mails) - app.add_url_rule('/mail//read', methods=['POST'], view_func=mails_controller.mark_mail_as_read) - app.add_url_rule('/mail//unread', methods=['POST'], view_func=mails_controller.mark_mail_as_unread) - app.add_url_rule('/mails/unread', methods=['POST'], view_func=mails_controller.mark_many_mail_unread) - app.add_url_rule('/mail/', methods=['GET'], view_func=mails_controller.mail) - app.add_url_rule('/mail/', methods=['DELETE'], view_func=mails_controller.delete_mail) - app.add_url_rule('/mails', methods=['DELETE'], view_func=mails_controller.delete_mails) - app.add_url_rule('/mails', methods=['POST'], view_func=mails_controller.send_mail) - app.add_url_rule('/mail//tags', methods=['POST'], view_func=mails_controller.mail_tags) - app.add_url_rule('/mails', methods=['PUT'], view_func=mails_controller.update_draft) - # tags - app.add_url_rule('/tags', methods=['GET'], view_func=tags_controller.tags) - # features - app.add_url_rule('/features', methods=['GET'], view_func=features_controller.features) - - -def start_user_agent(debug_enabled, app): - - with app.app_context(): - leap_session = LeapSession.open(app.config['LEAP_USERNAME'], app.config['LEAP_PASSWORD'], - app.config['LEAP_SERVER_NAME']) - tag_service = TagService() - soledad_querier = SoledadQuerier(soledad=leap_session.account._soledad) - pixelated_mailboxes = PixelatedMailBoxes(leap_session.account, soledad_querier) - pixelated_mail_sender = PixelatedMailSender(leap_session.account_email()) - mail_service = MailService(pixelated_mailboxes, pixelated_mail_sender, tag_service, soledad_querier) - search_engine = SearchEngine() - search_engine.index_mails(mail_service.all_mails()) - draft_service = DraftService(pixelated_mailboxes) - - MailboxListener.SEARCH_ENGINE = search_engine - InputMail.FROM_EMAIL_ADDRESS = leap_session.account_email() - - home_controller = HomeController() - features_controller = FeaturesController() - mails_controller = MailsController(mail_service=mail_service, - draft_service=draft_service, - search_engine=search_engine) - tags_controller = TagsController(search_engine=search_engine) - - _setup_routes(app, home_controller, mails_controller, tags_controller, features_controller) - - app.run(host=app.config['HOST'], debug=debug_enabled, - port=app.config['PORT'], use_reloader=False) - - -def setup(): - try: - default_config_path = os.path.join(os.environ['HOME'], '.pixelated') - - parser = argparse.ArgumentParser(description='Pixelated user agent.') - parser.add_argument('--debug', action='store_true', - help='DEBUG mode.') - parser.add_argument('--register', metavar='username', help='register user with name.') - parser.add_argument('-c', '--config', metavar='configfile', default=default_config_path, - help='use specified config file. Default is ~/.pixelated.') - - args = parser.parse_args() - debug_enabled = args.debug or os.environ.get('DEBUG', False) - reactor_manager.start_reactor(logging=debug_enabled) - - crochet.setup() - - app.config.from_pyfile(args.config) - - if args.register: - server_name = app.config['LEAP_SERVER_NAME'] - register_new_user(args.register, server_name) - else: - start_user_agent(debug_enabled, app) - finally: - reactor_manager.stop_reactor_on_exit() - - -if __name__ == '__main__': - setup() diff --git a/service/setup.py b/service/setup.py index eff0f3b6..fd3f5f72 100644 --- a/service/setup.py +++ b/service/setup.py @@ -66,7 +66,7 @@ setup(name='pixelated-user-agent', author='Thoughtworks', author_email='pixelated-team@thoughtworks.com', url='http://pixelated-project.github.io', - packages=['pixelated', 'pixelated.adapter', 'pixelated.bitmask_libraries', 'pixelated.config', 'pixelated.certificates', 'pixelated.support'], + packages=['pixelated', 'pixelated.adapter', 'pixelated.bitmask_libraries', 'pixelated.config', 'pixelated.certificates', 'pixelated.support', 'pixelated.controllers'], test_suite='nose.collector', install_requires=[ 'Twisted', @@ -86,7 +86,7 @@ setup(name='pixelated-user-agent', ], entry_points={ 'console_scripts': [ - 'pixelated-user-agent = pixelated.user_agent:setup' + 'pixelated-user-agent = pixelated.runserver:setup' ] }, data_files=data_files(), diff --git a/service/test/functional/features/environment.py b/service/test/functional/features/environment.py index f65b11a6..86f43d7f 100644 --- a/service/test/functional/features/environment.py +++ b/service/test/functional/features/environment.py @@ -18,7 +18,7 @@ import multiprocessing from selenium import webdriver from test.support.integration_helper import SoledadTestBase -import pixelated.user_agent +import pixelated.runserver def before_all(context): @@ -26,10 +26,10 @@ def before_all(context): context.soledad_test_base.setup_soledad() context.mailboxes = context.soledad_test_base.pixelated_mailboxes - context.app = pixelated.user_agent.app + context.app = pixelated.runserver.app context.app.mail_service = context.soledad_test_base.mail_service - worker = lambda app, port: pixelated.user_agent.app.run(port=4567, use_reloader=False) + worker = lambda app, port: pixelated.runserver.app.run(port=4567, use_reloader=False) context._process = multiprocessing.Process(target=worker, args=(context.app, 4567)) context._process.start() diff --git a/service/test/support/integration_helper.py b/service/test/support/integration_helper.py index 0d5d1125..8f2b8192 100644 --- a/service/test/support/integration_helper.py +++ b/service/test/support/integration_helper.py @@ -23,11 +23,13 @@ from pixelated.adapter.mail_service import MailService from pixelated.adapter.search import SearchEngine from pixelated.adapter.tag_service import TagService from pixelated.adapter.draft_service import DraftService -import pixelated.user_agent from pixelated.adapter.mail import PixelatedMail, InputMail +import pixelated.runserver from pixelated.adapter.pixelated_mailboxes import PixelatedMailBoxes from pixelated.adapter.soledad_querier import SoledadQuerier from pixelated.controllers import * +import pixelated.config.app_factory as app_factory + soledad_test_folder = "soledad-test" @@ -146,7 +148,7 @@ class SoledadTestBase: SearchEngine.INDEX_FOLDER = soledad_test_folder + '/search_index' - self.client = pixelated.user_agent.app.test_client() + self.client = pixelated.runserver.app.test_client() self._reset_routes(self.client.application) self.soledad_querier = SoledadQuerier(self.soledad) @@ -168,8 +170,8 @@ class SoledadTestBase: search_engine=self.search_engine) tags_controller = TagsController(search_engine=self.search_engine) - pixelated.user_agent._setup_routes(self.client.application, home_controller, mails_controller, tags_controller, - features_controller) + app_factory._setup_routes(self.client.application, home_controller, mails_controller, tags_controller, + features_controller) def get_mails_by_tag(self, tag): response = json.loads(self.client.get("/mails?q=tag:" + tag).data) diff --git a/service/test/unit/user_agent_test.py b/service/test/unit/user_agent_test.py index 3572a387..bd875dcc 100644 --- a/service/test/unit/user_agent_test.py +++ b/service/test/unit/user_agent_test.py @@ -20,7 +20,7 @@ import sys import pixelated.user_agent from mockito import * import crochet -import pixelated.reactor_manager as reactor_manager +import pixelated.config.reactor_manager as reactor_manager import pixelated.adapter.pixelated_mail import os -- cgit v1.2.3