component AP gateway: handle attachments
This commit is contained in:
parent
072f0cc723
commit
c3f97ec712
13 changed files with 168 additions and 97 deletions
|
|
@ -132,11 +132,6 @@ class Const(object):
|
|||
MESS_KEY_ENCRYPTED = "encrypted"
|
||||
MESS_KEY_TRUSTED = "trusted"
|
||||
|
||||
MESS_KEY_ATTACHMENTS = "attachments"
|
||||
MESS_KEY_ATTACHMENTS_MEDIA_TYPE = "media_type"
|
||||
MESS_KEY_ATTACHMENTS_PREVIEW = "preview"
|
||||
MESS_KEY_ATTACHMENTS_RESIZE = "resize"
|
||||
|
||||
# File encryption algorithms
|
||||
ENC_AES_GCM = "AES-GCM"
|
||||
|
||||
|
|
@ -368,6 +363,11 @@ class Const(object):
|
|||
## Common data keys ##
|
||||
KEY_THUMBNAILS = "thumbnails"
|
||||
KEY_PROGRESS_ID = "progress_id"
|
||||
KEY_ATTACHMENTS = "attachments"
|
||||
KEY_ATTACHMENTS_MEDIA_TYPE = "media_type"
|
||||
KEY_ATTACHMENTS_PREVIEW = "preview"
|
||||
KEY_ATTACHMENTS_RESIZE = "resize"
|
||||
|
||||
|
||||
## Common extra keys/values ##
|
||||
KEY_ORDER_BY = "order_by"
|
||||
|
|
|
|||
|
|
@ -821,7 +821,7 @@ class SatXMPPEntity(core_types.SatXMPPEntity):
|
|||
"""Return True if a message contain payload to show in frontends"""
|
||||
return (
|
||||
mess_data["message"] or mess_data["subject"]
|
||||
or mess_data["extra"].get(C.MESS_KEY_ATTACHMENTS)
|
||||
or mess_data["extra"].get(C.KEY_ATTACHMENTS)
|
||||
or mess_data["type"] == C.MESS_TYPE_INFO
|
||||
)
|
||||
|
||||
|
|
@ -1361,16 +1361,16 @@ class SatMessageProtocol(xmppim.MessageProtocol):
|
|||
|
||||
def completeAttachments(self, data):
|
||||
"""Complete missing metadata of attachments"""
|
||||
for attachment in data['extra'].get(C.MESS_KEY_ATTACHMENTS, []):
|
||||
for attachment in data['extra'].get(C.KEY_ATTACHMENTS, []):
|
||||
if "name" not in attachment and "url" in attachment:
|
||||
name = (Path(unquote(urlparse(attachment['url']).path)).name
|
||||
or C.FILE_DEFAULT_NAME)
|
||||
attachment["name"] = name
|
||||
if ((C.MESS_KEY_ATTACHMENTS_MEDIA_TYPE not in attachment
|
||||
if ((C.KEY_ATTACHMENTS_MEDIA_TYPE not in attachment
|
||||
and "name" in attachment)):
|
||||
media_type = mimetypes.guess_type(attachment['name'], strict=False)[0]
|
||||
if media_type:
|
||||
attachment[C.MESS_KEY_ATTACHMENTS_MEDIA_TYPE] = media_type
|
||||
attachment[C.KEY_ATTACHMENTS_MEDIA_TYPE] = media_type
|
||||
|
||||
return data
|
||||
|
||||
|
|
|
|||
|
|
@ -109,7 +109,7 @@ PLUGIN_INFO = {
|
|||
C.PI_DEPENDENCIES: [
|
||||
"XEP-0050", "XEP-0054", "XEP-0060", "XEP-0084", "XEP-0106", "XEP-0277",
|
||||
"XEP-0292", "XEP-0329", "XEP-0372", "XEP-0424", "XEP-0465", "XEP-0470",
|
||||
"PUBSUB_CACHE", "TEXT_SYNTAXES", "IDENTITY", "EVENTS"
|
||||
"XEP-0447", "PUBSUB_CACHE", "TEXT_SYNTAXES", "IDENTITY", "EVENTS"
|
||||
],
|
||||
C.PI_RECOMMENDATIONS: [],
|
||||
C.PI_MAIN: "APGateway",
|
||||
|
|
@ -131,7 +131,7 @@ class APGateway:
|
|||
# 1: log POST objects
|
||||
# 2: log POST and GET objects
|
||||
# 3: log POST and GET objects with HTTP headers for GET requests
|
||||
verbose = 0
|
||||
verbose = 3
|
||||
|
||||
def __init__(self, host):
|
||||
self.host = host
|
||||
|
|
@ -144,11 +144,12 @@ class APGateway:
|
|||
self._v = host.plugins["XEP-0292"]
|
||||
self._refs = host.plugins["XEP-0372"]
|
||||
self._r = host.plugins["XEP-0424"]
|
||||
self._sfs = host.plugins["XEP-0447"]
|
||||
self._pps = host.plugins["XEP-0465"]
|
||||
self._pa = host.plugins["XEP-0470"]
|
||||
self._c = host.plugins["PUBSUB_CACHE"]
|
||||
self._t = host.plugins["TEXT_SYNTAXES"]
|
||||
self._i = host.plugins["IDENTITY"]
|
||||
self._pa = host.plugins["XEP-0470"]
|
||||
self._events = host.plugins["EVENTS"]
|
||||
self._p.addManagedNode(
|
||||
"",
|
||||
|
|
@ -487,7 +488,7 @@ class APGateway:
|
|||
return ap_item["object"]
|
||||
else:
|
||||
# this is a blog item
|
||||
mb_data = await self._m.item2mbdata(
|
||||
mb_data = await self._m.item_2_mb_data(
|
||||
self.client, found_item, author_jid, node
|
||||
)
|
||||
ap_item = await self.mb_data_2_ap_item(self.client, mb_data)
|
||||
|
|
@ -901,7 +902,7 @@ class APGateway:
|
|||
pub_key = serialization.load_pem_public_key(pub_key_pem.encode())
|
||||
return key_id, owner, pub_key
|
||||
|
||||
def createActivity(
|
||||
def create_activity(
|
||||
self,
|
||||
activity: str,
|
||||
actor_id: str,
|
||||
|
|
@ -1094,7 +1095,7 @@ class APGateway:
|
|||
)
|
||||
else:
|
||||
# blog item
|
||||
mb_data = await self._m.item2mbdata(client, item, service, node)
|
||||
mb_data = await self._m.item_2_mb_data(client, item, service, node)
|
||||
author_jid = jid.JID(mb_data["author_jid"])
|
||||
if subscribe_extra_nodes and not self.isVirtualJID(author_jid):
|
||||
# we subscribe automatically to comment nodes if any
|
||||
|
|
@ -1232,7 +1233,7 @@ class APGateway:
|
|||
if not "noticed" in old_attachment:
|
||||
# new "noticed" attachment, we translate to "Like" activity
|
||||
activity_id = self.buildAPURL("like", item_account, item_id)
|
||||
activity = self.createActivity(
|
||||
activity = self.create_activity(
|
||||
TYPE_LIKE, publisher_actor_id, item_url, activity_id=activity_id
|
||||
)
|
||||
activity["to"] = [ap_account]
|
||||
|
|
@ -1242,12 +1243,12 @@ class APGateway:
|
|||
if "noticed" in old_attachment:
|
||||
# "noticed" attachment has been removed, we undo the "Like" activity
|
||||
activity_id = self.buildAPURL("like", item_account, item_id)
|
||||
activity = self.createActivity(
|
||||
activity = self.create_activity(
|
||||
TYPE_LIKE, publisher_actor_id, item_url, activity_id=activity_id
|
||||
)
|
||||
activity["to"] = [ap_account]
|
||||
activity["cc"] = [NS_AP_PUBLIC]
|
||||
undo = self.createActivity("Undo", publisher_actor_id, activity)
|
||||
undo = self.create_activity("Undo", publisher_actor_id, activity)
|
||||
await self.signAndPost(inbox, publisher_actor_id, undo)
|
||||
|
||||
# reactions
|
||||
|
|
@ -1260,7 +1261,7 @@ class APGateway:
|
|||
activity_id = self.buildAPURL(
|
||||
"reaction", item_account, item_id, reaction.encode().hex()
|
||||
)
|
||||
reaction_activity = self.createActivity(
|
||||
reaction_activity = self.create_activity(
|
||||
TYPE_REACTION, publisher_actor_id, item_url,
|
||||
activity_id=activity_id
|
||||
)
|
||||
|
|
@ -1268,7 +1269,7 @@ class APGateway:
|
|||
reaction_activity["to"] = [ap_account]
|
||||
reaction_activity["cc"] = [NS_AP_PUBLIC]
|
||||
if undo:
|
||||
activy = self.createActivity(
|
||||
activy = self.create_activity(
|
||||
"Undo", publisher_actor_id, reaction_activity
|
||||
)
|
||||
else:
|
||||
|
|
@ -1282,7 +1283,7 @@ class APGateway:
|
|||
if attending != old_attending:
|
||||
activity_type = TYPE_JOIN if attending == "yes" else TYPE_LEAVE
|
||||
activity_id = self.buildAPURL(activity_type.lower(), item_account, item_id)
|
||||
activity = self.createActivity(
|
||||
activity = self.create_activity(
|
||||
activity_type, publisher_actor_id, item_url, activity_id=activity_id
|
||||
)
|
||||
activity["to"] = [ap_account]
|
||||
|
|
@ -1293,7 +1294,7 @@ class APGateway:
|
|||
old_attending = old_attachment.get("rsvp", {}).get("attending", "no")
|
||||
if old_attending == "yes":
|
||||
activity_id = self.buildAPURL(TYPE_LEAVE.lower(), item_account, item_id)
|
||||
activity = self.createActivity(
|
||||
activity = self.create_activity(
|
||||
TYPE_LEAVE, publisher_actor_id, item_url, activity_id=activity_id
|
||||
)
|
||||
activity["to"] = [ap_account]
|
||||
|
|
@ -1645,8 +1646,8 @@ class APGateway:
|
|||
|
||||
async def ap_item_2_mb_data_and_elt(self, ap_item: dict) -> Tuple[dict, domish.Element]:
|
||||
"""Convert AP item to parsed microblog data and corresponding item element"""
|
||||
mb_data = await self.apItem2MBdata(ap_item)
|
||||
item_elt = await self._m.data2entry(
|
||||
mb_data = await self.ap_item_2_mb_data(ap_item)
|
||||
item_elt = await self._m.mb_data_2_entry_elt(
|
||||
self.client, mb_data, mb_data["id"], None, self._m.namespace
|
||||
)
|
||||
if "repeated" in mb_data["extra"]:
|
||||
|
|
@ -1742,7 +1743,7 @@ class APGateway:
|
|||
None
|
||||
)
|
||||
|
||||
async def apItem2MBdata(self, ap_item: dict) -> dict:
|
||||
async def ap_item_2_mb_data(self, ap_item: dict) -> dict:
|
||||
"""Convert AP activity or object to microblog data
|
||||
|
||||
@param ap_item: ActivityPub item to convert
|
||||
|
|
@ -1786,6 +1787,32 @@ class APGateway:
|
|||
False,
|
||||
)
|
||||
|
||||
if "attachment" in ap_object:
|
||||
attachments = mb_data["extra"][C.KEY_ATTACHMENTS] = []
|
||||
for ap_attachment in ap_object["attachment"]:
|
||||
try:
|
||||
url = ap_attachment["url"]
|
||||
except KeyError:
|
||||
log.warning(
|
||||
f'"url" missing in AP attachment, ignoring: {ap_attachment}'
|
||||
)
|
||||
continue
|
||||
|
||||
if not url.startswith("http"):
|
||||
log.warning(f"non HTTP URL in attachment, ignoring: {ap_attachment}")
|
||||
continue
|
||||
attachment = {"url": url}
|
||||
for ap_key, key in (
|
||||
("mediaType", "media_type"),
|
||||
# XXX: as weird as it seems, "name" is actually used for description
|
||||
# in AP world
|
||||
("name", "desc"),
|
||||
):
|
||||
value = ap_attachment.get(ap_key)
|
||||
if value:
|
||||
attachment[key] = value
|
||||
attachments.append(attachment)
|
||||
|
||||
# author
|
||||
if is_activity:
|
||||
authors = await self.apGetActors(ap_item, "actor")
|
||||
|
|
@ -1899,7 +1926,7 @@ class APGateway:
|
|||
TYPE_ITEM, parent_ap_account, parent_item
|
||||
)
|
||||
|
||||
async def repeatedMB2APItem(
|
||||
async def repeated_mb_2_ap_item(
|
||||
self,
|
||||
mb_data: dict
|
||||
) -> dict:
|
||||
|
|
@ -1952,7 +1979,7 @@ class APGateway:
|
|||
)
|
||||
announced_uri = self.buildAPURL("item", repeated_account, rep_item)
|
||||
|
||||
announce = self.createActivity(
|
||||
announce = self.create_activity(
|
||||
"Announce", repeater_id, announced_uri, activity_id=activity_id
|
||||
)
|
||||
announce["to"] = [NS_AP_PUBLIC]
|
||||
|
|
@ -1988,7 +2015,7 @@ class APGateway:
|
|||
"""
|
||||
extra = mb_data.get("extra", {})
|
||||
if "repeated" in extra:
|
||||
return await self.repeatedMB2APItem(mb_data)
|
||||
return await self.repeated_mb_2_ap_item(mb_data)
|
||||
if not mb_data.get("id"):
|
||||
mb_data["id"] = shortuuid.uuid()
|
||||
if not mb_data.get("author_jid"):
|
||||
|
|
@ -2011,6 +2038,32 @@ class APGateway:
|
|||
if language:
|
||||
ap_object["contentMap"] = {language: ap_object["content"]}
|
||||
|
||||
attachments = extra.get(C.KEY_ATTACHMENTS)
|
||||
if attachments:
|
||||
ap_attachments = ap_object["attachment"] = []
|
||||
for attachment in attachments:
|
||||
try:
|
||||
url = next(
|
||||
s['url'] for s in attachment["sources"] if 'url' in s
|
||||
)
|
||||
except (StopIteration, KeyError):
|
||||
log.warning(
|
||||
f"Ignoring attachment without URL: {attachment}"
|
||||
)
|
||||
continue
|
||||
ap_attachment = {
|
||||
"url": url
|
||||
}
|
||||
for key, ap_key in (
|
||||
("media_type", "mediaType"),
|
||||
# XXX: yes "name", cf. [ap_item_2_mb_data]
|
||||
("desc", "name"),
|
||||
):
|
||||
value = attachment.get(key)
|
||||
if value:
|
||||
ap_attachment[ap_key] = value
|
||||
ap_attachments.append(ap_attachment)
|
||||
|
||||
if public:
|
||||
ap_object["to"] = [NS_AP_PUBLIC]
|
||||
if self.auto_mentions:
|
||||
|
|
@ -2068,7 +2121,7 @@ class APGateway:
|
|||
mb_data
|
||||
)
|
||||
|
||||
return self.createActivity(
|
||||
return self.create_activity(
|
||||
"Create" if is_new else "Update", url_actor, ap_object, activity_id=url_item
|
||||
)
|
||||
|
||||
|
|
@ -2144,12 +2197,12 @@ class APGateway:
|
|||
)
|
||||
else:
|
||||
try:
|
||||
mb_data = await self._m.item2mbdata(self.client, items[0].data, jid_, node)
|
||||
mb_data = await self._m.item_2_mb_data(self.client, items[0].data, jid_, node)
|
||||
if "repeated" in mb_data["extra"]:
|
||||
# we are deleting a repeated item, we must translate this to an
|
||||
# "Undo" of the "Announce" activity instead of a "Delete" one
|
||||
announce = await self.repeatedMB2APItem(mb_data)
|
||||
undo = self.createActivity("Undo", author_actor_id, announce)
|
||||
announce = await self.repeated_mb_2_ap_item(mb_data)
|
||||
undo = self.create_activity("Undo", author_actor_id, announce)
|
||||
return author_actor_id, undo
|
||||
except Exception as e:
|
||||
log.debug(
|
||||
|
|
@ -2158,7 +2211,7 @@ class APGateway:
|
|||
)
|
||||
|
||||
url_item = self.buildAPURL(TYPE_ITEM, author_account, item_id)
|
||||
ap_item = self.createActivity(
|
||||
ap_item = self.create_activity(
|
||||
"Delete",
|
||||
author_actor_id,
|
||||
{
|
||||
|
|
@ -2223,6 +2276,12 @@ class APGateway:
|
|||
if origin_id:
|
||||
# we need to use origin ID when present to be able to retract the message
|
||||
mb_data["id"] = origin_id
|
||||
attachments = mess_data["extra"].get(C.KEY_ATTACHMENTS)
|
||||
if attachments:
|
||||
mb_data["extra"] = {
|
||||
C.KEY_ATTACHMENTS: attachments
|
||||
}
|
||||
|
||||
client = self.client.getVirtualClient(mess_data["from"])
|
||||
ap_item = await self.mb_data_2_ap_item(client, mb_data, public=False)
|
||||
ap_object = ap_item["object"]
|
||||
|
|
@ -2339,7 +2398,7 @@ class APGateway:
|
|||
|
||||
cached_item = cached_items[0]
|
||||
|
||||
mb_data = await self._m.item2mbdata(
|
||||
mb_data = await self._m.item_2_mb_data(
|
||||
client, cached_item.data, pubsub_service, pubsub_node
|
||||
)
|
||||
ap_item = await self.mb_data_2_ap_item(client, mb_data)
|
||||
|
|
@ -2396,7 +2455,7 @@ class APGateway:
|
|||
f"Can't find parent item at {parent_item_service} (node "
|
||||
f"{parent_item_node!r})\n{pformat(ap_item)}")
|
||||
return
|
||||
parent_item_parsed = await self._m.item2mbdata(
|
||||
parent_item_parsed = await self._m.item_2_mb_data(
|
||||
client, parent_item_elt, parent_item_service, parent_item_node
|
||||
)
|
||||
try:
|
||||
|
|
@ -2488,7 +2547,7 @@ class APGateway:
|
|||
is_public, targets, mentions = self.getAPItemTargets(item)
|
||||
if not is_public and targets.keys() == {TYPE_ACTOR}:
|
||||
# this is a direct message
|
||||
await self.handleMessageAPItem(
|
||||
await self.handle_message_ap_item(
|
||||
client, targets, mentions, destinee, item
|
||||
)
|
||||
else:
|
||||
|
|
@ -2496,7 +2555,7 @@ class APGateway:
|
|||
client, targets, mentions, destinee, node, item, is_public
|
||||
)
|
||||
|
||||
async def handleMessageAPItem(
|
||||
async def handle_message_ap_item(
|
||||
self,
|
||||
client: SatXMPPEntity,
|
||||
targets: Dict[str, Set[str]],
|
||||
|
|
@ -2517,7 +2576,14 @@ class APGateway:
|
|||
}
|
||||
if destinee is not None:
|
||||
targets_jids.add(destinee)
|
||||
mb_data = await self.apItem2MBdata(item)
|
||||
mb_data = await self.ap_item_2_mb_data(item)
|
||||
extra = {
|
||||
"origin_id": mb_data["id"]
|
||||
}
|
||||
attachments = mb_data["extra"].get(C.KEY_ATTACHMENTS)
|
||||
if attachments:
|
||||
extra[C.KEY_ATTACHMENTS] = attachments
|
||||
|
||||
defer_l = []
|
||||
for target_jid in targets_jids:
|
||||
defer_l.append(
|
||||
|
|
@ -2525,7 +2591,7 @@ class APGateway:
|
|||
target_jid,
|
||||
{'': mb_data.get("content", "")},
|
||||
mb_data.get("title"),
|
||||
extra={"origin_id": mb_data["id"]}
|
||||
extra=extra
|
||||
)
|
||||
)
|
||||
await defer.DeferredList(defer_l)
|
||||
|
|
|
|||
|
|
@ -230,7 +230,7 @@ class APEvents:
|
|||
"value": ap_wc_value
|
||||
})
|
||||
|
||||
activity = self.apg.createActivity(
|
||||
activity = self.apg.create_activity(
|
||||
"Create" if is_new else "Update", url_actor, ap_object, activity_id=url_item
|
||||
)
|
||||
activity["@context"].append(AP_EVENTS_CONTEXT)
|
||||
|
|
|
|||
|
|
@ -215,7 +215,7 @@ class HTTPAPGServer(web_resource.Resource):
|
|||
raise exceptions.InternalError('"subscribed" state was expected')
|
||||
inbox = await self.apg.getAPInboxFromId(signing_actor, use_shared=False)
|
||||
actor_id = self.apg.buildAPURL(TYPE_ACTOR, ap_account)
|
||||
accept_data = self.apg.createActivity(
|
||||
accept_data = self.apg.create_activity(
|
||||
"Accept", actor_id, object_=data
|
||||
)
|
||||
await self.apg.signAndPost(inbox, actor_id, accept_data)
|
||||
|
|
@ -715,7 +715,7 @@ class HTTPAPGServer(web_resource.Resource):
|
|||
ordered_items = [
|
||||
await self.apg.mb_data_2_ap_item(
|
||||
self.apg.client,
|
||||
await self.apg._m.item2mbdata(
|
||||
await self.apg._m.item_2_mb_data(
|
||||
self.apg.client,
|
||||
item,
|
||||
account_jid,
|
||||
|
|
|
|||
|
|
@ -514,7 +514,7 @@ class APPubsubService(rsm.PubSubService):
|
|||
requestor, service
|
||||
)
|
||||
|
||||
data = self.apg.createActivity("Follow", req_actor_id, recip_actor_id)
|
||||
data = self.apg.create_activity("Follow", req_actor_id, recip_actor_id)
|
||||
|
||||
resp = await self.apg.signAndPost(inbox, req_actor_id, data)
|
||||
if resp.code >= 300:
|
||||
|
|
@ -527,10 +527,10 @@ class APPubsubService(rsm.PubSubService):
|
|||
req_actor_id, recip_actor_id, inbox = await self.getAPActorIdsAndInbox(
|
||||
requestor, service
|
||||
)
|
||||
data = self.apg.createActivity(
|
||||
data = self.apg.create_activity(
|
||||
"Undo",
|
||||
req_actor_id,
|
||||
self.apg.createActivity(
|
||||
self.apg.create_activity(
|
||||
"Follow",
|
||||
req_actor_id,
|
||||
recip_actor_id
|
||||
|
|
|
|||
|
|
@ -59,6 +59,7 @@ class AttachPlugin:
|
|||
self.host = host
|
||||
self._u = host.plugins["UPLOAD"]
|
||||
host.trigger.add("sendMessage", self._sendMessageTrigger)
|
||||
host.trigger.add("sendMessageComponent", self._sendMessageTrigger)
|
||||
self._attachments_handlers = {'clear': [], 'encrypted': []}
|
||||
self.register(self.defaultCanHandle, self.defaultAttach, False, -1000)
|
||||
|
||||
|
|
@ -100,13 +101,13 @@ class AttachPlugin:
|
|||
"""
|
||||
# we check attachment for pre-treatment like large image resizing
|
||||
# media_type will be added if missing (and if it can be guessed from path)
|
||||
attachments = data["extra"][C.MESS_KEY_ATTACHMENTS]
|
||||
attachments = data["extra"][C.KEY_ATTACHMENTS]
|
||||
tmp_dirs_to_clean = []
|
||||
for attachment in attachments:
|
||||
if attachment.get(C.MESS_KEY_ATTACHMENTS_RESIZE, False):
|
||||
if attachment.get(C.KEY_ATTACHMENTS_RESIZE, False):
|
||||
path = Path(attachment["path"])
|
||||
try:
|
||||
media_type = attachment[C.MESS_KEY_ATTACHMENTS_MEDIA_TYPE]
|
||||
media_type = attachment[C.KEY_ATTACHMENTS_MEDIA_TYPE]
|
||||
except KeyError:
|
||||
media_type = mimetypes.guess_type(path, strict=False)[0]
|
||||
if media_type is None:
|
||||
|
|
@ -114,7 +115,7 @@ class AttachPlugin:
|
|||
_("Can't resize attachment of unknown type: {attachment}")
|
||||
.format(attachment=attachment))
|
||||
continue
|
||||
attachment[C.MESS_KEY_ATTACHMENTS_MEDIA_TYPE] = media_type
|
||||
attachment[C.KEY_ATTACHMENTS_MEDIA_TYPE] = media_type
|
||||
|
||||
main_type = media_type.split('/')[0]
|
||||
if main_type == "image":
|
||||
|
|
@ -188,6 +189,9 @@ class AttachPlugin:
|
|||
attachments = data["extra"]["attachments"]
|
||||
|
||||
for attachment in attachments:
|
||||
if "url" in attachment and not "path" in attachment:
|
||||
log.debug(f"attachment is external, we don't upload it: {attachment}")
|
||||
continue
|
||||
try:
|
||||
# we pop path because we don't want it to be stored, as the file can be
|
||||
# only in a temporary location
|
||||
|
|
@ -252,7 +256,7 @@ class AttachPlugin:
|
|||
|
||||
def _sendMessageTrigger(
|
||||
self, client, mess_data, pre_xml_treatments, post_xml_treatments):
|
||||
if mess_data['extra'].get(C.MESS_KEY_ATTACHMENTS):
|
||||
if mess_data['extra'].get(C.KEY_ATTACHMENTS):
|
||||
post_xml_treatments.addCallback(self._attachFiles, client=client)
|
||||
return True
|
||||
|
||||
|
|
@ -265,7 +269,7 @@ class AttachPlugin:
|
|||
body_elt = data["xml"].body
|
||||
if body_elt is None:
|
||||
body_elt = data["xml"].addElement("body")
|
||||
attachments = data["extra"][C.MESS_KEY_ATTACHMENTS]
|
||||
attachments = data["extra"][C.KEY_ATTACHMENTS]
|
||||
if attachments:
|
||||
body_links = '\n'.join(a['url'] for a in attachments)
|
||||
if str(body_elt).strip():
|
||||
|
|
|
|||
|
|
@ -156,7 +156,7 @@ class AESGCM(object):
|
|||
# TODO: this is to be removed when a better mechanism is available with OMEMO (now
|
||||
# possible with the 0.4 version of OMEMO, it's possible to encrypt other stanza
|
||||
# elements than body).
|
||||
attachments = data["extra"][C.MESS_KEY_ATTACHMENTS]
|
||||
attachments = data["extra"][C.KEY_ATTACHMENTS]
|
||||
if not data['message'] or data['message'] == {'': ''}:
|
||||
extra_attachments = attachments[1:]
|
||||
del attachments[1:]
|
||||
|
|
@ -165,7 +165,7 @@ class AESGCM(object):
|
|||
# we have a message, we must send first attachment separately
|
||||
extra_attachments = attachments[:]
|
||||
attachments.clear()
|
||||
del data["extra"][C.MESS_KEY_ATTACHMENTS]
|
||||
del data["extra"][C.KEY_ATTACHMENTS]
|
||||
|
||||
body_elt = data["xml"].body
|
||||
if body_elt is None:
|
||||
|
|
@ -181,7 +181,7 @@ class AESGCM(object):
|
|||
message={'': ''},
|
||||
subject=data['subject'],
|
||||
mess_type=data['type'],
|
||||
extra={C.MESS_KEY_ATTACHMENTS: [attachment]},
|
||||
extra={C.KEY_ATTACHMENTS: [attachment]},
|
||||
)
|
||||
|
||||
if ((not data['extra']
|
||||
|
|
@ -299,7 +299,7 @@ class AESGCM(object):
|
|||
else:
|
||||
data['message'][lang] = message
|
||||
mess_encrypted = client.encryption.isEncrypted(data)
|
||||
attachments = data['extra'].setdefault(C.MESS_KEY_ATTACHMENTS, [])
|
||||
attachments = data['extra'].setdefault(C.KEY_ATTACHMENTS, [])
|
||||
for link in links:
|
||||
path = parse.urlparse(link).path
|
||||
attachment = {
|
||||
|
|
@ -307,7 +307,7 @@ class AESGCM(object):
|
|||
}
|
||||
media_type = mimetypes.guess_type(path, strict=False)[0]
|
||||
if media_type is not None:
|
||||
attachment[C.MESS_KEY_ATTACHMENTS_MEDIA_TYPE] = media_type
|
||||
attachment[C.KEY_ATTACHMENTS_MEDIA_TYPE] = media_type
|
||||
|
||||
if mess_encrypted:
|
||||
# we don't add the encrypted flag if the message itself is not
|
||||
|
|
|
|||
|
|
@ -97,7 +97,7 @@ class XEP_0277(object):
|
|||
"namespace": NS_ATOM,
|
||||
"type": "blog",
|
||||
"to_sync": True,
|
||||
"parser": self.item2mbdata,
|
||||
"parser": self.item_2_mb_data,
|
||||
"match_cb": self._cacheNodeMatchCb,
|
||||
}
|
||||
)
|
||||
|
|
@ -249,7 +249,7 @@ class XEP_0277(object):
|
|||
for item in itemsEvent.items:
|
||||
if item.name == C.PS_ITEM:
|
||||
# FIXME: service and node should be used here
|
||||
self.item2mbdata(client, item, None, None).addCallbacks(
|
||||
self.item_2_mb_data(client, item, None, None).addCallbacks(
|
||||
manageItem, lambda failure: None, (C.PS_PUBLISH,)
|
||||
)
|
||||
elif item.name == C.PS_RETRACT:
|
||||
|
|
@ -260,12 +260,12 @@ class XEP_0277(object):
|
|||
## data/item transformation ##
|
||||
|
||||
@defer.inlineCallbacks
|
||||
def item2mbdata(
|
||||
def item_2_mb_data(
|
||||
self,
|
||||
client: SatXMPPEntity,
|
||||
item_elt: domish.Element,
|
||||
service: Optional[jid.JID],
|
||||
# FIXME: node is Optional until all calls to item2mbdata set properly service
|
||||
# FIXME: node is Optional until all calls to item_2_mb_data set properly service
|
||||
# and node. Once done, the Optional must be removed here
|
||||
node: Optional[str]
|
||||
) -> dict:
|
||||
|
|
@ -615,7 +615,7 @@ class XEP_0277(object):
|
|||
|
||||
defer.returnValue(microblog_data)
|
||||
|
||||
async def data2entry(self, client, mb_data, item_id, service, node):
|
||||
async def mb_data_2_entry_elt(self, client, mb_data, item_id, service, node):
|
||||
"""Convert a data dict to en entry usable to create an item
|
||||
|
||||
@param mb_data: data dict as given by bridge method.
|
||||
|
|
@ -1036,7 +1036,7 @@ class XEP_0277(object):
|
|||
await self._manageComments(client, data, service, node, item_id, access=None)
|
||||
except error.StanzaError:
|
||||
log.warning("Can't create comments node for item {}".format(item_id))
|
||||
item = await self.data2entry(client, data, item_id, service, node)
|
||||
item = await self.mb_data_2_entry_elt(client, data, item_id, service, node)
|
||||
|
||||
if not await self.host.trigger.asyncPoint(
|
||||
"XEP-0277_send", client, service, node, item, data
|
||||
|
|
@ -1165,9 +1165,9 @@ class XEP_0277(object):
|
|||
item_id = data.get("id", "")
|
||||
|
||||
# we have to serialise then deserialise to be sure that all triggers are called
|
||||
item_elt = await self.data2entry(client, data, item_id, service, node)
|
||||
item_elt = await self.mb_data_2_entry_elt(client, data, item_id, service, node)
|
||||
item_elt.uri = pubsub.NS_PUBSUB
|
||||
return await self.item2mbdata(client, item_elt, service, node)
|
||||
return await self.item_2_mb_data(client, item_elt, service, node)
|
||||
|
||||
|
||||
## retract ##
|
||||
|
|
@ -1243,7 +1243,7 @@ class XEP_0277(object):
|
|||
extra=extra,
|
||||
)
|
||||
mb_data_list, metadata = await self._p.transItemsDataD(
|
||||
items_data, partial(self.item2mbdata, client, service=service, node=node))
|
||||
items_data, partial(self.item_2_mb_data, client, service=service, node=node))
|
||||
encrypted = metadata.pop("encrypted", None)
|
||||
if encrypted is not None:
|
||||
for mb_data in mb_data_list:
|
||||
|
|
@ -1461,7 +1461,7 @@ class XEP_0277(object):
|
|||
d = self._p.transItemsDataD(
|
||||
items_data,
|
||||
# FIXME: service and node should be used here
|
||||
partial(self.item2mbdata, client),
|
||||
partial(self.item_2_mb_data, client),
|
||||
serialise=True
|
||||
)
|
||||
d.addCallback(lambda serialised: ("", serialised))
|
||||
|
|
@ -1663,7 +1663,7 @@ class XEP_0277(object):
|
|||
lambda items_data: self._p.transItemsDataD(
|
||||
items_data,
|
||||
partial(
|
||||
self.item2mbdata, client, service=service, node=node
|
||||
self.item_2_mb_data, client, service=service, node=node
|
||||
),
|
||||
serialise=True
|
||||
)
|
||||
|
|
@ -1704,7 +1704,7 @@ class XEP_0277(object):
|
|||
d.addCallback(
|
||||
lambda items_data: self._p.transItemsDataD(
|
||||
items_data,
|
||||
partial(self.item2mbdata, client, service=service, node=node),
|
||||
partial(self.item_2_mb_data, client, service=service, node=node),
|
||||
)
|
||||
)
|
||||
d.addCallback(getComments)
|
||||
|
|
|
|||
|
|
@ -267,7 +267,7 @@ class XEP_0447:
|
|||
@return: file-sharing data. It a dict whose keys correspond to
|
||||
[get_file_sharing_elt] parameters
|
||||
"""
|
||||
if file_sharing_elt.name != "file-sharing":
|
||||
if file_sharing_elt.name != "file-sharing" or file_sharing_elt.uri != NS_SFS:
|
||||
try:
|
||||
file_sharing_elt = next(
|
||||
file_sharing_elt.elements(NS_SFS, "file-sharing")
|
||||
|
|
@ -295,31 +295,30 @@ class XEP_0447:
|
|||
data: Dict[str, Any]
|
||||
) -> Dict[str, Any]:
|
||||
"""Check <message> for a shared file, and add it as an attachment"""
|
||||
# XXX: XEP-0447 doesn't support several attachments in a single message, thus only
|
||||
# one attachment can be added
|
||||
try:
|
||||
# XXX: XEP-0447 doesn't support several attachments in a single message, for now
|
||||
# however that should be fixed in future version, and so we accept several
|
||||
# <file-sharing> element in a message.
|
||||
for file_sharing_elt in message_elt.elements(NS_SFS, "file-sharing"):
|
||||
attachment = self.parse_file_sharing_elt(message_elt)
|
||||
except exceptions.NotFound:
|
||||
return data
|
||||
|
||||
if any(
|
||||
s.get(C.MESS_KEY_ENCRYPTED, False)
|
||||
for s in attachment["sources"]
|
||||
) and client.encryption.isEncrypted(data):
|
||||
# we don't add the encrypted flag if the message itself is not encrypted,
|
||||
# because the decryption key is part of the link, so sending it over
|
||||
# unencrypted channel is like having no encryption at all.
|
||||
attachment[C.MESS_KEY_ENCRYPTED] = True
|
||||
if any(
|
||||
s.get(C.MESS_KEY_ENCRYPTED, False)
|
||||
for s in attachment["sources"]
|
||||
) and client.encryption.isEncrypted(data):
|
||||
# we don't add the encrypted flag if the message itself is not encrypted,
|
||||
# because the decryption key is part of the link, so sending it over
|
||||
# unencrypted channel is like having no encryption at all.
|
||||
attachment[C.MESS_KEY_ENCRYPTED] = True
|
||||
|
||||
attachments = data['extra'].setdefault(C.MESS_KEY_ATTACHMENTS, [])
|
||||
attachments.append(attachment)
|
||||
attachments = data['extra'].setdefault(C.KEY_ATTACHMENTS, [])
|
||||
attachments.append(attachment)
|
||||
|
||||
return data
|
||||
|
||||
async def attach(self, client, data):
|
||||
# XXX: for now, XEP-0447 only allow to send one file per <message/>, thus we need
|
||||
# to send each file in a separate message
|
||||
attachments = data["extra"][C.MESS_KEY_ATTACHMENTS]
|
||||
attachments = data["extra"][C.KEY_ATTACHMENTS]
|
||||
if not data['message'] or data['message'] == {'': ''}:
|
||||
extra_attachments = attachments[1:]
|
||||
del attachments[1:]
|
||||
|
|
@ -327,7 +326,7 @@ class XEP_0447:
|
|||
# we have a message, we must send first attachment separately
|
||||
extra_attachments = attachments[:]
|
||||
attachments.clear()
|
||||
del data["extra"][C.MESS_KEY_ATTACHMENTS]
|
||||
del data["extra"][C.KEY_ATTACHMENTS]
|
||||
|
||||
if attachments:
|
||||
if len(attachments) > 1:
|
||||
|
|
@ -343,8 +342,10 @@ class XEP_0447:
|
|||
file_hash = None
|
||||
file_sharing_elt = self.get_file_sharing_elt(
|
||||
[{"url": attachment["url"]}],
|
||||
name=attachment["name"],
|
||||
size=attachment["size"],
|
||||
name=attachment.get("name"),
|
||||
size=attachment.get("size"),
|
||||
desc=attachment.get("desc"),
|
||||
media_type=attachment.get("media_type"),
|
||||
file_hash=file_hash
|
||||
)
|
||||
data["xml"].addChild(file_sharing_elt)
|
||||
|
|
@ -356,7 +357,7 @@ class XEP_0447:
|
|||
message={'': ''},
|
||||
subject=data['subject'],
|
||||
mess_type=data['type'],
|
||||
extra={C.MESS_KEY_ATTACHMENTS: [attachment]},
|
||||
extra={C.KEY_ATTACHMENTS: [attachment]},
|
||||
)
|
||||
|
||||
if ((not data['extra']
|
||||
|
|
|
|||
|
|
@ -263,7 +263,7 @@ class XEP_0448:
|
|||
# XXX: for now, XEP-0447/XEP-0448 only allow to send one file per <message/>, thus
|
||||
# we need to send each file in a separate message, in the same way as for
|
||||
# plugin_sec_aesgcm.
|
||||
attachments = data["extra"][C.MESS_KEY_ATTACHMENTS]
|
||||
attachments = data["extra"][C.KEY_ATTACHMENTS]
|
||||
if not data['message'] or data['message'] == {'': ''}:
|
||||
extra_attachments = attachments[1:]
|
||||
del attachments[1:]
|
||||
|
|
@ -271,7 +271,7 @@ class XEP_0448:
|
|||
# we have a message, we must send first attachment separately
|
||||
extra_attachments = attachments[:]
|
||||
attachments.clear()
|
||||
del data["extra"][C.MESS_KEY_ATTACHMENTS]
|
||||
del data["extra"][C.KEY_ATTACHMENTS]
|
||||
|
||||
if attachments:
|
||||
if len(attachments) > 1:
|
||||
|
|
@ -319,7 +319,7 @@ class XEP_0448:
|
|||
message={'': ''},
|
||||
subject=data['subject'],
|
||||
mess_type=data['type'],
|
||||
extra={C.MESS_KEY_ATTACHMENTS: [attachment]},
|
||||
extra={C.KEY_ATTACHMENTS: [attachment]},
|
||||
)
|
||||
|
||||
if ((not data['extra']
|
||||
|
|
|
|||
|
|
@ -145,7 +145,7 @@ class Send(base.CommandBase):
|
|||
to_send.append(msg)
|
||||
|
||||
if self.args.attachments:
|
||||
attachments = extra[C.MESS_KEY_ATTACHMENTS] = []
|
||||
attachments = extra[C.KEY_ATTACHMENTS] = []
|
||||
for attachment in self.args.attachments:
|
||||
try:
|
||||
file_path = str(Path(attachment).resolve(strict=True))
|
||||
|
|
@ -155,10 +155,10 @@ class Send(base.CommandBase):
|
|||
attachments.append({"path": file_path})
|
||||
|
||||
for idx, msg in enumerate(to_send):
|
||||
if idx > 0 and C.MESS_KEY_ATTACHMENTS in extra:
|
||||
if idx > 0 and C.KEY_ATTACHMENTS in extra:
|
||||
# if we send several messages, we only want to send attachments with the
|
||||
# first one
|
||||
del extra[C.MESS_KEY_ATTACHMENTS]
|
||||
del extra[C.KEY_ATTACHMENTS]
|
||||
try:
|
||||
await self.host.bridge.messageSend(
|
||||
dest_jid,
|
||||
|
|
|
|||
|
|
@ -223,7 +223,7 @@ class Message:
|
|||
|
||||
@property
|
||||
def attachments(self):
|
||||
return self.extra.get(C.MESS_KEY_ATTACHMENTS)
|
||||
return self.extra.get(C.KEY_ATTACHMENTS)
|
||||
|
||||
|
||||
class MessageWidget:
|
||||
|
|
@ -733,7 +733,7 @@ class QuickChat(quick_widgets.QuickWidget):
|
|||
)
|
||||
return
|
||||
|
||||
if ((not msg and not subject and not extra[C.MESS_KEY_ATTACHMENTS]
|
||||
if ((not msg and not subject and not extra[C.KEY_ATTACHMENTS]
|
||||
and type_ != C.MESS_TYPE_INFO)):
|
||||
log.warning("Received an empty message for uid {}".format(uid))
|
||||
return
|
||||
|
|
|
|||
Loading…
Reference in a new issue