예제 #1
0
 def ready(self):
     """
     Startup method for Tethys Apps django app.
     """
     # Perform App Harvesting
     harvester = SingletonAppHarvester()
     harvester.harvest_apps()
예제 #2
0
파일: utilities.py 프로젝트: wle0001/tethys
def sync_tethys_app_db():
    """
    Sync installed apps with database.
    """
    # Get the harvester
    harvester = SingletonAppHarvester()

    try:
        # Make pass to remove apps that were uninstalled
        db_apps = TethysApp.objects.all()
        installed_app_packages = [app.package for app in harvester.apps]

        for db_apps in db_apps:
            if db_apps.package not in installed_app_packages:
                db_apps.delete()

        # Make pass to add apps to db that are newly installed
        installed_apps = harvester.apps

        for installed_app in installed_apps:
            # Query to see if installed app is in the database
            db_apps = TethysApp.objects.\
                filter(package__exact=installed_app.package).\
                all()

            # If the app is not in the database, then add it
            if len(db_apps) == 0:
                app = TethysApp(
                    name=installed_app.name,
                    package=installed_app.package,
                    description=installed_app.description,
                    enable_feedback=installed_app.enable_feedback,
                    feedback_emails=installed_app.feedback_emails,
                    index=installed_app.index,
                    icon=installed_app.icon,
                    root_url=installed_app.root_url,
                    color=installed_app.color,
                    tags=installed_app.tags
                )
                app.save()

            # If the app is in the database, update developer-first attributes
            elif len(db_apps) == 1:
                db_app = db_apps[0]
                db_app.index = installed_app.index
                db_app.icon = installed_app.icon
                db_app.root_url = installed_app.root_url
                db_app.color = installed_app.color
                db_app.save()

            # More than one instance of the app in db... (what to do here?)
            elif len(db_apps) >= 2:
                continue
    except Exception as e:
        log.error(e)
예제 #3
0
파일: utilities.py 프로젝트: wle0001/tethys
def generate_app_url_patterns():
    """
    Generate the url pattern lists for each app and namespace them accordingly.
    """

    # Get controllers list from app harvester
    harvester = SingletonAppHarvester()
    apps = harvester.apps
    app_url_patterns = dict()

    for app in apps:
        if hasattr(app, 'url_maps'):
            url_maps = app.url_maps()
        elif hasattr(app, 'controllers'):
            url_maps = app.controllers()
        else:
            url_maps = None

        if url_maps:
            for url_map in url_maps:
                app_root = app.root_url
                app_namespace = app_root.replace('-', '_')

                if app_namespace not in app_url_patterns:
                    app_url_patterns[app_namespace] = []

                # Create django url object
                if isinstance(url_map.controller, basestring):
                    controller_parts = url_map.controller.split('.')
                    module_name = '.'.join(controller_parts[:-1])
                    function_name = controller_parts[-1]
                    try:
                        module = __import__(module_name, fromlist=[function_name])
                    except ImportError:
                        error_msg = 'The following error occurred while trying to import the controller function ' \
                                    '"{0}":\n {1}'.format(url_map.controller, traceback.format_exc(2))
                        log.error(error_msg)
                        sys.exit(1)
                    try:
                        controller_function = getattr(module, function_name)
                    except AttributeError, e:
                        error_msg = 'The following error occurred while tyring to access the controller function ' \
                                    '"{0}":\n {1}'.format(url_map.controller, traceback.format_exc(2))
                        log.error(error_msg)
                        sys.exit(1)
                else:
                    controller_function = url_map.controller
                django_url = url(url_map.url, controller_function, name=url_map.name)

                # Append to namespace list
                app_url_patterns[app_namespace].append(django_url)
예제 #4
0
파일: utilities.py 프로젝트: zhiyuli/tethys
def get_app_url_patterns():
    """
    Generate the url pattern lists for each app and namespace them accordingly.
    """

    # Get controllers list from app harvester
    harvester = SingletonAppHarvester()
    apps = harvester.apps
    app_url_patterns = dict()

    for app in apps:
        app_url_patterns.update(app.url_patterns)

    return app_url_patterns
예제 #5
0
def generate_app_url_patterns():
    """
    Generate the url pattern lists for each app and namespace them accordingly.
    """

    # Get controllers list from app harvester
    harvester = SingletonAppHarvester()
    apps = harvester.apps
    app_url_patterns = dict()

    for app in apps:
        if hasattr(app, 'url_maps'):
            url_maps = app.url_maps()
        elif hasattr(app, 'controllers'):
            url_maps = app.controllers()
        else:
            url_maps = None

        if url_maps:
            for url_map in url_maps:
                app_root = app.root_url
                app_namespace = app_root.replace('-', '_')

                if app_namespace not in app_url_patterns:
                    app_url_patterns[app_namespace] = []

                # Create django url object
                if isinstance(url_map.controller, basestring):
                    controller_parts = url_map.controller.split('.')
                    module_name = '.'.join(controller_parts[:-1])
                    function_name = controller_parts[-1]
                    try:
                        module = __import__(module_name, fromlist=[function_name])
                    except ImportError:
                        raise ValueError('"{0}" is not a valid controller function.'.format(url_map.controller))
                    try:
                        controller_function = getattr(module, function_name)
                    except AttributeError:
                        raise ValueError('"{0}" is not a valid controller function.'.format(url_map.controller))
                else:
                    controller_function = url_map.controller
                django_url = url(url_map.url, controller_function, name=url_map.name)

                # Append to namespace list
                app_url_patterns[app_namespace].append(django_url)

    return app_url_patterns
예제 #6
0
def tethys_apps_context(request):
    """
    Add the current Tethys app metadata to the template context.
    """
    # Setup variables
    harvester = SingletonAppHarvester()
    context = {'tethys_app': None}
    apps_root = 'apps'

    # Get url and parts
    url = request.path
    url_parts = url.split('/')

    # Find the app key
    if apps_root in url_parts:
        # The app root_url is the path item following (+1) the apps_root item
        app_root_url_index = url_parts.index(apps_root) + 1
        app_root_url = url_parts[app_root_url_index]

        # Get list of app dictionaries from the harvester
        apps = harvester.apps

        # If a match can be made, return the app dictionary as part of the context
        for app in apps:
            if app.root_url == app_root_url:
                context['tethys_app'] = {
                    'name': app.name,
                    'index': app.index,
                    'icon': app.icon,
                    'color': app.color,
                    'description': app.description
                }

                if hasattr(app,
                           'feedback_emails') and len(app.feedback_emails) > 0:
                    context['tethys_app'][
                        'feedback_emails'] = app.feedback_emails

                    if hasattr(app, 'enable_feedback'):
                        context['tethys_app'][
                            'enable_feedback'] = app.enable_feedback

    return context
예제 #7
0
파일: models.py 프로젝트: landco70/tethys
"""
********************************************************************************
* Name: models.py
* Author: Nathan Swain
* Created On: 2014
* Copyright: (c) Brigham Young University 2014
* License: BSD 2-Clause
********************************************************************************
"""
from tethys_apps.app_harvester import SingletonAppHarvester

# Perform App Harvesting
harvester = SingletonAppHarvester()
harvester.harvest_apps()
예제 #8
0
파일: utilities.py 프로젝트: zhiyuli/tethys
def register_app_permissions():
    """
    Register and sync the app permissions.
    """
    from guardian.shortcuts import assign_perm, remove_perm, get_perms
    from django.contrib.contenttypes.models import ContentType
    from django.contrib.auth.models import Permission, Group

    # Get the apps
    harvester = SingletonAppHarvester()
    apps = harvester.apps
    all_app_permissions = {}
    all_groups = {}

    for app in apps:
        perms = app.permissions()

        # Name spaced prefix for app permissions
        # e.g. my_first_app:view_things
        # e.g. my_first_app | View things
        perm_codename_prefix = app.package + ':'
        perm_name_prefix = app.package + ' | '

        if perms is not None:
            # Thing is either a Permission or a PermissionGroup object

            for thing in perms:
                # Permission Case
                if isinstance(thing, permissions.Permission):
                    # Name space the permissions and add it to the list
                    permission_codename = perm_codename_prefix + thing.name
                    permission_name = perm_name_prefix + thing.description
                    all_app_permissions[permission_codename] = permission_name

                # PermissionGroup Case
                elif isinstance(thing, permissions.PermissionGroup):
                    # Record in dict of groups
                    group_permissions = []
                    group_name = perm_codename_prefix + thing.name

                    for perm in thing.permissions:
                        # Name space the permissions and add it to the list
                        permission_codename = perm_codename_prefix + perm.name
                        permission_name = perm_name_prefix + perm.description
                        all_app_permissions[permission_codename] = permission_name
                        group_permissions.append(permission_codename)

                    # Store all groups for all apps
                    all_groups[group_name] = {'permissions': group_permissions, 'app_package': app.package}

    # Get the TethysApp content type
    tethys_content_type = ContentType.objects.get(
        app_label='tethys_apps',
        model='tethysapp'
    )

    # Remove any permissions that no longer exist
    db_app_permissions = Permission.objects.filter(content_type=tethys_content_type).all()

    for db_app_permission in db_app_permissions:
        # Delete the permission if the permission is no longer required by an app
        if db_app_permission.codename not in all_app_permissions:
            db_app_permission.delete()

    # Create permissions that need to be created
    for perm in all_app_permissions:
        # Create permission if it doesn't exist
        try:
            # If permission exists, update it
            p = Permission.objects.get(codename=perm)

            p.name = all_app_permissions[perm]
            p.content_type = tethys_content_type
            p.save()

        except Permission.DoesNotExist:
            p = Permission(
                name=all_app_permissions[perm],
                codename=perm,
                content_type=tethys_content_type
            )
            p.save()

    # Remove any groups that no longer exist
    db_groups = Group.objects.all()
    db_apps = TethysApp.objects.all()
    db_app_names = [db_app.package for db_app in db_apps]

    for db_group in db_groups:
        db_group_name_parts = db_group.name.split(':')

        # Only perform maintenance on groups that belong to Tethys Apps
        if (len(db_group_name_parts) > 1) and (db_group_name_parts[0] in db_app_names):

            # Delete groups that is no longer required by an app
            if db_group.name not in all_groups:
                db_group.delete()

    # Create groups that need to be created
    for group in all_groups:
        # Look up the app
        db_app = TethysApp.objects.get(package=all_groups[group]['app_package'])

        # Create group if it doesn't exist
        try:
            # If it exists, update the permissions assigned to it
            g = Group.objects.get(name=group)

            # Get the permissions for the group and remove all of them
            perms = get_perms(g, db_app)

            for p in perms:
                remove_perm(p, g, db_app)

            # Assign the permission to the group and the app instance
            for p in all_groups[group]['permissions']:
                assign_perm(p, g, db_app)

        except Group.DoesNotExist:
            # Create a new group
            g = Group(name=group)
            g.save()

            # Assign the permission to the group and the app instance
            for p in all_groups[group]['permissions']:
                assign_perm(p, g, db_app)
예제 #9
0
    def provision_persistent_stores(self, app_names, options):
        """
        Provision all persistent stores for all apps or for only the app name given.
        """
        # Set refresh parameter
        database_refresh = options['refresh']

        # Get the app harvester
        app_harvester = SingletonAppHarvester()

        # Define the list of target apps
        target_apps = []
        target_apps_check = []

        # Execute on all apps loaded
        if ALL_APPS in app_names:
            target_apps = app_harvester.apps

        # Execute only on apps given
        else:
            for app in app_harvester.apps:
                # Derive app_name from the index which follows the pattern app_name:home
                if app.package in app_names:
                    target_apps.append(app)
                    target_apps_check.append(app.package)

            # Verify all apps included in target apps
            for app_name in app_names:
                if app_name not in target_apps_check:
                    self.stdout.write('{0}WARNING:{1} The app named "{2}" cannot be found. Please make sure it is installed '
                                      'and try again.'.format(TerminalColors.WARNING, TerminalColors.ENDC, app_name))

        # Notify user of database provisioning
        self.stdout.write(TerminalColors.BLUE + '\nProvisioning Persistent Stores...' + TerminalColors.ENDC)

        # Get database manager url from the config
        database_manager_db = settings.TETHYS_DATABASES['tethys_db_manager']
        database_manager_url = 'postgresql://{0}:{1}@{2}:{3}/{4}'.format(database_manager_db['USER'] if 'USER' in database_manager_db else 'tethys_db_manager',
                                                                         database_manager_db['PASSWORD'] if 'PASSWORD' in database_manager_db else 'pass',
                                                                         database_manager_db['HOST'] if 'HOST' in database_manager_db else '127.0.0.1',
                                                                         database_manager_db['PORT'] if 'PORT' in database_manager_db else '5435',
                                                                         database_manager_db['NAME'] if 'NAME' in database_manager_db else 'tethys_db_manager')

        database_manager_name = database_manager_url.split('://')[1].split(':')[0]

        #--------------------------------------------------------------------------------------------------------------#
        # Get a list of existing databases
        #--------------------------------------------------------------------------------------------------------------#

        # Create connection engine
        engine = create_engine(database_manager_url)

        # Cannot create databases in a transaction: connect and commit to close transaction
        connection = engine.connect()

        # Check for Database
        existing_dbs_statement = '''
                                 SELECT d.datname as name
                                 FROM pg_catalog.pg_database d
                                 LEFT JOIN pg_catalog.pg_user u ON d.datdba = u.usesysid
                                 ORDER BY 1;
                                 '''

        existing_dbs = connection.execute(existing_dbs_statement)
        connection.close()

        # Compile list of db names
        existing_db_names = []

        for existing_db in existing_dbs:
            existing_db_names.append(existing_db.name)

        # Get apps and provision persistent stores if not already created
        for app in target_apps:
            # Create multiple persistent stores if necessary
            persistent_stores = app.persistent_stores()

            if persistent_stores:
                # Assemble list of target persistent stores
                target_persistent_stores = []

                # Target the persistent store provided
                if options['database']:
                    for persistent_store in persistent_stores:
                        if options['database'] == persistent_store.name:
                            target_persistent_stores.append(persistent_store)

                # Target all persistent stores
                else:
                    target_persistent_stores = persistent_stores

                for persistent_store in target_persistent_stores:
                    full_db_name = '_'.join((app.package, persistent_store.name))
                    new_database = True

                    #--------------------------------------------------------------------------------------------------#
                    # 1. Drop database if refresh option is included
                    #--------------------------------------------------------------------------------------------------#
                    if database_refresh and full_db_name in existing_db_names:
                        # Provide update for user
                        self.stdout.write('Dropping database {2}"{0}"{3} for app {2}"{1}"{3}...'.format(
                            persistent_store.name,
                            app.package,
                            TerminalColors.BLUE,
                            TerminalColors.ENDC
                        ))

                        # Connection
                        delete_connection = engine.connect()

                        # Drop db
                        drop_db_statement = 'DROP DATABASE IF EXISTS {0}'.format(full_db_name)

                        # Close transaction first then execute.
                        delete_connection.execute('commit')
                        delete_connection.execute(drop_db_statement)
                        delete_connection.close()

                        # Update the existing dbs query
                        existing_db_names.pop(existing_db_names.index(full_db_name))

                    #--------------------------------------------------------------------------------------------------#
                    # 2. Create the database if it does not already exist
                    #--------------------------------------------------------------------------------------------------#
                    if full_db_name not in existing_db_names:
                        # Provide Update for User
                        self.stdout.write('Creating database {2}"{0}"{3} for app {2}"{1}"{3}...'.format(
                            persistent_store.name,
                            app.package,
                            TerminalColors.BLUE,
                            TerminalColors.ENDC
                        ))

                        # Cannot create databases in a transaction: connect and commit to close transaction
                        create_connection = engine.connect()

                        # Create db
                        create_db_statement = '''
                                              CREATE DATABASE {0}
                                              WITH OWNER {1}
                                              TEMPLATE template0
                                              ENCODING 'UTF8'
                                              '''.format(full_db_name, database_manager_name)

                        # Close transaction first and then execute
                        create_connection.execute('commit')
                        create_connection.execute(create_db_statement)
                        create_connection.close()

                    else:
                        # Provide Update for User
                        self.stdout.write('Database {2}"{0}"{3} already exists for app {2}"{1}"{3}, skipping...'.format(
                            persistent_store.name,
                            app.package,
                            TerminalColors.BLUE,
                            TerminalColors.ENDC
                        ))

                        # Set var that is passed to initialization functions
                        new_database = False

                    #--------------------------------------------------------------------------------------------------#
                    # 3. Enable PostGIS extension
                    #--------------------------------------------------------------------------------------------------#
                    if (hasattr(persistent_store, 'spatial') and persistent_store.spatial) or persistent_store.postgis:
                        # Get URL for Tethys Superuser to enable extensions
                        super_db = settings.TETHYS_DATABASES['tethys_super']
                        super_url = 'postgresql://{0}:{1}@{2}:{3}/{4}'.format(super_db['USER'] if 'USER' in super_db else 'tethys_super',
                                                                              super_db['PASSWORD'] if 'PASSWORD' in super_db else 'pass',
                                                                              super_db['HOST'] if 'HOST' in super_db else '127.0.0.1',
                                                                              super_db['PORT'] if 'PORT' in super_db else '5435',
                                                                              super_db['NAME'] if 'NAME' in super_db else 'tethys_super')
                        super_parts = super_url.split('/')
                        new_db_url = '{0}//{1}/{2}'.format(super_parts[0], super_parts[2], full_db_name)

                        # Connect to new database
                        new_db_engine = create_engine(new_db_url)
                        new_db_connection = new_db_engine.connect()

                        # Notify user
                        self.stdout.write('Enabling PostGIS on database {2}"{0}"{3} for app {2}"{1}"{3}...'.format(
                            persistent_store.name,
                            app.package,
                            TerminalColors.BLUE,
                            TerminalColors.ENDC
                        ))
                        enable_postgis_statement = 'CREATE EXTENSION IF NOT EXISTS postgis'

                        # Execute postgis statement
                        new_db_connection.execute(enable_postgis_statement)
                        new_db_connection.close()

                #------------------------------------------------------------------------------------------------------#
                # 4. Run initialization functions for each store here
                #------------------------------------------------------------------------------------------------------#
                for persistent_store in target_persistent_stores:

                    if persistent_store.initializer_is_valid:
                        initializer = persistent_store.initializer_function
                    else:
                        if ':' in persistent_store.initializer:
                            print('DEPRECATION WARNING: The initializer attribute of a PersistentStore should now be in the form: "my_first_app.init_stores.init_spatial_db". The form "init_stores:init_spatial_db" is now deprecated.')

                            # Split into module name and function name
                            initializer_mod, initializer_function = persistent_store.initializer.split(':')

                            # Pre-process initializer path
                            initializer_path = '.'.join(('tethys_apps.tethysapp', app.package, initializer_mod))

                            try:
                                # Import module
                                module = __import__(initializer_path, fromlist=[initializer_function])
                            except ImportError:
                                pass
                            else:
                                # Get the function
                                initializer = getattr(module, initializer_function)

                    try:
                        if not initializer:
                            raise ValueError('"{0}" is not a valid function.'.format(persistent_store.initializer))
                    except UnboundLocalError:
                        raise ValueError('"{0}" is not a valid function.'.format(persistent_store.initializer))

                    self.stdout.write('Initializing database {3}"{0}"{4} for app {3}"{1}"{4} using initializer '
                                      '{3}"{2}"{4}...'.format(persistent_store.name,
                                                              app.package,
                                                              initializer.__name__,
                                                              TerminalColors.BLUE,
                                                              TerminalColors.ENDC
                                                              ))

                    if options['first_time']:
                        initializer(True)
                    else:
                        initializer(new_database)