def show_thx_to(message, user_name=None): """誰にGJしたか表示します :param message: slackbot.dispatcher.Message :param str user_name: GJしたユーザー名 """ channel_id = message.body['channel'] if not user_name: user_name = get_user_name(message.body['user']) s = Session() slack_id = get_slack_id(s, user_name) if not slack_id: message.send('{}はSlackのユーザーとして存在しません'.format(user_name)) return rows = [['GJされたユーザー', 'GJ内容']] thx = (s.query(ThxHistory).filter( ThxHistory.from_user_id == slack_id).filter( ThxHistory.channel_id == channel_id)) for t in thx: rows.append([get_user_name(t.user_id), t.word]) output = StringIO() w = csv.writer(output) w.writerows(rows) param = { 'token': settings.API_TOKEN, 'channels': channel_id, 'title': '{}がGJした一覧'.format(user_name) } requests.post(settings.FILE_UPLOAD_URL, params=param, files={'file': output.getvalue()})
def unalias_name(message, user_name, alias_name=None): """ユーザーに紐づくエイリアス名を削除する :param message: slackbotの各種パラメータを保持したclass :param str user_name: 削除するエイリアス名を持つSlackユーザー :param str alias_name: 削除するエイリアス名 alias_nameがNoneの場合、user_nameをalias_nameとして扱う 上記の場合user_nameは投稿者となる """ if alias_name: # ユーザー名とエイリアス名が指定されているパターン slack_id = get_slack_id_by_name(user_name) else: # 投稿者のエイリアス名を更新するパターン alias_name = user_name slack_id = message.body['user'] user_name = get_user_name(slack_id) if not slack_id: botsend(message, '{}に紐づくSlackのuser_idは存在しません'.format(user_name)) return s = Session() alias_user_name = (s.query(UserAliasName).filter( UserAliasName.slack_id == slack_id).filter( UserAliasName.alias_name == alias_name).one_or_none()) if alias_user_name: s.delete(alias_user_name) s.commit() botsend(message, '{}のエイリアス名から `{}` を削除しました'.format(user_name, alias_name)) else: botsend(message, '{}のエイリアス名 `{}` は登録されていません'.format(user_name, alias_name))
def show_user_alias_name(message, user_name=None): """ユーザーのエイリアス名一覧を表示する :param message: slackbotの各種パラメータを保持したclass :param str user: Slackのユーザー名 """ if user_name: slack_id = get_slack_id_by_name(user_name) else: slack_id = message.body['user'] user_name = get_user_name(slack_id) if not slack_id: botsend(message, '{}に紐づくSlackのuser_idは存在しません'.format(user_name)) return s = Session() alias_names = [ user.alias_name for user in s.query(UserAliasName).filter( UserAliasName.slack_id == slack_id) ] pt = PrettyTable(['ユーザー名', 'Slack ID', 'エイリアス名']) alias_name = ','.join(alias_names) pt.add_row([user_name, slack_id, alias_name]) botsend(message, '```{}```'.format(pt))
def show_kintai_history(message): """直近40日分の勤怠記録を表示します :param message: slackbotの各種パラメータを保持したclass """ user_id = message.body['user'] today = datetime.date.today() target_day = today - datetime.timedelta(days=40) s = Session() qs = (s.query(KintaiHistory).filter( KintaiHistory.user_id == user_id).filter( KintaiHistory.registered_at >= target_day).order_by( KintaiHistory.registered_at.asc())) kintai = OrderedDict() for q in qs: day_of_week = DAY_OF_WEEK[q.registered_at.date().weekday()] prefix_day = '{:%Y年%m月%d日}({})'.format(q.registered_at, day_of_week) registered_at = '{:%I:%M:%S}'.format(q.registered_at) kind = '出社' if q.is_workon else '退社' kintai.setdefault(prefix_day, []).append('{} {}'.format(kind, registered_at)) rows = [] for prefix, registered_ats in kintai.items(): sorted_times = ' '.join(sorted(registered_ats)) rows.append('{} {}'.format(prefix, sorted_times)) if not rows: rows = ['勤怠記録はありません'] user_name = get_user_name(user_id) message.send('{}の勤怠:\n{}'.format(user_name, '\n'.join(rows)))
def check_user_name(session, user_names): """Slackユーザー情報と照ら合わせ結果を辞書で返す :param list user_names: Slackで++対象のSlackユーザー名 :return dict user_dict: keyが `matched`: Slackユーザーに紐付いた名前 keyが `hint_name`: 紐付かなかったが、似た名前が存在する名前 keyが `not_matched`: Slackユーザーに紐付かなかった名前 """ user_dict = {} for name in [x for x in user_names.split(' ') if x]: # slackのsuggest機能でユーザーを++した場合(例: @wan++)、name引数は # `<@{slack_id}>` というstr型で渡ってくるので対応 if get_user_name(name.lstrip('<@').rstrip('>')): slack_id = name.lstrip('<@').rstrip('>') else: slack_id = get_slack_id(session, name) if slack_id: # slack_idに紐づくユーザーが存在 user_dict.setdefault('matched', []).append((slack_id, name)) else: # 一番近いユーザー名を算出 hint = get_close_matches(name, get_users_info().values()) if hint: user_dict.setdefault('hint_name', []).append(hint[0]) # 紐づくユーザーが存在しなかった場合 else: user_dict.setdefault('not_matched', []).append(name) return user_dict
def update_kudo(message, names): """ 指定された名前に対して ++ する OK: name++、name ++、name ++、@name++、name1 name2++ NG: name+ +、name++hoge、 name1,name2++ :param message: slackbot.dispatcher.Message :param name str: ++する対象の名前 """ slack_id = message.body['user'] name_list = [] for name in [x for x in names.split(' ') if x]: # slackのsuggest機能でユーザーを++した場合(例: @wan++)、name引数は # `<@{slack_id}>` というstr型で渡ってくるので対応 if get_user_name(name.lstrip('<@').rstrip('>')): name = get_user_name(name.lstrip('<@').rstrip('>')) s = Session() kudo = (s.query(KudoHistory) .filter(KudoHistory.name == name) .filter(KudoHistory.from_user_id == slack_id) .one_or_none()) if kudo is None: # name ×from_user_id の組み合わせが存在していない -> 新規登録 s.add(KudoHistory(name=name, from_user_id=slack_id, delta=1)) s.commit() else: # name ×from_user_id の組み合わせが存在 -> 更新 kudo.delta = kudo.delta + 1 s.commit() q = (s.query( func.sum(KudoHistory.delta).label('total_count')) .filter(KudoHistory.name == name)) total_count = q.one().total_count name_list.append((name, total_count)) msg = ['({}: 通算 {})'.format(n, tc) for n, tc in name_list] botsend(message, '\n'.join(msg))
def show_today_cleaning_list(message): """今日の掃除当番を表示する :param message: slackbot.dispatcher.Message """ dow = datetime.datetime.today().weekday() s = Session() users = [ get_user_name(c.slack_id) for c in s.query(Cleaning).filter(Cleaning.day_of_week == dow) ] botsend(message, '今日の掃除当番は{}です'.format('、'.join(users)))
def show_cleaning_list(message): """掃除当番の一覧を表示する :param message: slackbot.dispatcher.Message """ s = Session() dow2users = OrderedDict() cleaning = s.query(Cleaning).order_by(Cleaning.day_of_week.asc(), Cleaning.id.asc()) for c in cleaning: user = get_user_name(c.slack_id) dow2users.setdefault(c.day_of_week, []).append(user) pt = PrettyTable(['曜日', '掃除当番']) pt.align['掃除当番'] = 'l' for day_of_week, users in dow2users.items(): dow = DAY_OF_WEEK[day_of_week] str_users = ', '.join(users) pt.add_row([dow, str_users]) botsend(message, '```{}```'.format(pt))
def show_user_redbull_history(message): """RedBullのUserごとの消費履歴を返すコマンド :param message: slackbotの各種パラメータを保持したclass """ user_id = message.body['user'] user_name = get_user_name(user_id) s = Session() qs = (s.query(RedbullHistory).filter(RedbullHistory.user_id == user_id, RedbullHistory.delta < 0).order_by( RedbullHistory.id.asc())) tmp = [] for line in qs: tmp.append('[{:%Y年%m月%d日}] {}本'.format(line.ctime, -line.delta)) ret = '消費履歴はありません' if tmp: ret = '\n'.join(tmp) message.send('{}の消費したレッドブル:\n{}'.format(user_name, ret))
def manage_redbull_stock(message, delta): """RedBullの本数の増減を行うコマンド :param message: slackbotの各種パラメータを保持したclass :param str delta: POSTされた増減する本数 UserからPOSTされるdeltaの値は投入の場合は負数、消費の場合は正数 DBは投入の場合正数、消費の場合は負数を記録する """ delta = -int(delta) user_id = message.body['user'] user_name = get_user_name(user_id) s = Session() s.add(RedbullHistory(user_id=user_id, delta=delta)) s.commit() if delta > 0: message.send('レッドブルが{}により{}本投入されました'.format(user_name, delta)) else: message.send('レッドブルが{}により{}本消費されました'.format(user_name, -delta))
def find_thx(s, text): """Slackに投稿されたメッセージからthxを見つけて返す :param s: sqlalchemy.orm.session.Session :param str text: ユーザーが投稿した内容 :return Dict[str, List[Tuple[str, str]]] word_map_names_dict: キーがthx内容、バリューが対象Slackユーザーのリスト :return list hint_names: Slackユーザーに似た名前が存在する名前一覧 :return list not_matched: Slackユーザーとして存在しなかった名前の一覧 """ word_map_names_dict = {} hint_names = [] not_matched = [] thx_matcher = re.compile( r'(?P<user_names>.+)[ \t\f\v]*(?<!\+)\+\+[ \t\f\v]+(?P<word>.+)', re.MULTILINE) for thx in thx_matcher.finditer(text): user_names = [x for x in thx.group('user_names').split(' ') if x] for name in user_names: if get_user_name(name.lstrip('<@').rstrip('>')): slack_id = name.lstrip('<@').rstrip('>') else: slack_id = get_slack_id(s, name) if slack_id: word_map_names_dict.setdefault(thx.group('word'), []).append( (slack_id, name)) else: # 一番近いユーザー名を算出 names = [ profile['name'] for profile in get_users_info().values() ] hint = get_close_matches(name, names) if hint: hint_names.append(hint[0]) # 紐づくユーザーが存在しなかった場合 else: not_matched.append(name) return word_map_names_dict, hint_names, not_matched
def alias_name(message, user_name, alias_name=None): """指定したユーザにエイリアス名を紐付ける :param message: slackbotの各種パラメータを保持したclass :param str user_name: エイリアス名を紐付けるSlackユーザー :param str alias_name: Slackユーザーに紐付けるエイリアス名 alias_nameがNoneの場合、user_nameをalias_nameとして扱う 上記の場合user_nameは投稿者となる """ if alias_name: # ユーザー名とエイリアス名が指定されているパターン slack_id = get_slack_id_by_name(user_name) else: # 投稿者のエイリアス名を更新するパターン alias_name = user_name slack_id = message.body['user'] user_name = get_user_name(slack_id) user = get_slack_id_by_name(alias_name) if user: botsend(message, '`{}` はユーザーが存在しているので使用できません'.format(alias_name)) return if not slack_id: botsend(message, '{}に紐づくSlackのuser_idは存在しません'.format(user_name)) return s = Session() alias_user_name = (s.query(UserAliasName).filter( UserAliasName.alias_name == alias_name)) if s.query(alias_user_name.exists()).scalar(): botsend(message, 'エイリアス名 `{}` は既に登録されています'.format(alias_name)) return s.add(UserAliasName(slack_id=slack_id, alias_name=alias_name)) s.commit() botsend(message, '{}のエイリアス名に `{}` を追加しました'.format(user_name, alias_name))