Mercurial > libervia-backend
view sat/plugins/plugin_xep_0446.py @ 3922:0ff265725489
plugin XEP-0447: handle attachment and download:
- plugin XEP-0447 can now be used in message attachments and to retrieve an attachment
- plugin attach: `attachment` being processed is added to `extra` so the handler can inspect it
- plugin attach: `size` is added to attachment
- plugin download: a whole attachment dict is now used in `download` and
`file_download`/`file_download_complete`. `download_uri` can be used as a shortcut when
just a URI is used. In addition to URI scheme handler, whole attachment handlers can now
be registered with `register_download_handler`
- plugin XEP-0363: `file_http_upload` `XEP-0363_upload_size` triggers have been renamed to
`XEP-0363_upload_pre_slot` and is now using a dict with arguments, allowing for the size
but also the filename to be modified, which is necessary for encryption (filename may
be hidden from URL this way).
- plugin XEP-0446: fix wrong element name
- plugin XEP-0447: source handler can now be registered (`url-data` is registered by
default)
- plugin XEP-0447: source parsing has been put in a separated `parse_sources_elt` method,
as it may be useful to do it independently (notably with XEP-0448)
- plugin XEP-0447: parse received message and complete attachments when suitable
- plugin XEP-0447: can now be used with message attachments
- plugin XEP-0447: can now be used with attachments download
- renamed `options` arguments to `extra` for consistency
- some style change (progressive move from legacy camelCase to PEP8 snake_case)
- some typing
rel 379
author | Goffi <goffi@goffi.org> |
---|---|
date | Thu, 06 Oct 2022 16:02:05 +0200 |
parents | dbf0c7faaf49 |
children | 524856bd7b19 |
line wrap: on
line source
#!/usr/bin/env python3 # Copyright (C) 2009-2022 Jérôme Poisson (goffi@goffi.org) # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Affero General Public License for more details. # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. from logging import exception from typing import Optional, Union, Tuple, Dict, Any from pathlib import Path from twisted.words.xish import domish from sat.core.constants import Const as C from sat.core.i18n import _ from sat.core.log import getLogger from sat.core import exceptions from sat.tools import utils log = getLogger(__name__) PLUGIN_INFO = { C.PI_NAME: "File Metadata Element", C.PI_IMPORT_NAME: "XEP-0446", C.PI_TYPE: "XEP", C.PI_MODES: C.PLUG_MODE_BOTH, C.PI_PROTOCOLS: ["XEP-0446"], C.PI_DEPENDENCIES: ["XEP-0300"], C.PI_MAIN: "XEP_0446", C.PI_HANDLER: "no", C.PI_DESCRIPTION: _("""Implementation of XEP-0446 (File Metadata Element)"""), } NS_FILE_METADATA = "urn:xmpp:file:metadata:0" class XEP_0446: def __init__(self, host): log.info(_("XEP-0446 (File Metadata Element) plugin initialization")) host.registerNamespace("file-metadata", NS_FILE_METADATA) self._hash = host.plugins["XEP-0300"] def get_file_metadata_elt( self, name: Optional[str] = None, media_type: Optional[str] = None, desc: Optional[str] = None, size: Optional[int] = None, file_hash: Optional[Tuple[str, str]] = None, date: Optional[Union[float, int]] = None, width: Optional[int] = None, height: Optional[int] = None, length: Optional[int] = None, thumbnail: Optional[str] = None, ) -> domish.Element: """Generate the element describing a file @param name: name of the file @param media_type: media-type @param desc: description @param size: size in bytes @param file_hash: (algo, hash) @param date: timestamp of the last modification datetime @param width: image width in pixels @param height: image height in pixels @param length: video length in seconds @param thumbnail: URL to a thumbnail @return: ``<file/>`` element """ if name: name = Path(name).name file_elt = domish.Element((NS_FILE_METADATA, "file")) for name, value in ( ("name", name), ("media-type", media_type), ("desc", desc), ("size", size), ("width", width), ("height", height), ("length", length), ): if value is not None: file_elt.addElement(name, content=str(value)) if file_hash is not None: hash_algo, hash_ = file_hash file_elt.addChild(self._hash.buildHashElt(hash_, hash_algo)) if date is not None: file_elt.addElement("date", utils.xmpp_date(date)) if thumbnail is not None: # TODO: implement thumbnails log.warning("thumbnail is not implemented yet") return file_elt def parse_file_metadata_elt( self, file_metadata_elt: domish.Element ) -> Dict[str, Any]: """Parse <file/> element @param file_metadata_elt: <file/> element a parent element can also be used @return: file metadata. It's a dict whose keys correspond to [get_file_metadata_elt] parameters @raise exceptions.NotFound: no <file/> element has been found """ if file_metadata_elt.name != "file": try: file_metadata_elt = next( file_metadata_elt.elements(NS_FILE_METADATA, "file") ) except StopIteration: raise exceptions.NotFound data: Dict[str, Any] = {} for key, type_ in ( ("name", str), ("media-type", str), ("desc", str), ("size", int), ("date", "timestamp"), ("width", int), ("height", int), ("length", int), ): elt = next(file_metadata_elt.elements(NS_FILE_METADATA, key), None) if elt is not None: if type_ in (str, int): content = str(elt) if key == "name": # we avoid malformed names or names containing path elements content = Path(content).name elif key == "media-type": key = "media_type" data[key] = type_(content) elif type == "timestamp": data[key] = utils.parse_xmpp_date(str(elt)) else: raise exceptions.InternalError try: algo, hash_ = self._hash.parseHashElt(file_metadata_elt) except exceptions.NotFound: pass except exceptions.DataError: from sat.tools.xml_tools import pFmtElt log.warning("invalid <hash/> element:\n{pFmtElt(file_metadata_elt)}") else: data["file_hash"] = (algo, hash_) # TODO: thumbnails return data