flaskbb-plugin-conversations 2.1.0.dev2__tar.gz → 3.0.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {flaskbb_plugin_conversations-2.1.0.dev2 → flaskbb_plugin_conversations-3.0.1}/.gitignore +4 -0
- {flaskbb_plugin_conversations-2.1.0.dev2 → flaskbb_plugin_conversations-3.0.1}/PKG-INFO +1 -1
- {flaskbb_plugin_conversations-2.1.0.dev2 → flaskbb_plugin_conversations-3.0.1}/conversations/__init__.py +7 -9
- {flaskbb_plugin_conversations-2.1.0.dev2 → flaskbb_plugin_conversations-3.0.1}/conversations/forms.py +2 -2
- {flaskbb_plugin_conversations-2.1.0.dev2 → flaskbb_plugin_conversations-3.0.1}/conversations/migrations/201802171929_0625bc75ab77_add_conversations.py +1 -1
- flaskbb_plugin_conversations-3.0.1/conversations/migrations/202602062122_1770409336_update_sqlalchemy_2.py +76 -0
- {flaskbb_plugin_conversations-2.1.0.dev2 → flaskbb_plugin_conversations-3.0.1}/conversations/models.py +2 -7
- flaskbb_plugin_conversations-3.0.1/conversations/py.typed +0 -0
- {flaskbb_plugin_conversations-2.1.0.dev2/conversations/templates → flaskbb_plugin_conversations-3.0.1/conversations/templates/conversations}/_inject_navlink.html +1 -1
- {flaskbb_plugin_conversations-2.1.0.dev2/conversations/templates → flaskbb_plugin_conversations-3.0.1/conversations/templates/conversations}/conversation.html +3 -3
- {flaskbb_plugin_conversations-2.1.0.dev2/conversations/templates → flaskbb_plugin_conversations-3.0.1/conversations/templates/conversations}/conversation_list.html +5 -4
- {flaskbb_plugin_conversations-2.1.0.dev2/conversations/templates → flaskbb_plugin_conversations-3.0.1/conversations/templates/conversations}/drafts.html +2 -2
- {flaskbb_plugin_conversations-2.1.0.dev2/conversations/templates → flaskbb_plugin_conversations-3.0.1/conversations/templates/conversations}/inbox.html +2 -2
- {flaskbb_plugin_conversations-2.1.0.dev2/conversations/templates → flaskbb_plugin_conversations-3.0.1/conversations/templates/conversations}/message_form.html +1 -1
- {flaskbb_plugin_conversations-2.1.0.dev2/conversations/templates → flaskbb_plugin_conversations-3.0.1/conversations/templates/conversations}/message_layout.html +21 -21
- {flaskbb_plugin_conversations-2.1.0.dev2/conversations/templates → flaskbb_plugin_conversations-3.0.1/conversations/templates/conversations}/sent.html +2 -2
- {flaskbb_plugin_conversations-2.1.0.dev2/conversations/templates → flaskbb_plugin_conversations-3.0.1/conversations/templates/conversations}/trash.html +2 -2
- flaskbb_plugin_conversations-3.0.1/conversations/translations/en/LC_MESSAGES/messages.po +185 -0
- {flaskbb_plugin_conversations-2.1.0.dev2 → flaskbb_plugin_conversations-3.0.1}/conversations/utils.py +0 -1
- {flaskbb_plugin_conversations-2.1.0.dev2 → flaskbb_plugin_conversations-3.0.1}/conversations/views.py +58 -61
- flaskbb_plugin_conversations-3.0.1/pyproject.toml +257 -0
- flaskbb_plugin_conversations-3.0.1/tests/test_views.py +166 -0
- flaskbb_plugin_conversations-2.1.0.dev2/conversations/migrations/202602062122_1770409336_update_sqlalchemy_2.py +0 -46
- flaskbb_plugin_conversations-2.1.0.dev2/conversations/translations/en/LC_MESSAGES/messages.po +0 -181
- flaskbb_plugin_conversations-2.1.0.dev2/pyproject.toml +0 -99
- {flaskbb_plugin_conversations-2.1.0.dev2 → flaskbb_plugin_conversations-3.0.1}/LICENSE +0 -0
- {flaskbb_plugin_conversations-2.1.0.dev2 → flaskbb_plugin_conversations-3.0.1}/README.md +0 -0
- {flaskbb_plugin_conversations-2.1.0.dev2 → flaskbb_plugin_conversations-3.0.1}/conversations/migrations/202607311750_1785520254_move_message_quota_setting.py +0 -0
- {flaskbb_plugin_conversations-2.1.0.dev2 → flaskbb_plugin_conversations-3.0.1}/conversations/migrations/__init__.py +0 -0
- {flaskbb_plugin_conversations-2.1.0.dev2/conversations/templates → flaskbb_plugin_conversations-3.0.1/conversations/templates/conversations}/_inject_new_message_button.html +0 -0
- {flaskbb_plugin_conversations-2.1.0.dev2/conversations/templates → flaskbb_plugin_conversations-3.0.1/conversations/templates/conversations}/_inject_new_message_link.html +0 -0
- {flaskbb_plugin_conversations-2.1.0.dev2 → flaskbb_plugin_conversations-3.0.1}/tests/conftest.py +0 -0
- {flaskbb_plugin_conversations-2.1.0.dev2 → flaskbb_plugin_conversations-3.0.1}/tests/test_message_models.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: flaskbb-plugin-conversations
|
|
3
|
-
Version:
|
|
3
|
+
Version: 3.0.1
|
|
4
4
|
Summary: A private messaging plugin for FlaskBB
|
|
5
5
|
Project-URL: Homepage, https://github.com/flaskbb/flaskbb-plugin-conversations
|
|
6
6
|
Project-URL: Repository, https://github.com/flaskbb/flaskbb-plugin-conversations
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
# -*- coding: utf-8 -*-
|
|
2
1
|
"""
|
|
3
2
|
conversations
|
|
4
3
|
~~~~~~~~~~~~~
|
|
@@ -10,11 +9,12 @@ A conversations Plugin for FlaskBB.
|
|
|
10
9
|
"""
|
|
11
10
|
|
|
12
11
|
import os
|
|
12
|
+
from typing import Any, cast
|
|
13
13
|
|
|
14
14
|
from flask import Flask
|
|
15
15
|
from flask_login import current_user
|
|
16
|
-
from flaskbb.settings.definitions import IntSetting, SettingGroup
|
|
17
16
|
from flaskbb.forum.models import Post
|
|
17
|
+
from flaskbb.settings.definitions import IntSetting, SettingGroup
|
|
18
18
|
from flaskbb.user.models import User
|
|
19
19
|
from flaskbb.utils.helpers import real, render_template
|
|
20
20
|
from pluggy import HookimplMarker
|
|
@@ -58,20 +58,18 @@ def flaskbb_load_translations():
|
|
|
58
58
|
|
|
59
59
|
@hookimpl
|
|
60
60
|
def flaskbb_load_blueprints(app: Flask):
|
|
61
|
-
app.register_blueprint(
|
|
62
|
-
conversations_bp, url_prefix="/conversations", template_dir="templates"
|
|
63
|
-
)
|
|
61
|
+
app.register_blueprint(conversations_bp, url_prefix="/conversations", template_dir="templates")
|
|
64
62
|
|
|
65
63
|
|
|
66
64
|
@hookimpl
|
|
67
65
|
def flaskbb_current_user(app: Flask, user: User):
|
|
68
|
-
|
|
66
|
+
cast(Any, user).message_count = get_message_count(user.id)
|
|
69
67
|
|
|
70
68
|
|
|
71
69
|
@hookimpl
|
|
72
70
|
def flaskbb_tpl_user_nav_loggedin_before():
|
|
73
71
|
return render_template(
|
|
74
|
-
"_inject_navlink.html",
|
|
72
|
+
"conversations/_inject_navlink.html",
|
|
75
73
|
unread_messages=get_latest_messages(real(current_user).id),
|
|
76
74
|
unread_count=get_unread_count(real(current_user).id),
|
|
77
75
|
)
|
|
@@ -79,9 +77,9 @@ def flaskbb_tpl_user_nav_loggedin_before():
|
|
|
79
77
|
|
|
80
78
|
@hookimpl(trylast=True)
|
|
81
79
|
def flaskbb_tpl_profile_actions(user: User):
|
|
82
|
-
return render_template("_inject_new_message_button.html", user=user)
|
|
80
|
+
return render_template("conversations/_inject_new_message_button.html", user=user)
|
|
83
81
|
|
|
84
82
|
|
|
85
83
|
@hookimpl(trylast=True)
|
|
86
84
|
def flaskbb_tpl_post_author_info_after(user: User, post: Post):
|
|
87
|
-
return render_template("_inject_new_message_link.html", user=user, post=post)
|
|
85
|
+
return render_template("conversations/_inject_new_message_link.html", user=user, post=post)
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
# -*- coding: utf-8 -*-
|
|
2
1
|
"""
|
|
3
2
|
conversations.views
|
|
4
3
|
~~~~~~~~~~~~~~~~~~~
|
|
@@ -17,6 +16,7 @@ from flask_babelplus import lazy_gettext as _
|
|
|
17
16
|
from flask_login import current_user
|
|
18
17
|
from flask_wtf import FlaskForm
|
|
19
18
|
from flaskbb.user.models import User
|
|
19
|
+
from flaskbb.utils.helpers import real
|
|
20
20
|
from wtforms import Field, StringField, SubmitField, TextAreaField, ValidationError
|
|
21
21
|
from wtforms.validators import DataRequired
|
|
22
22
|
|
|
@@ -48,7 +48,7 @@ class ConversationForm(FlaskForm):
|
|
|
48
48
|
user = User.get_by(username=field.data)
|
|
49
49
|
if not user:
|
|
50
50
|
raise ValidationError(_("The username you entered does not exist."))
|
|
51
|
-
if user.id == current_user.id:
|
|
51
|
+
if user.id == real(current_user).id:
|
|
52
52
|
raise ValidationError(_("You cannot send a PM to yourself."))
|
|
53
53
|
|
|
54
54
|
def save(
|
|
@@ -21,7 +21,7 @@ def upgrade():
|
|
|
21
21
|
# ### commands auto generated by Alembic - please adjust! ###
|
|
22
22
|
con = op.get_bind()
|
|
23
23
|
|
|
24
|
-
if not sa.inspect(con
|
|
24
|
+
if not sa.inspect(con).has_table("conversations"):
|
|
25
25
|
op.create_table(
|
|
26
26
|
"conversations",
|
|
27
27
|
sa.Column("id", sa.Integer(), nullable=False),
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
"""Update SQLAlchemy 2
|
|
2
|
+
|
|
3
|
+
Revision ID: 1770409336
|
|
4
|
+
Revises: 0625bc75ab77
|
|
5
|
+
Create Date: 2026-02-06 21:22:16.464657
|
|
6
|
+
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
import sqlalchemy as sa
|
|
10
|
+
from alembic import op
|
|
11
|
+
|
|
12
|
+
# revision identifiers, used by Alembic.
|
|
13
|
+
revision = "1770409336"
|
|
14
|
+
down_revision = "0625bc75ab77"
|
|
15
|
+
branch_labels = ()
|
|
16
|
+
depends_on = None
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def upgrade():
|
|
20
|
+
# Version 1.x stored the 16 UUID bytes, sa.Uuid() stores 32 hex characters
|
|
21
|
+
# on MySQL and SQLite
|
|
22
|
+
bind = op.get_bind()
|
|
23
|
+
if bind.dialect.name == "sqlite":
|
|
24
|
+
# the column has NUMERIC affinity until the rebuild, which would turn
|
|
25
|
+
# hex strings like "1234e567..." into numbers - the "x" prevents that
|
|
26
|
+
op.execute(
|
|
27
|
+
"UPDATE conversations SET shared_id = 'x' || lower(hex(shared_id)) "
|
|
28
|
+
"WHERE typeof(shared_id) = 'blob'"
|
|
29
|
+
)
|
|
30
|
+
elif bind.dialect.name == "mysql":
|
|
31
|
+
shared_id = next(
|
|
32
|
+
column
|
|
33
|
+
for column in sa.inspect(bind).get_columns("conversations")
|
|
34
|
+
if column["name"] == "shared_id"
|
|
35
|
+
)
|
|
36
|
+
if isinstance(shared_id["type"], sa.BINARY):
|
|
37
|
+
op.alter_column(
|
|
38
|
+
"conversations",
|
|
39
|
+
"shared_id",
|
|
40
|
+
existing_type=shared_id["type"],
|
|
41
|
+
type_=sa.VARBINARY(32),
|
|
42
|
+
existing_nullable=False,
|
|
43
|
+
)
|
|
44
|
+
op.execute("UPDATE conversations SET shared_id = LOWER(HEX(shared_id))")
|
|
45
|
+
|
|
46
|
+
with op.batch_alter_table("conversations", schema=None) as batch_op:
|
|
47
|
+
batch_op.alter_column(
|
|
48
|
+
"shared_id",
|
|
49
|
+
existing_type=sa.NUMERIC(precision=16),
|
|
50
|
+
type_=sa.Uuid(),
|
|
51
|
+
existing_nullable=False,
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
if bind.dialect.name == "sqlite":
|
|
55
|
+
op.execute(
|
|
56
|
+
"UPDATE conversations SET shared_id = substr(shared_id, 2) WHERE shared_id LIKE 'x%'"
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
with op.batch_alter_table("messages", schema=None) as batch_op:
|
|
60
|
+
batch_op.alter_column("message", existing_type=sa.TEXT(), nullable=True)
|
|
61
|
+
# ### end Alembic commands ###
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def downgrade():
|
|
65
|
+
with op.batch_alter_table("messages", schema=None) as batch_op:
|
|
66
|
+
batch_op.alter_column("message", existing_type=sa.TEXT(), nullable=False)
|
|
67
|
+
|
|
68
|
+
with op.batch_alter_table("conversations", schema=None) as batch_op:
|
|
69
|
+
batch_op.alter_column(
|
|
70
|
+
"shared_id",
|
|
71
|
+
existing_type=sa.Uuid(),
|
|
72
|
+
type_=sa.NUMERIC(precision=16),
|
|
73
|
+
existing_nullable=False,
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
# ### end Alembic commands ###
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
# -*- coding: utf-8 -*-
|
|
2
1
|
"""
|
|
3
2
|
conversations.views
|
|
4
3
|
~~~~~~~~~~~~~~~~~~~
|
|
@@ -72,14 +71,10 @@ class Conversation(BaseModel):
|
|
|
72
71
|
)
|
|
73
72
|
|
|
74
73
|
# the user to whom the conversation is addressed
|
|
75
|
-
to_user: Mapped[User] = relationship(
|
|
76
|
-
"User", lazy="joined", foreign_keys=[to_user_id]
|
|
77
|
-
)
|
|
74
|
+
to_user: Mapped[User] = relationship("User", lazy="joined", foreign_keys=[to_user_id])
|
|
78
75
|
|
|
79
76
|
# the user who sent the message
|
|
80
|
-
from_user: Mapped[User] = relationship(
|
|
81
|
-
"User", lazy="joined", foreign_keys=[from_user_id]
|
|
82
|
-
)
|
|
77
|
+
from_user: Mapped[User] = relationship("User", lazy="joined", foreign_keys=[from_user_id])
|
|
83
78
|
|
|
84
79
|
@property
|
|
85
80
|
def first_message(self):
|
|
File without changes
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
{% if request.endpoint and request.endpoint.startswith("conversations_bp") %}active{% endif %}
|
|
3
3
|
{%- endmacro -%}
|
|
4
4
|
|
|
5
|
-
<ul class="navbar-nav me-2">
|
|
5
|
+
<ul class="navbar-nav me-2" id="conversations-nav">
|
|
6
6
|
<li class="nav-item dropdown">
|
|
7
7
|
<a class="nav-link dropdown-toggle {{ is_active() }}" href="#" id="navbarConvDropdown" role="button" data-bs-toggle="dropdown" aria-expanded="false">
|
|
8
8
|
<span class="fas fa-envelope fa-fw"></span> {% trans %}Inbox{% endtrans %}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
{% extends theme("message_layout.html") %}
|
|
1
|
+
{% extends theme("conversations/message_layout.html") %}
|
|
2
2
|
|
|
3
3
|
{% block message_content %}
|
|
4
4
|
{# quick check if the conversation is a draft #}
|
|
@@ -61,7 +61,7 @@
|
|
|
61
61
|
{% if conversation.draft %}
|
|
62
62
|
<p class="text-right"><a href="{{ url_for('conversations_bp.edit_conversation', conversation_id=conversation.id) }}" class="btn btn-primary btn-sm"><i class="fa fa-pencil"></i> edit</a></p>
|
|
63
63
|
{% else %}
|
|
64
|
-
<p class="{% if current_user.id == message.user_id %}left{% else %}right{% endif %}"><a href="#" class="btn btn-outline-dark btn-sm reply-btn" data-
|
|
64
|
+
<p class="{% if current_user.id == message.user_id %}left{% else %}right{% endif %}"><a href="#" class="btn btn-outline-dark btn-sm reply-btn" data-raw-url="{{ url_for('conversations_bp.raw_message', message_id=message.id) }}"><i class="fa fa-reply"></i> reply</a></p>
|
|
65
65
|
{% endif %}
|
|
66
66
|
</div>
|
|
67
67
|
|
|
@@ -112,7 +112,7 @@
|
|
|
112
112
|
|
|
113
113
|
{% if not conversation.draft and conversation.from_user != None and conversation.to_user != None %}
|
|
114
114
|
{% from "_macros/form.html" import render_editor_field, render_submit_field %}
|
|
115
|
-
<form action="#"
|
|
115
|
+
<form method="post" action="{{ url_for('conversations_bp.view_conversation', conversation_id=conversation.id) }}" hx-post="{{ url_for('conversations_bp.view_conversation', conversation_id=conversation.id) }}" hx-target="#message-content" hx-select="#message-content" hx-swap="outerHTML" hx-select-oob="#flashed-messages">
|
|
116
116
|
{{ form.hidden_tag() }}
|
|
117
117
|
<div class="row pt-3">
|
|
118
118
|
<div class="col-10 offset-2">
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
{% from theme('_macros/pagination.html') import generate_obj_id %}
|
|
2
|
-
|
|
2
|
+
{# the actions refresh the list, the navbar's unread messages and the flashed messages #}
|
|
3
|
+
<div class="card conversation mb-3" hx-target="#message-content" hx-select="#message-content" hx-swap="outerHTML" hx-select-oob="#flashed-messages,#conversations-nav">
|
|
3
4
|
<div class="card-header conversation-header">
|
|
4
5
|
<div class="row">
|
|
5
6
|
<div class="col me-auto">
|
|
@@ -64,7 +65,7 @@
|
|
|
64
65
|
<!-- actions -->
|
|
65
66
|
<div class="conversation-actions">
|
|
66
67
|
{% if include_move %}
|
|
67
|
-
<form class="d-inline" method="POST" action="{{ url_for('conversations_bp.move_conversation', conversation_id=conversation.id) }}">
|
|
68
|
+
<form class="d-inline" method="POST" action="{{ url_for('conversations_bp.move_conversation', conversation_id=conversation.id) }}" hx-post="{{ url_for('conversations_bp.move_conversation', conversation_id=conversation.id) }}">
|
|
68
69
|
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}" />
|
|
69
70
|
<button type="submit" class="btn btn-info btn-xs" title="Move to Trash" data-bs-toggle="tooltip">
|
|
70
71
|
<span class="fas fa-archive"></span>
|
|
@@ -73,7 +74,7 @@
|
|
|
73
74
|
{% endif %}
|
|
74
75
|
|
|
75
76
|
{% if include_delete %}
|
|
76
|
-
<form class="d-inline" method="POST" action="{{ url_for('conversations_bp.delete_conversation', conversation_id=conversation.id) }}">
|
|
77
|
+
<form class="d-inline" method="POST" action="{{ url_for('conversations_bp.delete_conversation', conversation_id=conversation.id) }}" hx-post="{{ url_for('conversations_bp.delete_conversation', conversation_id=conversation.id) }}" hx-confirm="{{ _('Are you sure?') }}">
|
|
77
78
|
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}" />
|
|
78
79
|
<button type="submit" class="btn btn-danger btn-xs" title="Delete this conversation" data-bs-toggle="tooltip">
|
|
79
80
|
<span class="fas fa-trash-alt"></span>
|
|
@@ -82,7 +83,7 @@
|
|
|
82
83
|
{% endif %}
|
|
83
84
|
|
|
84
85
|
{% if include_restore %}
|
|
85
|
-
<form class="d-inline" method="POST" action="{{ url_for('conversations_bp.restore_conversation', conversation_id=conversation.id) }}">
|
|
86
|
+
<form class="d-inline" method="POST" action="{{ url_for('conversations_bp.restore_conversation', conversation_id=conversation.id) }}" hx-post="{{ url_for('conversations_bp.restore_conversation', conversation_id=conversation.id) }}">
|
|
86
87
|
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}" />
|
|
87
88
|
<button type="submit" class="btn btn-success btn-xs" title="Restore this conversation" data-bs-toggle="tooltip">
|
|
88
89
|
<span class="fas fa-undo"></span>
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{% set page_title = _("Drafts") %}
|
|
2
2
|
|
|
3
3
|
{% from theme('_macros/pagination.html') import render_pagination %}
|
|
4
|
-
{% extends theme("message_layout.html") %}
|
|
4
|
+
{% extends theme("conversations/message_layout.html") %}
|
|
5
5
|
{% block message_content %}
|
|
6
6
|
|
|
7
7
|
{% set include_move = True %}
|
|
8
8
|
{% set include_edit = True %}
|
|
9
|
-
{% include theme("conversation_list.html") %}
|
|
9
|
+
{% include theme("conversations/conversation_list.html") %}
|
|
10
10
|
|
|
11
11
|
{{ render_pagination(conversations, url_for("conversations_bp.drafts")) }}
|
|
12
12
|
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
{% set page_title = _("Inbox") %}
|
|
2
2
|
|
|
3
3
|
{% from theme('_macros/pagination.html') import render_pagination %}
|
|
4
|
-
{% extends theme("message_layout.html") %}
|
|
4
|
+
{% extends theme("conversations/message_layout.html") %}
|
|
5
5
|
{% block message_content %}
|
|
6
6
|
|
|
7
7
|
{% set include_move = True %}
|
|
8
|
-
{% include theme("conversation_list.html") %}
|
|
8
|
+
{% include theme("conversations/conversation_list.html") %}
|
|
9
9
|
|
|
10
10
|
{{ render_pagination(conversations, url_for("conversations_bp.inbox")) }}
|
|
11
11
|
|
|
@@ -22,7 +22,8 @@
|
|
|
22
22
|
</ul>
|
|
23
23
|
</div><!--/.sidebar -->
|
|
24
24
|
</div><!--/.col-sm-3 -->
|
|
25
|
-
|
|
25
|
+
{# replaced by the htmx requests of the conversation list and the reply form #}
|
|
26
|
+
<div class="col-sm-9 col-md-10" id="message-content">
|
|
26
27
|
{% block message_content %}{% endblock %}
|
|
27
28
|
</div><!--/.col-sm-9 -->
|
|
28
29
|
</div><!--/.row -->
|
|
@@ -30,26 +31,25 @@
|
|
|
30
31
|
|
|
31
32
|
{% block scripts %}
|
|
32
33
|
<script>
|
|
33
|
-
// Reply conversation
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
34
|
+
// Reply conversation. delegated, so it keeps working on the messages htmx
|
|
35
|
+
// swapped in after a reply was sent
|
|
36
|
+
document.addEventListener("click", (event) => {
|
|
37
|
+
const button = event.target.closest(".reply-btn");
|
|
38
|
+
if (!button) return;
|
|
39
|
+
event.preventDefault();
|
|
39
40
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
);
|
|
41
|
+
const editor = document.querySelector(".flaskbb-editor");
|
|
42
|
+
fetch(button.dataset.rawUrl)
|
|
43
|
+
.then((response) => response.text())
|
|
44
|
+
.then((data) => {
|
|
45
|
+
editor.value = data;
|
|
46
|
+
editor.selectionStart = editor.selectionEnd = editor.value.length;
|
|
47
|
+
editor.scrollTop = editor.scrollHeight;
|
|
48
|
+
window.location.href = "#content";
|
|
49
|
+
})
|
|
50
|
+
.catch((error) => {
|
|
51
|
+
console.error("something bad happened", error);
|
|
52
|
+
});
|
|
53
|
+
});
|
|
54
54
|
</script>
|
|
55
55
|
{% endblock %}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
{% set page_title = _("Sent Messages") %}
|
|
2
2
|
|
|
3
3
|
{% from theme('_macros/pagination.html') import render_pagination %}
|
|
4
|
-
{% extends theme("message_layout.html") %}
|
|
4
|
+
{% extends theme("conversations/message_layout.html") %}
|
|
5
5
|
{% block message_content %}
|
|
6
6
|
|
|
7
7
|
{% set include_move = True %}
|
|
8
|
-
{% include theme("conversation_list.html") %}
|
|
8
|
+
{% include theme("conversations/conversation_list.html") %}
|
|
9
9
|
|
|
10
10
|
{{ render_pagination(conversations, url_for("conversations_bp.sent")) }}
|
|
11
11
|
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{% set page_title = _("Trash") %}
|
|
2
2
|
|
|
3
3
|
{% from theme('_macros/pagination.html') import render_pagination %}
|
|
4
|
-
{% extends theme("message_layout.html") %}
|
|
4
|
+
{% extends theme("conversations/message_layout.html") %}
|
|
5
5
|
{% block message_content %}
|
|
6
6
|
|
|
7
7
|
{% set include_restore = True %}
|
|
8
8
|
{% set include_delete = True %}
|
|
9
|
-
{% include theme("conversation_list.html") %}
|
|
9
|
+
{% include theme("conversations/conversation_list.html") %}
|
|
10
10
|
|
|
11
11
|
{{ render_pagination(conversations, url_for("conversations_bp.trash")) }}
|
|
12
12
|
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
# English translations for PROJECT.
|
|
2
|
+
# Copyright (C) 2018 ORGANIZATION
|
|
3
|
+
# This file is distributed under the same license as the PROJECT project.
|
|
4
|
+
# FIRST AUTHOR <EMAIL@ADDRESS>, 2018.
|
|
5
|
+
#
|
|
6
|
+
msgid ""
|
|
7
|
+
msgstr ""
|
|
8
|
+
"Project-Id-Version: PROJECT VERSION\n"
|
|
9
|
+
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
|
10
|
+
"POT-Creation-Date: 2026-09-14 21:28+0200\n"
|
|
11
|
+
"PO-Revision-Date: 2018-02-23 13:30+0100\n"
|
|
12
|
+
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
|
13
|
+
"Language: en\n"
|
|
14
|
+
"Language-Team: en <LL@li.org>\n"
|
|
15
|
+
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
|
16
|
+
"MIME-Version: 1.0\n"
|
|
17
|
+
"Content-Type: text/plain; charset=utf-8\n"
|
|
18
|
+
"Content-Transfer-Encoding: 8bit\n"
|
|
19
|
+
"Generated-By: Babel 2.18.0\n"
|
|
20
|
+
|
|
21
|
+
#: conversations/forms.py:30
|
|
22
|
+
msgid "Recipient"
|
|
23
|
+
msgstr ""
|
|
24
|
+
|
|
25
|
+
#: conversations/forms.py:31
|
|
26
|
+
msgid "A valid username is required."
|
|
27
|
+
msgstr ""
|
|
28
|
+
|
|
29
|
+
#: conversations/forms.py:35
|
|
30
|
+
msgid "Subject"
|
|
31
|
+
msgstr ""
|
|
32
|
+
|
|
33
|
+
#: conversations/forms.py:36
|
|
34
|
+
msgid "A Subject is required."
|
|
35
|
+
msgstr ""
|
|
36
|
+
|
|
37
|
+
#: conversations/forms.py:40 conversations/forms.py:78
|
|
38
|
+
#: conversations/templates/conversations/_inject_new_message_button.html:3
|
|
39
|
+
#: conversations/templates/conversations/_inject_new_message_link.html:3
|
|
40
|
+
#: conversations/templates/conversations/conversation.html:93
|
|
41
|
+
msgid "Message"
|
|
42
|
+
msgstr ""
|
|
43
|
+
|
|
44
|
+
#: conversations/forms.py:41 conversations/forms.py:79
|
|
45
|
+
msgid "A message is required."
|
|
46
|
+
msgstr ""
|
|
47
|
+
|
|
48
|
+
#: conversations/forms.py:44
|
|
49
|
+
msgid "Start Conversation"
|
|
50
|
+
msgstr ""
|
|
51
|
+
|
|
52
|
+
#: conversations/forms.py:45
|
|
53
|
+
msgid "Save Conversation"
|
|
54
|
+
msgstr ""
|
|
55
|
+
|
|
56
|
+
#: conversations/forms.py:50
|
|
57
|
+
msgid "The username you entered does not exist."
|
|
58
|
+
msgstr ""
|
|
59
|
+
|
|
60
|
+
#: conversations/forms.py:52
|
|
61
|
+
msgid "You cannot send a PM to yourself."
|
|
62
|
+
msgstr ""
|
|
63
|
+
|
|
64
|
+
#: conversations/forms.py:81
|
|
65
|
+
msgid "Send Message"
|
|
66
|
+
msgstr ""
|
|
67
|
+
|
|
68
|
+
#: conversations/views.py:56
|
|
69
|
+
msgid ""
|
|
70
|
+
"You cannot send any messages anymore because you have reached your "
|
|
71
|
+
"message limit."
|
|
72
|
+
msgstr ""
|
|
73
|
+
|
|
74
|
+
#: conversations/views.py:174 conversations/views.py:230
|
|
75
|
+
msgid "Compose Message"
|
|
76
|
+
msgstr ""
|
|
77
|
+
|
|
78
|
+
#: conversations/views.py:193 conversations/views.py:282
|
|
79
|
+
msgid "Message saved."
|
|
80
|
+
msgstr ""
|
|
81
|
+
|
|
82
|
+
#: conversations/views.py:226 conversations/views.py:307
|
|
83
|
+
msgid "Message sent."
|
|
84
|
+
msgstr ""
|
|
85
|
+
|
|
86
|
+
#: conversations/views.py:245 conversations/views.py:264
|
|
87
|
+
msgid "You cannot edit a sent message."
|
|
88
|
+
msgstr ""
|
|
89
|
+
|
|
90
|
+
#: conversations/views.py:254 conversations/views.py:315
|
|
91
|
+
msgid "Edit Message"
|
|
92
|
+
msgstr ""
|
|
93
|
+
|
|
94
|
+
#: conversations/templates/conversations/_inject_navlink.html:8
|
|
95
|
+
#: conversations/templates/conversations/_inject_navlink.html:34
|
|
96
|
+
#: conversations/templates/conversations/inbox.html:1
|
|
97
|
+
#: conversations/templates/conversations/message_layout.html:18
|
|
98
|
+
msgid "Inbox"
|
|
99
|
+
msgstr ""
|
|
100
|
+
|
|
101
|
+
#: conversations/templates/conversations/_inject_navlink.html:23
|
|
102
|
+
#: conversations/templates/conversations/conversation.html:101
|
|
103
|
+
#: conversations/templates/conversations/conversation_list.html:50
|
|
104
|
+
#: conversations/templates/conversations/conversation_list.html:57
|
|
105
|
+
msgid "Deleted User"
|
|
106
|
+
msgstr ""
|
|
107
|
+
|
|
108
|
+
#: conversations/templates/conversations/_inject_navlink.html:31
|
|
109
|
+
msgid "No unread messages."
|
|
110
|
+
msgstr ""
|
|
111
|
+
|
|
112
|
+
#: conversations/templates/conversations/_inject_navlink.html:35
|
|
113
|
+
#: conversations/templates/conversations/message_layout.html:16
|
|
114
|
+
msgid "New Message"
|
|
115
|
+
msgstr ""
|
|
116
|
+
|
|
117
|
+
#: conversations/templates/conversations/conversation.html:39
|
|
118
|
+
#: conversations/templates/conversations/conversation.html:90
|
|
119
|
+
msgid "Joined"
|
|
120
|
+
msgstr ""
|
|
121
|
+
|
|
122
|
+
#: conversations/templates/conversations/conversation.html:40
|
|
123
|
+
#: conversations/templates/conversations/conversation.html:91
|
|
124
|
+
msgid "Posts"
|
|
125
|
+
msgstr ""
|
|
126
|
+
|
|
127
|
+
#: conversations/templates/conversations/conversation.html:43
|
|
128
|
+
#: conversations/templates/conversations/conversation.html:97
|
|
129
|
+
msgid "Website"
|
|
130
|
+
msgstr ""
|
|
131
|
+
|
|
132
|
+
#: conversations/templates/conversations/conversation.html:102
|
|
133
|
+
msgid "Guest"
|
|
134
|
+
msgstr ""
|
|
135
|
+
|
|
136
|
+
#: conversations/templates/conversations/conversation_list.html:7
|
|
137
|
+
msgid "Conversations"
|
|
138
|
+
msgstr ""
|
|
139
|
+
|
|
140
|
+
#: conversations/templates/conversations/conversation_list.html:46
|
|
141
|
+
msgid "From"
|
|
142
|
+
msgstr ""
|
|
143
|
+
|
|
144
|
+
#: conversations/templates/conversations/conversation_list.html:53
|
|
145
|
+
msgid "to"
|
|
146
|
+
msgstr ""
|
|
147
|
+
|
|
148
|
+
#: conversations/templates/conversations/conversation_list.html:59
|
|
149
|
+
msgid "on"
|
|
150
|
+
msgstr ""
|
|
151
|
+
|
|
152
|
+
#: conversations/templates/conversations/conversation_list.html:77
|
|
153
|
+
msgid "Are you sure?"
|
|
154
|
+
msgstr ""
|
|
155
|
+
|
|
156
|
+
#: conversations/templates/conversations/conversation_list.html:105
|
|
157
|
+
msgid "No conversations found."
|
|
158
|
+
msgstr ""
|
|
159
|
+
|
|
160
|
+
#: conversations/templates/conversations/drafts.html:1
|
|
161
|
+
#: conversations/templates/conversations/message_layout.html:20
|
|
162
|
+
msgid "Drafts"
|
|
163
|
+
msgstr ""
|
|
164
|
+
|
|
165
|
+
#: conversations/templates/conversations/message_layout.html:6
|
|
166
|
+
msgid "Forum"
|
|
167
|
+
msgstr ""
|
|
168
|
+
|
|
169
|
+
#: conversations/templates/conversations/message_layout.html:8
|
|
170
|
+
msgid "Private Message"
|
|
171
|
+
msgstr ""
|
|
172
|
+
|
|
173
|
+
#: conversations/templates/conversations/message_layout.html:19
|
|
174
|
+
msgid "Sent"
|
|
175
|
+
msgstr ""
|
|
176
|
+
|
|
177
|
+
#: conversations/templates/conversations/message_layout.html:21
|
|
178
|
+
#: conversations/templates/conversations/trash.html:1
|
|
179
|
+
msgid "Trash"
|
|
180
|
+
msgstr ""
|
|
181
|
+
|
|
182
|
+
#: conversations/templates/conversations/sent.html:1
|
|
183
|
+
msgid "Sent Messages"
|
|
184
|
+
msgstr ""
|
|
185
|
+
|