def set_chat_id(email, tgname, chat_id): try: profile = None log.info( f"set chat id email: {email} tgname: {tgname} chat_id: {chat_id}") # find profile if email: # do not use tgname in this search! profile = Profile.objects.get(user__email=email) else: if tgname: # case-insensitive search for telegram_name profile = Profile.objects.get(telegram_name__iexact=tgname) else: profile = Profile.objects.get(telegram_name=str(chat_id)) log.info(f"got profile: {profile}") # verify profile if profile.telegram_name.lower() != tgname.lower( ) and profile.telegram_name != str(chat_id): if tgname: return 'Set telegram name {} in profile'.format(tgname) else: return 'Set telegram name {} in profile'.format(chat_id) rs = RemoteServer(ci=profile.ci) if tgname: jr = rs.api_admin_tglink(email, tgname, chat_id) else: jr = rs.api_admin_tglink(email, chat_id, chat_id) r = json.loads(jr) # sync if needed if rs.ci != myci(): for username in r['sync']: data = rs.get_user(username) ie = Impex() ie.set_verbosity(0) ie.preimport_cleanup(data) ie.import_data(data) return r['msg'] except Profile.DoesNotExist as e: log.info('Not found profile for tg user {}. Try little later?'.format( tgname)) if tgname: return "Telegram user with name '{}' not known in Okerr. Sorry. Please set this name in okerr profile first and try little later.".format( tgname) else: return "Telegram user with id {} not known in Okerr. Sorry. Please set this id in okerr profile first and try little later.".format( chat_id) except Profile.MultipleObjectsReturned as e: log.error('Multiple profiles for tg user {}'.format(tgname)) return "More then one telegram user '{}' in Okerr. Use /on <email> command.".format( tgname)
def sync(self, url, overwrite=True): rs = RemoteServer(url = url) User = get_user_model() Profile = self.get_model('Profile') ci = myci() rci = rs.get_ci() userlist = rs.get_userlist() for email in userlist: if not email: continue log.info('sync user {} from {} rci: {}'.format(email, url2host(url), rci)) self.vprint(2, 'sync user {} from {}'.format(email, url2host(url))) profile = None # get local user try: profile = Profile.objects.get(user__email=email) if profile.ci == ci and not overwrite: log.error('sync: user {} ci: {} is mine!!'.format(email, ci)) raise Exception('user: {} ci: {} is mine and not overwrite!'.format(email, ci)) except User.DoesNotExist: pass except Profile.DoesNotExist: # no profile. okay. we will re-create it. it's safe - we dont have profile anyway pass try: data = rs.get_user(email) except (requests.exceptions.RequestException, RemoteServerExc) as e: log.warning('sync error (user {} from {}): {}'.format(email, rs.name, str(e))) continue # delete this user before importing if profile: if overwrite: # log.debug("ZZZ luser.delete (profile: {})".format(profile)) profile.predelete() profile.delete() else: # do not import this user, because it's local and not overwrite continue #log.debug("ZZZ import data") self.import_data(data) self.delete_deleted(rs)
def syncmap(cls, hostname=None): if hostname is None: hostname = settings.HOSTNAME if not settings.SYNC_MAP: # None or empty dict return if not hostname in settings.SYNC_MAP: log.error('No {} in SYNC_MAP'.format(hostname)) return ie = Impex() ie.set_verbosity(0) for rsname in settings.SYNC_MAP[hostname]: rs = RemoteServer(name = rsname) try: log.info('syncmap from {} {}'.format(rsname, url2host(rs.url))) ie.sync(rs.url) except Exception as e: log.error('syncmap exception {}: {} {}: {}'.format(url2host(rsname), type(e), str(e), traceback.format_exc()))
def setci_remote(email,ci): me = RemoteServer.me() for rs in me.all_other(): if rs.is_net(): print(("update to rs {}: {}".format(rs.name, rs.url))) try: rs.set_ci(ci, email) except requests.exceptions.RequestException as e: print("FAILED: {}".format(str(e)))
def reinit(self): # no need to reinit anything in db app_model = oauth2_provider.models.get_application_model() if not hasattr(settings, 'OAUTH2_CLIENTS'): print( "skip reinit OAUTH2 because not configured (usually this is OK)" ) return User = get_user_model() app_model.objects.all().delete() appd = settings.OAUTH2_CLIENTS print("appd:", appd) app = app_model() app.user = None for f in self.fields: setattr(app, f, appd[f]) # generate redirect_uris redirect_uris = '' # allsrv = settings.CLUSTER + ['cp.okerr.com'] for rs in RemoteServer.all_rs(): url = rs.url + 'oauth2/callback' print("add cluster url:", url) redirect_uris += url + '\r\n' #if hasattr(settings, 'OAUTH2_REDIRECT_URI'): # for url in settings.OAUTH2_REDIRECT_URI: # print("add custom url:", url) # redirect_uris += url + '\r\n' app.redirect_uris = redirect_uris app.save()
def unset_chat_id(chat_id): try: for rs in RemoteServer.all_rs(): rs.api_admin_tglink(chat_id=chat_id) except Exception as e: print(e)
def cmd_qsum(update, ctx): bot = ctx.bot args = ctx.args reg_command(update, ctx) reported = 0 projects = list() if len(args): textid = args[0] else: textid = None chat_id = update.message.chat_id if textid: project = Project.get_by_textid(textid) if project is None: bot.send_message(chat_id=chat_id, text="No such project") return # has access? access = False for profile in Profile.objects.filter(telegram_chat_id=chat_id): if project.member(profile.user): access = True if access: projects.append(project) else: bot.send_message(chat_id=chat_id, text="No such project") return else: log.info('list all projects for #{}'.format(chat_id)) try: # all available projects for profile in Profile.objects.filter(telegram_chat_id=chat_id): for p in profile.projects(): if not p in projects: projects.append(p) except Exception as e: log.error('exc: {}'.format(e)) log.info("will list {} projects".format(len(projects))) if not projects: log.info("no projects!") bot.send_message(chat_id=chat_id, text="No projects", reply_markup=get_reply_markup(chat_id)) return for p in projects: rs = RemoteServer(ci=p.ci) data = rs.api_admin_qsum(p.get_textid()) log.info("show project {}".format(p.get_textid())) #msg = 'zzzzz' tpl = u''' Project *{}* ({}) Total {} (maintenance: {}, silent: {}, ERR: {}) ''' if data is None: log.error('api_admin_qsum for {} / {} returned None'.format( rs.name, p.get_textid())) bot.send_message( chat_id=chat_id, parse_mode=telegram.ParseMode.MARKDOWN, reply_markup=get_reply_markup(chat_id), text= 'Server {} for project {} unavailable at moment. Sorry. Try again later.' .format(rs.name, p.get_textid())) return msg = tpl.format(data['project'], data['textid'], data['cnt']['total'], data['cnt']['maintenance'], data['cnt']['silent'], data['cnt']['ERR']) for i in data['ERR'][:5]: try: link = rs.reverse('okerr:ilocator', { 'pid': data['textid'], 'iid': i['name'] }) msg += u'[{}]({}) = {} ({}) {} ago\n'.format( md_escape(i['name']), link, i['status'], md_escape(i['details']), i['age']) except Exception as e: print(e) if len(data['ERR']) > 5: msg += '(Only first 5 of {} shown)\n'.format(len(data['ERR'])) bot.send_message(chat_id=chat_id, parse_mode=telegram.ParseMode.MARKDOWN, reply_markup=get_reply_markup(chat_id), text=msg)
def main(): #global updater, log global log global bot global main_rs started = datetime.datetime.now() try: def_server = getattr(settings, 'SERVER_URL') except AttributeError: def_server = None parser = argparse.ArgumentParser(description='okerr telegram server.') parser.add_argument('-s', '--server', default=def_server, help='Remote okerr server URL') parser.add_argument('-v', dest='verbose', action='store_true', default=False, help='verbose mode') args = parser.parse_args() assert (settings.TGBOT_TOKEN) main_rs = RemoteServer(url=args.server) assert (main_rs) signal.signal(signal.SIGINT, sighandler) #logging.basicConfig( # format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', # level=logging.DEBUG) log = logging.getLogger('okerr-telebot') out = logging.StreamHandler(sys.stdout) out.setFormatter( logging.Formatter('%(asctime)s %(message)s', datefmt='%Y/%m/%d %H:%M:%S')) out.setLevel(logging.INFO) log.addHandler(out) err = logging.StreamHandler(sys.stderr) err.setLevel(logging.ERROR) log.addHandler(err) if args.verbose: log.setLevel(logging.DEBUG) else: log.setLevel(logging.INFO) log.propagate = False op.setlog(log) log.info("Start polling (pid: {} started: {})...".format( os.getpid(), started.strftime("%Y/%m/%d %H:%M:%S"))) # updater.start_polling() bot.infinity_polling() log.error("END OF INFINITY (pid: {} now: {} age: {})".format( os.getpid(), datetime.datetime.now().strftime("%Y/%m/%d %H:%M:%S"), (datetime.datetime.now() - started))) """
def cmd_qsum(message): reg_command(message) reported = 0 projects = list() chat_id = message.chat.id username = main_rs.api_admin_chat_id(chat_id) if username is None: tgname = message.from_user.username error_msg = "chat id: {} tg name: {} not linked to any account".format( chat_id, tgname) log.info(error_msg) bot.send_message(chat_id=chat_id, text=error_msg, reply_markup=get_reply_markup(chat_id)) return project_list = main_rs.api_admin_member(username) if project_list is None: log.info('Failed to get project list for user {} from {}'.format( username, main_rs)) bot.send_message(chat_id=chat_id, text="Internal exception, please contact support", reply_markup=get_reply_markup(chat_id)) return for textid in project_list: projects.append(textid) if not projects: log.info("no projects!") bot.send_message(chat_id=chat_id, text="No projects", reply_markup=get_reply_markup(chat_id)) return for textid in projects: url = main_rs.api_director(textid) rs = RemoteServer(url=url) data = rs.api_admin_qsum(textid) log.info("show project {}".format(textid)) #msg = 'zzzzz' tpl = ''' Project *{}* ({}) Total {} (maintenance: {}, silent: {}, ERR: {}) ''' if data is None: log.error('api_admin_qsum for {} / {} returned None'.format( rs.name, p.get_textid())) bot.send_message( chat_id=chat_id, parse_mode="Markdown", reply_markup=get_reply_markup(chat_id), text= 'Server {} for project {} unavailable at moment. Sorry. Try again later.' .format(rs.name, p.get_textid())) return msg = tpl.format(data['project'], data['textid'], data['cnt']['total'], data['cnt']['maintenance'], data['cnt']['silent'], data['cnt']['ERR']) for i in data['ERR'][:5]: try: link = rs.reverse('okerr:ilocator', { 'pid': data['textid'], 'iid': i['name'] }) msg += '[{}]({}) = {} ({}) {} ago\n'.format( md_escape(i['name']), link, i['status'], md_escape(i['details']), i['age']) except Exception as e: print(e) if len(data['ERR']) > 5: msg += '(Only first 5 of {} shown)\n'.format(len(data['ERR'])) bot.send_message(chat_id=chat_id, parse_mode="Markdown", reply_markup=get_reply_markup(chat_id), text=msg)
def cmd_recheck(message): reg_command(message) projects = list() chat_id = message.chat.id username = main_rs.api_admin_chat_id(chat_id) if username is None: tgname = message.from_user.username error_msg = "chat id: {} tg name: {} not linked to any account".format( chat_id, tgname) log.info(error_msg) bot.send_message(chat_id=chat_id, text=error_msg, reply_markup=get_reply_markup(chat_id)) return project_list = main_rs.api_admin_member(username) if project_list is None: log.info('Failed to get project list for user {} from {}'.format( username, main_rs)) bot.send_message(chat_id=chat_id, text="Internal exception, please contact support", reply_markup=get_reply_markup(chat_id)) return for textid in project_list: projects.append(textid) if not projects: log.info("no projects!") bot.send_message(chat_id=chat_id, text="No projects", reply_markup=get_reply_markup(chat_id)) return for textid in projects: url = main_rs.api_director(textid) rs = RemoteServer(url=url) l = rs.api_recheck(textid) if l is None: log.error('api_recheck for {} / {} returned None'.format( rs.name, p.get_textid())) bot.send_message( chat_id=chat_id, parse_mode="Markdown", reply_markup=get_reply_markup(chat_id), text= 'Server {} for project {} unavailable at moment. Sorry. Try again later.' .format(rs.name, p.get_textid())) return log.info("rechecked project {}: {} indicators".format(textid, len(l))) if l: # not empty list msg = "Project {}: recheck: {}".format(textid, ' '.join(l[:5])) else: msg = "Project {}: nothing to recheck".format(textid) bot.send_message(chat_id=chat_id, parse_mode="Markdown", reply_markup=get_reply_markup(chat_id), text=msg)
def handle(self, *args, **options): #print "options:",options user = None profile = None if options['verbosity'] >= 1: log = logging.getLogger('okerr') log.setLevel(logging.DEBUG) log.addHandler(logging.StreamHandler()) # prepare data try: if options['user'] and not options['clone']: email = options['user'] user = User.objects.get(email=options['user']) profile = user.profile except User.DoesNotExist: print("No such user") except Profile.DoesNotExist: print("No such profile") if options['dblog']: l = logging.getLogger('django.db.backends') l.setLevel(logging.DEBUG) l.addHandler(logging.StreamHandler()) if options['skip']: for s in options['skip']: RemoteServer.skip(s) if options['hostinfo']: if options['hostinfo'] == 'all': rs = RemoteServer.me() for rrs in rs.all_rs(): print("== Hostinfo for %s" % rrs) print(rrs.hostinfo()) else: rs = RemoteServer(name = options['hostinfo']) print(rs.hostinfo()) return if options['cluster']: print(json.dumps(settings.MACHINES, indent=4)) return if options['compare']: ul = dict() users = list() badusers = list() me = RemoteServer.me() for rs in me.all_rs(): ul[rs.name] = rs.list() for ulist in list(ul.values()): for u in ulist: email = u['user'] if not email in users: users.append(email) mnames = sorted(ul.keys()) fmt = "{:<50}|{:1}| " + "{:<15}| " * (len(mnames)) titles = list() for m in mnames: rs = RemoteServer(name = m) print(rs, rs.ci) titles.append("{} ({})".format(rs.name, rs.ci)) print(fmt.format('EMAIL','X', *titles)) print(fmt.format('-'*50,'-',*["-"*15 for x in range(len(mnames))])) for username in users: cil = list() for m in mnames: urec = [urec for urec in ul[m] if urec['user'] == username] if urec: cil.append(urec[0]['ci']) else: cil.append('-') if cil[1:] == cil[:-1]: cil.insert(0,'') if options['verbosity']>=1: print(fmt.format(username, *cil)) else: cil.insert(0,'X') print(fmt.format(username, *cil)) return if options['reanimate']: if profile: print("single reanimate", profile) profile.reanimate() else: for p in Profile.objects.filter(ci = myci()): print("reanimate",p) p.reanimate() return if options['info']: print("Host: {} Cluster: {} ci: {}".format(repr(settings.HOSTNAME), repr(settings.CLUSTER_NAME), myci())) print("Profiles: {} / {}".format(Profile.objects.filter(ci=myci()).count(), Profile.objects.count())) return if options['list']: for p in Profile.objects.all(): print(p.ci, p.user.username) elif options['cilist'] is not None: for p in Profile.objects.filter(ci=options['cilist']).all(): print(p.user.username) elif options['wipe']: if not (user or profile): print("need either user ({}) or profile ({})".format(user, profile)) if user: user.delete() if profile: profile.delete() print("deleted") elif options['ciwipe'] is not None: if options['ciwipe'] == myci(): print("cannot ciwipe for my own ci {}".format(myci())) return for p in Profile.objects.filter(ci=options['ciwipe']).all(): if options['verbosity']>=1: print("delete {} ci: {}".format(p, p.ci)) p.user.delete() p.delete() elif options['otherciwipe']: ci = myci() for p in Profile.objects.all(): if p.ci == ci: if options['verbosity']>=1: print("skip profile {} ci: {}".format(p, p.ci)) else: if options['verbosity']>=1: print("delete {} ci: {}".format(p, p.ci)) p.user.delete() p.delete() elif options['export']: if profile: handle_export(profile, options['file'], options['verbosity']) else: print("Need --user") elif options['import']: data = get_content(filename = options['file'], url = options['url'], email = options['user']) if options['clone']: data = clone(data, options['user']) handle_import(data, options['overwrite'], options['verbosity']) elif options['sync']: handle_sync(options['sync'], options['overwrite'], options['verbosity']) elif options['syncmap']: ie = Impex() ie.set_verbosity(options['verbosity']) ie.syncmap() return elif options['takeci'] is not None: for profile in Profile.objects.filter(ci=options['takeci']): print("process profile", profile) ## profile = Profile.objects.get(user__email = options['user']) setci_local(profile, myci()) if options['remote']: setci_remote(profile.user.username, myci()) else: print("skip remote, because no --remote") return elif options['setci'] is not None: if options['user']: profile = Profile.objects.get(user__email = options['user']) setci_local(profile, options['setci']) if options['remote']: setci_remote(options['user'], options['setci']) else: print("skip remote, because no --remote") else: print("need --user") return print("setci {} for user {}".format(options['setci'], email)) # change for profile and projects ci = options['setci'] profile.set_ci(options['setci']) profile.save() else: print("Whaat?")