Improved users, now /create and /edit require user login, changed savepoint() helper

This commit is contained in:
Yusur 2023-01-07 23:04:06 +01:00
parent 83e2c892b3
commit f4d536dc47
9 changed files with 102 additions and 42 deletions

86
app.py
View file

@ -210,6 +210,13 @@ class Page(BaseModel):
return PagePropertyDict(self) return PagePropertyDict(self)
def is_editable(self): def is_editable(self):
return not self.is_locked return not self.is_locked
def can_edit(self, user):
if self.is_locked:
return user.id == self.owner.id
return True
def is_owned_by(self, user):
return user.id == self.owner.id
class PageText(BaseModel): class PageText(BaseModel):
@ -508,12 +515,16 @@ def error_404(body):
def error_403(body): def error_403(body):
return render_template('forbidden.html'), 403 return render_template('forbidden.html'), 403
@app.errorhandler(500) @app.errorhandler(400)
def error_400(body): def error_400(body):
return render_template('badrequest.html'), 400 return render_template('badrequest.html'), 400
@app.errorhandler(500)
def error_500(body):
return render_template('internalservererror.html'), 500
# Middle point during page editing. # Middle point during page editing.
def savepoint(form, is_preview=False, pageid=None): def savepoint(form, is_preview=False, pageobj=None):
if is_preview: if is_preview:
preview = md(form['text'], math='enablemath' in form) preview = md(form['text'], math='enablemath' in form)
else: else:
@ -522,7 +533,7 @@ def savepoint(form, is_preview=False, pageid=None):
pl_js_info['editing'] = dict( pl_js_info['editing'] = dict(
original_text = None, # TODO original_text = None, # TODO
preview_text = form['text'], preview_text = form['text'],
page_id = pageid page_id = pageobj.id if pageobj else None
) )
return render_template( return render_template(
'edit.html', 'edit.html',
@ -531,11 +542,15 @@ def savepoint(form, is_preview=False, pageid=None):
pl_text=form['text'], pl_text=form['text'],
pl_tags=form['tags'], pl_tags=form['tags'],
pl_enablemath='enablemath' in form, pl_enablemath='enablemath' in form,
pl_is_locked='lockpage' in form,
pl_owner_is_current_user=pageobj.is_owned_by(current_user) if pageobj else True,
preview=preview, preview=preview,
pl_js_info=pl_js_info pl_js_info=pl_js_info,
pl_readonly=not pageobj.can_edit(current_user) if pageobj else False
) )
@app.route('/create/', methods=['GET', 'POST']) @app.route('/create/', methods=['GET', 'POST'])
@login_required
def create(): def create():
if request.method == 'POST': if request.method == 'POST':
if request.form.get('preview'): if request.form.get('preview'):
@ -559,7 +574,9 @@ def create():
title=request.form['title'], title=request.form['title'],
is_redirect=False, is_redirect=False,
touched=datetime.datetime.now(), touched=datetime.datetime.now(),
is_math_enabled='enablemath' in request.form owner=current_user,
is_math_enabled='enablemath' in request.form,
is_locked = 'lockpage' in request.form
) )
p.change_tags(p_tags) p.change_tags(p_tags)
except IntegrityError as e: except IntegrityError as e:
@ -567,7 +584,7 @@ def create():
return savepoint(request.form) return savepoint(request.form)
pr = PageRevision.create( pr = PageRevision.create(
page=p, page=p,
user_id=0, user_id=p.owner.id,
comment='', comment='',
textref=PageText.create_content(request.form['text']), textref=PageText.create_content(request.form['text']),
pub_date=datetime.datetime.now(), pub_date=datetime.datetime.now(),
@ -575,37 +592,49 @@ def create():
) )
PageLink.parse_links(p, request.form['text']) PageLink.parse_links(p, request.form['text'])
return redirect(p.get_url()) return redirect(p.get_url())
return render_template('edit.html', pl_url=request.args.get('url')) return savepoint({
"url": request.args.get("url"),
"title": "",
"text": "",
"tags": ""
})
@app.route('/edit/<int:id>/', methods=['GET', 'POST']) @app.route('/edit/<int:id>/', methods=['GET', 'POST'])
@login_required
def edit(id): def edit(id):
p = Page[id] p = Page[id]
if request.method == 'POST': if request.method == 'POST':
# check if page is locked first!
if not p.can_edit(current_user):
flash('You are trying to edit a locked page!')
abort(403)
if request.form.get('preview'): if request.form.get('preview'):
return savepoint(request.form, is_preview=True, pageid=id) return savepoint(request.form, is_preview=True, pageobj=p)
p_url = request.form['url'] or None p_url = request.form['url'] or None
if p_url: if p_url:
if not is_valid_url(p_url): if not is_valid_url(p_url):
flash('Invalid URL. Valid URLs contain only letters, numbers and hyphens.') flash('Invalid URL. Valid URLs contain only letters, numbers and hyphens.')
return savepoint(request.form, pageid=id) return savepoint(request.form, pageobj=p)
elif not is_url_available(p_url) and p_url != p.url: elif not is_url_available(p_url) and p_url != p.url:
flash('This URL is not available.') flash('This URL is not available.')
return savepoint(request.form, pageid=id) return savepoint(request.form, pageobj=p)
p_tags = [x.strip().lower().replace(' ', '-').replace('_', '-').lstrip('#') p_tags = [x.strip().lower().replace(' ', '-').replace('_', '-').lstrip('#')
for x in request.form.get('tags', '').split(',')] for x in request.form.get('tags', '').split(',')]
p_tags = [x for x in p_tags if x] p_tags = [x for x in p_tags if x]
if any(not re.fullmatch(SLUG_RE, x) for x in p_tags): if any(not re.fullmatch(SLUG_RE, x) for x in p_tags):
flash('Invalid tags text. Tags contain only letters, numbers and hyphens, and are separated by comma.') flash('Invalid tags text. Tags contain only letters, numbers and hyphens, and are separated by comma.')
return savepoint(request.form, pageid=id) return savepoint(request.form, pageobj=p)
p.url = p_url p.url = p_url
p.title = request.form['title'] p.title = request.form['title']
p.touched = datetime.datetime.now() p.touched = datetime.datetime.now()
p.is_math_enabled = 'enablemath' in request.form p.is_math_enabled = 'enablemath' in request.form
p.is_locked = 'lockpage' in request.form
p.save() p.save()
p.change_tags(p_tags) p.change_tags(p_tags)
pr = PageRevision.create( pr = PageRevision.create(
page=p, page=p,
user_id=0, user_id=current_user.id,
comment='', comment='',
textref=PageText.create_content(request.form['text']), textref=PageText.create_content(request.form['text']),
pub_date=datetime.datetime.now(), pub_date=datetime.datetime.now(),
@ -613,22 +642,19 @@ def edit(id):
) )
PageLink.parse_links(p, request.form['text']) PageLink.parse_links(p, request.form['text'])
return redirect(p.get_url()) return redirect(p.get_url())
pl_js_info = dict()
pl_js_info['editing'] = dict(
original_text = None, # TODO
preview_text = None,
page_id = id
)
return render_template( form = {
'edit.html', "url": p.url,
pl_url=p.url, "title": p.title,
pl_title=p.title, "text": p.latest.text,
pl_text=p.latest.text, "tags": ','.join(x.name for x in p.tags)
pl_tags=','.join(x.name for x in p.tags), }
pl_js_info=pl_js_info, if p.is_math_enabled:
pl_enablemath = p.is_math_enabled form["enablemath"] = "1"
) if p.is_locked:
form["lockpage"] = "1"
return savepoint(form, pageobj=p)
@app.route("/__sync_start") @app.route("/__sync_start")
def __sync_start(): def __sync_start():
@ -805,6 +831,8 @@ def theme_switch():
@app.route('/accounts/login/', methods=['GET','POST']) @app.route('/accounts/login/', methods=['GET','POST'])
def accounts_login(): def accounts_login():
if current_user.is_authenticated:
return redirect(request.args.get('next', '/'))
if request.method == 'POST': if request.method == 'POST':
try: try:
username = request.form['username'] username = request.form['username']
@ -826,8 +854,6 @@ def accounts_login():
@app.route('/accounts/register/', methods=['GET','POST']) @app.route('/accounts/register/', methods=['GET','POST'])
def accounts_register(): def accounts_register():
if current_user.is_authenticated:
return redirect(request.args.get('next', '/'))
if request.method == 'POST': if request.method == 'POST':
username = request.form['username'] username = request.form['username']
password = request.form['password'] password = request.form['password']
@ -980,7 +1006,7 @@ class Importer(object):
rev = PageRevision.create( rev = PageRevision.create(
page = p, page = p,
user = self.owner.id, user_id = self.owner.id,
textref = textref, textref = textref,
comment = revobj.get('comment'), comment = revobj.get('comment'),
pub_date = datetime.datetime.fromtimestamp(revobj['timestamp']), pub_date = datetime.datetime.fromtimestamp(revobj['timestamp']),

View file

@ -54,6 +54,7 @@
"privacy-policy": "Privacy Policy", "privacy-policy": "Privacy Policy",
"already-have-account": "Already have an account?", "already-have-account": "Already have an account?",
"logged-in-as": "Logged in as", "logged-in-as": "Logged in as",
"not-logged-in": "Not logged in" "not-logged-in": "Not logged in",
"owner": "Owner"
} }
} }

View file

@ -45,6 +45,7 @@
"notes-count-with-url": "Numero di note con URL impostato", "notes-count-with-url": "Numero di note con URL impostato",
"revision-count": "Numero di revisioni", "revision-count": "Numero di revisioni",
"revision-count-per-page": "Media di revisioni per pagina", "revision-count-per-page": "Media di revisioni per pagina",
"remember-me-for": "Ricordami per" "remember-me-for": "Ricordami per",
"owner": "Proprietario"
} }
} }

View file

@ -45,7 +45,13 @@
</ul> </ul>
<div class="footer"> <div class="footer">
<div class="footer-copyright">&copy; 20202023 Sakuragasaki46.</div> <div class="footer-copyright">&copy; 20202023 Sakuragasaki46.</div>
<div class="footer-loggedinas">{% if current_user %}{{ T('logged-in-as') }}: <strong>{{ current_user.username }}</strong>{% else %}{{ T('not-logged-in') }}{% endif %}</div> <div class="footer-loggedinas">
{% if current_user.is_authenticated %}
{{ T('logged-in-as') }}: <strong>{{ current_user.username }}</strong>
{% else %}
{{ T('not-logged-in') }}. <a href="/accounts/login">{{ T("login") }}</a>
{% endif %}
</div>
<div class="footer-actions" id="page-actions">{% block actions %}{% endblock %}</div> <div class="footer-actions" id="page-actions">{% block actions %}{% endblock %}</div>
<div class="footer-versions">{{app_name}} version {{app_version}}</div> <div class="footer-versions">{{app_name}} version {{app_version}}</div>
</div> </div>

View file

@ -11,7 +11,7 @@
<meta name="robots" content="noindex,nofollow" /> <meta name="robots" content="noindex,nofollow" />
{% endblock %} {% endblock %}
{% block json_info %}<script>window.page_info={{ ( pl_js_info or {} )|tojson|safe }};</script>{% endblock %} {% block json_info %}<script>/*<![CDATA[*/window.page_info={{ ( pl_js_info or {} )|tojson|safe }};/*]]>*/</script>{% endblock %}
{% block content %} {% block content %}
@ -35,25 +35,32 @@
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}" /> <input type="hidden" name="csrf_token" value="{{ csrf_token() }}" />
<div> <div>
<label for="title"><span class="material-icons">link</span> /</label> <label for="title"><span class="material-icons">link</span> /</label>
<input type="text" name="url" class="url-input" placeholder="(No URL)" maxlength="64" value="{{ pl_url or '' }}"> <input type="text" name="url" class="url-input" placeholder="(No URL)" maxlength="64" value="{{ pl_url or '' }}" {% if pl_readonly %}disabled=""{% endif %}>
</div> </div>
<div> <div>
<input type="text" required name="title" placeholder="Title (required)" class="title-input" maxlength="256" value="{{ pl_title }}"> <input type="text" required name="title" placeholder="Title (required)" class="title-input" maxlength="256" value="{{ pl_title }}" {% if pl_readonly %}disabled=""{% endif %}>
</div> </div>
<div id="editing-area"> <div id="editing-area">
{% if not pl_readonly %}
<div class="pre-text-input"> <div class="pre-text-input">
<p>This editor is using Markdown for text formatting (e.g. bold, italic, headers and tables). <a href="https://github.com/adam-p/markdown-here/wiki/Markdown-Cheatsheet" rel="nofollow">More info on Markdown</a>.</p> <p>This editor is using Markdown for text formatting (e.g. bold, italic, headers and tables). <a href="https://github.com/adam-p/markdown-here/wiki/Markdown-Cheatsheet" rel="nofollow">More info on Markdown</a>.</p>
{% if math_version %} {% if math_version and pl_enablemath %}
<p>Math with KaTeX is <mark>enabled</mark>. <a href="https://katex.org/docs/supported.html">KaTeX guide</a></p> <p>Math with KaTeX is <mark>enabled</mark>. <a href="https://katex.org/docs/supported.html">KaTeX guide</a></p>
{% endif %} {% endif %}
</div> </div>
<div class="over-text-input"></div> <div class="over-text-input"></div>
<textarea name="text" class="text-input">{{ pl_text }}</textarea> {% else %}
<div class="pre-text-input">
<p>This page was locked by the owner, and is therefore not editable. You can still copy the source text.</p>
</div>
{% endif %}
<textarea name="text" class="text-input" {% if pl_readonly %}disabled=""{% endif %}>{{ pl_text }}</textarea>
</div> </div>
<div> <div>
<label for="tags">Tags (comma separated):</label> <label for="tags">Tags (comma separated):</label>
<input type="text" name="tags" class="tags-input" placeholder="No tags" value="{{ pl_tags }}"> <input type="text" name="tags" class="tags-input" placeholder="No tags" value="{{ pl_tags }}">
</div> </div>
{% if not pl_readonly %}
<div> <div>
<input type="submit" value="Save" id="save-button" class="submit-primary"> <input type="submit" value="Save" id="save-button" class="submit-primary">
<input type="submit" name="preview" value="Preview" id="preview-button" class="submit-secondary"> <input type="submit" name="preview" value="Preview" id="preview-button" class="submit-secondary">
@ -63,6 +70,13 @@
<input type="checkbox" id="CB__enablemath" name="enablemath" {% if math_version and pl_enablemath %}checked=""{% elif not math_version %}disabled=""{% endif %}> <input type="checkbox" id="CB__enablemath" name="enablemath" {% if math_version and pl_enablemath %}checked=""{% elif not math_version %}disabled=""{% endif %}>
<label for="CB__enablemath">Enable math expressions parsing {% if not math_version %}(disabled for this instance){% endif %}</label> <label for="CB__enablemath">Enable math expressions parsing {% if not math_version %}(disabled for this instance){% endif %}</label>
</div> </div>
{% if pl_owner_is_current_user %}
<div>
<input type="checkbox" id="CB__lockpage" name="lockpage" {% if pl_is_locked %}checked=""{% endif %}>
<label for="CB__lockpage">Lock page for editing by other users</label>
</div>
{% endif %}
{% endif %}
</form> </form>
{% endblock %} {% endblock %}

View file

@ -16,6 +16,8 @@
#{{ rev.id }} #{{ rev.id }}
&middot; &middot;
{{ rev.pub_date.strftime("%B %-d, %Y %H:%M:%S") }} {{ rev.pub_date.strftime("%B %-d, %Y %H:%M:%S") }}
by
{{ rev.user.username }}
</a></li> </a></li>
{% endfor %} {% endfor %}
</ul> </ul>

View file

@ -0,0 +1,9 @@
{% extends "base.html" %}
{% block title %}Internal Server Error - {{ app_name }}{% endblock %}
{% block content %}
<h1>Internal Server Error</h1>
<p>Were sorry, an unexpected error occurred. Try refreshing the page.</p>
{% endblock %}

View file

@ -17,18 +17,18 @@
</div> </div>
<div> <div>
<label>{{ T('confirm-password') }}:</label> <label>{{ T('confirm-password') }}:</label>
<input type="password" name="confirmpassword" /> <input type="password" name="confirm_password" />
</div> </div>
<div> <div>
<label>{{ T('email') }} ({{ T('optional') }}):</label> <label>{{ T('email') }} ({{ T('optional') }}):</label>
<input type="email" name="email" /> <input type="text" name="email" />
</div> </div>
<div> <div>
<input type="checkbox" name="legal" value="1" /> <input type="checkbox" name="legal" value="1" />
<label>{{ T('have-read-terms').format(T('terms-of-service'), T('privacy-policy')) }}</label> <label>{{ T('have-read-terms').format(T('terms-of-service'), T('privacy-policy')) }}</label>
</div> </div>
<div> <div>
<input type="submit" value="{{ T('login') }}" /> <input type="submit" value="{{ T('sign-up') }}" />
</div> </div>
</form> </form>

View file

@ -38,7 +38,8 @@
<a href="/history/{{ p.id }}/">{{ T('action-history') }}</a> - <a href="/history/{{ p.id }}/">{{ T('action-history') }}</a> -
<a href="/backlinks/{{ p.id }}/">Backlinks</a> - <a href="/backlinks/{{ p.id }}/">Backlinks</a> -
{{ T('last-changed') }} <time datetime="{{ rev.pub_date.isoformat() }}">{{ rev.pub_date.strftime('%B %-d, %Y at %H:%M:%S') }}</time> - {{ T('last-changed') }} <time datetime="{{ rev.pub_date.isoformat() }}">{{ rev.pub_date.strftime('%B %-d, %Y at %H:%M:%S') }}</time> -
{{ T('page-id') }}: {{ p.id }} {{ T('page-id') }}: {{ p.id }} -
{{ T('owner') }}: {{ p.owner.username }}
{% endblock %} {% endblock %}
{% block scripts %} {% block scripts %}