comparison sat_frontends/jp/cmd_roster.py @ 3028:ab2696e34d29

Python 3 port: /!\ this is a huge commit /!\ starting from this commit, SàT is needs Python 3.6+ /!\ SàT maybe be instable or some feature may not work anymore, this will improve with time This patch port backend, bridge and frontends to Python 3. Roughly this has been done this way: - 2to3 tools has been applied (with python 3.7) - all references to python2 have been replaced with python3 (notably shebangs) - fixed files not handled by 2to3 (notably the shell script) - several manual fixes - fixed issues reported by Python 3 that where not handled in Python 2 - replaced "async" with "async_" when needed (it's a reserved word from Python 3.7) - replaced zope's "implements" with @implementer decorator - temporary hack to handle data pickled in database, as str or bytes may be returned, to be checked later - fixed hash comparison for password - removed some code which is not needed anymore with Python 3 - deactivated some code which needs to be checked (notably certificate validation) - tested with jp, fixed reported issues until some basic commands worked - ported Primitivus (after porting dependencies like urwid satext) - more manual fixes
author Goffi <goffi@goffi.org>
date Tue, 13 Aug 2019 19:08:41 +0200
parents 7c8773723200
children fee60f17ebac
comparison
equal deleted inserted replaced
3027:ff5bcb12ae60 3028:ab2696e34d29
16 # GNU Affero General Public License for more details. 16 # GNU Affero General Public License for more details.
17 17
18 # You should have received a copy of the GNU Affero General Public License 18 # You should have received a copy of the GNU Affero General Public License
19 # along with this program. If not, see <http://www.gnu.org/licenses/>. 19 # along with this program. If not, see <http://www.gnu.org/licenses/>.
20 20
21 import base 21 from . import base
22 from collections import OrderedDict 22 from collections import OrderedDict
23 from functools import partial 23 from functools import partial
24 from sat.core.i18n import _ 24 from sat.core.i18n import _
25 from sat_frontends.jp.constants import Const as C 25 from sat_frontends.jp.constants import Const as C
26 from twisted.words.protocols.jabber import jid 26 from twisted.words.protocols.jabber import jid
41 41
42 def start(self): 42 def start(self):
43 self.host.bridge.getContacts(profile_key=self.host.profile, callback=self.gotContacts, errback=self.error) 43 self.host.bridge.getContacts(profile_key=self.host.profile, callback=self.gotContacts, errback=self.error)
44 44
45 def error(self, failure): 45 def error(self, failure):
46 print (_("Error while retrieving the contacts [%s]") % failure) 46 print((_("Error while retrieving the contacts [%s]") % failure))
47 self.host.quit(1) 47 self.host.quit(1)
48 48
49 def ask_confirmation(self, no_sub, no_from, no_to): 49 def ask_confirmation(self, no_sub, no_from, no_to):
50 """Ask the confirmation before removing contacts. 50 """Ask the confirmation before removing contacts.
51 51
53 @param no_from (list[unicode]): list of contacts with no 'from' subscription 53 @param no_from (list[unicode]): list of contacts with no 'from' subscription
54 @param no_to (list[unicode]): list of contacts with no 'to' subscription 54 @param no_to (list[unicode]): list of contacts with no 'to' subscription
55 @return bool 55 @return bool
56 """ 56 """
57 if no_sub: 57 if no_sub:
58 print "There's no subscription between profile [%s] and the following contacts:" % self.host.profile 58 print("There's no subscription between profile [%s] and the following contacts:" % self.host.profile)
59 print " " + "\n ".join(no_sub) 59 print(" " + "\n ".join(no_sub))
60 if no_from: 60 if no_from:
61 print "There's no 'from' subscription between profile [%s] and the following contacts:" % self.host.profile 61 print("There's no 'from' subscription between profile [%s] and the following contacts:" % self.host.profile)
62 print " " + "\n ".join(no_from) 62 print(" " + "\n ".join(no_from))
63 if no_to: 63 if no_to:
64 print "There's no 'to' subscription between profile [%s] and the following contacts:" % self.host.profile 64 print("There's no 'to' subscription between profile [%s] and the following contacts:" % self.host.profile)
65 print " " + "\n ".join(no_to) 65 print(" " + "\n ".join(no_to))
66 message = "REMOVE them from profile [%s]'s roster" % self.host.profile 66 message = "REMOVE them from profile [%s]'s roster" % self.host.profile
67 while True: 67 while True:
68 res = raw_input("%s (y/N)? " % message) 68 res = input("%s (y/N)? " % message)
69 if not res or res.lower() == 'n': 69 if not res or res.lower() == 'n':
70 return False 70 return False
71 if res.lower() == 'y': 71 if res.lower() == 'y':
72 return True 72 return True
73 73
85 elif self.args.no_from: 85 elif self.args.no_from:
86 no_from.append(contact) 86 no_from.append(contact)
87 elif not to and self.args.no_to: 87 elif not to and self.args.no_to:
88 no_to.append(contact) 88 no_to.append(contact)
89 if not no_sub and not no_from and not no_to: 89 if not no_sub and not no_from and not no_to:
90 print "Nothing to do - there's a from and/or to subscription(s) between profile [%s] and each of its contacts" % self.host.profile 90 print("Nothing to do - there's a from and/or to subscription(s) between profile [%s] and each of its contacts" % self.host.profile)
91 elif self.ask_confirmation(no_sub, no_from, no_to): 91 elif self.ask_confirmation(no_sub, no_from, no_to):
92 for contact in no_sub + no_from + no_to: 92 for contact in no_sub + no_from + no_to:
93 self.host.bridge.delContact(contact, profile_key=self.host.profile, callback=lambda __: None, errback=lambda failure: None) 93 self.host.bridge.delContact(contact, profile_key=self.host.profile, callback=lambda __: None, errback=lambda failure: None)
94 self.host.quit() 94 self.host.quit()
95 95
105 105
106 def start(self): 106 def start(self):
107 self.host.bridge.getContacts(profile_key=self.host.profile, callback=self.gotContacts, errback=self.error) 107 self.host.bridge.getContacts(profile_key=self.host.profile, callback=self.gotContacts, errback=self.error)
108 108
109 def error(self, failure): 109 def error(self, failure):
110 print (_("Error while retrieving the contacts [%s]") % failure) 110 print((_("Error while retrieving the contacts [%s]") % failure))
111 self.host.quit(1) 111 self.host.quit(1)
112 112
113 def gotContacts(self, contacts): 113 def gotContacts(self, contacts):
114 """Process the list of contacts. 114 """Process the list of contacts.
115 115
133 if groups: 133 if groups:
134 unique_groups.update(groups) 134 unique_groups.update(groups)
135 total_group_subscription += len(groups) 135 total_group_subscription += len(groups)
136 if not groups: 136 if not groups:
137 no_group += 1 137 no_group += 1
138 hosts = OrderedDict(sorted(hosts.items(), key=lambda item:-item[1])) 138 hosts = OrderedDict(sorted(list(hosts.items()), key=lambda item:-item[1]))
139 139
140 print 140 print()
141 print "Total number of contacts: %d" % len(contacts) 141 print("Total number of contacts: %d" % len(contacts))
142 print "Number of different hosts: %d" % len(hosts) 142 print("Number of different hosts: %d" % len(hosts))
143 print 143 print()
144 for host, count in hosts.iteritems(): 144 for host, count in hosts.items():
145 print "Contacts on {host}: {count} ({rate:.1f}%)".format(host=host, count=count, rate=100 * float(count) / len(contacts)) 145 print("Contacts on {host}: {count} ({rate:.1f}%)".format(host=host, count=count, rate=100 * float(count) / len(contacts)))
146 print 146 print()
147 print "Contacts with no 'from' subscription: %d" % no_from 147 print("Contacts with no 'from' subscription: %d" % no_from)
148 print "Contacts with no 'to' subscription: %d" % no_to 148 print("Contacts with no 'to' subscription: %d" % no_to)
149 print "Contacts with no subscription at all: %d" % no_sub 149 print("Contacts with no subscription at all: %d" % no_sub)
150 print 150 print()
151 print "Total number of groups: %d" % len(unique_groups) 151 print("Total number of groups: %d" % len(unique_groups))
152 try: 152 try:
153 contacts_per_group = float(total_group_subscription) / len(unique_groups) 153 contacts_per_group = float(total_group_subscription) / len(unique_groups)
154 except ZeroDivisionError: 154 except ZeroDivisionError:
155 contacts_per_group = 0 155 contacts_per_group = 0
156 print "Average contacts per group: {:.1f}".format(contacts_per_group) 156 print("Average contacts per group: {:.1f}".format(contacts_per_group))
157 try: 157 try:
158 groups_per_contact = float(total_group_subscription) / len(contacts) 158 groups_per_contact = float(total_group_subscription) / len(contacts)
159 except ZeroDivisionError: 159 except ZeroDivisionError:
160 groups_per_contact = 0 160 groups_per_contact = 0
161 print "Average groups' subscriptions per contact: {:.1f}".format(groups_per_contact) 161 print("Average groups' subscriptions per contact: {:.1f}".format(groups_per_contact))
162 print "Contacts not assigned to any group: %d" % no_group 162 print("Contacts not assigned to any group: %d" % no_group)
163 self.host.quit() 163 self.host.quit()
164 164
165 165
166 class Get(base.CommandBase): 166 class Get(base.CommandBase):
167 167
176 176
177 def start(self): 177 def start(self):
178 self.host.bridge.getContacts(profile_key=self.host.profile, callback=self.gotContacts, errback=self.error) 178 self.host.bridge.getContacts(profile_key=self.host.profile, callback=self.gotContacts, errback=self.error)
179 179
180 def error(self, failure): 180 def error(self, failure):
181 print (_("Error while retrieving the contacts [%s]") % failure) 181 print((_("Error while retrieving the contacts [%s]") % failure))
182 self.host.quit(1) 182 self.host.quit(1)
183 183
184 def gotContacts(self, contacts): 184 def gotContacts(self, contacts):
185 """Process the list of contacts. 185 """Process the list of contacts.
186 186
198 if self.args.subscriptions: 198 if self.args.subscriptions:
199 args.append("ask" if C.bool(attrs["ask"]) else "") 199 args.append("ask" if C.bool(attrs["ask"]) else "")
200 args.append("from" if C.bool(attrs["from"]) else "") 200 args.append("from" if C.bool(attrs["from"]) else "")
201 args.append("to" if C.bool(attrs["to"]) else "") 201 args.append("to" if C.bool(attrs["to"]) else "")
202 if self.args.name: 202 if self.args.name:
203 args.append(unicode(attrs.get("name", ""))) 203 args.append(str(attrs.get("name", "")))
204 if self.args.groups: 204 if self.args.groups:
205 args.append(u"\t".join(groups) if groups else "") 205 args.append("\t".join(groups) if groups else "")
206 print u";".join(["{}"] * field_count).format(*args).encode("utf-8") 206 print(";".join(["{}"] * field_count).format(*args).encode("utf-8"))
207 self.host.quit() 207 self.host.quit()
208 208
209 209
210 class Resync(base.CommandBase): 210 class Resync(base.CommandBase):
211 211
212 def __init__(self, host): 212 def __init__(self, host):
213 super(Resync, self).__init__( 213 super(Resync, self).__init__(
214 host, 'resync', help=_(u'do a full resynchronisation of roster with server')) 214 host, 'resync', help=_('do a full resynchronisation of roster with server'))
215 self.need_loop = True 215 self.need_loop = True
216 216
217 def add_parser_options(self): 217 def add_parser_options(self):
218 pass 218 pass
219 219
220 def rosterResyncCb(self): 220 def rosterResyncCb(self):
221 self.disp(_(u"Roster resynchronized")) 221 self.disp(_("Roster resynchronized"))
222 self.host.quit(C.EXIT_OK) 222 self.host.quit(C.EXIT_OK)
223 223
224 def start(self): 224 def start(self):
225 self.host.bridge.rosterResync(profile_key=self.host.profile, 225 self.host.bridge.rosterResync(profile_key=self.host.profile,
226 callback=self.rosterResyncCb, 226 callback=self.rosterResyncCb,
227 errback=partial( 227 errback=partial(
228 self.errback, 228 self.errback,
229 msg=_(u"can't resynchronise roster: {}"), 229 msg=_("can't resynchronise roster: {}"),
230 exit_code=C.EXIT_BRIDGE_ERRBACK, 230 exit_code=C.EXIT_BRIDGE_ERRBACK,
231 )) 231 ))
232 232
233 233
234 class Roster(base.CommandBase): 234 class Roster(base.CommandBase):