Ejemplo n.º 1
0
def edit(ID):
    if not allowed_knowl_id.match(ID):
        flask.flash("""Oops, knowl id '%s' is not allowed.
                  It must consist of lowercase characters,
                  no spaces, numbers or '.', '_' and '-'.""" % ID, "error")
        return flask.redirect(url_for(".index"))
    knowl = Knowl(ID)

    from knowl import is_locked, set_locked
    lock = False
    if request.args.get("lock", "") != 'ignore':
        lock = is_locked(knowl.id)
    # lock, if either lock is false or (lock is active), current user is editing again
    author_edits = lock and lock['who'] == current_user.get_id()
    logger.debug(author_edits)
    if not lock or author_edits:
        set_locked(knowl, current_user.get_id())
    if author_edits:
        lock = False

    b = get_bread([("Edit '%s'" % ID, url_for('.edit', ID=ID))])
    return render_template("knowl-edit.html",
                           title="Edit Knowl '%s'" % ID,
                           k=knowl,
                           bread=b,
                           lock=lock)
Ejemplo n.º 2
0
Archivo: main.py Proyecto: koffie/lmfdb
def edit(ID):
    from psycopg2 import DatabaseError
    if not allowed_knowl_id.match(ID):
        flask.flash("""Oops, knowl id '%s' is not allowed.
                  It must consist of lowercase characters,
                  no spaces, numbers or '.', '_' and '-'.""" % ID, "error")
        return flask.redirect(url_for(".index"))
    knowl = Knowl(ID)

    lock = None
    if request.args.get("lock", "") != 'ignore':
        try:
            lock = knowldb.is_locked(knowl.id)
        except DatabaseError as e:
            logger.info("Oops, failed to get the lock. Error: %s" %e)
    author_edits = lock and lock['who'] == current_user.get_id()
    logger.debug(author_edits)
    if author_edits:
        lock = None
    if not lock:
        try:
            knowldb.set_locked(knowl, current_user.get_id())
        except DatabaseError as e:
            logger.info("Oops, failed to set the lock. Error: %s" %e)

    b = get_bread([("Edit '%s'" % ID, url_for('.edit', ID=ID))])
    return render_template("knowl-edit.html",
                           title="Edit Knowl '%s'" % ID,
                           k=knowl,
                           bread=b,
                           lock=lock)
Ejemplo n.º 3
0
Archivo: main.py Proyecto: koffie/lmfdb
def edit(ID):
    from psycopg2 import DatabaseError
    if not allowed_knowl_id.match(ID):
        flask.flash(
            """Oops, knowl id '%s' is not allowed.
                  It must consist of lowercase characters,
                  no spaces, numbers or '.', '_' and '-'.""" % ID, "error")
        return flask.redirect(url_for(".index"))
    knowl = Knowl(ID)

    lock = None
    if request.args.get("lock", "") != 'ignore':
        try:
            lock = knowldb.is_locked(knowl.id)
        except DatabaseError as e:
            logger.info("Oops, failed to get the lock. Error: %s" % e)
    author_edits = lock and lock['who'] == current_user.get_id()
    logger.debug(author_edits)
    if author_edits:
        lock = None
    if not lock:
        try:
            knowldb.set_locked(knowl, current_user.get_id())
        except DatabaseError as e:
            logger.info("Oops, failed to set the lock. Error: %s" % e)

    b = get_bread([("Edit '%s'" % ID, url_for('.edit', ID=ID))])
    return render_template("knowl-edit.html",
                           title="Edit Knowl '%s'" % ID,
                           k=knowl,
                           bread=b,
                           lock=lock)
Ejemplo n.º 4
0
def edit(ID):
    from psycopg2 import DatabaseError
    if not allowed_id(ID):
        return redirect(url_for(".index"))
    knowl = Knowl(ID, editing=True)
    for elt in knowl.edit_history:
        # We will be printing these within a javascript ` ` string
        # so need to escape backticks
        elt['content'] = json.dumps(elt['content'])
    author = knowl._last_author
    # Existing comments can only be edited by admins and the author
    if knowl.type == -2 and author and not (current_user.is_admin() or
                                            current_user.get_id() == author):
        flash_error("You can only edit your own comments")
        return redirect(url_for(".show", ID=knowl.source))

    lock = None
    if request.args.get("lock", "") != 'ignore':
        try:
            lock = knowldb.is_locked(knowl.id)
        except DatabaseError as e:
            logger.info("Oops, failed to get the lock. Error: %s" % e)
    author_edits = lock and lock['username'] == current_user.get_id()
    logger.debug(author_edits)
    if author_edits:
        lock = None
    if not lock:
        try:
            knowldb.set_locked(knowl, current_user.get_id())
        except DatabaseError as e:
            logger.info("Oops, failed to set the lock. Error: %s" % e)

    b = get_bread([("Edit '%s'" % ID, url_for('.edit', ID=ID))])
    if knowl.type == -2:
        title = "Comment on '%s'" % knowl.source
    elif knowl.type == 0:
        title = "Edit Knowl '%s'" % ID
    elif knowl.type == 2:
        pieces = ID.split(".")
        title = f"Edit column information for '{pieces[2]}' in '{pieces[1]}'"
        knowl.title = f"Column {pieces[2]} of table {pieces[1]}"
        from lmfdb import db
        if pieces[1] in db.tablenames:
            knowl.coltype = db[pieces[1]].col_type.get(pieces[2], "DEFUNCT")
        else:
            knowl.coltype = "DEFUNCT"
    else:
        ann_type = 'Top' if knowl.type == 1 else 'Bottom'
        title = 'Edit %s Knowl for <a href="/%s">%s</a>' % (
            ann_type, knowl.source, knowl.source_name)
    return render_template("knowl-edit.html",
                           title=title,
                           k=knowl,
                           bread=b,
                           lock=lock)
Ejemplo n.º 5
0
def edit(ID):
    from psycopg2 import DatabaseError
    if not allowed_id(ID):
        return redirect(url_for(".index"))
    knowl = Knowl(ID, editing=True)
    for elt in knowl.edit_history:
        # We will be printing these within a javascript ` ` string
        # so need to escape backticks
        elt['content'] = json.dumps(elt['content'])
    author = knowl._last_author
    # Existing comments can only be edited by admins and the author
    if knowl.type == -2 and author and not (current_user.is_admin() or current_user.get_id() == author):
        flash("You can only edit your own comments", "error")
        return redirect(url_for(".show", ID=knowl.source))

    lock = None
    if request.args.get("lock", "") != 'ignore':
        try:
            lock = knowldb.is_locked(knowl.id)
        except DatabaseError as e:
            logger.info("Oops, failed to get the lock. Error: %s" %e)
    author_edits = lock and lock['username'] == current_user.get_id()
    logger.debug(author_edits)
    if author_edits:
        lock = None
    if not lock:
        try:
            knowldb.set_locked(knowl, current_user.get_id())
        except DatabaseError as e:
            logger.info("Oops, failed to set the lock. Error: %s" %e)

    b = get_bread([("Edit '%s'" % ID, url_for('.edit', ID=ID))])
    if knowl.type == -2:
        title = "Comment on '%s'" % knowl.source
    elif knowl.type == 0:
        title = "Edit Knowl '%s'" % ID
    else:
        ann_type = 'Top' if knowl.type == 1 else 'Bottom'
        title = 'Edit %s Knowl for <a href="/%s">%s</a>' % (ann_type, knowl.source, knowl.source_name)
    return render_template("knowl-edit.html",
                           title=title,
                           k=knowl,
                           bread=b,
                           lock=lock)
Ejemplo n.º 6
0
def render_knowl(ID,
                 footer=None,
                 kwargs=None,
                 raw=False,
                 k=None,
                 allow_deleted=False,
                 timestamp=None):
    """
    this method renders the given Knowl (ID) to insert it
    dynamically in a website. It is intended to be used
    by an AJAX call, but should do a similar job server-side
    only, too.

    Note, that the used knowl-render.html template is *not*
    based on any globally defined website and just creates
    a small and simple html snippet!

    the keyword 'raw' is used in knowledge.show and knowl_inc to
    include *just* the string and not the response object.
    """
    # logger.debug("kwargs: %s", request.args)
    kwargs = kwargs or dict(((k, v) for k, v in request.args.items()))
    # logger.debug("kwargs: %s" , kwargs)
    if timestamp is None:
        # fetch and convert the ms timestamp to datetime
        try:
            timestamp = timestamp_in_ms_to_datetime(int(kwargs['timestamp']))
        except KeyError:
            pass

    if k is None:
        try:
            k = Knowl(ID, allow_deleted=allow_deleted, timestamp=timestamp)
        except Exception:
            logger.critical("Failed to render knowl %s" % ID)
            errmsg = "Sorry, the knowledge database is currently unavailable."
            return errmsg if raw else make_response(errmsg)

        # If we are rendering a reviewed knowl on nonbeta,
        # we always include the timestamp
        if timestamp is None and k.status == 1 and not is_beta():
            kwargs['timestamp'] = k.ms_timestamp

    # kw_params is inserted *verbatim* into the url_for(...) function inside the template
    # the idea is to pass the keyword arguments of the knowl further along the chain
    # of links, in this case the title and the permalink!
    # so, this kw_params should be plain python, e.g. "a=1, b='xyz'"
    kw_params = ', '.join(('%s="%s"' % (k, v) for k, v in kwargs.items()))
    logger.debug("kw_params: %s" % kw_params)

    # this is a very simple template based on no other template to render one single Knowl
    # for inserting into a website via AJAX or for server-side operations.
    if request.method == "POST":
        con = request.form['content']
        foot = footer or request.form['footer']
    elif request.method == "GET":
        con = request.args.get("content", k.content)
        foot = footer or request.args.get("footer", "1")

    # authors = []
    # for a in k.author_links():
    #  authors.append("<a href='%s'>%s</a>" %
    #    (url_for('users.profile', userid=a['_id']), a['full_name'] or a['_id'] ))
    # authors = ', '.join(authors)

    render_me = u"""\
  {%% include "knowl-defs.html" %%}
  {%% from "knowl-defs.html" import KNOWL with context %%}
  {%% from "knowl-defs.html" import KNOWL_LINK with context %%}
  {%% from "knowl-defs.html" import KNOWL_INC with context %%}
  {%% from "knowl-defs.html" import TEXT_DATA with context %%}

  <div class="knowl">"""
    if foot == "1":
        render_me += """\
  <div class="knowl-header">
    <a href="{{ url_for('.show', ID='%(ID)s', %(kw_params)s ) }}">%(title)s</a>
  </div>""" % {
            'ID': k.id,
            'title': (k.title or k.id),
            'kw_params': kw_params
        }

    render_me += """<div><div class="knowl-content">%(content)s</div></div>"""

    review_status = ""
    if foot == "1":
        render_me += """\
  <div class="knowl-footer">
    <a href="{{ url_for('.show', ID='%(ID)s', %(kw_params)s) }}">permalink</a>
    {%% if user_is_authenticated %%}
      &middot;
      <a href="{{ url_for('.edit', ID='%(ID)s') }}">edit</a>
    {%% endif %%}
    %(review_status)s
  </div>"""
        # """ &middot; Authors: %(authors)s """
        if k.status == 0 and k.type != -2:
            review_status = """&middot; (awaiting review)"""
    render_me += "</div>"
    # render_me = render_me % {'content' : con, 'ID' : k.id }
    con = md_preprocess(con)

    # markdown enabled
    render_me = render_me % {
        'content': md.convert(con),
        'ID': k.id,
        'review_status': review_status,
        'kw_params': kw_params
    }  #, 'authors' : authors }
    # Pass the text on to markdown.  Note, backslashes need to be escaped for
    # this, but not for the javascript markdown parser

    # logger.debug("rendering template string:\n%s" % render_me)

    # TODO improve the error message
    # so that the user has a clue. Most likely, the {{ KNOWL('...') }} has the wrong syntax!
    try:
        data = render_template_string(render_me, k=k, **kwargs)
        if raw:
            # note, this is just internally for the .show method, raw rendering
            # doesn't exist right now and will wrap this into a make_reponse!
            return data
        resp = make_response(data)
        # cache if it is a usual GET
        if request.method == 'GET':
            resp.headers['Cache-Control'] = 'max-age=%d, public' % (
                _cache_time, )
            resp.headers['Access-Control-Allow-Origin'] = '*'
        return resp
    except Exception as e:
        return "ERROR in the template: %s. Please edit it to resolve the problem." % e
Ejemplo n.º 7
0
def index():
    # bypassing the Knowl objects to speed things up
    from knowl import get_knowls
    # See issue #1169
    #    try:
    #        get_knowls().ensure_index('_keywords')
    #        get_knowls().ensure_index('cat')
    #    except pymongo.errors.OperationFailure:
    #        pass

    cur_cat = request.args.get("category", "")

    qualities = []
    defaults = "filter" not in request.args
    filtermode = "filter" in request.args
    searchmode = "search" in request.args
    categorymode = "category" in request.args

    from knowl import knowl_qualities
    # TODO wrap this into a loop:
    reviewed = request.args.get("reviewed", "") == "on" or defaults
    ok = request.args.get("ok", "") == "on" or defaults
    beta = request.args.get("beta", "") == "on" or defaults

    if reviewed:
        qualities.append("reviewed")
    if ok:
        qualities.append("ok")
    if beta:
        qualities.append("beta")

    s_query = {}

    if filtermode:
        quality_q = {'$in': qualities}
        s_query['quality'] = quality_q

    keyword = request.args.get("search", "").lower()
    if searchmode and keyword:
        keywords = filter(lambda _: len(_) >= 3, keyword.split(" "))
        # logger.debug("keywords: %s" % keywords)
        keyword_q = {'_keywords': {"$all": keywords}}
        s_query.update(keyword_q)

    if categorymode:
        s_query.update({'cat': cur_cat})  # { "$regex" : r"^%s\..+" % cur_cat }

    logger.debug("search query: %s" % s_query)
    knowls = get_knowls().find(s_query, ['title'])

    def first_char(k):
        t = k['title']
        if len(t) == 0:
            return "?"
        if t[0] not in string.ascii_letters:
            return "?"
        return t[0].upper()

    # way to additionally narrow down the search
    # def incl(knwl):
    #   if keyword in knwl['_id'].lower():   return True
    #   if keyword in knwl['title'].lower(): return True
    #   return False
    # if keyword: knowls = filter(incl, knowls)

    from knowl import get_categories
    cats = get_categories()

    def knowl_sort_key(knowl):
        '''sort knowls, special chars at the end'''
        title = knowl['title']
        if title and title[0] in string.ascii_letters:
            return (0, title.lower())
        else:
            return (1, title.lower())

    knowls = sorted(knowls, key=knowl_sort_key)
    from itertools import groupby
    knowls = groupby(knowls, first_char)
    return render_template("knowl-index.html",
                           title="Knowledge Database",
                           bread=get_bread(),
                           knowls=knowls,
                           search=keyword,
                           searchbox=searchbox(request.args.get("search", ""),
                                               searchmode),
                           knowl_qualities=knowl_qualities,
                           searchmode=searchmode,
                           filters=(beta, ok, reviewed),
                           categories=cats,
                           cur_cat=cur_cat,
                           categorymode=categorymode)
Ejemplo n.º 8
0
def render_knowl(ID, footer=None, kwargs=None,
        raw=False, k=None, allow_deleted=False, timestamp=None):
    """
    this method renders the given Knowl (ID) to insert it
    dynamically in a website. It is intended to be used
    by an AJAX call, but should do a similar job server-side
    only, too.

    Note, that the used knowl-render.html template is *not*
    based on any globally defined website and just creates
    a small and simple html snippet!

    the keyword 'raw' is used in knowledge.show and knowl_inc to
    include *just* the string and not the response object.
    """
    # logger.debug("kwargs: %s", request.args)
    kwargs = kwargs or dict(((k, v) for k, v in request.args.iteritems()))
    # logger.debug("kwargs: %s" , kwargs)
    if timestamp is None:
        # fetch and convert the ms timestamp to datetime
        try:
            timestamp = timestamp_in_ms_to_datetime(int(kwargs['timestamp']))
        except KeyError:
            pass

    if k is None:
        try:
            k = Knowl(ID, allow_deleted=allow_deleted, timestamp=timestamp)
        except Exception:
            logger.critical("Failed to render knowl %s"%ID)
            errmsg = "Sorry, the knowledge database is currently unavailable."
            return errmsg if raw else make_response(errmsg)

        # If we are rendering a reviewed knowl on nonbeta,
        # we always include the timestamp
        if timestamp is None and k.status == 1 and not is_beta():
            kwargs['timestamp'] = k.ms_timestamp;



    # kw_params is inserted *verbatim* into the url_for(...) function inside the template
    # the idea is to pass the keyword arguments of the knowl further along the chain
    # of links, in this case the title and the permalink!
    # so, this kw_params should be plain python, e.g. "a=1, b='xyz'"
    kw_params = ', '.join(('%s="%s"' % (k, v) for k, v in kwargs.iteritems()))
    logger.debug("kw_params: %s" % kw_params)

    # this is a very simple template based on no other template to render one single Knowl
    # for inserting into a website via AJAX or for server-side operations.
    if request.method == "POST":
        con = request.form['content']
        foot = footer or request.form['footer']
    elif request.method == "GET":
        con = request.args.get("content", k.content)
        foot = footer or request.args.get("footer", "1")

    # authors = []
    # for a in k.author_links():
    #  authors.append("<a href='%s'>%s</a>" %
    #    (url_for('users.profile', userid=a['_id']), a['full_name'] or a['_id'] ))
    # authors = ', '.join(authors)

    render_me = u"""\
  {%% include "knowl-defs.html" %%}
  {%% from "knowl-defs.html" import KNOWL with context %%}
  {%% from "knowl-defs.html" import KNOWL_LINK with context %%}
  {%% from "knowl-defs.html" import KNOWL_INC with context %%}
  {%% from "knowl-defs.html" import TEXT_DATA with context %%}

  <div class="knowl">"""
    if foot == "1":
        render_me += """\
  <div class="knowl-header">
    <a href="{{ url_for('.show', ID='%(ID)s', %(kw_params)s ) }}">%(title)s</a>
  </div>""" % {'ID': k.id, 'title': (k.title or k.id), 'kw_params': kw_params}

    render_me += """<div><div class="knowl-content">%(content)s</div></div>"""

    review_status = ""
    if foot == "1":
        render_me += """\
  <div class="knowl-footer">
    <a href="{{ url_for('.show', ID='%(ID)s', %(kw_params)s) }}">permalink</a>
    {%% if user_is_authenticated %%}
      &middot;
      <a href="{{ url_for('.edit', ID='%(ID)s') }}">edit</a>
    {%% endif %%}
    %(review_status)s
  </div>"""
        # """ &middot; Authors: %(authors)s """
        if k.status == 0 and k.type != -2:
            review_status = """&middot; (awaiting review)"""
    render_me += "</div>"
    # render_me = render_me % {'content' : con, 'ID' : k.id }
    con = md_preprocess(con)

    # markdown enabled
    render_me = render_me % {'content': md.convert(con), 'ID': k.id, 'review_status': review_status,
                             'kw_params': kw_params} #, 'authors' : authors }
    # Pass the text on to markdown.  Note, backslashes need to be escaped for
    # this, but not for the javascript markdown parser

    # logger.debug("rendering template string:\n%s" % render_me)

    # TODO improve the error message
    # so that the user has a clue. Most likely, the {{ KNOWL('...') }} has the wrong syntax!
    try:
        data = render_template_string(render_me, k=k, **kwargs)
        if raw:
            # note, this is just internally for the .show method, raw rendering
            # doesn't exist right now and will wrap this into a make_reponse!
            return data
        resp = make_response(data)
        # cache if it is a usual GET
        if request.method == 'GET':
            resp.headers['Cache-Control'] = 'max-age=%d, public' % (_cache_time,)
            resp.headers['Access-Control-Allow-Origin'] = '*'
        return resp
    except Exception, e:
        return "ERROR in the template: %s. Please edit it to resolve the problem." % e
Ejemplo n.º 9
0
def index():
    # bypassing the Knowl objects to speed things up
    from knowl import get_knowls
    try:
        get_knowls().ensure_index('_keywords')
        get_knowls().ensure_index('cat')
    except pymongo.errors.OperationFailure:
        pass

    cur_cat = request.args.get("category", "")

    qualities = []
    defaults = "filter" not in request.args
    filtermode = "filter" in request.args
    searchmode = "search" in request.args
    categorymode = "category" in request.args

    from knowl import knowl_qualities
    # TODO wrap this into a loop:
    reviewed = request.args.get("reviewed", "") == "on" or defaults
    ok = request.args.get("ok", "") == "on" or defaults
    beta = request.args.get("beta", "") == "on" or defaults

    if reviewed:
        qualities.append("reviewed")
    if ok:
        qualities.append("ok")
    if beta:
        qualities.append("beta")

    s_query = {}

    if filtermode:
        quality_q = {'$in': qualities}
        s_query['quality'] = quality_q

    keyword = request.args.get("search", "").lower()
    if searchmode and keyword:
        keywords = filter(lambda _: len(_) >= 3, keyword.split(" "))
        # logger.debug("keywords: %s" % keywords)
        keyword_q = {'_keywords': {"$all": keywords}}
        s_query.update(keyword_q)

    if categorymode:
        s_query.update({'cat': cur_cat})  # { "$regex" : r"^%s\..+" % cur_cat }

    logger.debug("search query: %s" % s_query)
    knowls = get_knowls().find(s_query, ['title'])

    def first_char(k):
        t = k['title']
        if len(t) == 0:
            return "?"
        if t[0] not in string.ascii_letters:
            return "?"
        return t[0].upper()

    # way to additionally narrow down the search
    # def incl(knwl):
    #   if keyword in knwl['_id'].lower():   return True
    #   if keyword in knwl['title'].lower(): return True
    #   return False
    # if keyword: knowls = filter(incl, knowls)

    from knowl import get_categories
    cats = get_categories()

    def knowl_sort_key(knowl):
        '''sort knowls, special chars at the end'''
        title = knowl['title']
        if title and title[0] in string.ascii_letters:
            return (0, title.lower())
        else:
            return (1, title.lower())

    knowls = sorted(knowls, key=knowl_sort_key)
    from itertools import groupby
    knowls = groupby(knowls, first_char)
    return render_template("knowl-index.html",
                           title="Knowledge Database",
                           bread=get_bread(),
                           knowls=knowls,
                           search=keyword,
                           searchbox=searchbox(request.args.get("search", ""), searchmode),
                           knowl_qualities=knowl_qualities,
                           searchmode=searchmode,
                           filters=(beta, ok, reviewed),
                           categories = cats,
                           cur_cat = cur_cat,
                           categorymode = categorymode)
Ejemplo n.º 10
0
def render(ID, footer=None, kwargs=None, raw=False):
    """
    this method renders the given Knowl (ID) to insert it
    dynamically in a website. It is intended to be used
    by an AJAX call, but should do a similar job server-side
    only, too.

    Note, that the used knowl-render.html template is *not*
    based on any globally defined website and just creates
    a small and simple html snippet!

    the keyword 'raw' is used in knowledge.show and knowl_inc to
    include *just* the string and not the response object.
    """
    k = Knowl(ID)

    # logger.debug("kwargs: %s", request.args)
    kwargs = kwargs or dict(((k, v) for k, v in request.args.iteritems()))
    # logger.debug("kwargs: %s" , kwargs)

    # kw_params is inserted *verbatim* into the url_for(...) function inside the template
    # the idea is to pass the keyword arguments of the knowl further along the chain
    # of links, in this case the title and the permalink!
    # so, this kw_params should be plain python, e.g. "a=1, b='xyz'"
    kw_params = ", ".join(('%s="%s"' % (k, v) for k, v in kwargs.iteritems()))
    logger.debug("kw_params: %s" % kw_params)

    # this is a very simple template based on no other template to render one single Knowl
    # for inserting into a website via AJAX or for server-side operations.
    if request.method == "POST":
        con = request.form["content"]
        foot = footer or request.form["footer"]
    elif request.method == "GET":
        con = request.args.get("content", k.content)
        foot = footer or request.args.get("footer", "1")

    # authors = []
    # for a in k.author_links():
    #  authors.append("<a href='%s'>%s</a>" %
    #    (url_for('users.profile', userid=a['_id']), a['full_name'] or a['_id'] ))
    # authors = ', '.join(authors)

    render_me = u"""\
  {%% include "knowl-defs.html" %%}
  {%% from "knowl-defs.html" import KNOWL with context %%}
  {%% from "knowl-defs.html" import KNOWL_LINK with context %%}
  {%% from "knowl-defs.html" import KNOWL_INC with context %%}
  {%% from "knowl-defs.html" import TEXT_DATA with context %%}

  <div class="knowl">"""
    if foot == "1":
        render_me += """\
  <div class="knowl-header">
    <a href="{{ url_for('.show', ID='%(ID)s', %(kw_params)s ) }}">%(title)s</a>
  </div>""" % {
            "ID": k.id,
            "title": (k.title or k.id),
            "kw_params": kw_params,
        }

    render_me += """<div><div class="knowl-content">%(content)s</div></div>"""

    if foot == "1":
        render_me += """\
  <div class="knowl-footer">
    <a href="{{ url_for('.show', ID='%(ID)s', %(kw_params)s) }}">permalink</a>
    {%% if user_is_authenticated %%}
      &middot;
      <a href="{{ url_for('.edit', ID='%(ID)s') }}">edit</a>
    {%% endif %%}
  </div>"""
    # """ &middot; Authors: %(authors)s """
    render_me += "</div>"
    # render_me = render_me % {'content' : con, 'ID' : k.id }
    # markdown enabled
    render_me = render_me % {"content": md.convert(con), "ID": k.id, "kw_params": kw_params}
    # , 'authors' : authors }
    # Pass the text on to markdown.  Note, backslashes need to be escaped for
    # this, but not for the javascript markdown parser

    # logger.debug("rendering template string:\n%s" % render_me)

    # TODO improve the error message
    # so that the user has a clue. Most likely, the {{ KNOWL('...') }} has the wrong syntax!
    try:
        data = render_template_string(render_me, k=k, **kwargs)
        if raw:
            return data
        resp = make_response(data)
        # cache 10 minutes if it is a usual GET
        if request.method == "GET":
            resp.headers["Cache-Control"] = "max-age=%s, public" % (10 * 60)
        return resp
    except Exception, e:
        return "ERROR in the template: %s. Please edit it to resolve the problem." % e