Mercurial > libervia-backend
comparison sat/plugins/plugin_xep_0329.py @ 3321:8bbd2ed924e8
plugin XEP-0329: added way to change `access_model` using PubSub-like configuration:
Those methods are not standard, but have been done in a PubSub-like way to prepare the
move to a PubSub based file sharing system.
author | Goffi <goffi@goffi.org> |
---|---|
date | Sat, 01 Aug 2020 16:14:37 +0200 |
parents | bb92085720c8 |
children | ac9342f359e9 |
comparison
equal
deleted
inserted
replaced
3320:bb92085720c8 | 3321:8bbd2ed924e8 |
---|---|
56 | 56 |
57 IQ_FIS_REQUEST = f'{C.IQ_GET}/query[@xmlns="{NS_FIS}"]' | 57 IQ_FIS_REQUEST = f'{C.IQ_GET}/query[@xmlns="{NS_FIS}"]' |
58 # not in the standard, but needed, and it's handy to keep it here | 58 # not in the standard, but needed, and it's handy to keep it here |
59 IQ_FIS_AFFILIATION_GET = f'{C.IQ_GET}/affiliations[@xmlns="{NS_FIS_AFFILIATION}"]' | 59 IQ_FIS_AFFILIATION_GET = f'{C.IQ_GET}/affiliations[@xmlns="{NS_FIS_AFFILIATION}"]' |
60 IQ_FIS_AFFILIATION_SET = f'{C.IQ_SET}/affiliations[@xmlns="{NS_FIS_AFFILIATION}"]' | 60 IQ_FIS_AFFILIATION_SET = f'{C.IQ_SET}/affiliations[@xmlns="{NS_FIS_AFFILIATION}"]' |
61 IQ_FIS_CONFIGURATION_GET = f'{C.IQ_GET}/configuration[@xmlns="{NS_FIS_CONFIGURATION}"]' | |
62 IQ_FIS_CONFIGURATION_SET = f'{C.IQ_SET}/configuration[@xmlns="{NS_FIS_CONFIGURATION}"]' | |
61 SINGLE_FILES_DIR = "files" | 63 SINGLE_FILES_DIR = "files" |
62 TYPE_VIRTUAL = "virtual" | 64 TYPE_VIRTUAL = "virtual" |
63 TYPE_PATH = "path" | 65 TYPE_PATH = "path" |
64 SHARE_TYPES = (TYPE_PATH, TYPE_VIRTUAL) | 66 SHARE_TYPES = (TYPE_PATH, TYPE_VIRTUAL) |
65 KEY_TYPE = "type" | 67 KEY_TYPE = "type" |
315 in_sign="sssa{ss}s", | 317 in_sign="sssa{ss}s", |
316 out_sign="", | 318 out_sign="", |
317 method=self._affiliationsSet, | 319 method=self._affiliationsSet, |
318 async_=True, | 320 async_=True, |
319 ) | 321 ) |
322 host.bridge.addMethod( | |
323 "FISConfigurationGet", | |
324 ".plugin", | |
325 in_sign="ssss", | |
326 out_sign="a{ss}", | |
327 method=self._configurationGet, | |
328 async_=True, | |
329 ) | |
330 host.bridge.addMethod( | |
331 "FISConfigurationSet", | |
332 ".plugin", | |
333 in_sign="sssa{ss}s", | |
334 out_sign="", | |
335 method=self._configurationSet, | |
336 async_=True, | |
337 ) | |
320 host.bridge.addSignal("FISSharedPathNew", ".plugin", signature="sss") | 338 host.bridge.addSignal("FISSharedPathNew", ".plugin", signature="sss") |
321 host.bridge.addSignal("FISSharedPathRemoved", ".plugin", signature="ss") | 339 host.bridge.addSignal("FISSharedPathRemoved", ".plugin", signature="ss") |
322 host.trigger.add("XEP-0234_fileSendingRequest", self._fileSendingRequestTrigger) | 340 host.trigger.add("XEP-0234_fileSendingRequest", self._fileSendingRequestTrigger) |
323 host.registerNamespace("fis", NS_FIS) | 341 host.registerNamespace("fis", NS_FIS) |
324 | 342 |
854 await self.host.memory.setFileAffiliations(client, file_data, affiliations) | 872 await self.host.memory.setFileAffiliations(client, file_data, affiliations) |
855 | 873 |
856 iq_result_elt = xmlstream.toResponse(iq_elt, "result") | 874 iq_result_elt = xmlstream.toResponse(iq_elt, "result") |
857 client.send(iq_result_elt) | 875 client.send(iq_result_elt) |
858 | 876 |
877 # configuration | |
878 | |
879 def _configurationGet(self, service_jid_s, namespace, path, profile): | |
880 client = self.host.getClient(profile) | |
881 service = jid.JID(service_jid_s) | |
882 d = defer.ensureDeferred(self.configurationGet( | |
883 client, service, namespace or None, path)) | |
884 d.addCallback( | |
885 lambda configuration: { | |
886 str(entity): affiliation for entity, affiliation in configuration.items() | |
887 } | |
888 ) | |
889 return d | |
890 | |
891 async def configurationGet( | |
892 self, | |
893 client: SatXMPPEntity, | |
894 service: jid.JID, | |
895 namespace: Optional[str], | |
896 path: str | |
897 ) -> Dict[str, str]: | |
898 if not path: | |
899 raise ValueError(f"invalid path: {path!r}") | |
900 iq_elt = client.IQ("get") | |
901 iq_elt['to'] = service.full() | |
902 configuration_elt = iq_elt.addElement((NS_FIS_CONFIGURATION, "configuration")) | |
903 if namespace: | |
904 configuration_elt["namespace"] = namespace | |
905 configuration_elt["path"] = path | |
906 iq_result_elt = await iq_elt.send() | |
907 try: | |
908 configuration_elt = next(iq_result_elt.elements(NS_FIS_CONFIGURATION, "configuration")) | |
909 except StopIteration: | |
910 raise exceptions.DataError(f"Invalid result to configuration request: {iq_result_elt.toXml()}") | |
911 | |
912 form = data_form.findForm(configuration_elt, NS_FIS_CONFIGURATION) | |
913 configuration = {f.var: f.value for f in form.fields.values()} | |
914 | |
915 return configuration | |
916 | |
917 def _configurationSet(self, service_jid_s, namespace, path, configuration, profile): | |
918 client = self.host.getClient(profile) | |
919 service = jid.JID(service_jid_s) | |
920 return defer.ensureDeferred(self.configurationSet( | |
921 client, service, namespace or None, path, configuration)) | |
922 | |
923 async def configurationSet( | |
924 self, | |
925 client: SatXMPPEntity, | |
926 service: jid.JID, | |
927 namespace: Optional[str], | |
928 path: str, | |
929 configuration: Dict[jid.JID, str], | |
930 ): | |
931 if not path: | |
932 raise ValueError(f"invalid path: {path!r}") | |
933 iq_elt = client.IQ("set") | |
934 iq_elt['to'] = service.full() | |
935 configuration_elt = iq_elt.addElement((NS_FIS_CONFIGURATION, "configuration")) | |
936 if namespace: | |
937 configuration_elt["namespace"] = namespace | |
938 configuration_elt["path"] = path | |
939 form = data_form.Form(formType="submit", formNamespace=NS_FIS_CONFIGURATION) | |
940 form.makeFields(configuration) | |
941 configuration_elt.addChild(form.toElement()) | |
942 await iq_elt.send() | |
943 | |
944 def _onComponentConfigurationGet(self, iq_elt, client): | |
945 iq_elt.handled = True | |
946 defer.ensureDeferred(self.onComponentConfigurationGet(client, iq_elt)) | |
947 | |
948 async def onComponentConfigurationGet(self, client, iq_elt): | |
949 try: | |
950 ( | |
951 from_jid, configuration_elt, path, namespace, file_data | |
952 ) = await self._parseElement(client, iq_elt, "configuration", NS_FIS_CONFIGURATION) | |
953 except exceptions.CancelError: | |
954 return | |
955 except RootPathException: | |
956 client.sendError(iq_elt, 'bad-request', "Root path can't be used") | |
957 return | |
958 try: | |
959 access_type = file_data['access'][C.ACCESS_PERM_READ]['type'] | |
960 except KeyError: | |
961 access_model = 'whitelist' | |
962 else: | |
963 access_model = 'open' if access_type == C.ACCESS_TYPE_PUBLIC else 'whitelist' | |
964 | |
965 iq_result_elt = xmlstream.toResponse(iq_elt, "result") | |
966 configuration_elt = iq_result_elt.addElement((NS_FIS_CONFIGURATION, 'configuration')) | |
967 form = data_form.Form(formType="form", formNamespace=NS_FIS_CONFIGURATION) | |
968 form.makeFields({'access_model': access_model}) | |
969 configuration_elt.addChild(form.toElement()) | |
970 client.send(iq_result_elt) | |
971 | |
972 def _onComponentConfigurationSet(self, iq_elt, client): | |
973 iq_elt.handled = True | |
974 defer.ensureDeferred(self.onComponentConfigurationSet(client, iq_elt)) | |
975 | |
976 async def onComponentConfigurationSet(self, client, iq_elt): | |
977 try: | |
978 ( | |
979 from_jid, configuration_elt, path, namespace, file_data | |
980 ) = await self._parseElement(client, iq_elt, "configuration", NS_FIS_CONFIGURATION) | |
981 except exceptions.CancelError: | |
982 return | |
983 except RootPathException: | |
984 client.sendError(iq_elt, 'bad-request', "Root path can't be used") | |
985 return | |
986 | |
987 from_jid_bare = from_jid.userhostJID() | |
988 is_owner = from_jid_bare == file_data.get('owner') | |
989 if not is_owner: | |
990 log.warning( | |
991 f"{from_jid} tried to modify {path} configuration while the owner is " | |
992 f"{file_data['owner']}" | |
993 ) | |
994 client.sendError(iq_elt, 'forbidden') | |
995 return | |
996 | |
997 form = data_form.findForm(configuration_elt, NS_FIS_CONFIGURATION) | |
998 for name, value in form.items(): | |
999 if name == 'access_model': | |
1000 await self.host.memory.setFileAccessModel(client, file_data, value) | |
1001 else: | |
1002 # TODO: send a IQ error? | |
1003 log.warning( | |
1004 f"Trying to set a not implemented configuration option: {name}") | |
1005 iq_result_elt = xmlstream.toResponse(iq_elt, "result") | |
1006 client.send(iq_result_elt) | |
1007 | |
859 # file methods # | 1008 # file methods # |
860 | 1009 |
861 def _serializeData(self, files_data): | 1010 def _serializeData(self, files_data): |
862 for file_data in files_data: | 1011 for file_data in files_data: |
863 for key, value in file_data.items(): | 1012 for key, value in file_data.items(): |