1# -*- coding: utf-8 -*- 2 3# Copyright(C) 2010-2012 Romain Bignon 4# 5# This file is part of weboob. 6# 7# weboob is free software: you can redistribute it and/or modify 8# it under the terms of the GNU Lesser General Public License as published by 9# the Free Software Foundation, either version 3 of the License, or 10# (at your option) any later version. 11# 12# weboob is distributed in the hope that it will be useful, 13# but WITHOUT ANY WARRANTY; without even the implied warranty of 14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15# GNU Lesser General Public License for more details. 16# 17# You should have received a copy of the GNU Lesser General Public License 18# along with weboob. If not, see <http://www.gnu.org/licenses/>. 19 20from __future__ import print_function 21 22from copy import copy 23 24from weboob.core import CallErrors 25from weboob.tools.application.repl import ReplApplication 26from weboob.applications.boobmsg import Boobmsg 27from weboob.capabilities.dating import CapDating, OptimizationNotFound 28from weboob.tools.application.formatters.iformatter import PrettyFormatter 29 30 31__all__ = ['HaveDate'] 32 33 34class EventListFormatter(PrettyFormatter): 35 MANDATORY_FIELDS = ('date', 'type') 36 37 def get_title(self, event): 38 s = u'(%s) %s' % (event.date, event.type) 39 if hasattr(event, 'contact') and event.contact: 40 s += u' — %s (%s)' % (event.contact.name, event.contact.id) 41 42 return s 43 44 def get_description(self, event): 45 if hasattr(event, 'message'): 46 return event.message 47 48 49class HaveDate(Boobmsg): 50 APPNAME = 'havedate' 51 VERSION = '2.0' 52 COPYRIGHT = 'Copyright(C) 2010-YEAR Romain Bignon' 53 DESCRIPTION = "Console application allowing to interact with various dating websites " \ 54 "and to optimize seduction algorithmically." 55 SHORT_DESCRIPTION = "interact with dating websites" 56 STORAGE_FILENAME = 'dating.storage' 57 STORAGE = {'optims': {}} 58 CAPS = CapDating 59 EXTRA_FORMATTERS = copy(Boobmsg.EXTRA_FORMATTERS) 60 EXTRA_FORMATTERS['events'] = EventListFormatter 61 COMMANDS_FORMATTERS = copy(Boobmsg.COMMANDS_FORMATTERS) 62 COMMANDS_FORMATTERS['optim'] = 'table' 63 COMMANDS_FORMATTERS['events'] = 'events' 64 65 def load_default_backends(self): 66 self.load_backends(CapDating, storage=self.create_storage(self.STORAGE_FILENAME)) 67 68 def main(self, argv): 69 self.load_config() 70 71 try: 72 self.do('init_optimizations').wait() 73 except CallErrors as e: 74 self.bcall_errors_handler(e) 75 76 optimizations = self.storage.get('optims') 77 for optim, backends in optimizations.items(): 78 self.optims('start', backends, optim, store=False) 79 80 return ReplApplication.main(self, argv) 81 82 def do_query(self, id): 83 """ 84 query ID 85 86 Send a query to someone. 87 """ 88 _id, backend_name = self.parse_id(id, unique_backend=True) 89 90 for query in self.do('send_query', _id, backends=backend_name): 91 print('%s' % query.message) 92 93 def edit_optims(self, backend_names, optims_names, stop=False): 94 if optims_names is None: 95 print('Error: missing parameters.', file=self.stderr) 96 return 2 97 98 for optim_name in optims_names.split(): 99 backends_optims = {} 100 for optim in self.do('get_optimization', optim_name, backends=backend_names): 101 if optim: 102 backends_optims[optim.backend] = optim 103 for backend_name, optim in backends_optims.items(): 104 if len(optim.CONFIG) == 0: 105 print('%s.%s does not require configuration.' % (backend_name, optim_name)) 106 continue 107 108 was_running = optim.is_running() 109 if stop and was_running: 110 print('Stopping %s: %s' % (optim_name, backend_name)) 111 optim.stop() 112 params = optim.get_config() 113 if params is None: 114 params = {} 115 print('Configuration of %s.%s' % (backend_name, optim_name)) 116 print('-----------------%s-%s' % ('-' * len(backend_name), '-' * len(optim_name))) 117 for key, value in optim.CONFIG.items(): 118 params[key] = self.ask(value, default=params[key] if (key in params) else value.default) 119 120 optim.set_config(params) 121 if stop and was_running: 122 print('Starting %s: %s' % (optim_name, backend_name)) 123 optim.start() 124 125 def optims(self, function, backend_names, optims, store=True): 126 if optims is None: 127 print('Error: missing parameters.', file=self.stderr) 128 return 2 129 130 for optim_name in optims.split(): 131 try: 132 if store: 133 storage_optim = set(self.storage.get('optims', optim_name, default=[])) 134 self.stdout.write('%sing %s:' % (function.capitalize(), optim_name)) 135 for optim in self.do('get_optimization', optim_name, backends=backend_names): 136 if optim: 137 # It's useless to start a started optim, or to stop a stopped one. 138 if (function == 'start' and optim.is_running()) or \ 139 (function == 'stop' and not optim.is_running()): 140 continue 141 142 # Optim is not configured and would be, ask user to do it. 143 if function == 'start' and len(optim.CONFIG) > 0 and optim.get_config() is None: 144 self.edit_optims(optim.backend, optim_name) 145 146 ret = getattr(optim, function)() 147 self.stdout.write(' ' + optim.backend) 148 if not ret: 149 self.stdout.write('(failed)') 150 self.stdout.flush() 151 if store: 152 if function == 'start' and ret: 153 storage_optim.add(optim.backend) 154 elif function == 'stop': 155 try: 156 storage_optim.remove(optim.backend) 157 except KeyError: 158 pass 159 self.stdout.write('.\n') 160 except CallErrors as errors: 161 for backend, error, backtrace in errors: 162 if isinstance(error, OptimizationNotFound): 163 self.logger.error(u'Error(%s): Optimization "%s" not found' % (backend.name, optim_name)) 164 else: 165 self.bcall_error_handler(backend, error, backtrace) 166 if store: 167 if len(storage_optim) > 0: 168 self.storage.set('optims', optim_name, list(storage_optim)) 169 else: 170 self.storage.delete('optims', optim_name) 171 if store: 172 self.storage.save() 173 174 def complete_optim(self, text, line, *ignored): 175 args = line.split(' ') 176 if len(args) == 2: 177 return ['list', 'start', 'stop', 'edit'] 178 elif len(args) == 3: 179 return [backend.name for backend in self.enabled_backends] 180 elif len(args) >= 4: 181 if args[2] == '*': 182 backend = None 183 else: 184 backend = args[2] 185 optims = set() 186 for optim in self.do('iter_optimizations', backends=backend): 187 optims.add(optim.id) 188 return sorted(optims - set(args[3:])) 189 190 def do_optim(self, line): 191 """ 192 optim [list | start | edit | stop] BACKEND [OPTIM1 [OPTIM2 ...]] 193 194 All dating backends offer optimization services. This command can be 195 manage them. 196 Use * us BACKEND value to apply command to all backends. 197 198 Commands: 199 * list list all available optimizations of a backend 200 * start start optimization services on a backend 201 * edit configure an optimization service for a backend 202 * stop stop optimization services on a backend 203 """ 204 cmd, backend_name, optims_names = self.parse_command_args(line, 3) 205 206 if backend_name == '*': 207 backend_name = None 208 elif backend_name is not None and backend_name not in [b.name for b in self.enabled_backends]: 209 print('Error: No such backend "%s"' % backend_name, file=self.stderr) 210 return 1 211 212 if cmd == 'start': 213 return self.optims('start', backend_name, optims_names) 214 if cmd == 'stop': 215 return self.optims('stop', backend_name, optims_names) 216 if cmd == 'edit': 217 self.edit_optims(backend_name, optims_names, stop=True) 218 return 219 if cmd == 'list' or cmd is None: 220 if optims_names is not None: 221 optims_names = optims_names.split() 222 223 optims = {} 224 backends = set() 225 for optim in self.do('iter_optimizations', backends=backend_name): 226 if optims_names is not None and optim.id not in optims_names: 227 continue 228 if optim.is_running(): 229 status = 'RUNNING' 230 else: 231 status = '-------' 232 if optim.id not in optims: 233 optims[optim.id] = {optim.backend: status} 234 else: 235 optims[optim.id][optim.backend] = status 236 backends.add(optim.backend) 237 238 backends = sorted(backends) 239 for name, backends_status in optims.items(): 240 line = [('name', name)] 241 for b in backends: 242 try: 243 status = backends_status[b] 244 except KeyError: 245 status = '' 246 line.append((b, status)) 247 self.format(tuple(line)) 248 return 249 print("No such command '%s'" % cmd, file=self.stderr) 250 return 1 251 252 def do_events(self, line): 253 """ 254 events 255 256 Display dating events. 257 """ 258 self.change_path([u'events']) 259 self.start_format() 260 for event in self.do('iter_events'): 261 self.cached_format(event) 262