diff options
| -rw-r--r-- | apioforum/auth.py | 5 | ||||
| -rw-r--r-- | apioforum/forum.py | 19 | ||||
| -rw-r--r-- | apioforum/mdrender.py | 1 | ||||
| -rw-r--r-- | apioforum/static/style.css | 97 | ||||
| -rw-r--r-- | apioforum/templates/auth/register.html | 2 | ||||
| -rw-r--r-- | apioforum/templates/common.html | 6 | ||||
| -rw-r--r-- | apioforum/templates/user_settings.html | 4 | ||||
| -rw-r--r-- | apioforum/templates/view_forum.html | 85 | 
8 files changed, 118 insertions, 101 deletions
| diff --git a/apioforum/auth.py b/apioforum/auth.py index 8a34700..39cf1f8 100644 --- a/apioforum/auth.py +++ b/apioforum/auth.py @@ -54,6 +54,10 @@ def register():              "SELECT 1 FROM users WHERE username = ?;", (username,)          ).fetchone() is not None:              err = f"User {username} is already registered." +        elif len(username) > 20: +            err = "username can't be longer than 20 characters" +        elif not username.isalnum(): +            err = "username must be alphanumeric"          if err is None:              db.execute( @@ -63,7 +67,6 @@ def register():              db.commit()              flash("successfully created account")              session['user'] = username -            flash("registered successfully")              return redirect(get_next())          flash(err) diff --git a/apioforum/forum.py b/apioforum/forum.py index e2e5474..09d3166 100644 --- a/apioforum/forum.py +++ b/apioforum/forum.py @@ -11,6 +11,8 @@ from .mdrender import render  from sqlite3 import OperationalError +from sqlite3 import OperationalError +  bp = Blueprint("forum", __name__, url_prefix="/")  @bp.route("/") @@ -31,6 +33,7 @@ def view_forum(forum_id):          ORDER BY threads.updated DESC;          """,(forum_id,)).fetchall()      thread_tags = {} +    preview_post = {}      #todo: somehow optimise this      for thread in threads:          thread_tags[thread['id']] = db.execute( @@ -39,12 +42,16 @@ def view_forum(forum_id):              WHERE thread_tags.thread = ?              ORDER BY tags.id;              """,(thread['id'],)).fetchall() -    return render_template( -        "view_forum.html", -        threads=threads, -        thread_tags=thread_tags, -        forum=forum -    ) +        preview_post[thread['id']]  = db.execute( +            """SELECT * FROM posts WHERE thread = ? +            ORDER BY created DESC; +            """,(thread['id'],)).fetchone() +    return render_template("view_forum.html", +            forum=forum, +            threads=threads, +            thread_tags=thread_tags, +            preview_post=preview_post +            )  @bp.route("/<int:forum_id>/create_thread",methods=("GET","POST"))  def create_thread(forum_id): diff --git a/apioforum/mdrender.py b/apioforum/mdrender.py index 5f5292d..8c59c42 100644 --- a/apioforum/mdrender.py +++ b/apioforum/mdrender.py @@ -12,6 +12,7 @@ allowed_tags = [      'del',      'mark',      'img', +    'marquee'  ]  allowed_attributes = bleach.sanitizer.ALLOWED_ATTRIBUTES.copy() diff --git a/apioforum/static/style.css b/apioforum/static/style.css index 21fc5ef..86611f6 100644 --- a/apioforum/static/style.css +++ b/apioforum/static/style.css @@ -88,53 +88,66 @@ nav#navbar .links { display: flex; }  /* todo: make the navbar less bad */  .flashmsg { border: 1px solid black; background-color: yellow; max-width: max-content; padding: 5px; clear: both;} -.threadlisting:nth-child(even) { background-color: var(--alternating-colour-even) } -.threadlisting:nth-child(odd) { background-color: var(--alternating-colour-odd) } - +.thread-listing:nth-child(even) { background-color: var(--alternating-colour-even) } +.thread-listing:nth-child(odd) { background-color: var(--alternating-colour-odd) } +.thread-listing { +    border-left: 1px solid black; +    border-right: 1px solid black; +    border-top: 1px solid black; +	padding: 10px; +} +.thread-listing:last-of-type { border-bottom: 1px solid black; } +.thread-listing-main {  +	display: flex;  +	align-items: center; +} +.thread-listing-title {  +	overflow: hidden; +	font-size: larger;  +	white-space: nowrap; +	text-overflow: ellipsis; +	flex-grow: 1; +} +.thread-listing-tags {  +	display: flex; +	align-items: center; +	flex-wrap: nowrap; +	flex-shrink: 0; +} +.thread-listing-tags .tag { margin-left: 5px; } +.thread-listing-creation {  +	display: flex;  +	margin-left: 5px;  +	flex-wrap: nowrap;  +} +.thread-listing-creator { margin-right: 5px; } +.thread-preview {  +	overflow: hidden; +	font-size: smaller;  +	white-space: nowrap; +	text-overflow: ellipsis; +	margin-top: 10px; +} +.thread-preview-post a, .thread-preview-post a:visited {  +	color: black;  +	text-decoration: none;  +} +.thread-preview-post { font-style: italic; } +.thread-preview-ts { font-weight: bold; }  /* wide screens */ -@media all and (min-width: 800px) { -    .threadlisting { display: contents } -    .threadlistings { -        display: grid; -        grid-template-columns: 2fr repeat(5,1fr) 0.4fr; -    } - -    .threadlisting-part { -        border-left: 1px solid black; -        border-top: 1px solid black; -    } -    .threadlistings { -        border-right: 1px solid black; -        border-bottom: 1px solid black; -    } - -    .only-small { display: none !important } - - -} +@media all and (min-width: 600px) { }  /* small screens */ -@media not all and (min-width: 800px) { -    .threadlisting { -        display: grid; -        grid-template-columns: repeat(5,1fr); -        margin-bottom: 5px; -    } -    .threadlisting-part-title { -        grid-column: 1 / -1; -    } -    .threadlisting-part { -        border-left: 1px solid black; -        border-top: 1px solid black; -    } -    .threadlisting { -        border-right: 1px solid black; -        border-bottom: 1px solid black; -    } - -    .only-big { display: none !important } +@media not all and (min-width: 600px) { +	.thread-listing-creation { font-size: small; } +	.thread-listing-creator { +		max-width: 75px;  +		overflow: hidden; +		white-space: nowrap; +		text-overflow: ellipsis; +	}  } diff --git a/apioforum/templates/auth/register.html b/apioforum/templates/auth/register.html index 7d079c2..5d27b90 100644 --- a/apioforum/templates/auth/register.html +++ b/apioforum/templates/auth/register.html @@ -7,7 +7,7 @@  <p>create a new account here. if you already have an account, <a href="{{url_for('auth.login')}}">login</a> instead.</p>  <form method="post">      <label for="username">Username</label> -    <input name="username" id="username" required> +    <input name="username" id="username" maxlength="20" required>      <br>      <label for="password">Password</label>      <input type="password" name="password" id="password" required> diff --git a/apioforum/templates/common.html b/apioforum/templates/common.html index 28598e7..9301a49 100644 --- a/apioforum/templates/common.html +++ b/apioforum/templates/common.html @@ -2,6 +2,10 @@  <a href="{{url_for('user.view_user',username=username)}}" class="username">{{username}}</a>  {%- endmacro %} +{% macro post_url(post) -%} +	{{url_for('thread.view_thread', thread_id=post.thread)}}#post_{{post.id}} +{%- endmacro %} +  {% macro disp_post(post, buttons=False) %}  <div class="post" id="post_{{post.id}}">      <div class="post-heading"> @@ -19,7 +23,7 @@              <a class="actionbutton"                 href="{{url_for('thread.delete_post',post_id=post.id)}}">delete</a>          {% endif %} -        <a class="post-anchor-link" href="{{url_for('thread.view_thread', thread_id=post.thread)}}#post_{{post.id}}">#{{post.id}}</a> +		<a class="post-anchor-link" href="{{post_url(post)}}">#{{post.id}}</a>          </span>      </div>      <div class="post-content"> diff --git a/apioforum/templates/user_settings.html b/apioforum/templates/user_settings.html index cac613a..d463eee 100644 --- a/apioforum/templates/user_settings.html +++ b/apioforum/templates/user_settings.html @@ -5,9 +5,9 @@  <fieldset>  <legend>change password</legend>  <label for="password">current password</label> -<input type="text" id="password" name="password"><br> +<input type="password" id="password" name="password"><br>  <label for="new_password">new password</label> -<input type="text" id="new_password" name="new_password"> +<input type="password" id="new_password" name="new_password">  </fieldset>  <fieldset>  <legend>change bio</legend> diff --git a/apioforum/templates/view_forum.html b/apioforum/templates/view_forum.html index c5bcef1..f83503b 100644 --- a/apioforum/templates/view_forum.html +++ b/apioforum/templates/view_forum.html @@ -1,5 +1,5 @@  {% extends 'base.html' %} -{% from 'common.html' import ts, tag, disp_user %} +{% from 'common.html' import ts, tag, disp_user, post_url %}  {% block header %}<h1>{% block title %}{{forum.name}}{%endblock%}</h1>{%endblock%}  {%block nmcontent%}  <main class="widemain"> @@ -9,53 +9,42 @@  {% else %}  <p>please log in to create a new thread</p>  {% endif %} -<div class="threadlistings"> -<div class="threadlisting"> -    <div class="threadlisting-part threadlisting-part-title threadlisting-header"> -        name<span class="only-small"> & tags</span> -    </div> -    <div class="threadlisting-part threadlisting-part-tags threadlisting-header only-big"> -        tags -    </div> -    <div class="threadlisting-part threadlisting-part-creator threadlisting-header"> -        creator -    </div> -    <div class="threadlisting-part threadlisting-part-created threadlisting-header"> -        created -    </div> -    <div class="threadlisting-part threadlisting-part-updated threadlisting-header"> -        last updated -    </div> -    <div class="threadlisting-part threadlisting-part-lastactivityby threadlisting-header"> -        last post by -    </div> -    <div class="threadlisting-part threadlisting-part-numreplies threadlisting-header"> -        posts -    </div> -</div> -{%for thread in threads%} -<div class="threadlisting"> -    <div class="threadlisting-part threadlisting-part-title"><a href="{{url_for('thread.view_thread',thread_id=thread.id)}}">{{thread.title}}</a> -        {% if thread_tags[thread.id]|length > 0 %} -            <span class="only-small"> -                {% for the_tag in thread_tags[thread.id] %} -                    {{tag(the_tag)}} -                {% endfor %} -            </span> -        {%endif%} -    </div> -    <div class="threadlisting-part threadlisting-part-tags only-big"> -        {% for the_tag in thread_tags[thread.id] %} -            {{tag(the_tag)}} -        {% endfor %} -    </div> -    <div class="threadlisting-part threadlisting-part-creator">{{disp_user(thread.creator)}}</div> -    <div class="threadlisting-part threadlisting-part-created">{{ts(thread.created)}}</div> -    <div class="threadlisting-part threadlisting-part-updated">{{ts(thread.updated)}}</div> -    <div class="threadlisting-part threadlisting-part-lastactivityby">{{disp_user(thread.last_user)}}</div> -    <div class="threadlisting-part threadlisting-part-numreplies">{{thread.num_replies}}</div> -</div> -{%endfor%} +<div class="thread-list"> +	{%for thread in threads%} +		<div class="thread-listing"> +			<div class="thread-listing-main"> +				<div class="thread-listing-title"> +					<a href="{{url_for('thread.view_thread',thread_id=thread.id)}}"> +						{{- thread.title -}} +					</a> +				</div> +				<div class="thread-listing-tags"> +					{% for the_tag in thread_tags[thread.id] %} +						{{tag(the_tag)}} +					{% endfor %} +				</div> +				<div class="thread-listing-creation"> +					<div class="thread-listing-creator"> +						{{ disp_user(thread.creator) }}  +					</div> +					{{ ts(thread.created) }} +				</div> +			</div> +			{% if preview_post[thread.id] %} +				<div class="thread-preview"> +					{{ disp_user(preview_post[thread.id].author) }} +					<span class="thread-preview-ts"> +						{{ ts(preview_post[thread.id].created) }} +					</span> +					<span class="thread-preview-post"> +						<a href="{{post_url(preview_post[thread.id])}}"> +							{{ preview_post[thread.id].content[:500]|e }} +						</a> +					</span> +				</div> +			{% endif %} +		</div> +	{%endfor%}  </div>  </main>  {%endblock%} | 
