コード例 #1
0
def queue_index_actions(blog, include_manual=False):
    '''
    Pushes to the publishing queue all the index pages for a given blog
    that are marked for Immediate publishing.

    :param blog:
        The blog object whose index templates will be pushed to the queue.
    :param include_manual:
        If set to True, all templates, including those set to the Manual publishing mode,
        will be pushed to the queue. Default is False, since those templates are not
        pushed in most publishing actions.
    '''

    templates = blog.index_templates.select().where(
        Template.publishing_mode != publishing_mode.do_not_publish)

    if include_manual is False:
        templates = templates.select().where(
            Template.publishing_mode == publishing_mode.immediate)

    if templates.count() == 0:
        raise Template.DoesNotExist(
            "No valid index templates exist for blog {}.".format(blog.for_log))

    mappings = TemplateMapping.select().where(
        TemplateMapping.template << templates)

    fileinfos = FileInfo.select().where(FileInfo.template_mapping << mappings)

    for f in fileinfos:
        Queue.push(job_type=job_type.index,
                   priority=1,
                   blog=blog,
                   site=blog.site,
                   data_integer=f.id)
コード例 #2
0
def queue_index_actions(blog):
    '''
    Pushes to the publishing queue all the index pages for a given blog
    that are marked for Immediate publishing.
    '''

    try:
        templates = Template.select().where(
            Template.blog == blog,
            Template.template_type == template_type.index,
            Template.publishing_mode == publishing_mode.immediate)

        if templates.count() == 0:
            raise Template.DoesNotExist

    except Template.DoesNotExist:
        raise Template.DoesNotExist(
            "No index templates exist for blog {}.".format(blog.for_log))

    else:

        mappings = TemplateMapping.select().where(
            TemplateMapping.template << templates)

        fileinfos = FileInfo.select().where(
            FileInfo.template_mapping << mappings)

        for f in fileinfos:

            push_to_queue(job_type=job_type.index,
                          priority=1,
                          blog=blog,
                          site=blog.site,
                          data_integer=f.id)
コード例 #3
0
def build_indexes_fileinfos(templates):
    '''
    Rebuilds a fileinfo entry for a given main index.

    This will need to be run every time we create a new index type,
    or change a mapping. (Most of these should have a 1:1 mapping)

    A control message should not be needed, since these are 1:1

    This will port the code currently found in build_blog_fileinfo, much as the above function did.

    '''
    n = 0

    for template in templates:
        n += 1

        index_mappings = TemplateMapping.select().where(
            TemplateMapping.template == template)

        blog = index_mappings[0].template.blog

        tags = template_tags(blog_id=blog.id)

        for i in index_mappings:
            path_string = tpl(tpl_oneline(i.path_string), **tags.__dict__)
            if path_string == '':
                continue
            master_path_string = path_string
            add_page_fileinfo(None, i, master_path_string,
                              blog.url + "/" + master_path_string,
                              blog.path + '/' + master_path_string)

    return n
コード例 #4
0
def build_pages_fileinfos(pages):
    '''
    Creates fileinfo entries for the template mappings associated with
    an iterable list of Page objects.
    '''

    n = 0
    for page in pages:
        n += 1
        template_mappings = page.template_mappings

        if template_mappings.count() == 0:
            raise TemplateMapping.DoesNotExist(
                'No template mappings found for this page.')

        tags = template_tags(page_id=page.id)

        for t in template_mappings:
            path_string = generate_date_mapping(page.publication_date.date(),
                                                tags, t.path_string)
            if path_string == '':
                continue
            master_path_string = path_string + "." + page.blog.base_extension
            add_page_fileinfo(page, t, master_path_string,
                              page.blog.url + "/" + master_path_string,
                              page.blog.path + '/' + master_path_string,
                              str(page.publication_date))

    return n
コード例 #5
0
ファイル: queue.py プロジェクト: syegulalp/mercury
def queue_index_actions(blog, include_manual=False):
    '''
    Pushes to the publishing queue all the index pages for a given blog
    that are marked for Immediate publishing.

    :param blog:
        The blog object whose index templates will be pushed to the queue.
    :param include_manual:
        If set to True, all templates, including those set to the Manual publishing mode,
        will be pushed to the queue. Default is False, since those templates are not
        pushed in most publishing actions.
    '''

    templates = blog.index_templates.select().where(
        Template.publishing_mode != publishing_mode.do_not_publish)

    if include_manual is False:
        templates = templates.select().where(
            Template.publishing_mode == publishing_mode.immediate)

    if templates.count() == 0:
        raise Template.DoesNotExist("No valid index templates exist for blog {}.".format(
            blog.for_log))

    mappings = TemplateMapping.select().where(TemplateMapping.template << templates)

    fileinfos = FileInfo.select().where(FileInfo.template_mapping << mappings)

    for f in fileinfos:
        Queue.push(job_type=job_type.index,
            priority=1,
            blog=blog,
            site=blog.site,
            data_integer=f.id)
コード例 #6
0
def delete(template):

    t0 = FileInfo.delete().where(
        FileInfo.template_mapping << template.mappings)
    t0.execute()
    t1 = TemplateMapping.delete().where(
        TemplateMapping.id << template.mappings)
    t1.execute()
    t2 = Template.delete().where(Template.id == template.id)
    t2.execute()
コード例 #7
0
def build_archives_fileinfos(pages):
    '''
    Takes a page (maybe a collection of same) and produces fileinfos
    for the date-based archive entries for each
    '''

    counter = 0

    mapping_list = {}

    for page in pages:

        tags = template_tags(page_id=page.id)

        if page.archive_mappings.count() == 0:
            raise TemplateMapping.DoesNotExist(
                'No template mappings found for the archives for this page.')

        for m in page.archive_mappings:

            path_string = generate_date_mapping(page.publication_date, tags,
                                                m.path_string)
            if path_string == '':
                continue
            if path_string in mapping_list:
                continue

            # tag_context = generate_archive_context_from_page(m.archive_xref, page.blog, page)
            mapping_list[path_string] = ((
                None,
                m,
                path_string,
                page.blog.url + "/" + path_string,
                page.blog.path + '/' + path_string,
            ), (page))

    for n in mapping_list:
        counter += 1
        new_fileinfo = add_page_fileinfo(*mapping_list[n][0])
        archive_context = []
        m = mapping_list[n][0][1]

        for r in m.archive_xref:
            archive_context.append(archive_functions[r]["format"](
                archive_functions[r]["mapping"](mapping_list[n][1])))

        for t, r in zip(archive_context, m.archive_xref):
            new_fileinfo_context = FileInfoContext.get_or_create(
                fileinfo=new_fileinfo, object=r, ref=t)

        new_fileinfo.mapping_sort = archive_context
        new_fileinfo.save()

    # @return mapping_list
    return counter
コード例 #8
0
ファイル: theme.py プロジェクト: janusnic/MeTal
def export_theme_for_blog(blog_id):
    
    from core.models import Template, TemplateMapping, KeyValue

    theme_to_export = Template.select().where(
        Template.blog == blog_id)
    
    theme = {}
    theme["title"] = theme_to_export[0].theme.title
    theme["description"] = theme_to_export[0].theme.description
    theme["data"] = {}
    
    for n in theme_to_export:
        theme["data"][n.id] = {}
        theme["data"][n.id]["template"] = json_dump(n)
        
        mappings_to_export = TemplateMapping.select().where(
            TemplateMapping.template == n)
        
        theme["data"][n.id]["mapping"] = {}
        
        for m in mappings_to_export:
            theme["data"][n.id]["mapping"][m.id] = json_dump(m)

    theme["kv"] = {}
    
    kv_list = []
    
    top_kvs = KeyValue.select().where(
        KeyValue.object == 'Theme',
        KeyValue.objectid == theme_to_export[0].theme.id,
        KeyValue.is_schema == True)
    
    for n in top_kvs:        
        kv_list.append(n)
    
    while len(kv_list) > 0:
        theme["kv"][kv_list[0].id] = json_dump(kv_list[0]) 
        next_kvs = KeyValue.select().where(
            KeyValue.parent == kv_list[0],
            KeyValue.is_schema == True)
        for f in next_kvs:
            kv_list.append(f)
        del kv_list[0]
        
    import settings
    with open(settings.APPLICATION_PATH + settings._sep + "install" + settings._sep + 
        "templates.json", "w", encoding='utf-8') as output_file:
        output_file.write(json.dumps(theme,
            indent=1,
            sort_keys=True,
            allow_nan=True))
        
    return theme
コード例 #9
0
ファイル: template.py プロジェクト: ra2003/mercury
def new_template(blog_id, tpl_type):
    with db.atomic() as txn:
        user = auth.is_logged_in(request)
        blog = Blog.load(blog_id)
        permission = auth.is_blog_designer(user, blog)

        auth.check_template_lock(blog)

        mappings_index = template_mapping_index.get(tpl_type, None)
        if mappings_index is None:
            raise Exception('Mapping type not found')

        template = Template(
            blog=blog,
            theme=blog.theme,
            template_type=tpl_type,
            publishing_mode=publishing_mode.do_not_publish,
            body='',
        )
        template.save(user)
        template.title = 'Untitled Template #{}'.format(template.id)
        template.save(user)

        if tpl_type != template_type.media:

            new_template_mapping = TemplateMapping(
                template=template,
                is_default=True,
                path_string="'" + utils.create_basename(template.title, blog) +
                "'")

            new_template_mapping.save()
            from core.cms import fileinfo
            fileinfo.build_mapping_xrefs((new_template_mapping, ))

    from settings import BASE_URL
    redirect(BASE_URL + '/template/{}/edit'.format(template.id))
コード例 #10
0
def build_pages_fileinfos(pages, template_mappings=None):
    '''
    Creates fileinfo entries for the template mappings associated with
    an iterable list of Page objects.
    :param pages:
        List of page objects to build fileinfos for.
    '''

    fileinfos = []

    for n, page in enumerate(pages):

        if template_mappings is None:
            mappings = page.template_mappings
        else:
            mappings = template_mappings

        if mappings.count() == 0:
            raise TemplateMapping.DoesNotExist('No template mappings found for this page.')

        tags = template_tags(page=page)

        for t in mappings:

            # path_string = replace_mapping_tags(t.path_string)
            path_string = generate_date_mapping(
                page.publication_date_tz.date(), tags,
                replace_mapping_tags(t.path_string))

            # for tag archives, we need to return a list from the date mapping
            # in the event that we have a tag present that's an iterable like the tag list
            # e.g., for /%t/%Y, for a given page that has five tags
            # we return five values, one for each tag, along with the year

            if path_string == '' or path_string is None:
                continue

            # master_path_string = path_string

            fileinfos.append(
                add_page_fileinfo(page, t, path_string,
                    page.blog.url + "/" + path_string,
                    page.blog.path + '/' + path_string,
                    str(page.publication_date_tz))
                )

    return fileinfos
コード例 #11
0
def build_indexes_fileinfos(templates):

    '''
    Rebuilds a fileinfo entry for a given main index.

    This will need to be run every time we create a new index type,
    or change a mapping. (Most of these should have a 1:1 mapping)

    A control message should not be needed, since these are 1:1

    This will port the code currently found in build_blog_fileinfo, much as the above function did.

    :param templates:
        A list of templates, typically for main indexes, to rebuild fileinfo entries for.

    '''
    for n, template in enumerate(templates):

        index_mappings = TemplateMapping.select().where(
            TemplateMapping.template == template)

        blog = index_mappings[0].template.blog

        tags = template_tags(blog_id=blog.id)

        for i in index_mappings:
            path_string = replace_mapping_tags(i.path_string)
            path_string = eval(path_string, tags.__dict__)

            if path_string == '' or path_string is None:
                continue

            # why are we doing this twice?
            # path_string = replace_mapping_tags(path_string)

            # raise Exception(path_string)

            master_path_string = path_string
            add_page_fileinfo(None, i, master_path_string,
                 blog.url + "/" + master_path_string,
                 blog.path + '/' + master_path_string)

    try:
        return n + 1
    except Exception:
        return 0
コード例 #12
0
ファイル: mgmt.py プロジェクト: janusnic/MeTal
def theme_apply_to_blog(theme, blog):
    '''
    Applies a given theme to a given blog.
    Removes and regenerates fileinfos for the pages on the blog.
    '''

    from core import cms
    cms.purge_fileinfos(blog.fileinfos)

    mappings_to_remove = TemplateMapping.delete().where(
        TemplateMapping.template << blog.templates)
    mappings_to_remove.execute()

    theme_to_remove = Template.delete().where(Template.blog == blog)
    theme_to_remove.execute()

    theme_install_to_blog(theme, blog)
コード例 #13
0
ファイル: template.py プロジェクト: ra2003/mercury
def template_save(request, user, cms_template, blog=None):
    '''
    Core logic for saving changes to a template.
    '''

    # TODO: move the bulk of this into the actual model
    # the .getunicode stuff should be moved out,
    # make that part of the ui
    # we should just submit cms_template as self,
    # make whatever mods to it are needed in the ui func,
    # and perform the validation we did elsewhere, perhaps

    from core.cms import fileinfo, invalidate_cache
    from core.utils import is_blank
    from core.error import TemplateSaveException, PageNotChanged
    import datetime

    status = []

    _forms = request.forms

    cms_template.title = _forms.getunicode('template_title')
    cms_template.body = _forms.getunicode('template_body')

    if is_blank(cms_template.title):
        cms_template.title = "New Template (#{})".format(cms_template.id)

    mode = _forms.getunicode('publishing_mode')

    if mode in publishing_mode.modes:
        cms_template.publishing_mode = mode
    else:
        raise TemplateSaveException("Invalid publishing mode selected.")

    cms_template.modified_date = datetime.datetime.utcnow()

    try:
        cms_template.save(user)
    except PageNotChanged as e:
        status.append("(Template unchanged.)")
    except Exception as e:
        raise e

    new_mappings = []

    for n in _forms:
        if n.startswith('template_mapping_'):
            mapping_id = int(n[len('template_mapping_'):])
            try:
                template_mapping = TemplateMapping.get(
                    TemplateMapping.id == mapping_id)
            except TemplateMapping.DoesNotExist:
                raise TemplateSaveException(
                    'Template mapping with ID #{} does not exist.'.format(
                        mapping_id))
            else:
                if is_blank(_forms.getunicode(n)):
                    raise TemplateSaveException(
                        'Template mapping #{} ({}) cannot be blank. Use None to specify no mapping.'
                        .format(mapping_id, template_mapping.path_string))
                else:
                    if _forms.getunicode(n) != template_mapping.path_string:
                        template_mapping.path_string = _forms.getunicode(n)
                        new_mappings.append(template_mapping)

    for n in new_mappings:
        n.save()
        status.append("Mapping #{} ({}) rebuilt.".format(n.id, n.path_string))

    if new_mappings:
        fileinfo.build_mapping_xrefs(new_mappings)
        build_action = "all"
    else:
        build_action = "fast"

    invalidate_cache()

    # TODO: eventually everything after this will be removed b/c of AJAX save
    # tags = template_tags(template_id=cms_template.id, user=user)

    save_action = _forms.getunicode('save')

    from core.libs.bottle import response
    from settings import BASE_URL
    from core.models import Queue

    x_open = False

    if int(save_action) in (2, 3):

        if cms_template.template_type == template_type.page:
            x_open = True
            response.add_header(
                'X-Open',
                '{}/template/{}/queue/{}'.format(BASE_URL, cms_template.id,
                                                 build_action))

        if cms_template.template_type == template_type.archive:
            x_open = True
            response.add_header(
                'X-Open',
                '{}/template/{}/queue/{}'.format(BASE_URL, cms_template.id,
                                                 build_action))
        if cms_template.template_type in (template_type.include,
                                          template_type.index):

            # I don't think this is needed anymore, we can remove it
            # TODO: test it
            # if new_mappings:
            # cms.build_archives_fileinfos_by_mappings(cms_template)

            for f in cms_template.fileinfos_published:
                Queue.push(job_type=f.template_mapping.template.template_type,
                           blog=cms_template.blog,
                           site=cms_template.blog.site,
                           data_integer=f.id)

        status.append(
            "{} files regenerated from template and sent to publishing queue.".
            format(cms_template.fileinfos_published.count()))

    if blog is not None:
        blog.theme_modified = True
        blog.save()

    from core.log import logger
    logger.info("Template {} edited by user {}.".format(
        cms_template.for_log, user.for_log))

    response.body = ' '.join(status)

    if x_open:
        return response
    else:
        return response.body
コード例 #14
0
def build_archives_fileinfos(pages):
    '''
    Takes a page (maybe a collection of same) and produces fileinfos
    for the date-based archive entries for each
    :param pages:
        List of pages to produce fileinfos for date-based archive entries for.
    '''

    counter = 0
    mapping_list = {}

    try:

        for page in pages:
            tags = template_tags(page=page)
            if page.archive_mappings.count() == 0:
                raise TemplateMapping.DoesNotExist('No template mappings found for the archives for this page.')
            s = []
            for m in page.archive_mappings:
                q = replace_mapping_tags(m.path_string)
                s.append(q)
                paths_list = eval_paths(m.path_string, tags.__dict__)

                if type(paths_list) in (list,):
                    paths = []
                    for n in paths_list:
                        if n is None:
                            continue
                        p = page.proxy(n[0])
                        # FIXME: eliminate the need for page proxies passed manually
                        # at this stage of the process we should generate those
                        # page context in one column, whatever it is, and path strings in another
                        paths.append((p, n[1]))

                else:
                    paths = (
                        (page, paths_list)
                        ,)

                for page, path in paths:
                    path_string = generate_date_mapping(page.publication_date_tz,
                        tags, path, do_eval=False)

                    if path_string == '' or path_string is None:
                        continue
                    if path_string in mapping_list:
                        continue

                    mapping_list[path_string] = (
                        (None, m, path_string,
                        page.blog.url + "/" + path_string,
                        page.blog.path + '/' + path_string,)
                        ,
                        (page),
                        )
        # raise Exception(s)
        for counter, n in enumerate(mapping_list):
            # TODO: we should bail if there is already a fileinfo for this page?
            new_fileinfo = add_page_fileinfo(*mapping_list[n][0])
            FileInfoContext.delete().where(FileInfoContext.fileinfo == new_fileinfo).execute()
            archive_context = []
            m = mapping_list[n][0][1]

            for r in m.archive_xref:
                archive_context.append(
                    archive_functions[r]["format"](
                        archive_functions[r]["mapping"](mapping_list[n][1])
                        )
                    )

            for t, r in zip(archive_context, m.archive_xref):
                new_fileinfo_context = FileInfoContext.get_or_create(
                    fileinfo=new_fileinfo,
                    object=r,
                    ref=t
                    ).save()

            new_fileinfo.mapping_sort = '/'.join(archive_context)
            new_fileinfo.save()

        return counter + 1

    except Exception:
        return 0
コード例 #15
0
def build_archives_fileinfos_by_mappings(template, pages=None, early_exit=False):

    # build list of mappings if not supplied
    # if the list has no dirty mappings, exit

    # also check to make sure we're not using a do-not-publish template

    # TODO: Maybe the smart thing to do is to check the
    # underlying archive type for the template first,
    # THEN create the mappings, so we don't have to do the awkward
    # stuff that we do with tag archives

    # counter = 0
    mapping_list = {}

    if pages is None:
        pages = template.blog.pages.published

    for page in pages:
        tags = template_tags(page=page)
        if page.archive_mappings.count() == 0:
            raise TemplateMapping.DoesNotExist('No template mappings found for the archives for this page.')
        for mapping in template.mappings:
            paths_list = eval_paths(mapping.path_string, tags.__dict__)

            if type(paths_list) in (list,):
                paths = []
                for n in paths_list:
                    if n is None:
                        continue
                    p = page.proxy(n[0])
                    paths.append((p, n[1]))
            else:
                paths = (
                    (page, paths_list)
                    ,)

            for page, path in paths:
                path_string = generate_date_mapping(page.publication_date_tz,
                    tags, path, do_eval=False)

                if path_string == '' or path_string is None:
                    continue
                if path_string in mapping_list:
                    continue

                mapping_list[path_string] = (
                    (None, mapping, path_string,
                    page.blog.url + "/" + path_string,
                    page.blog.path + '/' + path_string,)
                    ,
                    (page),
                    )

        if early_exit and len(mapping_list) > 0:
            # return mapping_list
            break

    fileinfo_list = []

    for n in mapping_list:
        # TODO: we should bail if there is already a fileinfo for this page?
        new_fileinfo = add_page_fileinfo(*mapping_list[n][0])
        FileInfoContext.delete().where(FileInfoContext.fileinfo == new_fileinfo).execute()
        archive_context = []
        m = mapping_list[n][0][1]

        for r in m.archive_xref:
            archive_context.append(
                archive_functions[r]["format"](
                    archive_functions[r]["mapping"](mapping_list[n][1])
                   )
                )

        for t, r in zip(archive_context, m.archive_xref):
            new_fileinfo_context = FileInfoContext.get_or_create(
                fileinfo=new_fileinfo,
                object=r,
                ref=t
                )

        new_fileinfo.mapping_sort = '/'.join(archive_context)
        new_fileinfo.save()
        fileinfo_list.append(new_fileinfo)

    return fileinfo_list
コード例 #16
0
def save(request, user, cms_template):

    status = ''

    _forms = request.forms

    cms_template.title = _forms.getunicode('template_title')
    cms_template.body = _forms.getunicode('template_body')

    if is_blank(cms_template.title):
        cms_template.title = "New Template (#{})".format(cms_template.id)

    mode = _forms.getunicode('publishing_mode')

    if mode in publishing_mode.modes:
        cms_template.publishing_mode = mode
    else:
        raise TemplateSaveException("Invalid publishing mode selected.")

    cms_template.save()

    mappings = []

    for n in _forms:
        if n.startswith('template_mapping_'):
            mapping_id = int(n[len('template_mapping_'):])
            try:
                template_mapping = TemplateMapping.get(
                    TemplateMapping.id == mapping_id)
            except TemplateMapping.DoesNotExist:
                raise TemplateSaveException(
                    'Template mapping with ID #{} does not exist.'.format(
                        mapping_id))
            else:
                if is_blank(_forms.getunicode(n)):
                    raise TemplateSaveException(
                        'Template mapping #{} ({}) cannot be blank.'.format(
                            mapping_id, template_mapping.path_string))
                else:
                    if _forms.getunicode(n) != template_mapping.path_string:
                        template_mapping.path_string = _forms.getunicode(n)
                        # need to check for mapping validation
                        # if invalid, return some kind of warning
                        # not an exception per se?
                        # template_mapping.save()
                        mappings.append(template_mapping)

    for n in mappings:
        n.save()
        status += " Mapping #{} ({}) rebuilt.".format(n.id, n.path_string)
    build_mapping_xrefs(mappings)

    # TODO: eventually everything after this will be removed b/c of AJAX save
    tags = template_tags(template_id=cms_template.id, user=user)

    if int(_forms.getunicode('save')) == 2:
        from core import cms
        for f in cms_template.fileinfos_published:
            cms.push_to_queue(
                job_type=f.template_mapping.template.template_type,
                blog=cms_template.blog,
                site=cms_template.blog.site,
                data_integer=f.id)

        status += " {} files regenerated from template.".format(
            cms_template.fileinfos_published.count())

    logger.info("Template {} edited by user {}.".format(
        cms_template.for_log, user.for_log))

    return status
コード例 #17
0
ファイル: mgmt.py プロジェクト: janusnic/MeTal
def theme_install_to_blog(installed_theme, blog):

    json_obj = json.loads(installed_theme.json)
    templates = json_obj["data"]
    kvs = json_obj["kv"]

    for t in templates:

        template = templates[t]["template"]
        table_obj = Template()

        for name in table_obj._meta.fields:
            if name not in ("id"):
                setattr(table_obj, name, template[name])

        table_obj.theme = installed_theme
        table_obj.blog = blog
        table_obj.save()

        mappings = templates[t]["mapping"]

        for mapping in mappings:
            mapping_obj = TemplateMapping()

            for name in mapping_obj._meta.fields:
                if name not in ("id"):
                    setattr(mapping_obj, name, mappings[mapping][name])

            mapping_obj.template = table_obj
            mapping_obj.save()

    kv_index = {}
    kx = System()

    for kv in kvs:
        kv_current = kvs[kv]
        new_kv = kx.add_kv(**kv_current)
        kv_index[kv_current['id']] = new_kv.id

    for kv in kv_index:
        kv_current = kv
        new_kv_value = kv_index[kv]

        kv_to_change = KeyValue.get(KeyValue.id == new_kv_value)

        parent = kv_to_change.__dict__['_data']['parent']

        if parent is None:
            continue

        kv_to_change.parent = kv_index[parent]
        kv_to_change.save()

    from core import cms

    # TODO: use purge_blog instead

    # for n in blog.pages():
    cms.build_pages_fileinfos(blog.pages())

    # for n in blog.index_templates:
    cms.build_indexes_fileinfos(blog.index_templates)