def delete_comment(ID): try: comment = Knowl(ID) if comment.type != -2: raise ValueError # We allow admins and the original author to delete comments. if not (current_user.is_admin() or current_user.get_id() == comment.authors[0]): raise ValueError comment.delete() except ValueError: flash("Only admins and the original author can delete comments", "error") return redirect(url_for(".show", ID=comment.source))
def delete_comment(ID): try: comment = Knowl(ID) if comment.type != -2: raise ValueError # We allow admins and the original author to delete comments. if not (current_user.is_admin() or current_user.get_id() == comment.authors[0]): raise ValueError comment.delete() except ValueError: flash_error("Only admins and the original author can delete comments") return redirect(url_for(".show", ID=comment.source))
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)
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)
def raw(ID): k = Knowl(ID) data = render(ID, footer="0", raw=True) resp = make_response(data) # cache 2 minutes and allow CORS resp.headers['Cache-Control'] = 'max-age=%s, public' % (2 * 60) resp.headers['Access-Control-Allow-Origin'] = '*' return resp
def review_recent(days): if len(request.args) > 0: try: info = to_dict(request.args) beta = None ID = info.get('review') if ID: beta = False else: ID = info.get('beta') if ID: beta = True if beta is not None: k = Knowl(ID) k.review(who=current_user.get_id(), set_beta=beta) return jsonify({"success": 1}) raise ValueError except Exception: return jsonify({"success": 0}) knowls = knowldb.needs_review(days) for k in knowls: k.rendered = render_knowl(k.id, footer="0", raw=True, k=k) k.reviewed_content = json.dumps(k.reviewed_content) k.content = json.dumps(k.content) b = get_bread([("Reviewing Recent", url_for('.review_recent', days=days))]) return render_template("knowl-review-recent.html", title="Reviewing %s days of knowls" % days, knowls=knowls, bread=b)
def save_form(): ID = request.form["id"] if not ID: raise Exception("no id") if not allowed_knowl_id.match(ID): flask.flash( """Oops, knowl id '%s' is not allowed. It must consist of lower/uppercase characters, no spaces, numbers or '.', '_' and '-'.""" % ID, "error", ) return flask.redirect(url_for(".index")) k = Knowl(ID) k.title = request.form["title"] k.content = request.form["content"] k.quality = request.form["quality"] k.timestamp = datetime.now() k.save(who=current_user.get_id()) from knowl import save_history save_history(k, current_user.get_id()) return flask.redirect(url_for(".show", ID=ID))
def content(ID, timestamp): if timestamp is not None: timestamp = timestamp_in_ms_to_datetime(timestamp) data = Knowl(ID, timestamp=timestamp).content resp = make_response(data) # cache and allow CORS resp.headers['Cache-Control'] = 'max-age=%d, public' % (_cache_time, ) resp.headers['Access-Control-Allow-Origin'] = '*' return resp
def test(): """ just a test page """ logger.info("test") return render_template("knowl-test.html", bread=get_bread([("Test", url_for(".test"))]), title="Knowledge Test", k1=Knowl("k1"))
def show(ID): k = Knowl(ID) r = render(ID, footer="0") b = get_bread([('%s' % k.title, url_for('.show', ID=ID))]) return render_template("knowl-show.html", title=k.title, k=k, render=r, bread=b, navi_raw=searchbox())
def remove_author(ID): k = Knowl(ID) uid = current_user.get_id() if uid not in k.authors: flash_error("You are not an author on %s", k.id) elif len(k.authors) == 1: flash_error( "You cannot remove yourself unless there are other authors") else: knowldb.remove_author(ID, uid) return redirect(url_for(".show", ID=ID))
def show(ID): k = Knowl(ID) r = render(ID, footer="0", raw=True) title = k.title or "'%s'" % k.id b = get_bread([('%s' % title, url_for('.show', ID=ID))]) return render_template("knowl-show.html", title=k.title, k=k, render=r, bread=b)
def edit(ID): if not allowed_knowl_id.match(ID): flask.flash( """Oops, knowl id '%s' is not allowed. It must consist of lower/uppercase characters, no spaces, numbers or '.', '_' and '-'.""" % ID, "error") return flask.redirect(url_for(".index")) knowl = Knowl(ID) 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)
def show(ID): timestamp = request.args.get('timestamp') if timestamp is not None: timestamp = timestamp_in_ms_to_datetime(timestamp) k = Knowl(ID, timestamp=timestamp, showing=True) if k.exists(): r = render_knowl(ID, footer="0", raw=True) title = k.title or "'%s'" % k.id if not is_beta(): if k.status == 0: title += " (awaiting review)" else: title += " (reviewed)" else: if current_user.is_admin() and k.exists(allow_deleted=True): k = Knowl(ID, showing=True, allow_deleted=True) r = render_knowl(ID, footer="0", raw=True, allow_deleted=True) title = (k.title or "'%s'" % k.id) + " (DELETED)" else: return abort(404, "No knowl found with the given id") for elt in k.edit_history: # We will be printing these within a javascript ` ` string # so need to escape backticks elt['content'] = json.dumps(elt['content']) # Modify the comments list to add information on whether this user can delete if k.type != -2: for i, (cid, author, timestamp) in enumerate(k.comments): can_delete = (current_user.is_admin() or current_user.get_id() == author) author_name = userdb.lookup(author)["full_name"] k.comments[i] = (cid, author_name, timestamp, can_delete) b = get_bread([(k.category, url_for('.index', category=k.category)), ('%s' % title, url_for('.show', ID=ID))]) return render_template(u"knowl-show.html", title=title, k=k, cur_username=current_user.get_id(), render=r, bread=b)
def show(ID): try: k = Knowl(ID) r = render(ID, footer="0", raw=True) title = k.title or "'%s'" % k.id b = get_bread([('%s' % title, url_for('.show', ID=ID))]) return render_template("knowl-show.html", title=k.title, k=k, render=r, bread=b) except Exception: flask.abort(404, "No knowl found with the given id")
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 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)
def save_form(): ID = request.form['id'] if not ID: raise Exception("no id") if not allowed_knowl_id.match(ID): flask.flash( """Oops, knowl id '%s' is not allowed. It must consist of lower/uppercase characters, no spaces, numbers or '.', '_' and '-'.""" % ID, "error") return flask.redirect(url_for(".index")) k = Knowl(ID) k.title = request.form['title'] k.content = request.form['content'] k.quality = request.form['quality'] k.timestamp = datetime.now() k.save(who=current_user.get_id()) return flask.redirect(url_for(".show", ID=ID))
def save_form(): ID = request.form['id'] if not ID: raise Exception("no id") if not allowed_id(ID): return redirect(url_for(".index")) NEWID = request.form.get('krename', '').strip() FINISH_RENAME = request.form.get('finish_rename', '') k = Knowl(ID, saving=True, renaming=bool(NEWID)) new_title = request.form['title'] new_content = request.form['content'] who = current_user.get_id() if new_title != k.title or new_content != k.content: if not k.content and not k.title and k.exists(allow_deleted=True): # Creating a new knowl with the same id as one that had previously been deleted k.resurrect() flash("Knowl successfully created. Note that a knowl with this id existed previously but was deleted; its history has been restored.") k.title = new_title k.content = new_content k.timestamp = datetime.now() k.status = 0 k.save(who=who) if NEWID: if not current_user.is_admin(): flash("You do not have permissions to rename knowl", "error") elif not allowed_id(NEWID): pass else: try: k.start_rename(NEWID, who) except ValueError as err: flash(str(err)) else: if k.sed_safety == 1: flash("Knowl rename process started. You can change code references using".format(NEWID)) flash("git grep -l '{0}' | xargs sed -i '' -e 's/{0}/{1}/g' (Mac)".format(ID, NEWID)) flash("git grep -l '{0}' | xargs sed -i 's/{0}/{1}/g' (Linux)".format(ID, NEWID)) elif k.sed_safety == -1: flash("Knowl rename process started. This knowl appears in the code (see references below), but cannot trivially be replaced with grep/sed".format(NEWID)) else: time.sleep(0.01) k.actually_rename() flash("Knowl renamed to {0} successfully.".format(NEWID)) ID = NEWID elif FINISH_RENAME: # We need to sleep briefly so that we don't have two identical timestamps time.sleep(0.01) if FINISH_RENAME == 'finish': k.actually_rename() elif FINISH_RENAME == 'undo': k.undo_rename() if k.type == -2: return redirect(url_for(".show", ID=k.source)) else: return redirect(url_for(".show", ID=ID))
def delete(ID): k = Knowl(ID) k.delete() flash(Markup("Knowl %s has been deleted." % ID)) return redirect(url_for(".index"))
def resurrect(ID): k = Knowl(ID) k.resurrect() flash(Markup("Knowl %s has been resurrected." % ID)) return redirect(url_for(".show", ID=ID))
def demote(ID, timestamp): timestamp = timestamp_in_ms_to_datetime(timestamp) k = Knowl(ID, timestamp=timestamp) k.review(who=current_user.get_id(), set_beta=True) flash("Knowl %s has been returned to beta." % ID) return redirect(url_for(".show", ID=ID))
def resurrect(ID): k = Knowl(ID) k.resurrect() flash("Knowl %s has been resurrected." % ID) return redirect(url_for(".show", ID=ID))
def delete(ID): k = Knowl(ID) k.delete() flash("Knowl %s has been deleted." % ID) return redirect(url_for(".index"))
def delete(ID): k = Knowl(ID) k.delete() flask.flash("Snif! Knowl %s deleted and gone forever :-(" % ID) return flask.redirect(url_for(".index"))
def render(ID, footer=None, kwargs=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! """ 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) #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"> <div class="knowl-content">%(content)s</div>""" if foot == "1": render_me += """\ <div class="knowl-footer"> <a href="{{ url_for('.show', ID='%(ID)s') }}">permalink</a> {%% if user_is_authenticated %%} · <a href="{{ url_for('.edit', ID='%(ID)s') }}">edit</a> {%% endif %%} </div>""" # """ · 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 } #, '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 wrap this string-rendering into a try/catch and return a proper error message # so that the user has a clue. Most likely, the {{ KNOWL('...') }} has the wrong syntax! logger.debug("kwargs: %s" % k.template_kwargs) return render_template_string(render_me, k=k, **kwargs)
def review(ID, timestamp): timestamp = timestamp_in_ms_to_datetime(timestamp) k = Knowl(ID, timestamp=timestamp) k.review(who=current_user.get_id()) flash(Markup("Knowl %s has been positively reviewed." % ID)) return redirect(url_for(".show", ID=ID))
def demote(ID, timestamp): timestamp = timestamp_in_ms_to_datetime(timestamp) k = Knowl(ID, timestamp=timestamp) k.review(who=current_user.get_id(), set_beta=True) flash(Markup("Knowl %s has been returned to beta." % ID)) return redirect(url_for(".show", ID=ID))
def review(ID, timestamp): timestamp = timestamp_in_ms_to_datetime(timestamp) k = Knowl(ID, timestamp=timestamp) k.review(who=current_user.get_id()) flash("Knowl %s has been positively reviewed." % ID) return redirect(url_for(".show", ID=ID))
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. """ try: k = Knowl(ID) except: logger.critical("Failed to render knowl %s" % ID) errmsg = "Sorry, the knowledge database is currently unavailable." return errmsg if raw else make_response(errmsg) # 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 %%} · <a href="{{ url_for('.edit', ID='%(ID)s') }}">edit</a> {%% endif %%} </div>""" # """ · Authors: %(authors)s """ 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, '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 2 minutes if it is a usual GET if request.method == 'GET': resp.headers['Cache-Control'] = 'max-age=%s, public' % (2 * 60) 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
def save_form(): ID = request.form['id'] if not ID: raise Exception("no id") if not allowed_id(ID): return redirect(url_for(".index")) FINISH_RENAME = request.form.get('finish_rename', '') UNDO_RENAME = request.form.get('undo_rename', '') if FINISH_RENAME: k = Knowl(ID) k.actually_rename() flash( Markup( "Renaming complete; the history of %s has been merged into %s" % (ID, k.source_name))) return redirect(url_for(".show", ID=k.source_name)) elif UNDO_RENAME: k = Knowl(ID) k.undo_rename() flash( Markup( "Renaming undone; the history of %s has been merged back into %s" % (k.source_name, ID))) return redirect(url_for(".show", ID=ID)) NEWID = request.form.get('krename', '').strip() k = Knowl(ID, saving=True, renaming=bool(NEWID)) new_title = request.form['title'] new_content = request.form['content'] who = current_user.get_id() if new_title != k.title or new_content != k.content: if not k.content and not k.title and k.exists(allow_deleted=True): # Creating a new knowl with the same id as one that had previously been deleted k.resurrect() flash( Markup( "Knowl successfully created. Note that a knowl with this id existed previously but was deleted; its history has been restored." )) k.title = new_title k.content = new_content k.timestamp = datetime.now() k.status = 0 k.save(who=who) if NEWID: if not current_user.is_admin(): flash_error("You do not have permissions to rename knowl") elif not allowed_id(NEWID): pass else: try: if k.sed_safety == 0: time.sleep(0.01) k.actually_rename(NEWID) flash( Markup("Knowl renamed to {0} successfully.".format( NEWID))) else: k.start_rename(NEWID, who) except ValueError as err: flash_error(str(err), "error") else: if k.sed_safety == 1: flash( Markup( "Knowl rename process started. You can change code references using" .format(NEWID))) flash( Markup( "git grep -l '{0}' | xargs sed -i '' -e 's/{0}/{1}/g' (Mac)" .format(ID, NEWID))) flash( Markup( "git grep -l '{0}' | xargs sed -i 's/{0}/{1}/g' (Linux)" .format(ID, NEWID))) elif k.sed_safety == -1: flash( Markup( "Knowl rename process started. This knowl appears in the code (see references below), but cannot trivially be replaced with grep/sed" .format(NEWID))) ID = NEWID if k.type == -2: return redirect(url_for(".show", ID=k.source)) else: return redirect(url_for(".show", ID=ID))