Mercurial > libervia-backend
comparison sat_frontends/jp/cmd_roster.py @ 2562:26edcf3a30eb
core, setup: huge cleaning:
- moved directories from src and frontends/src to sat and sat_frontends, which is the recommanded naming convention
- move twisted directory to root
- removed all hacks from setup.py, and added missing dependencies, it is now clean
- use https URL for website in setup.py
- removed "Environment :: X11 Applications :: GTK", as wix is deprecated and removed
- renamed sat.sh to sat and fixed its installation
- added python_requires to specify Python version needed
- replaced glib2reactor which use deprecated code by gtk3reactor
sat can now be installed directly from virtualenv without using --system-site-packages anymore \o/
author | Goffi <goffi@goffi.org> |
---|---|
date | Mon, 02 Apr 2018 19:44:50 +0200 |
parents | frontends/src/jp/cmd_roster.py@0046283a285d |
children | 378188abe941 |
comparison
equal
deleted
inserted
replaced
2561:bd30dc3ffe5a | 2562:26edcf3a30eb |
---|---|
1 #!/usr/bin/env python2 | |
2 # -*- coding: utf-8 -*- | |
3 | |
4 # jp: a SAT command line tool | |
5 # Copyright (C) 2009-2018 Jérôme Poisson (goffi@goffi.org) | |
6 # Copyright (C) 2003-2016 Adrien Cossa (souliane@mailoo.org) | |
7 | |
8 # This program is free software: you can redistribute it and/or modify | |
9 # it under the terms of the GNU Affero General Public License as published by | |
10 # the Free Software Foundation, either version 3 of the License, or | |
11 # (at your option) any later version. | |
12 | |
13 # This program is distributed in the hope that it will be useful, | |
14 # but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 # GNU Affero General Public License for more details. | |
17 | |
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/>. | |
20 | |
21 import base | |
22 from sat_frontends.jp.constants import Const as C | |
23 from sat.core.i18n import _ | |
24 | |
25 from twisted.words.protocols.jabber import jid | |
26 from collections import OrderedDict | |
27 | |
28 __commands__ = ["Roster"] | |
29 | |
30 | |
31 | |
32 class Purge(base.CommandBase): | |
33 | |
34 def __init__(self, host): | |
35 super(Purge, self).__init__(host, 'purge', help=_('Purge the roster from its contacts with no subscription')) | |
36 self.need_loop = True | |
37 | |
38 def add_parser_options(self): | |
39 self.parser.add_argument("--no_from", action="store_true", help=_("Also purge contacts with no 'from' subscription")) | |
40 self.parser.add_argument("--no_to", action="store_true", help=_("Also purge contacts with no 'to' subscription")) | |
41 | |
42 def start(self): | |
43 self.host.bridge.getContacts(profile_key=self.host.profile, callback=self.gotContacts, errback=self.error) | |
44 | |
45 def error(self, failure): | |
46 print (_("Error while retrieving the contacts [%s]") % failure) | |
47 self.host.quit(1) | |
48 | |
49 def ask_confirmation(self, no_sub, no_from, no_to): | |
50 """Ask the confirmation before removing contacts. | |
51 | |
52 @param no_sub (list[unicode]): list of contacts with no 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 | |
55 @return bool | |
56 """ | |
57 if no_sub: | |
58 print "There's no subscription between profile [%s] and the following contacts:" % self.host.profile | |
59 print " " + "\n ".join(no_sub) | |
60 if no_from: | |
61 print "There's no 'from' subscription between profile [%s] and the following contacts:" % self.host.profile | |
62 print " " + "\n ".join(no_from) | |
63 if no_to: | |
64 print "There's no 'to' subscription between profile [%s] and the following contacts:" % self.host.profile | |
65 print " " + "\n ".join(no_to) | |
66 message = "REMOVE them from profile [%s]'s roster" % self.host.profile | |
67 while True: | |
68 res = raw_input("%s (y/N)? " % message) | |
69 if not res or res.lower() == 'n': | |
70 return False | |
71 if res.lower() == 'y': | |
72 return True | |
73 | |
74 def gotContacts(self, contacts): | |
75 """Process the list of contacts. | |
76 | |
77 @param contacts(list[tuple]): list of contacts with their attributes and groups | |
78 """ | |
79 no_sub, no_from, no_to = [], [], [] | |
80 for contact, attrs, groups in contacts: | |
81 from_, to = C.bool(attrs["from"]), C.bool(attrs["to"]) | |
82 if not from_: | |
83 if not to: | |
84 no_sub.append(contact) | |
85 elif self.args.no_from: | |
86 no_from.append(contact) | |
87 elif not to and self.args.no_to: | |
88 no_to.append(contact) | |
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 | |
91 elif self.ask_confirmation(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 dummy: None, errback=lambda failure: None) | |
94 self.host.quit() | |
95 | |
96 | |
97 class Stats(base.CommandBase): | |
98 | |
99 def __init__(self, host): | |
100 super(Stats, self).__init__(host, 'stats', help=_('Show statistics about a roster')) | |
101 self.need_loop = True | |
102 | |
103 def add_parser_options(self): | |
104 pass | |
105 | |
106 def start(self): | |
107 self.host.bridge.getContacts(profile_key=self.host.profile, callback=self.gotContacts, errback=self.error) | |
108 | |
109 def error(self, failure): | |
110 print (_("Error while retrieving the contacts [%s]") % failure) | |
111 self.host.quit(1) | |
112 | |
113 def gotContacts(self, contacts): | |
114 """Process the list of contacts. | |
115 | |
116 @param contacts(list[tuple]): list of contacts with their attributes and groups | |
117 """ | |
118 hosts = {} | |
119 unique_groups = set() | |
120 no_sub, no_from, no_to, no_group, total_group_subscription = 0, 0, 0, 0, 0 | |
121 for contact, attrs, groups in contacts: | |
122 from_, to = C.bool(attrs["from"]), C.bool(attrs["to"]) | |
123 if not from_: | |
124 if not to: | |
125 no_sub += 1 | |
126 else: | |
127 no_from += 1 | |
128 elif not to: | |
129 no_to += 1 | |
130 host = jid.JID(contact).host | |
131 hosts.setdefault(host, 0) | |
132 hosts[host] += 1 | |
133 if groups: | |
134 unique_groups.update(groups) | |
135 total_group_subscription += len(groups) | |
136 if not groups: | |
137 no_group += 1 | |
138 hosts = OrderedDict(sorted(hosts.items(), key=lambda item:-item[1])) | |
139 | |
140 print | |
141 print "Total number of contacts: %d" % len(contacts) | |
142 print "Number of different hosts: %d" % len(hosts) | |
143 print | |
144 for host, count in hosts.iteritems(): | |
145 print "Contacts on {host}: {count} ({rate:.1f}%)".format(host=host, count=count, rate=100 * float(count) / len(contacts)) | |
146 print | |
147 print "Contacts with no 'from' subscription: %d" % no_from | |
148 print "Contacts with no 'to' subscription: %d" % no_to | |
149 print "Contacts with no subscription at all: %d" % no_sub | |
150 print | |
151 print "Total number of groups: %d" % len(unique_groups) | |
152 try: | |
153 contacts_per_group = float(total_group_subscription) / len(unique_groups) | |
154 except ZeroDivisionError: | |
155 contacts_per_group = 0 | |
156 print "Average contacts per group: {:.1f}".format(contacts_per_group) | |
157 try: | |
158 groups_per_contact = float(total_group_subscription) / len(contacts) | |
159 except ZeroDivisionError: | |
160 groups_per_contact = 0 | |
161 print "Average groups' subscriptions per contact: {:.1f}".format(groups_per_contact) | |
162 print "Contacts not assigned to any group: %d" % no_group | |
163 self.host.quit() | |
164 | |
165 | |
166 class Get(base.CommandBase): | |
167 | |
168 def __init__(self, host): | |
169 super(Get, self).__init__(host, 'get', help=_('Retrieve the roster contacts')) | |
170 self.need_loop = True | |
171 | |
172 def add_parser_options(self): | |
173 self.parser.add_argument("--subscriptions", action="store_true", help=_("Show the contacts' subscriptions")) | |
174 self.parser.add_argument("--groups", action="store_true", help=_("Show the contacts' groups")) | |
175 self.parser.add_argument("--name", action="store_true", help=_("Show the contacts' names")) | |
176 | |
177 def start(self): | |
178 self.host.bridge.getContacts(profile_key=self.host.profile, callback=self.gotContacts, errback=self.error) | |
179 | |
180 def error(self, failure): | |
181 print (_("Error while retrieving the contacts [%s]") % failure) | |
182 self.host.quit(1) | |
183 | |
184 def gotContacts(self, contacts): | |
185 """Process the list of contacts. | |
186 | |
187 @param contacts(list[tuple]): list of contacts with their attributes and groups | |
188 """ | |
189 field_count = 1 # only display the contact by default | |
190 if self.args.subscriptions: | |
191 field_count += 3 # ask, from, to | |
192 if self.args.name: | |
193 field_count += 1 | |
194 if self.args.groups: | |
195 field_count += 1 | |
196 for contact, attrs, groups in contacts: | |
197 args = [contact] | |
198 if self.args.subscriptions: | |
199 args.append("ask" if C.bool(attrs["ask"]) else "") | |
200 args.append("from" if C.bool(attrs["from"]) else "") | |
201 args.append("to" if C.bool(attrs["to"]) else "") | |
202 if self.args.name: | |
203 args.append(unicode(attrs.get("name", ""))) | |
204 if self.args.groups: | |
205 args.append(u"\t".join(groups) if groups else "") | |
206 print u";".join(["{}"] * field_count).format(*args).encode("utf-8") | |
207 self.host.quit() | |
208 | |
209 | |
210 class Roster(base.CommandBase): | |
211 subcommands = (Get, Stats, Purge) | |
212 | |
213 def __init__(self, host): | |
214 super(Roster, self).__init__(host, 'roster', use_profile=True, help=_("Manage an entity's roster")) |