comparison sat/plugins/plugin_xep_0277.py @ 3502:6132d363f0e9

plugin XEP-0277: user friendly ID: when publishing a blog post without `id` specified, instead of using uuid, a user friendly ID based on title or content is used. This allow to have better URLs in web frontend. There is a (very low) risk of name collision if several articles with the same title or content are published on the same pubsub node, user friendly ID can be deactivated by using `user_friendly_id=False` in blog data to avoid that.
author Goffi <goffi@goffi.org>
date Fri, 16 Apr 2021 18:33:00 +0200
parents b54bdd4ec507
children 753d151da886
comparison
equal deleted inserted replaced
3501:85b8a899f407 3502:6132d363f0e9
14 # GNU Affero General Public License for more details. 14 # GNU Affero General Public License for more details.
15 15
16 # You should have received a copy of the GNU Affero General Public License 16 # You should have received a copy of the GNU Affero General Public License
17 # along with this program. If not, see <http://www.gnu.org/licenses/>. 17 # along with this program. If not, see <http://www.gnu.org/licenses/>.
18 18
19 import shortuuid
20 import time 19 import time
21 import dateutil 20 import dateutil
22 import calendar 21 import calendar
23 import urllib.parse 22 import urllib.parse
23 from secrets import token_urlsafe
24 from typing import Optional 24 from typing import Optional
25 from functools import partial 25 from functools import partial
26
27 import shortuuid
26 28
27 from twisted.words.protocols.jabber import jid, error 29 from twisted.words.protocols.jabber import jid, error
28 from twisted.words.protocols.jabber.xmlstream import XMPPHandler 30 from twisted.words.protocols.jabber.xmlstream import XMPPHandler
29 from twisted.words.xish import domish 31 from twisted.words.xish import domish
30 from twisted.internet import defer 32 from twisted.internet import defer
43 from sat.tools import xml_tools 45 from sat.tools import xml_tools
44 from sat.tools import sat_defer 46 from sat.tools import sat_defer
45 from sat.tools import utils 47 from sat.tools import utils
46 from sat.tools.common import data_format 48 from sat.tools.common import data_format
47 from sat.tools.common import uri as xmpp_uri 49 from sat.tools.common import uri as xmpp_uri
50 from sat.tools.common import regex
48 51
49 52
50 log = getLogger(__name__) 53 log = getLogger(__name__)
51 54
52 55
805 node = node if node else NS_MICROBLOG 808 node = node if node else NS_MICROBLOG
806 client = self.host.getClient(profile_key) 809 client = self.host.getClient(profile_key)
807 data = data_format.deserialise(data) 810 data = data_format.deserialise(data)
808 return self.send(client, data, service, node) 811 return self.send(client, data, service, node)
809 812
813 def friendlyId(self, data):
814 """Generate a user friendly id from title or content"""
815 id_base = regex.urlFriendlyText(data.get('title') or data.get('content', ''))
816 return f"{id_base}-{token_urlsafe(3)}"
817
810 @defer.inlineCallbacks 818 @defer.inlineCallbacks
811 def send(self, client, data, service=None, node=NS_MICROBLOG): 819 def send(self, client, data, service=None, node=NS_MICROBLOG):
812 """Send XEP-0277's microblog data 820 """Send XEP-0277's microblog data
813 821
814 @param data(dict): microblog data (must include at least a "content" or a "title" key). 822 @param data(dict): microblog data (must include at least a "content" or a "title" key).
821 # TODO: check that all data keys are used, this would avoid sending publicly a private message 829 # TODO: check that all data keys are used, this would avoid sending publicly a private message
822 # by accident (e.g. if group plugin is not loaded, and "group*" key are not used) 830 # by accident (e.g. if group plugin is not loaded, and "group*" key are not used)
823 if node is None: 831 if node is None:
824 node = NS_MICROBLOG 832 node = NS_MICROBLOG
825 833
826 item_id = data.get("id") or str(shortuuid.uuid()) 834 item_id = data.get("id")
835 if item_id is None:
836 if data.get("user_friendly_id", True):
837 item_id = self.friendlyId(data)
838 else:
839 item_id = str(shortuuid.uuid())
827 840
828 try: 841 try:
829 yield self._manageComments(client, data, service, node, item_id, access=None) 842 yield self._manageComments(client, data, service, node, item_id, access=None)
830 except error.StanzaError: 843 except error.StanzaError:
831 log.warning("Can't create comments node for item {}".format(item_id)) 844 log.warning("Can't create comments node for item {}".format(item_id))