Exemple #1
0
    def __init__(self, app_name: str) -> None:
        super().__init__()

        self.application = None

        self.app_name = app_name

        self.translatable = False

        self.models = {}
        self.pages = {}

        self.page_imports = ImportSet()
        self.model_imports = ImportSet()

        self.deps = []
        self._apps = [app_name]
        self.extensions = []

        self._freeze()
Exemple #2
0
def generate(target_path, project):
    for app_name, application in project.applications.items():
        has_i18n = any([x.translatable for x in application.models.values()])
        if not has_i18n:
            continue

        imports = ImportSet()
        imports.add('modeltranslation.translator', 'translator')
        imports.add('modeltranslation.translator', 'TranslationOptions')

        for col in application.models.values():
            if not col.translatable:
                continue

            imports.add('{}.models'.format(app_name), col.class_name)

        generate_file(target_path, '{}/translation.py'.format(app_name), 'translation.py.tpl', {
            'imports': imports.import_sting(),
            'models': [(name, col) for name, col in application.models.items() if col.translatable]
        })
Exemple #3
0
def generate_urls_file(target_path, app_name, application, pages, i18n=False):
    url_imports = ImportSet()
    url_imports.add('django.conf.urls', 'url')

    for page in pages:
        url_imports.add('.views', page.view_name)

    context = {
        'i18n': i18n,
        'package_name': app_name,
        'application': application,
        'pages': pages,
        'url_imports': url_imports.import_sting(),
    }

    filepath = os.path.join(package_to_path(app_name),
                            'urls_i18n.py' if i18n else 'urls.py')

    generate_file(target_path, filepath, 'urls.py.tpl', context)
Exemple #4
0
def generate(target_path, project):
    has_views = False

    for app_name, application in project.applications.items():
        if not len(application.pages):  # and not application.rest:
            continue
        has_views = True

        imports = ImportSet()

        for col in application.models.values():
            imports.add('{}.models'.format(app_name), col.class_name)

        generated_templates = []
        if len(application.pages.items()) > 0:
            imports.add('django.views.generic', 'TemplateView')

            for page in application.pages.values():

                if not page.parent_name:
                    imports.add('app.utils.views', 'Data')

                for import_spec in page.get_imports():
                    imports.add(*import_spec)

                for item in page.page_items.values():
                    for import_spec in item.get_imports():
                        imports.add(*import_spec)

                if page.template:
                    template = page.defined_template_name
                    if template:
                        template_name = f'{app_name}/templates/{template}'

                        generate_file(
                            target_path, template_name, 'theme/default.html', {
                                'app_name':
                                app_name,
                                'page':
                                page,
                                'parent':
                                application.resolve_page(page.parent_name)
                                if page.parent_name else None
                            })

                        generated_templates.append(template_name)

        generate_file(
            target_path, '{}/views.py'.format(app_name), 'views.py.tpl', {
                'imports': imports.import_sting(),
                'application': application,
                'pages': application.pages.values()
            })

        # urls
        pages_i18n = [
            page for page in application.pages.values()
            if page.has_uri and page.i18n
        ]
        if len(pages_i18n) > 0:
            generate_urls_file(target_path,
                               app_name,
                               application,
                               pages_i18n,
                               i18n=True)

        # urls i18n
        pages = [
            page for page in application.pages.values()
            if page.has_uri and not page.i18n
        ]
        if application.pages:
            generate_urls_file(target_path,
                               app_name,
                               application,
                               pages,
                               i18n=False)

        if len(application.pages) > 0:
            generate_file(target_path,
                          '{}/templates/{}/_base.html'.format(
                              app_name, app_name),
                          template_name='theme/base_app.html',
                          context={
                              'application': application,
                          })

    if has_views:
        generate_package('app.utils', path=target_path)
        generate_file(target_path,
                      'app/utils/views.py',
                      template_name='views.utils.py.tpl')
Exemple #5
0
def generate(target_path, project):
    if not project.applications_support(ChannelsAppExtension):
        return

    streams = []
    imports = ImportSet()
    for app in project.applications.values():
        for page in app.pages_with(StreamPageExtension):
            streams.append((app, page))
            imports.add(f'{app.app_name}.channels', f'{page.view_name}Consumer')

    generate_file(target_path, f'app/routing.py', 'channels.routing_main.tpl', context={
        'streams': streams,
        'imports': imports,
    })

    for app in project.applications.values():
        if app.pages_support(StreamPageExtension):
            imports = ImportSet()
            imports.add('channels.layers', 'get_channel_layer')
            imports.add('channels.generic.websocket', 'AsyncWebsocketConsumer')
            imports.add('django.db.models.signals', 'post_save', 'm2m_changed', 'post_delete')
            imports.add('django_query_signals', 'post_bulk_create', 'post_delete as post_delete_bulk',
                        'post_get_or_create', 'post_update_or_create', 'post_update')
            imports.add('channels.db', 'database_sync_to_async')
            imports.add('asgiref.sync', 'async_to_sync')
            imports.add('asyncio', 'sleep')
            imports.add('django.dispatch', 'receiver')
            imports.add('app.utils.rest', 'ZmeiJsonEncoder')

            pages = app.pages_with(StreamPageExtension)

            for page in pages:
                for model in page[StreamPageExtension].models:
                    imports.add(f'{model.model_app_name}.models', model.model_class_name)
                imports.add(f'.views', page.view_name)

            generate_file(target_path, f'{app.app_name}/channels.py', 'channels.py.tpl', context={
                'pages': pages,
                'ext': StreamPageExtension,
                'imports': imports,
            })
Exemple #6
0
def generate(target_path, project):
    for app_name, application in project.applications.items():

        if not application.models_support(AdminModelExtension):
            continue

        imports = ImportSet()
        imports.add('django.contrib', 'admin')
        imports.add('django', 'forms')

        for model in application.models_with(AdminModelExtension):
            imports.add('{}.models'.format(app_name), model.class_name)

            for class_import in model[AdminModelExtension].classes:
                imports.add(*class_import)

            if model.polymorphic:
                for child in model.child_models:
                    imports.add('{}.models'.format(app_name), child.class_name)

            # inlines
            for inline in model[AdminModelExtension].inlines:
                for declaration in inline.type_declarations:
                    imports.add(*declaration)

                if inline.inline_type == 'polymorphic':
                    for target_model in inline.target_model.child_models:

                        if target_model.translatable:
                            imports.add('cratis_i18n.admin',
                                        'TranslatableInlineModelAdmin')

                        imports.add('{}.models'.format(app_name),
                                    target_model.class_name)

                imports.add('{}.models'.format(app_name),
                            inline.target_model.class_name)

            for field in model.fields.values():
                if field.get_admin_widget():
                    import_data, model_field = field.get_admin_widget()

                    for source, what in import_data:
                        imports.add(source, what)

        generate_file(
            target_path, '{}/admin.py'.format(app_name), 'admin.py.tpl', {
                'imports':
                imports.import_sting(),
                'ext':
                AdminModelExtension,
                'application':
                application,
                'models': [(name, model)
                           for name, model in application.models.items()
                           if model.supports(AdminModelExtension)]
            })
Exemple #7
0
def generate(target_path, project):
    for app_name, application in project.applications.items():
        if not len(application.models):
            continue

        imports = ImportSet()
        imports.add('django.db', 'models')

        for model in application.models.values():  # type: ModelDef

            for handlers, code in model.signal_handlers:
                for signal_import in handlers:
                    imports.add('django.dispatch', 'receiver')
                    imports.add(*signal_import)

            if model.polymorphic and model.tree:
                imports.add('polymorphic_tree.models', 'PolymorphicMPTTModel',
                            'PolymorphicTreeForeignKey')
            else:
                if model.polymorphic:
                    imports.add('polymorphic.models', 'PolymorphicModel')

                if model.tree:
                    imports.add('mptt.models', 'MPTTModel', 'TreeForeignKey')

            if model.validators:
                imports.add('django.core.exceptions', 'ValidationError')

            if model.mixin_classes:
                for import_decl in model.mixin_classes:
                    pkg, cls, alias = import_decl
                    if alias != cls:
                        cls = '{} as {}'.format(cls, alias)
                    imports.add(*(pkg, cls))

            for field in model.own_fields:  # type: FieldDef
                model_field = field.get_model_field()
                if model_field:
                    import_data, model_field = model_field  # type: FieldDeclaration

                    for source, what in import_data:
                        imports.add(source, what)

        generate_file(
            target_path, '{}/models.py'.format(app_name), 'models.py.tpl', {
                'imports': imports.import_sting(),
                'application': application,
                'models': application.models.items()
            })
Exemple #8
0
def generate(target_path, project):
    has_api = False

    for application in project.applications.values():
        if not application.models_support(
                ApiModelExtension) and not application.models_support(
                    RestModelExtension):
            continue

        app_name = application.app_name

        has_api = True
        imports = ImportSet()
        imports.add('rest_framework', 'serializers')

        for model in application.models_with(RestModelExtension):
            for name, rest_conf in model[RestModelExtension].rest_conf.items():
                rest_conf.configure_model_imports(imports)

        generate_file(
            target_path, '{}/serializers.py'.format(app_name),
            'serializers.py.tpl', {
                'imports':
                imports.import_sting(),
                'application':
                application,
                'rest_ext':
                RestModelExtension,
                'api_ext':
                ApiModelExtension,
                'models':
                [(model.ref, model)
                 for model in application.models_with(RestModelExtension)],
            })

        url_imports = ImportSet()
        url_imports.add('django.conf.urls', 'url')
        url_imports.add('django.conf.urls', 'include')
        url_imports.add('rest_framework', 'routers')

        for model in application.models_with(RestModelExtension):
            for rest_conf in model[RestModelExtension].published_apis.values():
                url_imports.add('.views_rest',
                                f'{rest_conf.serializer_name}ViewSet')

        context = {
            'package_name': app_name,
            'application': application,
            'ext': RestModelExtension,
            'url_imports': url_imports.import_sting(),
        }
        filepath = os.path.join(package_to_path(app_name), 'urls_rest.py')
        generate_file(target_path, filepath, 'urls_rest.py.tpl', context)

        # views_rest.py

        imports = ImportSet()

        for model in application.models_with(RestModelExtension):
            for name, rest_conf in model[RestModelExtension].rest_conf.items():
                rest_conf.configure_imports(imports)

        generate_file(
            target_path, f'{app_name}/views_rest.py', 'views_rest.py.tpl', {
                'package_name':
                app_name,
                'application':
                application,
                'ext':
                RestModelExtension,
                'models': [(name, model)
                           for name, model in application.models.items()
                           if model.supports(RestModelExtension)],
                'imports':
                imports
            })

    has_pages = False
    for application in project.applications.values():
        if len(application.pages):
            has_pages = True

    if has_api or has_pages:
        generate_package('app.utils', path=target_path)
        generate_file(target_path,
                      'app/utils/rest.py',
                      template_name='rest.utils.py.tpl')
Exemple #9
0
def generate(target_path, project):
    has_react = False

    react_pages = []
    react_pages_by_app = {}
    index_imports = ImportSet()

    for app_name, application in project.applications.items():
        if not application.pages_support(ReactPageExtension):
            continue

        has_react = True

        react_pages_by_app[app_name] = {}

        app_cmp_name = to_camel_case(app_name)

        for name, page in application.pages.items():
            ext = page.get_own_or_parent_extension(ReactPageExtension)
            if not ext:
                continue

            page_cmp_name = to_camel_case(page.name)

            name = f'{page_cmp_name}Page'
            name_ui = f'{page_cmp_name}Ui'

            if page.uri:
                react_pages.append(
                    (app_cmp_name, name_ui, format_uri(page.uri)))
                react_pages_by_app[app_name][page.name] = format_uri(page.uri)

            page_component_name = f'Page{page_cmp_name}'

            react_components_imports = ImportSet()
            react_components_imports.add('react', 'React')
            # react_components_imports.add(f'../Components/{el.tag}', '*' + el.tag)

            imports = ImportSet()
            imports.add('react', 'React')
            imports.add(f'../../layout', 'BaseLayout')
            imports.add(f'../layouts/{app_cmp_name}Layout',
                        f'{app_cmp_name}Layout')

            react_components_imports.add(
                f'../Reducers/{page_component_name}Reducers',
                f'*reloadPageDataAction')

            index_imports.add(f'./pages/{name}', '*' + name)

            wrappers = [
                f'PageContextProvider', f'BaseLayout', f'{app_cmp_name}Layout'
            ]

            def wrap(source, cmp_list):
                source = indent(source, '    ')

                if not len(cmp_list):
                    return dedent(source)

                w = cmp_list.pop()

                return wrap(
                    f'<{w} {{...this.props}} page={{this}}>\n{source}\n</{w}>',
                    wrappers)

            blocks_rendered = {}
            for area, blocks in page.get_blocks(
                    platform=ReactPageExtension).items():
                blocks_rendered[area] = []
                for index, block in enumerate(blocks):

                    rendered = block.render(area=area, index=index)

                    try:
                        import_section, rendered = rendered.split('<',
                                                                  maxsplit=1)
                    except ValueError:
                        pass
                    else:
                        for im in REACT_IMPORT_RX.findall(import_section):
                            what = [
                                '*' + x.strip() for x in im[3].split(',')
                                if x != ''
                            ]
                            def_what = im[0].strip(' ,')

                            if len(def_what):
                                what.append(def_what)
                            src = im[5]

                            imports.add(src, *what)

                        rendered = '<' + rendered

                        blocks_rendered[area].append((block.ref, rendered))

            streams = page.list_own_or_parent_extensions(StreamPageExtension)
            generate_file(
                target_path,
                'react/src/{}/pages/{}.jsx'.format(app_name, name),
                'react/page.jsx.tpl', {
                    'imports': imports.import_sting_js(),
                    'name': name,
                    'page': page,
                    'blocks': blocks_rendered,
                    'ext': ReactPageExtension,
                    'app_name': app_name,
                    'streams': streams,
                    'to_camel_case': to_camel_case,
                    'source': wrap('{this.renderContent()}', wrappers)
                })

            ui_imports = ImportSet()
            ui_imports.add('react', 'React')
            ui_imports.add(f'../pages/{name}', name)

            generate_file(
                target_path, f'react/src/{app_name}/ui/{name_ui}.jsx',
                'react/ui.jsx.tpl', {
                    'imports': ui_imports.import_sting_js(),
                    'parent': name,
                    'name': name_ui
                })

        generate_file(
            target_path,
            f'react/src/{app_name}/layouts/{app_cmp_name}Layout.jsx',
            'react/cmp.jsx.tpl', {
                'name': f'{app_cmp_name}Layout',
                'source': '<>{children}</>'
            })

        if not len(react_pages_by_app[app_name]):
            del react_pages_by_app[app_name]

    # sort react_pages
    react_pages = sorted(react_pages)

    # sort routes
    temp_dict = {}
    for key in sorted(react_pages_by_app):
        temp_dict.update({key: react_pages_by_app[key]})
    react_pages_by_app = temp_dict

    if has_react:
        generate_file(target_path, f'react/src/layout.jsx',
                      'react/cmp.jsx.tpl', {
                          'name': f'BaseLayout',
                          'source': '<>{children}</>'
                      })
        generate_file(target_path, f'react/src/index.scss',
                      'react/index.scss.tpl', {'pages': react_pages})
        generate_file(target_path, 'app/utils/react.py', 'react/utils.py.tpl')
        generate_file(target_path, 'react/src/index.jsx',
                      'react/index.jsx.tpl')
        generate_file(target_path, 'react/src/state.jsx', 'react/state.js.tpl')
        generate_file(target_path, 'react/src/streams.jsx',
                      'react/streams.js.tpl')
        generate_file(target_path, 'react/src/reducer.jsx',
                      'react/reducer.js.tpl', {'name': 'Root'})
        generate_file(
            target_path, 'react/src/router.jsx', 'react/router.jsx.tpl', {
                'name': 'Root',
                'pages': react_pages,
                'pages_index': react_pages_by_app,
                'to_camel_case': to_camel_case
            })

        generate_file(target_path, 'react/package.json',
                      'react/package.json.tpl', {'packages': {}})
        generate_file(target_path, 'react/webpack.config.js',
                      'react/webpack.config.js.tpl',
                      {'entries': {
                          'all': f'./src/index.jsx'
                      }})