You've already forked snikket-web-portal
Compare commits
1 Commits
fix/rc2-ru
...
feature/ci
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
788ca73d86 |
@@ -28,6 +28,7 @@ from flask_babel import lazy_gettext as _l, _
|
||||
|
||||
from . import prosodyclient, _version
|
||||
from .infra import client, circle_name, BaseForm
|
||||
from .user import EAVATARTOOBIG
|
||||
|
||||
bp = Blueprint("admin", __name__, url_prefix="/admin")
|
||||
|
||||
@@ -443,6 +444,10 @@ class EditCircleForm(BaseForm):
|
||||
validators=[wtforms.validators.InputRequired()],
|
||||
)
|
||||
|
||||
avatar = wtforms.FileField(
|
||||
_l("Avatar")
|
||||
)
|
||||
|
||||
user_to_add = wtforms.SelectField(
|
||||
_l("Select user"),
|
||||
validate_choice=False,
|
||||
@@ -466,6 +471,8 @@ class EditCircleForm(BaseForm):
|
||||
@bp.route("/circle/<id_>", methods=["GET", "POST"])
|
||||
@client.require_admin_session()
|
||||
async def edit_circle(id_: str) -> typing.Union[str, werkzeug.Response]:
|
||||
max_avatar_size = current_app.config["MAX_AVATAR_SIZE"]
|
||||
|
||||
async with client.authenticated_session() as session:
|
||||
try:
|
||||
circle = await client.get_group_by_id(
|
||||
@@ -511,6 +518,20 @@ async def edit_circle(id_: str) -> typing.Union[str, werkzeug.Response]:
|
||||
id_,
|
||||
new_name=form.name.data,
|
||||
)
|
||||
file_info = (await request.files).get(form.avatar.name)
|
||||
if file_info is not None:
|
||||
mimetype = file_info.mimetype
|
||||
data = file_info.stream.read()
|
||||
if len(data) > max_avatar_size:
|
||||
form.avatar.errors.append(EAVATARTOOBIG)
|
||||
ok = False
|
||||
elif len(data) > 0:
|
||||
print("setting muc avatar")
|
||||
await client.set_muc_avatar(
|
||||
circle.muc_jid,
|
||||
data,
|
||||
mimetype,
|
||||
)
|
||||
await flash(
|
||||
_("Circle data updated"),
|
||||
"success",
|
||||
@@ -550,6 +571,9 @@ async def edit_circle(id_: str) -> typing.Union[str, werkzeug.Response]:
|
||||
form=form,
|
||||
circle_members=circle_members,
|
||||
invite_form=invite_form,
|
||||
max_avatar_size=max_avatar_size,
|
||||
avatar_too_big_warning_header=_l("Error"),
|
||||
avatar_too_big_warning=EAVATARTOOBIG,
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -1246,3 +1246,23 @@ class ProsodyClient:
|
||||
json=payload) as resp:
|
||||
self._raise_error_from_response(resp)
|
||||
resp.raise_for_status()
|
||||
|
||||
@autosession
|
||||
async def set_muc_avatar(
|
||||
self,
|
||||
muc_jid: str,
|
||||
data: bytes,
|
||||
mimetype: str,
|
||||
*,
|
||||
session: aiohttp.ClientSession,
|
||||
):
|
||||
xmpputil.extract_iq_reply(
|
||||
await self._xml_iq_call(
|
||||
session,
|
||||
xmpputil.make_muc_avatar_set_request(
|
||||
muc_jid,
|
||||
data,
|
||||
mimetype,
|
||||
),
|
||||
)
|
||||
)
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
{% extends "admin_app.html" %}
|
||||
{% from "library.j2" import form_button, standard_button, value_or_hint, custom_form_button, clipboard_button, icon %}
|
||||
{% from "library.j2" import form_button, standard_button, value_or_hint, custom_form_button, clipboard_button, icon, avatar with context %}
|
||||
{% block head_lead %}
|
||||
{{ super() }}
|
||||
{% include "copy-snippet.html" %}
|
||||
{% endblock %}
|
||||
{% block content %}
|
||||
<h1>{% trans circle_name=(target_circle | circle_name) %}Edit circle {{ circle_name }}{% endtrans %}</h1>
|
||||
<form method="POST">
|
||||
<form method="POST" enctype="multipart/form-data">
|
||||
{{- form.csrf_token -}}
|
||||
{%- if target_circle.id_ == "default" -%}
|
||||
<input type="hidden" name="{{ form.name.name }}" value="{{ form.name.data }}">{#- -#}
|
||||
@@ -39,6 +39,15 @@
|
||||
<p>{% trans %}This circle has no group chat associated.{% endtrans %}<p>
|
||||
{%- endif -%}
|
||||
</div>
|
||||
<div class="f-ebox">
|
||||
{{ form.avatar.label }}
|
||||
<div class="avatar-wrap">
|
||||
{{ form.avatar(accept="image/png",
|
||||
data_maxsize=max_avatar_size,
|
||||
data_warning_header=avatar_too_big_warning_header,
|
||||
data_maxsize_warning=avatar_too_big_warning) }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="f-bbox">
|
||||
{%- call standard_button("back", url_for(".circles"), class="tertiary") -%}
|
||||
{% trans %}Return to circle list{% endtrans %}
|
||||
|
||||
@@ -49,6 +49,8 @@ TAG_DATA_FORM_VALUE = "{{{}}}value".format(NS_DATA_FORM)
|
||||
FORM_NODE_CONFIG = "http://jabber.org/protocol/pubsub#node_config"
|
||||
FORM_FIELD_PUBSUB_ACCESS_MODEL = "pubsub#access_model"
|
||||
|
||||
NS_VCARD_TEMP = "vcard-temp"
|
||||
|
||||
|
||||
SimpleJID = typing.Tuple[typing.Optional[str], str, typing.Optional[str]]
|
||||
T = typing.TypeVar("T")
|
||||
@@ -226,6 +228,35 @@ def make_avatar_metadata_set_request(
|
||||
return req
|
||||
|
||||
|
||||
def make_muc_avatar_set_request(
|
||||
to: str,
|
||||
data: bytes,
|
||||
mimetype: str,
|
||||
) -> ET.Element:
|
||||
req = ET.Element("iq", type="set", to=to)
|
||||
vcard = ET.SubElement(
|
||||
req,
|
||||
"vCard",
|
||||
xmlns=NS_VCARD_TEMP,
|
||||
)
|
||||
photo_el = ET.SubElement(
|
||||
vcard,
|
||||
"PHOTO",
|
||||
xmlns=NS_VCARD_TEMP,
|
||||
)
|
||||
ET.SubElement(
|
||||
photo_el,
|
||||
"BINVAL",
|
||||
xmlns=NS_VCARD_TEMP,
|
||||
).text = base64.b64encode(data).decode("ascii")
|
||||
ET.SubElement(
|
||||
photo_el,
|
||||
"TYPE",
|
||||
xmlns=NS_VCARD_TEMP,
|
||||
).text = mimetype
|
||||
return req
|
||||
|
||||
|
||||
def _require_child(t: ET.Element, tag: str) -> ET.Element:
|
||||
el = t.find(tag)
|
||||
if el is None:
|
||||
|
||||
Reference in New Issue
Block a user