Пример #1
0
    def take_action(self, parsed_args: argparse.Namespace) -> None:
        super(DeleteDBCommand, self).take_action(parsed_args)
        config_uri = parsed_args.config_file
        # setup_logging(config_uri)
        settings = get_appsettings(config_uri)
        settings.update(settings.global_conf)
        app_config = CFG(settings)
        app_config.configure_filedepot()
        engine = get_engine(app_config)

        if parsed_args.force:
            print("Database deletion begin.")
            DeclarativeBase.metadata.drop_all(engine)
            print("Database deletion done.")
            try:
                print("Cleaning depot begin.")
                depot = DepotManager.get()
                depot_files = depot.list()
                for file_ in depot_files:
                    try:
                        depot.delete(file_)
                    # TODO - G.M - 2019-05-09 - better handling of specific exception here
                    except Exception as exc:
                        traceback.print_exc()
                        print("Something goes wrong during deletion of {}".format(file_))
                        raise exc
                print("Cleaning depot done.")
            except FileNotFoundError:
                print("Warning! Can delete depots file, is depot path correctly" " configured?")
        else:
            raise ForceArgumentNeeded(
                "Warning, You should use --force if you really want to" " delete database."
            )
Пример #2
0
 def _populate_database(
         cls,
         settings: plaster_pastedeploy.ConfigDict,
         add_test_data: bool
 ) -> None:
     engine = get_engine(settings)
     session_factory = get_session_factory(engine)
     app_config = CFG(settings)
     print("- Populate database with default data -")
     with transaction.manager:
         dbsession = get_tm_session(session_factory, transaction.manager)
         try:
             fixtures = [BaseFixture]
             fixtures_loader = FixturesLoader(dbsession, app_config)
             fixtures_loader.loads(fixtures)
             transaction.commit()
             if add_test_data:
                 app_config.configure_filedepot()
                 fixtures = [ContentFixture]
                 fixtures_loader.loads(fixtures)
             transaction.commit()
             print("Database initialized.")
         except IntegrityError as exc:
             transaction.abort()
             print('Database initialization failed')
             raise DatabaseInitializationFailed(
                 'Warning, there was a problem when adding default data'
                 ', it may have already been added.'
             ) from exc
Пример #3
0
 def check_config(self, app_config: CFG) -> None:
     if app_config.COLLABORATIVE_DOCUMENT_EDITION__SOFTWARE == COLLABORA_DOCUMENT_EDITION_SLUG:
         app_config.check_mandatory_param(
             "COLLABORATIVE_DOCUMENT_EDITION__COLLABORA__BASE_URL",
             app_config.COLLABORATIVE_DOCUMENT_EDITION__COLLABORA__BASE_URL,
             when_str="if collabora feature is activated",
         )
Пример #4
0
class TracimEnv(BaseMiddleware):
    def __init__(self, application, config):
        super().__init__(application, config)
        self._application = application
        self.settings = config["tracim_settings"]
        self.app_config = CFG(self.settings)
        self.app_config.configure_filedepot()
        self.plugin_manager = init_plugin_manager(self.app_config)
        self.engine = get_engine(self.app_config)
        self.session_factory = get_session_factory(self.engine)

    def __call__(self, environ, start_response):
        # TODO - G.M - 18-05-2018 - This code should not create trouble
        # with thread and database, this should be verify.
        # see https://github.com/tracim/tracim_backend/issues/62
        registry = get_current_registry()
        registry.ldap_connector = None
        if AuthType.LDAP in self.app_config.AUTH_TYPES:
            registry = self.setup_ldap(registry, self.app_config)
        environ["tracim_registry"] = registry
        tracim_context = WebdavTracimContext(environ, self.app_config,
                                             self.plugin_manager)
        session = create_dbsession_for_context(self.session_factory,
                                               transaction.manager,
                                               tracim_context)
        tracim_context.dbsession = session
        environ["tracim_context"] = tracim_context
        try:
            for chunk in self._application(environ, start_response):
                yield chunk
            transaction.commit()
        except Exception:
            transaction.abort()
            raise
        finally:
            # NOTE SGD 2020-06-30: avoid circular reference between environment dict and context.
            # This ensures the context will be deleted as soon as this function is exited
            del environ["tracim_context"]
            tracim_context.cleanup()

    def setup_ldap(self, registry: Registry, app_config: CFG):
        manager = ConnectionManager(
            uri=app_config.LDAP_URL,
            bind=app_config.LDAP_BIND_DN,
            passwd=app_config.LDAP_BIND_PASS,
            tls=app_config.LDAP_TLS,
            use_pool=app_config.LDAP_USE_POOL,
            pool_size=app_config.LDAP_POOL_SIZE,
            pool_lifetime=app_config.LDAP_POOL_LIFETIME,
            get_info=app_config.LDAP_GET_INFO,
        )
        registry.ldap_login_query = _LDAPQuery(
            base_dn=app_config.LDAP_USER_BASE_DN,
            filter_tmpl=app_config.LDAP_USER_FILTER,
            scope=ldap3.LEVEL,
            attributes=ldap3.ALL_ATTRIBUTES,
            cache_period=0,
        )
        registry.ldap_connector = Connector(registry, manager)
        return registry
Пример #5
0
    def take_action(self, parsed_args: argparse.Namespace) -> None:
        super(DeleteDBCommand, self).take_action(parsed_args)
        config_uri = parsed_args.config_file
        # setup_logging(config_uri)
        settings = get_appsettings(config_uri)
        settings.update(settings.global_conf)
        if 'sqlalchemy.url' not in settings or not settings['sqlalchemy.url']:
            raise InvalidSettingFile('Wrong or empty sqlalchemy database url,'
                                     'check config file')
        engine = get_engine(settings)
        app_config = CFG(settings)
        app_config.configure_filedepot()

        if parsed_args.force:
            print('Database deletion begin.')
            DeclarativeBase.metadata.drop_all(engine)
            print('Database deletion done.')
            try:
                print('Cleaning depot begin.')
                depot = DepotManager.get()
                depot_files = depot.list()
                for file_ in depot_files:
                    depot.delete(file_)
                print('Cleaning depot done.')
            except FileNotFoundError:
                print(
                    'Warning! Can delete depots file, is depot path correctly'
                    ' configured?'
                )
        else:
            raise ForceArgumentNeeded(
                'Warning, You should use --force if you really want to'
                ' delete database.'
            )
Пример #6
0
 def __init__(self, application, config):
     super().__init__(application, config)
     self._application = application
     self.settings = config['tracim_settings']
     self.engine = get_engine(self.settings)
     self.session_factory = get_scoped_session_factory(self.engine)
     self.app_config = CFG(self.settings)
     self.app_config.configure_filedepot()
Пример #7
0
def initialize_config_from_environment() -> CFG:
    config_uri = os.environ["TRACIM_CONF_PATH"]
    setup_logging(config_uri)
    settings = get_appsettings(config_uri)
    settings.update(settings.global_conf)
    app_config = CFG(settings)
    app_config.configure_filedepot()
    return app_config
Пример #8
0
 def __init__(self, application, config):
     super().__init__(application, config)
     self._application = application
     self.settings = config["tracim_settings"]
     self.app_config = CFG(self.settings)
     self.app_config.configure_filedepot()
     self.plugin_manager = init_plugin_manager(self.app_config)
     self.engine = get_engine(self.app_config)
     self.session_factory = get_session_factory(self.engine)
Пример #9
0
class TracimEnv(BaseMiddleware):

    def __init__(self, application, config):
        super().__init__(application, config)
        self._application = application
        self.settings = config['tracim_settings']
        self.engine = get_engine(self.settings)
        self.session_factory = get_scoped_session_factory(self.engine)
        self.app_config = CFG(self.settings)
        self.app_config.configure_filedepot()

    def __call__(self, environ, start_response):
        # TODO - G.M - 18-05-2018 - This code should not create trouble
        # with thread and database, this should be verify.
        # see https://github.com/tracim/tracim_backend/issues/62
        tm = transaction.manager
        session = get_tm_session(self.session_factory, tm)
        registry = get_current_registry()
        registry.ldap_connector = None
        if AuthType.LDAP in self.app_config.AUTH_TYPES:
            registry = self.setup_ldap(registry, self.app_config)
        environ['tracim_registry'] =  registry
        environ['tracim_context'] = WebdavTracimContext(environ, self.app_config, session)
        try:
            app = self._application(environ, start_response)
        except Exception as exc:
            transaction.rollback()
            raise exc
        finally:
            transaction.commit()
            session.close()
        return app

    def setup_ldap(self, registry: Registry, app_config: CFG):
        manager = ConnectionManager(
            uri=app_config.LDAP_URL,
            bind=app_config.LDAP_BIND_DN,
            passwd=app_config.LDAP_BIND_PASS,
            tls=app_config.LDAP_TLS,
            use_pool=app_config.LDAP_USE_POOL,
            pool_size=app_config.LDAP_POOL_SIZE,
            pool_lifetime=app_config.LDAP_POOL_LIFETIME,
            get_info=app_config.LDAP_GET_INFO
        )
        registry.ldap_login_query = _LDAPQuery(
            base_dn=app_config.LDAP_USER_BASE_DN,
            filter_tmpl=app_config.LDAP_USER_FILTER,
            scope=ldap3.LEVEL,
            attributes=ldap3.ALL_ATTRIBUTES,
            cache_period=0
        )
        registry.ldap_connector = Connector(registry, manager)
        return registry
Пример #10
0
class TracimEnv(BaseMiddleware):
    def __init__(self, application, config):
        super().__init__(application, config)
        self._application = application
        self.settings = config["tracim_settings"]
        self.app_config = CFG(self.settings)
        self.app_config.configure_filedepot()
        self.engine = get_engine(self.app_config)
        self.session_factory = get_scoped_session_factory(self.engine)

    def __call__(self, environ, start_response):
        # TODO - G.M - 18-05-2018 - This code should not create trouble
        # with thread and database, this should be verify.
        # see https://github.com/tracim/tracim_backend/issues/62
        tm = transaction.manager
        session = get_tm_session(self.session_factory, tm)
        registry = get_current_registry()
        registry.ldap_connector = None
        if AuthType.LDAP in self.app_config.AUTH_TYPES:
            registry = self.setup_ldap(registry, self.app_config)
        environ["tracim_registry"] = registry
        environ["tracim_context"] = WebdavTracimContext(
            environ, self.app_config, session)
        try:
            app = self._application(environ, start_response)
        except Exception as exc:
            transaction.rollback()
            raise exc
        finally:
            transaction.commit()
            session.close()
        return app

    def setup_ldap(self, registry: Registry, app_config: CFG):
        manager = ConnectionManager(
            uri=app_config.LDAP_URL,
            bind=app_config.LDAP_BIND_DN,
            passwd=app_config.LDAP_BIND_PASS,
            tls=app_config.LDAP_TLS,
            use_pool=app_config.LDAP_USE_POOL,
            pool_size=app_config.LDAP_POOL_SIZE,
            pool_lifetime=app_config.LDAP_POOL_LIFETIME,
            get_info=app_config.LDAP_GET_INFO,
        )
        registry.ldap_login_query = _LDAPQuery(
            base_dn=app_config.LDAP_USER_BASE_DN,
            filter_tmpl=app_config.LDAP_USER_FILTER,
            scope=ldap3.LEVEL,
            attributes=ldap3.ALL_ATTRIBUTES,
            cache_period=0,
        )
        registry.ldap_connector = Connector(registry, manager)
        return registry
Пример #11
0
 def setUp(self) -> None:
     self._set_logger()
     DepotManager._clear()
     settings = plaster.get_settings(self.config_uri, self.config_section)
     self.settings = self.override_settings(settings)
     hapic.reset_context()
     self.connect_database(create_tables=True)
     self.app_config = CFG(self.settings)
     self.app_config.configure_filedepot()
     self.init_database(self.settings)
     DepotManager._clear()
     self.run_app()
Пример #12
0
 def override_app_config(self, app_config: CFG) -> CFG:
     """
     Override CFG parameter
     Disable sqlalchemy.url app config parameter with wrong value
     """
     app_config.SQLALCHEMY__URL = "sqlite://"
     return app_config
Пример #13
0
 def __init__(self, **settings):
     logger.info(self, "Add additional radicale config")
     self.radicale_config = load_radicale_config(())
     self.radicale_config = self._parse_additional_radicale_config(
         self.radicale_config, settings)
     self.app_config = CFG(settings)
     self.create_dir_tree(self.radicale_config, self.app_config)
Пример #14
0
 def __init__(self, application, config):
     super().__init__(application, config)
     self._application = application
     self.settings = config['tracim_settings']
     self.engine = get_engine(self.settings)
     self.session_factory = get_scoped_session_factory(self.engine)
     self.app_config = CFG(self.settings)
     self.app_config.configure_filedepot()
Пример #15
0
 def setUp(self) -> None:
     self._set_logger()
     DepotManager._clear()
     settings = plaster.get_settings(self.config_uri, self.config_section)
     self.settings = self.override_settings(settings)
     # INFO - G.M - 2019-03-19 - Reset all hapic context: PyramidContext
     # and controllers
     hapic.reset_context()
     # TODO - G.M - 2019-03-19 - Replace this code by something better, see
     # https://github.com/algoo/hapic/issues/144
     hapic._controllers = []
     self.app_config = CFG(self.settings)  # type: CFG
     self.app_config = self.override_app_config(self.app_config)
     self.app_config.configure_filedepot()
     self.connect_database(create_tables=True)
     self.init_database()
     DepotManager._clear()
     self.run_app()
Пример #16
0
    def _initConfig(self, **settings):
        """Setup configuration dictionary from default,
         command line and configuration file."""

        # Set config defaults
        config = DEFAULT_CONFIG.copy()
        # Get pyramid Env
        config['tracim_settings'] = settings
        app_config = CFG(settings)

        # use only basic_auth, disable digest auth
        config['acceptbasic'] = True
        config['acceptdigest'] = False
        config['defaultdigest'] = False
        # check this for apache auth mecanism
        if app_config.REMOTE_USER_HEADER:
            config['trusted_auth_header'] = app_config.REMOTE_USER_HEADER

        config['verbose'] = app_config.WEBDAV_VERBOSE_LEVEL
        config['dir_browser']['enable'] = app_config.WEBDAV_DIR_BROWSER_ENABLED
        config['dir_browser'][
            'response_trailer'] = app_config.WEBDAV_DIR_BROWSER_FOOTER

        if not useLxml and config["verbose"] >= 1:
            print(
                "WARNING: Could not import lxml: using xml instead (slower). "
                "consider installing lxml from http://codespeak.net/lxml/.")

        config['provider_mapping'] = {
            app_config.WEBDAV_ROOT_PATH:
            Provider(
                show_history=app_config.WEBDAV_SHOW_ARCHIVED,
                show_archived=app_config.WEBDAV_SHOW_DELETED,
                show_deleted=app_config.WEBDAV_SHOW_HISTORY,
                manage_locks=app_config.WEBDAV_MANAGE_LOCK,
                app_config=app_config,
            )
        }
        config['block_size'] = app_config.WEBDAV_BLOCK_SIZE

        config['domaincontroller'] = TracimDomainController(
            presetdomain=None,
            presetserver=None,
            app_config=app_config,
        )

        config['middleware_stack'] = [
            TracimEnforceHTTPS,
            WsgiDavDirBrowser,
            HTTPAuthenticator,
            ErrorPrinter,
            TracimWsgiDavDebugFilter,
            TracimEnv,
        ]
        return config
Пример #17
0
 def take_action(self, parsed_args: argparse.Namespace) -> None:
     super(InitializeDBCommand, self).take_action(parsed_args)
     config_uri = parsed_args.config_file
     settings = get_appsettings(config_uri)
     # INFO - G.M - 2018-06-178 - We need to add info from [DEFAULT]
     # section of config file in order to have both global and
     # web app specific param.
     settings.update(settings.global_conf)
     app_config = CFG(settings)
     self._create_schema(app_config)
     self._populate_database(app_config, add_test_data=parsed_args.test_data)
Пример #18
0
 def load_config(self, app_config: CFG) -> None:
     app_config.COLLABORATIVE_DOCUMENT_EDITION__SOFTWARE = app_config.get_raw_config(
         "collaborative_document_edition.software")
     app_config.COLLABORATIVE_DOCUMENT_EDITION__COLLABORA__BASE_URL = app_config.get_raw_config(
         "collaborative_document_edition.collabora.base_url")
     default_file_template_dir = app_config.here_macro_replace(
         "%(here)s/tracim_backend/templates/open_documents")
     app_config.COLLABORATIVE_DOCUMENT_EDITION__FILE_TEMPLATE_DIR = app_config.get_raw_config(
         "collaborative_document_edition.file_template_dir",
         default_file_template_dir)
Пример #19
0
 def check_config(self, app_config: CFG) -> None:
     """
     Check if config is correctly setted for caldav features
     """
     app_config.check_mandatory_param(
         "CALDAV__RADICALE_PROXY__BASE_URL",
         app_config.CALDAV__RADICALE_PROXY__BASE_URL,
         when_str="when caldav feature is enabled",
     )
     # TODO - G.M - 2019-05-06 - convert "caldav.radicale.storage.filesystem_folder"
     # as tracim global parameter
     app_config.check_mandatory_param(
         "CALDAV__RADICALE__STORAGE__FILESYSTEM_FOLDER",
         app_config.CALDAV__RADICALE__STORAGE__FILESYSTEM_FOLDER,
         when_str="if caldav feature is enabled",
     )
     app_config.check_directory_path_param(
         "CALDAV__RADICALE__STORAGE__FILESYSTEM_FOLDER",
         app_config.CALDAV__RADICALE__STORAGE__FILESYSTEM_FOLDER,
         writable=True,
     )
     radicale_storage_type = app_config.settings.get("caldav.radicale.storage.type")
     if radicale_storage_type != "multifilesystem":
         raise ConfigurationError(
             '"{}" should be set to "{}"'
             " (currently only valid value)"
             " when {} app is active".format(
                 "caldav.radicale.storage.type", "multifilesystem", "agenda"
             )
         )
Пример #20
0
    def _initConfig(self, **settings):
        """Setup configuration dictionary from default,
         command line and configuration file."""

        # Set config defaults
        config = DEFAULT_CONFIG.copy()
        # Get pyramid Env
        config["tracim_settings"] = settings
        app_config = CFG(settings)

        # use only basic_auth, disable digest auth
        config["acceptbasic"] = True
        config["acceptdigest"] = False
        config["defaultdigest"] = False
        # check this for apache authentication mechanism
        if app_config.REMOTE_USER_HEADER:
            config["trusted_auth_header"] = app_config.REMOTE_USER_HEADER

        config["verbose"] = app_config.WEBDAV__VERBOSE__LEVEL
        config["dir_browser"][
            "enable"] = app_config.WEBDAV__DIR_BROWSER__ENABLED
        config["dir_browser"][
            "response_trailer"] = app_config.WEBDAV__DIR_BROWSER__FOOTER

        if not useLxml and config["verbose"] >= 1:
            print(
                "WARNING: Could not import lxml: using xml instead (slower). "
                "consider installing lxml from http://codespeak.net/lxml/.")

        config["provider_mapping"] = {
            app_config.WEBDAV__ROOT_PATH:
            TracimDavProvider(
                manage_locks=app_config.WEBDAV_MANAGE_LOCK,
                app_config=app_config,
            )
        }
        config["block_size"] = app_config.WEBDAV__BLOCK_SIZE

        config["domaincontroller"] = TracimDomainController(
            presetdomain=None, presetserver=None, app_config=app_config)

        config["middleware_stack"] = [
            TracimEnforceHTTPS,
            WsgiDavDirBrowser,
            HTTPAuthenticator,
            ErrorPrinter,
            TracimWsgiDavDebugFilter,
            TracimEnv,
        ]
        return config
Пример #21
0
 def load_config(self, app_config: CFG) -> None:
     # share content email
     template_dir = app_config.here_macro_replace(
         "%(here)s/tracim_backend/templates/mail")
     app_config.EMAIL__NOTIFICATION__SHARE_CONTENT_TO_RECEIVER__TEMPLATE__HTML = app_config.get_raw_config(
         "email.notification.share_content_to_receiver.template.html",
         "{}/{}".format(template_dir,
                        "shared_content_to_receiver_body_html.mak"),
     )
     app_config.EMAIL__NOTIFICATION__SHARE_CONTENT_TO_RECEIVER__SUBJECT = app_config.get_raw_config(
         "email.notification.share_content_to_receiver.subject",
         _('[{website_title}] {emitter_name} shared the file "{content_filename}" with you'
           ),
     )
     app_config.EMAIL__NOTIFICATION__SHARE_CONTENT_TO_EMITTER__TEMPLATE__HTML = app_config.get_raw_config(
         "email.notification.share_content_to_emitter.template.html",
         "{}/{}".format(template_dir,
                        "shared_content_to_emitter_body_html.mak"),
     )
     app_config.EMAIL__NOTIFICATION__SHARE_CONTENT_TO_EMITTER__SUBJECT = app_config.get_raw_config(
         "email.notification.share_content_to_emitter.subject",
         _('[{website_title}] You shared "{content_filename}" with {nb_receivers} people'
           ),
     )
Пример #22
0
    def setUp(self) -> None:
        self._set_logger()
        logger.debug(self, 'Setup Test...')
        self.settings = plaster.get_settings(self.config_uri,
                                             self.config_section)
        self.config = testing.setUp(settings=self.settings)
        self.config.include('tracim_backend.models')
        DepotManager._clear()
        DepotManager.configure(
            'test', {'depot.backend': 'depot.io.memory.MemoryFileStorage'})
        settings = self.config.get_settings()
        self.app_config = CFG(settings)
        from tracim_backend.models import (
            get_engine,
            get_session_factory,
            get_tm_session,
        )

        self.engine = get_engine(settings)
        self.session_factory = get_session_factory(self.engine)
        self.init_database()
        self.session = get_tm_session(self.session_factory,
                                      transaction.manager)
Пример #23
0
    def setUp(self) -> None:
        self._set_logger()
        logger.debug(self, "Setup Test...")
        self.settings = plaster.get_settings(self.config_uri,
                                             self.config_section)
        self.config = testing.setUp(settings=self.settings)
        DepotManager._clear()
        DepotManager.configure(
            "test", {"depot.backend": "depot.io.memory.MemoryFileStorage"})
        settings = self.config.get_settings()
        self.app_config = CFG(settings)
        init_models(self.config, self.app_config)
        from tracim_backend.models.setup_models import (
            get_engine,
            get_session_factory,
            get_tm_session,
        )

        self.engine = get_engine(self.app_config)
        self.session_factory = get_session_factory(self.engine)
        self.init_database()
        self.session = get_tm_session(self.session_factory,
                                      transaction.manager)
Пример #24
0
 def load_config(self, app_config: CFG) -> None:
     template_dir = app_config.here_macro_replace("%(here)s/tracim_backend/templates/mail")
     app_config.EMAIL__NOTIFICATION__UPLOAD_PERMISSION_TO_RECEIVER__TEMPLATE__HTML = app_config.get_raw_config(
         "email.notification.upload_permission_to_receiver.template.html",
         "{}/{}".format(template_dir, "upload_permission_to_receiver_body_html.mak"),
     )
     app_config.EMAIL__NOTIFICATION__UPLOAD_PERMISSION_TO_RECEIVER__SUBJECT = app_config.get_raw_config(
         "email.notification.upload_permission_to_receiver.subject",
         _('{emitter_name} invited you to upload files on "{website_title}"'),
     )
     app_config.EMAIL__NOTIFICATION__UPLOAD_PERMISSION_TO_EMITTER__TEMPLATE__HTML = app_config.get_raw_config(
         "email.notification.upload_permission_to_emitter.template.html",
         "{}/{}".format(template_dir, "upload_permission_to_emitter_body_html.mak"),
     )
     app_config.EMAIL__NOTIFICATION__UPLOAD_PERMISSION_TO_EMITTER__SUBJECT = app_config.get_raw_config(
         "email.notification.upload_permission_to_emitter.subject",
         _(
             '[{website_title}] You invited {nb_receivers} people to upload files on "{workspace_name}"'
         ),
     )
     app_config.EMAIL__NOTIFICATION__NEW_UPLOAD_EVENT__TEMPLATE__HTML = app_config.get_raw_config(
         "email.notification.new_upload_event.template.html",
         "{}/{}".format(template_dir, "new_upload_event_body_html.mak"),
     )
     app_config.EMAIL__NOTIFICATION__NEW_UPLOAD_EVENT__SUBJECT = app_config.get_raw_config(
         "email.notification.new_upload_event.subject",
         _(
             '[{website_title}] {uploader_username} shared {nb_uploaded_contents} files in "{workspace_name}"'
         ),
     )
Пример #25
0
class FunctionalTest(unittest.TestCase):

    fixtures = [BaseFixture]
    config_uri = 'tests_configs.ini'
    config_section = 'functional_test'

    def _set_logger(self) -> None:
        """
        Set all logger to a high level to avoid getting too much noise for tests
        """
        logger._logger.setLevel('ERROR')
        logging.getLogger().setLevel('ERROR')
        logging.getLogger('sqlalchemy').setLevel('ERROR')
        logging.getLogger('txn').setLevel('ERROR')
        logging.getLogger('cliff').setLevel('ERROR')
        logging.getLogger('_jb_pytest_runner').setLevel('ERROR')

    def setUp(self) -> None:
        self._set_logger()
        DepotManager._clear()
        settings = plaster.get_settings(self.config_uri, self.config_section)
        self.settings = self.override_settings(settings)
        hapic.reset_context()
        self.connect_database(create_tables=True)
        self.app_config = CFG(self.settings)
        self.app_config.configure_filedepot()
        self.init_database(self.settings)
        DepotManager._clear()
        self.run_app()

    def connect_database(self, create_tables: bool = False) -> None:
        self.engine = get_engine(self.settings)
        if create_tables:
            DeclarativeBase.metadata.create_all(self.engine)
        self.session_factory = get_session_factory(self.engine)
        self.session = get_tm_session(self.session_factory,
                                      transaction.manager)

    def override_settings(
        self, settings: typing.Dict[str, typing.Any]
    ) -> typing.Dict[str, typing.Any]:  # nopep8
        """
        Allow to override some setting by code.
        by default : do nothing.
        """
        return settings

    def run_app(self) -> None:
        app = web({}, **self.settings)
        self.testapp = TestApp(app)

    def init_database(self, settings: typing.Dict[str, typing.Any]):
        with transaction.manager:
            try:
                fixtures_loader = FixturesLoader(self.session, self.app_config)
                fixtures_loader.loads(self.fixtures)
                transaction.commit()
                logger.info(self, "Database initialized.")
            except IntegrityError:
                logger.error(
                    self,
                    'Warning, there was a problem when adding default data'  # nopep8
                    ', it may have already been added:')
                import traceback
                logger.error(self, traceback.format_exc())
                transaction.abort()
                logger.error(self, 'Database initialization failed')

    def disconnect_database(self, remove_tables: bool = False) -> None:
        self.session.rollback()
        transaction.abort()
        self.session.close_all()
        self.engine.dispose()
        if remove_tables:
            DeclarativeBase.metadata.drop_all(self.engine)
        DepotManager._clear()

    def tearDown(self) -> None:
        logger.debug(self, 'TearDown Test...')
        self.disconnect_database(remove_tables=True)
        testing.tearDown()
Пример #26
0
# coding=utf-8
# Runner for daemon
import os
from pyramid.paster import get_appsettings
from pyramid.paster import setup_logging
from tracim_backend.config import CFG
from tracim_backend.lib.mail_fetcher.daemon import MailFetcherDaemon

config_uri = os.environ['TRACIM_CONF_PATH']

setup_logging(config_uri)
settings = get_appsettings(config_uri)
settings.update(settings.global_conf)
app_config = CFG(settings)
app_config.configure_filedepot()

daemon = MailFetcherDaemon(app_config, burst=False)
daemon.run()
Пример #27
0
 def load_config(self, app_config: CFG) -> None:
     """
     load config for caldav related stuff
     """
     app_config.CALDAV__RADICALE_PROXY__BASE_URL = app_config.get_raw_config(
         "caldav.radicale_proxy.base_url", "http://localhost:5232"
     )
     default_caldav_storage_dir = app_config.here_macro_replace("%(here)s/radicale_storage")
     app_config.CALDAV__RADICALE__STORAGE__FILESYSTEM_FOLDER = app_config.get_raw_config(
         "caldav.radicale.storage.filesystem_folder", default_caldav_storage_dir
     )
     app_config.CALDAV__RADICALE__AGENDA_DIR = "agenda"
     app_config.CALDAV__RADICALE__WORKSPACE_SUBDIR = "workspace"
     app_config.CALDAV__RADICALE__USER_SUBDIR = "user"
     app_config.CALDAV__RADICALE__BASE_PATH = "/{}/".format(
         app_config.CALDAV__RADICALE__AGENDA_DIR
     )
     app_config.CALDAV__RADICALE__USER_PATH = "/{}/{}/".format(
         app_config.CALDAV__RADICALE__AGENDA_DIR, app_config.CALDAV__RADICALE__USER_SUBDIR
     )
     app_config.CALDAV_RADICALE_WORKSPACE_PATH = "/{}/{}/".format(
         app_config.CALDAV__RADICALE__AGENDA_DIR, app_config.CALDAV__RADICALE__WORKSPACE_SUBDIR
     )
Пример #28
0
def web(global_config, **local_settings):
    """ This function returns a Pyramid WSGI application.
    """
    settings = global_config
    settings.update(local_settings)
    # set CFG object
    app_config = CFG(settings)
    app_config.configure_filedepot()
    settings['CFG'] = app_config
    configurator = Configurator(settings=settings, autocommit=True)
    # Add AuthPolicy
    configurator.include("pyramid_beaker")
    configurator.include("pyramid_multiauth")
    policies = []
    if app_config.REMOTE_USER_HEADER:
        policies.append(
            RemoteAuthentificationPolicy(
                remote_user_email_login_header=app_config.REMOTE_USER_HEADER,
            ))
    policies.append(
        CookieSessionAuthentificationPolicy(
            reissue_time=app_config.SESSION_REISSUE_TIME),  # nopep8
    )
    if app_config.API_KEY:
        policies.append(
            ApiTokenAuthentificationPolicy(
                api_key_header=TRACIM_API_KEY_HEADER,
                api_user_email_login_header=TRACIM_API_USER_EMAIL_LOGIN_HEADER
            ), )
    policies.append(
        TracimBasicAuthAuthenticationPolicy(realm=BASIC_AUTH_WEBUI_REALM), )
    # Hack for ldap
    if AuthType.LDAP in app_config.AUTH_TYPES:
        import ldap3
        configurator.include('pyramid_ldap3')
        configurator.ldap_setup(app_config.LDAP_URL,
                                bind=app_config.LDAP_BIND_DN,
                                passwd=app_config.LDAP_BIND_PASS,
                                use_tls=app_config.LDAP_TLS,
                                use_pool=app_config.LDAP_USE_POOL,
                                pool_size=app_config.LDAP_POOL_SIZE,
                                pool_lifetime=app_config.LDAP_POOL_LIFETIME,
                                get_info=app_config.LDAP_GET_INFO)
        configurator.ldap_set_login_query(
            base_dn=app_config.LDAP_USER_BASE_DN,
            filter_tmpl=app_config.LDAP_USER_FILTER,
            scope=ldap3.LEVEL,
            attributes=ldap3.ALL_ATTRIBUTES)

    configurator.include(add_cors_support)
    # make sure to add this before other routes to intercept OPTIONS
    configurator.add_cors_preflight_handler()
    # Default authorization : Accept anything.
    configurator.set_authorization_policy(AcceptAllAuthorizationPolicy())
    authn_policy = MultiAuthenticationPolicy(policies)
    configurator.set_authentication_policy(authn_policy)
    # INFO - GM - 11-04-2018 - set default perm
    # setting default perm is needed to force authentification
    # mecanism in all views.
    configurator.set_default_permission(TRACIM_DEFAULT_PERM)
    # Override default request
    configurator.set_request_factory(TracimRequest)
    # Pyramids "plugin" include.
    configurator.include('pyramid_jinja2')
    # Add SqlAlchemy DB
    configurator.include('.models.setup_models')
    # set Hapic
    context = PyramidContext(
        configurator=configurator,
        default_error_builder=ErrorSchema(),
        debug=app_config.DEBUG,
    )
    hapic.set_context(context)
    # INFO - G.M - 2018-07-04 - global-context exceptions
    # Not found
    context.handle_exception(PageNotFound, HTTPStatus.NOT_FOUND)
    # Bad request
    context.handle_exception(WorkspaceNotFoundInTracimRequest,
                             HTTPStatus.BAD_REQUEST)  # nopep8
    context.handle_exception(UserNotFoundInTracimRequest,
                             HTTPStatus.BAD_REQUEST)  # nopep8
    context.handle_exception(ContentNotFoundInTracimRequest,
                             HTTPStatus.BAD_REQUEST)  # nopep8
    context.handle_exception(WorkspaceNotFound, HTTPStatus.BAD_REQUEST)
    context.handle_exception(UserDoesNotExist, HTTPStatus.BAD_REQUEST)
    context.handle_exception(ContentNotFound, HTTPStatus.BAD_REQUEST)
    context.handle_exception(ContentTypeNotExist, HTTPStatus.BAD_REQUEST)
    context.handle_exception(ContentInNotEditableState, HTTPStatus.BAD_REQUEST)
    context.handle_exception(ContentTypeNotAllowed, HTTPStatus.BAD_REQUEST)
    context.handle_exception(InvalidId, HTTPStatus.BAD_REQUEST)
    context.handle_exception(SameValueError, HTTPStatus.BAD_REQUEST)
    # Auth exception
    context.handle_exception(NotAuthenticated, HTTPStatus.UNAUTHORIZED)
    context.handle_exception(UserAuthenticatedIsNotActive,
                             HTTPStatus.FORBIDDEN)
    context.handle_exception(AuthenticationFailed, HTTPStatus.FORBIDDEN)
    context.handle_exception(InsufficientUserRoleInWorkspace,
                             HTTPStatus.FORBIDDEN)  # nopep8
    context.handle_exception(InsufficientUserProfile, HTTPStatus.FORBIDDEN)
    # Internal server error
    context.handle_exception(OperationalError,
                             HTTPStatus.INTERNAL_SERVER_ERROR)
    context.handle_exception(Exception, HTTPStatus.INTERNAL_SERVER_ERROR)

    # Add controllers
    session_controller = SessionController()
    system_controller = SystemController()
    user_controller = UserController()
    account_controller = AccountController()
    reset_password_controller = ResetPasswordController()
    workspace_controller = WorkspaceController()
    comment_controller = CommentController()
    html_document_controller = HTMLDocumentController()
    thread_controller = ThreadController()
    file_controller = FileController()
    folder_controller = FolderController()
    configurator.include(session_controller.bind, route_prefix=BASE_API_V2)
    configurator.include(system_controller.bind, route_prefix=BASE_API_V2)
    configurator.include(user_controller.bind, route_prefix=BASE_API_V2)
    configurator.include(account_controller.bind, route_prefix=BASE_API_V2)
    configurator.include(reset_password_controller.bind,
                         route_prefix=BASE_API_V2)  # nopep8
    configurator.include(workspace_controller.bind, route_prefix=BASE_API_V2)
    configurator.include(comment_controller.bind, route_prefix=BASE_API_V2)
    configurator.include(html_document_controller.bind,
                         route_prefix=BASE_API_V2)  # nopep8
    configurator.include(thread_controller.bind, route_prefix=BASE_API_V2)
    configurator.include(file_controller.bind, route_prefix=BASE_API_V2)
    configurator.include(folder_controller.bind, route_prefix=BASE_API_V2)
    if app_config.FRONTEND_SERVE:
        configurator.include('pyramid_mako')
        frontend_controller = FrontendController(
            app_config.FRONTEND_DIST_FOLDER_PATH)  # nopep8
        configurator.include(frontend_controller.bind)

    hapic.add_documentation_view(
        '/api/v2/doc',
        'Tracim v2 API',
        'API of Tracim v2',
    )
    return configurator.make_wsgi_app()
Пример #29
0
class FunctionalTest(unittest.TestCase):

    fixtures = [BaseFixture]
    config_uri = "tests_configs.ini"
    config_section = "functional_test"

    def _set_logger(self) -> None:
        """
        Set all logger to a high level to avoid getting too much noise for tests
        """
        logger._logger.setLevel("ERROR")
        logging.getLogger().setLevel("ERROR")
        logging.getLogger("sqlalchemy").setLevel("ERROR")
        logging.getLogger("txn").setLevel("ERROR")
        logging.getLogger("cliff").setLevel("ERROR")
        logging.getLogger("_jb_pytest_runner").setLevel("ERROR")

    def setUp(self) -> None:
        self._set_logger()
        DepotManager._clear()
        settings = plaster.get_settings(self.config_uri, self.config_section)
        self.settings = self.override_settings(settings)
        # INFO - G.M - 2019-03-19 - Reset all hapic context: PyramidContext
        # and controllers
        hapic.reset_context()
        # TODO - G.M - 2019-03-19 - Replace this code by something better, see
        # https://github.com/algoo/hapic/issues/144
        hapic._controllers = []
        self.app_config = CFG(self.settings)  # type: CFG
        self.app_config = self.override_app_config(self.app_config)
        self.app_config.configure_filedepot()
        self.connect_database(create_tables=True)
        self.init_database()
        DepotManager._clear()
        self.run_app()

    def connect_database(self, create_tables: bool = False) -> None:
        self.engine = get_engine(self.app_config)
        if create_tables:
            DeclarativeBase.metadata.create_all(self.engine)
        self.session_factory = get_session_factory(self.engine)
        self.session = get_tm_session(self.session_factory,
                                      transaction.manager)

    def override_settings(
        self,
        settings: typing.Dict[str,
                              typing.Any]) -> typing.Dict[str, typing.Any]:
        """
        Allow to override some setting by code.
        by default : do nothing.
        """
        return settings

    def override_app_config(self, app_config: CFG) -> CFG:
        """
        Allow to override app_config parameter for tests
        by default : do nothing.
        """
        return app_config

    def run_app(self) -> None:
        app = web({}, **self.settings)
        self.testapp = TestApp(app)

    def init_database(self):
        with transaction.manager:
            try:
                fixtures_loader = FixturesLoader(self.session, self.app_config)
                fixtures_loader.loads(self.fixtures)
                transaction.commit()
                logger.info(self, "Database initialized.")
            except IntegrityError:
                logger.error(
                    self,
                    "Warning, there was a problem when adding default data"
                    ", it may have already been added:",
                )
                import traceback

                logger.error(self, traceback.format_exc())
                transaction.abort()
                logger.error(self, "Database initialization failed")

    def disconnect_database(self, remove_tables: bool = False) -> None:
        self.session.rollback()
        transaction.abort()
        self.session.close_all()
        self.engine.dispose()
        if remove_tables:
            DeclarativeBase.metadata.drop_all(self.engine)
        DepotManager._clear()

    def tearDown(self) -> None:
        logger.debug(self, "TearDown Test...")
        self.disconnect_database(remove_tables=True)
        testing.tearDown()
Пример #30
0
def web(global_config, **local_settings):
    """ This function returns a Pyramid WSGI application.
    """
    settings = deepcopy(global_config)
    settings.update(local_settings)
    # set CFG object
    app_config = CFG(settings)
    app_config.configure_filedepot()
    settings["CFG"] = app_config
    configurator = Configurator(settings=settings, autocommit=True)
    # Add beaker session cookie
    tracim_setting_for_beaker = sliced_dict(settings, beginning_key_string="session.")
    tracim_setting_for_beaker["session.data_dir"] = app_config.SESSION__DATA_DIR
    tracim_setting_for_beaker["session.lock_dir"] = app_config.SESSION__LOCK_DIR
    session_factory = pyramid_beaker.session_factory_from_settings(tracim_setting_for_beaker)
    configurator.set_session_factory(session_factory)
    pyramid_beaker.set_cache_regions_from_settings(tracim_setting_for_beaker)
    # Add AuthPolicy
    configurator.include("pyramid_multiauth")
    policies = []
    if app_config.REMOTE_USER_HEADER:
        policies.append(
            RemoteAuthentificationPolicy(
                remote_user_email_login_header=app_config.REMOTE_USER_HEADER
            )
        )
    policies.append(
        CookieSessionAuthentificationPolicy(reissue_time=app_config.SESSION__REISSUE_TIME)
    )
    if app_config.API__KEY:
        policies.append(
            ApiTokenAuthentificationPolicy(
                api_key_header=TRACIM_API_KEY_HEADER,
                api_user_email_login_header=TRACIM_API_USER_EMAIL_LOGIN_HEADER,
            )
        )
    policies.append(TracimBasicAuthAuthenticationPolicy(realm=BASIC_AUTH_WEBUI_REALM))
    # Hack for ldap
    if AuthType.LDAP in app_config.AUTH_TYPES:
        import ldap3

        configurator.include("pyramid_ldap3")
        configurator.ldap_setup(
            app_config.LDAP_URL,
            bind=app_config.LDAP_BIND_DN,
            passwd=app_config.LDAP_BIND_PASS,
            use_tls=app_config.LDAP_TLS,
            use_pool=app_config.LDAP_USE_POOL,
            pool_size=app_config.LDAP_POOL_SIZE,
            pool_lifetime=app_config.LDAP_POOL_LIFETIME,
            get_info=app_config.LDAP_GET_INFO,
        )
        configurator.ldap_set_login_query(
            base_dn=app_config.LDAP_USER_BASE_DN,
            filter_tmpl=app_config.LDAP_USER_FILTER,
            scope=ldap3.LEVEL,
            attributes=ldap3.ALL_ATTRIBUTES,
        )

    configurator.include(add_cors_support)
    # make sure to add this before other routes to intercept OPTIONS
    configurator.add_cors_preflight_handler()
    # Default authorization : Accept anything.
    configurator.set_authorization_policy(AcceptAllAuthorizationPolicy())
    authn_policy = MultiAuthenticationPolicy(policies)
    configurator.set_authentication_policy(authn_policy)
    # INFO - GM - 11-04-2018 - set default perm
    # setting default perm is needed to force authentification
    # mecanism in all views.
    configurator.set_default_permission(TRACIM_DEFAULT_PERM)
    # Override default request
    configurator.set_request_factory(TracimRequest)
    # Pyramids "plugin" include.
    configurator.include("pyramid_jinja2")
    # Add SqlAlchemy DB
    init_models(configurator, app_config)
    # set Hapic
    context = PyramidContext(
        configurator=configurator, default_error_builder=ErrorSchema(), debug=app_config.DEBUG
    )
    hapic.set_context(context)
    # INFO - G.M - 2018-07-04 - global-context exceptions
    # Not found
    context.handle_exception(PageNotFound, HTTPStatus.NOT_FOUND)
    # Bad request
    context.handle_exception(WorkspaceNotFoundInTracimRequest, HTTPStatus.BAD_REQUEST)
    context.handle_exception(UserNotFoundInTracimRequest, HTTPStatus.BAD_REQUEST)
    context.handle_exception(ContentNotFoundInTracimRequest, HTTPStatus.BAD_REQUEST)
    context.handle_exception(WorkspaceNotFound, HTTPStatus.BAD_REQUEST)
    context.handle_exception(UserDoesNotExist, HTTPStatus.BAD_REQUEST)
    context.handle_exception(ContentNotFound, HTTPStatus.BAD_REQUEST)
    context.handle_exception(ContentTypeNotExist, HTTPStatus.BAD_REQUEST)
    context.handle_exception(ContentInNotEditableState, HTTPStatus.BAD_REQUEST)
    context.handle_exception(ContentTypeNotAllowed, HTTPStatus.BAD_REQUEST)
    context.handle_exception(InvalidId, HTTPStatus.BAD_REQUEST)
    context.handle_exception(SameValueError, HTTPStatus.BAD_REQUEST)
    # Auth exception
    context.handle_exception(NotAuthenticated, HTTPStatus.UNAUTHORIZED)
    context.handle_exception(UserGivenIsNotTheSameAsAuthenticated, HTTPStatus.FORBIDDEN)
    context.handle_exception(UserAuthenticatedIsNotActive, HTTPStatus.FORBIDDEN)
    context.handle_exception(AuthenticationFailed, HTTPStatus.FORBIDDEN)
    context.handle_exception(InsufficientUserRoleInWorkspace, HTTPStatus.FORBIDDEN)
    context.handle_exception(InsufficientUserProfile, HTTPStatus.FORBIDDEN)
    # Internal server error
    context.handle_exception(OperationalError, HTTPStatus.INTERNAL_SERVER_ERROR)
    context.handle_exception(Exception, HTTPStatus.INTERNAL_SERVER_ERROR)

    # Add controllers
    session_controller = SessionController()
    system_controller = SystemController()
    user_controller = UserController()
    account_controller = AccountController()
    reset_password_controller = ResetPasswordController()
    workspace_controller = WorkspaceController()
    comment_controller = CommentController()
    html_document_controller = HTMLDocumentController()
    thread_controller = ThreadController()
    file_controller = FileController()
    folder_controller = FolderController()
    configurator.include(session_controller.bind, route_prefix=BASE_API_V2)
    configurator.include(system_controller.bind, route_prefix=BASE_API_V2)
    configurator.include(user_controller.bind, route_prefix=BASE_API_V2)
    configurator.include(account_controller.bind, route_prefix=BASE_API_V2)
    configurator.include(reset_password_controller.bind, route_prefix=BASE_API_V2)
    configurator.include(workspace_controller.bind, route_prefix=BASE_API_V2)
    configurator.include(comment_controller.bind, route_prefix=BASE_API_V2)
    configurator.include(html_document_controller.bind, route_prefix=BASE_API_V2)
    configurator.include(thread_controller.bind, route_prefix=BASE_API_V2)
    configurator.include(file_controller.bind, route_prefix=BASE_API_V2)
    configurator.include(folder_controller.bind, route_prefix=BASE_API_V2)
    if app_config.CALDAV__ENABLED:
        # FIXME - G.M - 2019-03-18 - check if possible to avoid this import here,
        # import is here because import AgendaController without adding it to
        # pyramid make trouble in hapic which try to get view related
        # to controller but failed.
        from tracim_backend.views.agenda_api.agenda_controller import AgendaController

        configurator.include(add_www_authenticate_header_for_caldav)
        # caldav exception
        context.handle_exception(CaldavNotAuthorized, HTTPStatus.FORBIDDEN)
        context.handle_exception(CaldavNotAuthenticated, HTTPStatus.UNAUTHORIZED)
        # controller
        radicale_proxy_controller = RadicaleProxyController(
            proxy_base_address=app_config.CALDAV__RADICALE_PROXY__BASE_URL,
            radicale_base_path=app_config.CALDAV__RADICALE__BASE_PATH,
            radicale_user_path=app_config.CALDAV__RADICALE__USER_PATH,
            radicale_workspace_path=app_config.CALDAV_RADICALE_WORKSPACE_PATH,
        )
        agenda_controller = AgendaController()
        configurator.include(agenda_controller.bind, route_prefix=BASE_API_V2)
        configurator.include(radicale_proxy_controller.bind)

    if app_config.FRONTEND__SERVE:
        configurator.include("pyramid_mako")
        frontend_controller = FrontendController(app_config.FRONTEND__DIST_FOLDER_PATH)
        configurator.include(frontend_controller.bind)

    hapic.add_documentation_view("/api/v2/doc", "Tracim v2 API", "API of Tracim v2")
    return configurator.make_wsgi_app()
Пример #31
0
def web(global_config: OrderedDict, **local_settings) -> Router:
    """ This function returns a Pyramid WSGI application.
    """
    settings = deepcopy(global_config)
    settings.update(local_settings)
    # set CFG object
    app_config = CFG(settings)
    app_config.configure_filedepot()
    settings["CFG"] = app_config

    # Init plugin manager
    plugin_manager = init_plugin_manager(app_config)
    settings["plugin_manager"] = plugin_manager

    configurator = Configurator(settings=settings, autocommit=True)
    # Add beaker session cookie
    tracim_setting_for_beaker = sliced_dict(settings, beginning_key_string="session.")
    tracim_setting_for_beaker["session.data_dir"] = app_config.SESSION__DATA_DIR
    tracim_setting_for_beaker["session.lock_dir"] = app_config.SESSION__LOCK_DIR
    tracim_setting_for_beaker["session.httponly"] = app_config.SESSION__HTTPONLY
    tracim_setting_for_beaker["session.secure"] = app_config.SESSION__SECURE
    session_factory = pyramid_beaker.session_factory_from_settings(tracim_setting_for_beaker)
    configurator.set_session_factory(session_factory)
    pyramid_beaker.set_cache_regions_from_settings(tracim_setting_for_beaker)
    # Add AuthPolicy
    configurator.include("pyramid_multiauth")
    policies = []
    if app_config.REMOTE_USER_HEADER:
        policies.append(
            RemoteAuthentificationPolicy(remote_user_login_header=app_config.REMOTE_USER_HEADER)
        )
    policies.append(CookieSessionAuthentificationPolicy())
    policies.append(QueryTokenAuthentificationPolicy())
    if app_config.API__KEY:
        policies.append(
            ApiTokenAuthentificationPolicy(
                api_key_header=TRACIM_API_KEY_HEADER,
                api_user_login_header=TRACIM_API_USER_LOGIN_HEADER,
            )
        )
    policies.append(TracimBasicAuthAuthenticationPolicy(realm=BASIC_AUTH_WEBUI_REALM))
    # Hack for ldap
    if AuthType.LDAP in app_config.AUTH_TYPES:
        import ldap3

        configurator.include("pyramid_ldap3")
        configurator.ldap_setup(
            app_config.LDAP_URL,
            bind=app_config.LDAP_BIND_DN,
            passwd=app_config.LDAP_BIND_PASS,
            use_tls=app_config.LDAP_TLS,
            use_pool=app_config.LDAP_USE_POOL,
            pool_size=app_config.LDAP_POOL_SIZE,
            pool_lifetime=app_config.LDAP_POOL_LIFETIME,
            get_info=app_config.LDAP_GET_INFO,
        )
        configurator.ldap_set_login_query(
            base_dn=app_config.LDAP_USER_BASE_DN,
            filter_tmpl=app_config.LDAP_USER_FILTER,
            scope=ldap3.LEVEL,
            attributes=ldap3.ALL_ATTRIBUTES,
        )

    configurator.include(add_cors_support)
    # make sure to add this before other routes to intercept OPTIONS
    configurator.add_cors_preflight_handler()
    # Default authorization : Accept anything.
    configurator.set_authorization_policy(AcceptAllAuthorizationPolicy())
    authn_policy = MultiAuthenticationPolicy(policies)
    configurator.set_authentication_policy(authn_policy)
    # INFO - GM - 11-04-2018 - set default perm
    # setting default perm is needed to force authentification
    # mechanism in all views.
    configurator.set_default_permission(TRACIM_DEFAULT_PERM)
    # Override default request
    configurator.set_request_factory(TracimRequest)
    # Pyramids "plugin" include.
    # Add SqlAlchemy DB
    init_models(configurator, app_config)
    # set Hapic
    context = TracimPyramidContext(
        configurator=configurator, default_error_builder=ErrorSchema(), debug=app_config.DEBUG
    )
    hapic.set_context(context)
    # INFO - G.M - 2018-07-04 - global-context exceptions
    # Not found
    context.handle_exception(PageNotFound, HTTPStatus.NOT_FOUND)
    # Bad request
    context.handle_exception(WorkspaceNotFoundInTracimRequest, HTTPStatus.BAD_REQUEST)
    context.handle_exception(UserNotFoundInTracimRequest, HTTPStatus.BAD_REQUEST)
    context.handle_exception(ContentNotFoundInTracimRequest, HTTPStatus.BAD_REQUEST)
    context.handle_exception(WorkspaceNotFound, HTTPStatus.BAD_REQUEST)
    context.handle_exception(UserDoesNotExist, HTTPStatus.BAD_REQUEST)
    context.handle_exception(ContentNotFound, HTTPStatus.BAD_REQUEST)
    context.handle_exception(ContentTypeNotExist, HTTPStatus.BAD_REQUEST)
    context.handle_exception(ContentInNotEditableState, HTTPStatus.BAD_REQUEST)
    context.handle_exception(ContentTypeNotAllowed, HTTPStatus.BAD_REQUEST)
    context.handle_exception(InvalidId, HTTPStatus.BAD_REQUEST)
    context.handle_exception(SameValueError, HTTPStatus.BAD_REQUEST)
    # Auth exception
    context.handle_exception(NotAuthenticated, HTTPStatus.UNAUTHORIZED)
    context.handle_exception(UserGivenIsNotTheSameAsAuthenticated, HTTPStatus.FORBIDDEN)
    context.handle_exception(UserAuthenticatedIsNotActive, HTTPStatus.FORBIDDEN)
    context.handle_exception(AuthenticationFailed, HTTPStatus.FORBIDDEN)
    context.handle_exception(InsufficientUserRoleInWorkspace, HTTPStatus.FORBIDDEN)
    context.handle_exception(InsufficientUserProfile, HTTPStatus.FORBIDDEN)
    # Internal server error
    context.handle_exception(OperationalError, HTTPStatus.INTERNAL_SERVER_ERROR)
    context.handle_exception(Exception, HTTPStatus.INTERNAL_SERVER_ERROR)

    # Add controllers
    session_controller = SessionController()
    system_controller = SystemController()
    user_controller = UserController()
    account_controller = AccountController()
    reset_password_controller = ResetPasswordController()
    workspace_controller = WorkspaceController()
    comment_controller = CommentController()
    configurator.include(session_controller.bind, route_prefix=BASE_API)
    configurator.include(system_controller.bind, route_prefix=BASE_API)
    configurator.include(user_controller.bind, route_prefix=BASE_API)
    configurator.include(account_controller.bind, route_prefix=BASE_API)
    configurator.include(reset_password_controller.bind, route_prefix=BASE_API)
    configurator.include(workspace_controller.bind, route_prefix=BASE_API)
    configurator.include(comment_controller.bind, route_prefix=BASE_API)

    app_lib = ApplicationApi(app_list=app_list)
    for app in app_lib.get_all():
        app.load_controllers(
            app_config=app_config, configurator=configurator, route_prefix=BASE_API, context=context
        )

    configurator.scan("tracim_backend.lib.utils.authentification")

    # TODO - G.M - 2019-05-17 - check if possible to avoid this import here,
    # import is here because import SearchController without adding it to
    # pyramid make trouble in hapic which try to get view related
    # to controller but failed.
    from tracim_backend.lib.search.search_factory import SearchFactory

    search_controller = SearchFactory.get_search_controller(app_config)

    configurator.include(search_controller.bind, route_prefix=BASE_API)
    if app_config.FRONTEND__SERVE:
        configurator.include("pyramid_mako")
        frontend_controller = FrontendController(
            dist_folder_path=app_config.FRONTEND__DIST_FOLDER_PATH,
            custom_toolbox_folder_path=app_config.FRONTEND__CUSTOM_TOOLBOX_FOLDER_PATH,
            cache_token=app_config.FRONTEND__CACHE_TOKEN,
        )
        configurator.include(frontend_controller.bind)

    # INFO - G.M - 2019-11-27 - Include plugin custom web code
    plugin_manager.hook.web_include(configurator=configurator, app_config=app_config)

    hapic.add_documentation_view("/api/doc", "Tracim API", "API of Tracim")
    return configurator.make_wsgi_app()
Пример #32
0
def web(global_config, **local_settings):
    """ This function returns a Pyramid WSGI application.
    """
    settings = global_config
    settings.update(local_settings)
    # set CFG object
    app_config = CFG(settings)
    app_config.configure_filedepot()
    settings['CFG'] = app_config
    configurator = Configurator(settings=settings, autocommit=True)
    # Add AuthPolicy
    configurator.include("pyramid_beaker")
    configurator.include("pyramid_multiauth")
    policies = []
    if app_config.REMOTE_USER_HEADER:
        policies.append(
            RemoteAuthentificationPolicy(
                remote_user_email_login_header=app_config.REMOTE_USER_HEADER,
            )
        )
    policies.append(
        CookieSessionAuthentificationPolicy(
            reissue_time=app_config.SESSION_REISSUE_TIME),  # nopep8
    )
    if app_config.API_KEY:
        policies.append(
            ApiTokenAuthentificationPolicy(
                api_key_header=TRACIM_API_KEY_HEADER,
                api_user_email_login_header=TRACIM_API_USER_EMAIL_LOGIN_HEADER
            ),
        )
    policies.append(
        TracimBasicAuthAuthenticationPolicy(
            realm=BASIC_AUTH_WEBUI_REALM
        ),
    )
    # Hack for ldap
    if AuthType.LDAP in app_config.AUTH_TYPES:
        import ldap3
        configurator.include('pyramid_ldap3')
        configurator.ldap_setup(
            app_config.LDAP_URL,
            bind=app_config.LDAP_BIND_DN,
            passwd=app_config.LDAP_BIND_PASS,
            use_tls=app_config.LDAP_TLS,
            use_pool=app_config.LDAP_USE_POOL,
            pool_size=app_config.LDAP_POOL_SIZE,
            pool_lifetime=app_config.LDAP_POOL_LIFETIME,
            get_info=app_config.LDAP_GET_INFO
        )
        configurator.ldap_set_login_query(
            base_dn=app_config.LDAP_USER_BASE_DN,
            filter_tmpl=app_config.LDAP_USER_FILTER,
            scope=ldap3.LEVEL,
            attributes=ldap3.ALL_ATTRIBUTES
        )

    configurator.include(add_cors_support)
    # make sure to add this before other routes to intercept OPTIONS
    configurator.add_cors_preflight_handler()
    # Default authorization : Accept anything.
    configurator.set_authorization_policy(AcceptAllAuthorizationPolicy())
    authn_policy = MultiAuthenticationPolicy(policies)
    configurator.set_authentication_policy(authn_policy)
    # INFO - GM - 11-04-2018 - set default perm
    # setting default perm is needed to force authentification
    # mecanism in all views.
    configurator.set_default_permission(TRACIM_DEFAULT_PERM)
    # Override default request
    configurator.set_request_factory(TracimRequest)
    # Pyramids "plugin" include.
    configurator.include('pyramid_jinja2')
    # Add SqlAlchemy DB
    configurator.include('.models.setup_models')
    # set Hapic
    context = PyramidContext(
        configurator=configurator,
        default_error_builder=ErrorSchema(),
        debug=app_config.DEBUG,
    )
    hapic.set_context(context)
    # INFO - G.M - 2018-07-04 - global-context exceptions
    # Not found
    context.handle_exception(PageNotFound, HTTPStatus.NOT_FOUND)
    # Bad request
    context.handle_exception(WorkspaceNotFoundInTracimRequest, HTTPStatus.BAD_REQUEST)  # nopep8
    context.handle_exception(UserNotFoundInTracimRequest, HTTPStatus.BAD_REQUEST)  # nopep8
    context.handle_exception(ContentNotFoundInTracimRequest, HTTPStatus.BAD_REQUEST)  # nopep8
    context.handle_exception(WorkspaceNotFound, HTTPStatus.BAD_REQUEST)
    context.handle_exception(UserDoesNotExist, HTTPStatus.BAD_REQUEST)
    context.handle_exception(ContentNotFound, HTTPStatus.BAD_REQUEST)
    context.handle_exception(ContentTypeNotExist, HTTPStatus.BAD_REQUEST)
    context.handle_exception(ContentInNotEditableState, HTTPStatus.BAD_REQUEST)
    context.handle_exception(ContentTypeNotAllowed, HTTPStatus.BAD_REQUEST)
    context.handle_exception(InvalidId, HTTPStatus.BAD_REQUEST)
    context.handle_exception(SameValueError, HTTPStatus.BAD_REQUEST)
    # Auth exception
    context.handle_exception(NotAuthenticated, HTTPStatus.UNAUTHORIZED)
    context.handle_exception(UserAuthenticatedIsNotActive, HTTPStatus.FORBIDDEN)
    context.handle_exception(AuthenticationFailed, HTTPStatus.FORBIDDEN)
    context.handle_exception(InsufficientUserRoleInWorkspace, HTTPStatus.FORBIDDEN)  # nopep8
    context.handle_exception(InsufficientUserProfile, HTTPStatus.FORBIDDEN)
    # Internal server error
    context.handle_exception(OperationalError, HTTPStatus.INTERNAL_SERVER_ERROR)
    context.handle_exception(Exception, HTTPStatus.INTERNAL_SERVER_ERROR)

    # Add controllers
    session_controller = SessionController()
    system_controller = SystemController()
    user_controller = UserController()
    account_controller = AccountController()
    reset_password_controller = ResetPasswordController()
    workspace_controller = WorkspaceController()
    comment_controller = CommentController()
    html_document_controller = HTMLDocumentController()
    thread_controller = ThreadController()
    file_controller = FileController()
    folder_controller = FolderController()
    configurator.include(session_controller.bind, route_prefix=BASE_API_V2)
    configurator.include(system_controller.bind, route_prefix=BASE_API_V2)
    configurator.include(user_controller.bind, route_prefix=BASE_API_V2)
    configurator.include(account_controller.bind, route_prefix=BASE_API_V2)
    configurator.include(reset_password_controller.bind, route_prefix=BASE_API_V2)  # nopep8
    configurator.include(workspace_controller.bind, route_prefix=BASE_API_V2)
    configurator.include(comment_controller.bind, route_prefix=BASE_API_V2)
    configurator.include(html_document_controller.bind, route_prefix=BASE_API_V2)  # nopep8
    configurator.include(thread_controller.bind, route_prefix=BASE_API_V2)
    configurator.include(file_controller.bind, route_prefix=BASE_API_V2)
    configurator.include(folder_controller.bind, route_prefix=BASE_API_V2)
    if app_config.FRONTEND_SERVE:
        configurator.include('pyramid_mako')
        frontend_controller = FrontendController(app_config.FRONTEND_DIST_FOLDER_PATH)  # nopep8
        configurator.include(frontend_controller.bind)

    hapic.add_documentation_view(
        '/api/v2/doc',
        'Tracim v2 API',
        'API of Tracim v2',
    )
    return configurator.make_wsgi_app()
Пример #33
0
    def take_action(self, parsed_args: argparse.Namespace) -> None:
        super(UpdateNamingConventionsV1ToV2Command,
              self).take_action(parsed_args)
        config_uri = parsed_args.config_file
        settings = get_appsettings(config_uri)
        settings.update(settings.global_conf)
        app_config = CFG(settings)
        app_config.configure_filedepot()
        engine = get_engine(app_config)
        inspector = reflection.Inspector.from_engine(engine)
        v1_unique_convention = re.compile(r"uk__(\w+)__(\w+)")
        v1_foreign_key_convention = re.compile(r"fk__(\w+)__(\w+)__(\w+)")
        v1_primary_key_convention = re.compile(r"pk__(\w+)")

        if not engine.dialect.name.startswith("postgresql"):
            raise ValueError(
                "This command is only supported on PostgreSQL databases")

        with engine.begin():
            for table_name in inspector.get_table_names():
                if table_name == "migrate_version":
                    continue

                for unique_constraint in inspector.get_unique_constraints(
                        table_name):
                    match = v1_unique_convention.search(
                        unique_constraint["name"])
                    if match:
                        new_name = "uq__{}__{}".format(match.group(1),
                                                       match.group(2))
                        engine.execute(
                            "ALTER TABLE {} RENAME CONSTRAINT {} TO {}".format(
                                table_name, unique_constraint["name"],
                                new_name))

                for foreign_key in inspector.get_foreign_keys(table_name):
                    match = v1_foreign_key_convention.search(
                        foreign_key["name"])
                    # special cases for content_revisions and revision_read_status
                    if foreign_key[
                            "name"] == "fk__content_revisions__owner_id":
                        new_name = "fk_content_revisions_owner_id_users"
                        engine.execute(
                            "ALTER TABLE {} RENAME CONSTRAINT {} TO {}".format(
                                table_name, foreign_key["name"], new_name))
                    elif foreign_key[
                            "name"] == "revision_read_status_revision_id_fkey":
                        new_name = "fk_revision_read_status_revision_id_content_revisions"
                        engine.execute(
                            "ALTER TABLE {} RENAME CONSTRAINT {} TO {}".format(
                                table_name, foreign_key["name"], new_name))
                    elif foreign_key[
                            "name"] == "revision_read_status_user_id_fkey":
                        new_name = "fk_revision_read_status_user_id_users"
                        engine.execute(
                            "ALTER TABLE {} RENAME CONSTRAINT {} TO {}".format(
                                table_name, foreign_key["name"], new_name))
                    elif match:
                        new_name = "fk_{}_{}_{}".format(
                            match.group(1), match.group(2), match.group(3))
                        engine.execute(
                            "ALTER TABLE {} RENAME CONSTRAINT {} TO {}".format(
                                table_name, foreign_key["name"], new_name))

                primary_key = inspector.get_pk_constraint(table_name)
                if primary_key:
                    match = v1_primary_key_convention.search(
                        primary_key["name"])
                    if primary_key["name"] == "pk__users__user_id":
                        engine.execute(
                            "ALTER INDEX {} RENAME TO pk_users".format(
                                primary_key["name"]))
                    elif primary_key[
                            "name"] == "pk__content_revisions__revision_id":
                        engine.execute(
                            "ALTER INDEX {} RENAME TO pk_content_revisions".
                            format(primary_key["name"]))
                    elif primary_key[
                            "name"] == "pk__user_workspace__user_id__workspace_id":
                        engine.execute(
                            "ALTER INDEX {} RENAME TO pk_user_workspace".
                            format(primary_key["name"]))
                    elif primary_key["name"] == "pk__workspace__workspace_id":
                        engine.execute(
                            "ALTER INDEX {} RENAME TO pk_workspaces".format(
                                primary_key["name"]))
                    elif primary_key["name"] == "revision_read_status_pkey":
                        engine.execute(
                            "ALTER INDEX {} RENAME TO pk_revision_read_status".
                            format(primary_key["name"]))
                    elif match:
                        new_name = "pk_{}".format(match.group(1))
                        engine.execute("ALTER INDEX {} RENAME TO {}".format(
                            primary_key["name"], new_name))