Cet article est l'article du 24ème jour du SLP KBIT Advent Calendar 2019. Ça fait longtemps, je suis Gakki. Cette fois, j'ai créé Slackbot, je vais donc en écrire un enregistrement.
Dans mon cercle, Slack est utilisé comme principal outil de contact avec le ** plan gratuit **. Dans de telles circonstances, de nombreux membres l'utilisent comme espace de travail. Parfois, des mentions sont faites sur des sujets sans rapport, alors je me suis demandé si je pouvais atténuer cela. J'ai décidé de créer un bot capable de gérer des groupes d'utilisateurs. (Cela n'a aucun sens d'activer les notifications pour la plupart des messages ...)
J'ai fait référence au site de ici.
De là, nous allons commencer le sujet principal. Je vais l'écrire séparément dans le contenu suivant.
Afin de gérer le groupe d'utilisateurs créé cette fois, Comme il n'était pas possible de le faire uniquement avec l'autorité en tant qu'utilisateur de bot, nous définissons l'autorité nécessaire comme suit.
La structure des dossiers est la suivante. Le traitement au-delà de la fonction de l'utilisateur du bot est décrit dans my_mention.py et subMethod.py, et il est importé par run.py de main.
Cette fois, nous avons implémenté un groupe de commandes pour gérer les groupes d'utilisateurs. De plus, j'ai également créé une commande liée au questionnaire avec elle, donc j'écrirai un peu à ce sujet. Les principales fonctions sont les suivantes.
--Créer un groupe d'utilisateurs --Supprimer le groupe d'utilisateurs --Modifier les membres du groupe d'utilisateurs
Tout d'abord, comme prémisse, je vais expliquer à partir du concept de groupe d'utilisateurs créé cette fois. Comme mentionné précédemment, l'espace de travail avec le bot est un plan gratuit, donc Les méthodes API liées aux groupes d'utilisateurs ne peuvent pas être utilisées. Par conséquent, créez un dictionnaire avec la clé comme nom du groupe d'utilisateurs et la valeur comme tableau de membres du groupe. J'ai décidé d'en faire un pseudo groupe d'utilisateurs en l'enregistrant dans un fichier statique. Par conséquent, veuillez comprendre que c'est le cas lorsque le contenu lié au dictionnaire apparaît dans les programmes suivants.
Le programme est le suivant.
@respond_to('create\s([a-zA-Z0-9]*)\s([\w\s,]+)')
def create_usergroup(message, usergroup_name, member):
usergroup = subMethod.get_usergroup_list()
member_list = subMethod.get_member()['members']
for usergroup_dict in usergroup:
if usergroup_dict['usergroup_name'] == usergroup_name:
message.send("`" + usergroup_name+' is already exist.`\n> please choose another name.')
return
data = {}
member_id = []
data['usergroup_name'] = usergroup_name
try:
member_name = [x.strip() for x in member.split(',')]
except AttributeError:
member_name = []
member_id = member
ml_id = [ml['id'] for ml in member_list]
ml_name = [ml['name'] for ml in member_list]
ml_rname = [ml['real_name'] if 'real_name' in ml else 'no_name' for ml in member_list]
ml_dname = [ml['profile']['display_name'] for ml in member_list]
for mn in member_name:
if mn in ml_name:
member_id.append(ml_id[ml_name.index(mn)])
elif mn in ml_rname:
member_id.append(ml_id[ml_rname.index(mn)])
elif mn in ml_dname:
member_id.append(ml_id[ml_dname.index(mn)])
else:
message.send("`" + mn + " is not in this channel`")
data['member'] = member_id
usergroup.append(data)
subMethod.set_usergroup_list(usergroup)
message.send('Created a usergroup')
Il est exécuté lorsqu'un message au format create {nom du groupe d'utilisateurs} {nom du membre,…}
est reçu.
En tant que processus interne, vérifiez d'abord si le groupe d'utilisateurs spécifié a déjà été créé.
Après vérification, s'il n'existe pas encore, créez-le et ajoutez des membres.
À ce stade, il est confirmé en même temps si le membre spécifié existe dans l'espace de travail.
Les utilisateurs existant dans l'espace de travail peuvent obtenir une liste à l'aide de la méthode user_list.
Cependant, le problème ici est le format.
Dans slack, les utilisateurs peuvent avoir des valeurs dans trois formats: userID, fullname et displayname.
Comme il est difficile d'envoyer un identifiant lors de l'envoi d'un message, je pense que vous allez spécifier le nom complet ou le nom d'affichage, donc
J'y ai rendu possible une conversion mutuelle.
Après ce processus, si l'utilisateur existe, l'ID est ajouté et s'il n'existe pas, un message d'erreur est envoyé.
La raison de l'ajout de l'ID sera expliquée dans la section sur la mention de groupe ci-dessous.
Une fois exécuté, ce sera comme ci-dessous.
Le programme est le suivant.
@respond_to('delete_usergroup\s([a-zA-Z0-9]*)')
def delete_usergroup(message, usergroup_name):
usergroup = subMethod.get_usergroup_list()
usergroup_name_list = [x['usergroup_name'] for x in usergroup]
if usergroup_name not in usergroup_name_list:
message.send("`" + usergroup_name + ' is not exist.`\n> type `@secretary list` and check usergroup_name')
return
new_usergroup = []
for usergroup_dict in usergroup:
if usergroup_dict['usergroup_name'] == usergroup_name:
continue
new_usergroup.append(usergroup_dict)
subMethod.set_usergroup_list(new_usergroup)
message.send('Deleted a usergroup')
Reçoit et exécute un message au format delete_usergroup {usergroup name}
.
À cet égard, il s'agit presque simplement d'une opération de dictionnaire.
S'il existe un groupe d'utilisateurs spécifié, supprimez-le simplement du dictionnaire.
Sinon, un message d'erreur sera envoyé.
Quand j'essaye de l'utiliser, ça ressemble à ça.
Le programme est le suivant.
@respond_to('add\s([a-zA-Z0-9]*)\s([\w\s,]+)')
def add_member(message, usergroup_name, member):
usergroup = subMethod.get_usergroup_list()
usergroup_name_list = [usergroup_dict['usergroup_name'] for usergroup_dict in usergroup]
if usergroup_name not in usergroup_name_list:
message.send("`" + usergroup_name + " is not exist`\n> please type `@secretary list` and check usergroup_name.")
return
member_list = subMethod.get_member()['members']
usergroup_member = subMethod.get_usergroup_member(usergroup_name)
member_id = []
try:
member_name = [x.strip() for x in member.split(',')]
except AttributeError:
member_name = []
member_id = member
add_member_name = []
for mn in member_name:
if mn not in usergroup_member:
add_member_name.append(mn)
else:
message.send("`" + mn + ' already belongs`')
ml_id = [ml['id'] for ml in member_list]
ml_name = [ml['name'] for ml in member_list]
ml_rname = [ml['real_name'] if 'real_name' in ml else 'no_name' for ml in member_list]
ml_dname = [ml['profile']['display_name'] for ml in member_list]
for mn in add_member_name:
if mn in ml_name:
member_id.append(ml_id[ml_name.index(mn)])
elif mn in ml_rname:
member_id.append(ml_id[ml_rname.index(mn)])
elif mn in ml_dname:
member_id.append(ml_id[ml_dname.index(mn)])
else:
message.send("`" + mn + " is not in this channel`")
if len(member_id) == 0:
message.send("`No one will add`")
return
for usergroup_dict in usergroup:
if usergroup_dict['usergroup_name'] == usergroup_name:
usergroup_dict['member'].extend(member_id)
usergroup_dict['member'] = list(set(usergroup_dict['member']))
break
subMethod.set_usergroup_list(usergroup)
message.send('Added some member')
@respond_to('delete\s([a-zA-Z0-9]*)\s([\w\s,]+)')
def delete_member(message, usergroup_name, member):
usergroup = subMethod.get_usergroup_list()
usergroup_name_list = [usergroup_dict['usergroup_name'] for usergroup_dict in usergroup]
if usergroup_name not in usergroup_name_list:
message.send("`" + usergroup_name + " is not exist`\n> type `@secretary list` and check usergroup_name")
return
member_list = subMethod.get_member()['members']
member_id = []
try:
member_name = [x.strip() for x in member.split(',')]
except AttributeError:
member_name = []
member_id = member
ml_id = [ml['id'] for ml in member_list]
ml_name = [ml['name'] for ml in member_list]
ml_rname = [ml['real_name'] if 'real_name' in ml else 'no_name' for ml in member_list]
ml_dname = [ml['profile']['display_name'] for ml in member_list]
for mn in member_name:
if mn in ml_name:
member_id.append(ml_id[ml_name.index(mn)])
elif mn in ml_rname:
member_id.append(ml_id[ml_rname.index(mn)])
elif mn in ml_dname:
member_id.append(ml_id[ml_dname.index(mn)])
else:
message.send("`" + mn + " is not in this channel`")
if len(member_id) == 0:
message.send("`No one will delete`")
return
for usergroup_dict in usergroup:
if usergroup_dict['usergroup_name'] == usergroup_name:
for mi in member_id:
if mi not in usergroup_dict['member']:
message.send("`" + ml_name[ml_id.index(mi)] + " doesn't belong to this`")
else:
usergroup_dict['member'].remove(mi)
break
subMethod.set_usergroup_list(usergroup)
message.send('Deleted some member')
Ajouter un membre au groupe d'utilisateurs pour le message ʻadd {nom du groupe d'utilisateurs} {nom du membre,…} ` Supprime les membres du groupe d'utilisateurs pour le message «delete {nom du groupe d'utilisateurs} {nom du membre,…}». Le traitement supplémentaire est le même que le traitement de création si le groupe d'utilisateurs spécifié existe. Dans le processus de suppression, lorsque le groupe d'utilisateurs spécifié existe, les membres appartenant à ce groupe d'utilisateurs sont supprimés un par un. Il s'agit d'une erreur si le groupe d'utilisateurs et les membres spécifiés n'existent pas.
Le programme est le suivant.
@listen_to('@[a-zA-Z0-9]+\s([\s\S]*)')
def reply_to_thread(message, text):
usergroup = subMethod.get_usergroup_list()
message.body['text'].replace('\n', ' ')
mention = message.body['text'].split()[0].strip('@')
mention_dict = []
for dictionary in usergroup:
if dictionary['usergroup_name'] == mention:
mention_dict = dictionary
break
if len(mention_dict) == 0:
message.send('`' + mention + ' is not exist`')
return
sentence = ""
for member in mention_dict['member']:
sentence = sentence + "<@" + member + "> "
sentence = sentence + "\n"
message.send(sentence,
thread_ts=message.thread_ts)
Cette méthode est différente du contenu écrit précédemment.
Les méthodes précédentes ne peuvent être exécutées qu'en conjonction avec la mention au bot,
Cette méthode répond aux messages de la forme @ {nom du groupe d'utilisateurs} {message}
sans elle.
La méthode écrite en tant que respond nécessite une mention, et la méthode écrite en tant qu'écoute n'est pas requise.
Bien qu'il s'agisse d'un processus interne, le @ {nom du groupe d'utilisateurs} inclus au début du message est extrait et
Extrait la valeur de l'élément avec le nom de groupe d'utilisateurs spécifié comme clé.
Comme expliqué précédemment, value est un format de tableau, donc l'instruction for retire les éléments un par un et les combine pour créer un message.
C'est le message à mentionner.
Ici, ID est utilisé dans slack lors de la mention. Par conséquent, il était nécessaire de se souvenir de la pièce d'identité.
Si le message créé est envoyé à TL, il ne gênera que s'il y a un grand nombre de membres dans le groupe d'utilisateurs.
Par conséquent, cette fois, le message est envoyé sous la forme d'un fil pour le message d'origine.
La méthode d'envoi à un fil est message.send (phrase, thread_ts = message.thread_ts)
.
L'écran réel ressemble à celui ci-dessous.
Les méthodes liées aux groupes d'utilisateurs sont les suivantes. En plus de ceux mentionnés ci-dessus, une liste de groupes et de membres, Il y a des choses comme changer le nom du groupe et combiner des groupes d'utilisateurs, mais je les omettrai car ils peuvent être combinés jusqu'à présent.
Quand j'ai répondu à un questionnaire avec du mou, j'essayais d'obtenir une réaction au message. Avec ce format, c'était très gênant de voir les réactions une par une et de confirmer qui votait où. Lorsque vous créez un groupe d'utilisateurs, si vous regroupez les personnes qui répondront au questionnaire dans un groupe d'utilisateurs, Je pensais que le bot pouvait le gérer, alors j'ai fait environ deux fonctions. (Il semble qu'un simple sondage ait été publié récemment ...)
Le programme est le suivant.
@respond_to('count')
def count_up_reaction(message):
response = subMethod.get_message(message.body['channel'],
message.thread_ts)
if not response:
message.direct_reply("Can't use count method in DM")
return
sentence = ''
if 'reactions' in response['messages'][0]:
data = response['messages'][0]['reactions']
sorted_data = sorted(data, reverse=True, key=lambda x:x['count'])
sentence = response['messages'][0]['text'] + '\n\n*Result*\n'
for datum in sorted_data:
sentence = sentence + ":" + datum['name'] + ":" + " "
for user in datum['users']:
sentence = sentence + "<@" + user + "> "
sentence = sentence + "\n"
else:
sentence = 'No reactions'
message.direct_reply(sentence)
Il est exécuté en envoyant count
au fil du message pour lequel vous souhaitez agréger les réactions.
En tant que processus, lorsque vous recevez le message en haut du fil de discussion, il y a une partie qui résume les données de réaction, alors organisez-la.
Les données de réaction sont incluses dans le formulaire ci-dessous. Après tout, puisqu'il s'agit d'un dictionnaire, il acquiert des données, les façonne et les envoie à l'utilisateur qui a envoyé «count» par DM.
L'écran d'exécution est illustré ci-dessous.
Le programme est le suivant.
@respond_to('diff')
def check_reactor(message):
response = subMethod.get_message(message.body['channel'],
message.thread_ts)
if not response:
message.direct_reply("Can't use count method in DM")
return
target_usergroup = response['messages'][0]['text'].replace('\n', ' ').split()[0].strip('@')
all_target_audience = subMethod.get_usergroup_member_id(target_usergroup)
if len(all_target_audience) == 0:
sentence = 'No specified user group'
elif 'reactions' in response['messages'][0]:
data = response['messages'][0]['reactions']
reacted_users = []
reacted_users.extend([user for datum in data for user in datum['users']])
target_audience = []
target_audience.extend([user for user in all_target_audience if user not in reacted_users])
sentence = "*Hasn't yet reacted*\n"
for user in target_audience:
sentence = sentence + "<@" + user + ">\n"
else:
sentence = "*Hasn't yet reacted*\n"
for user in all_target_audience:
sentence = sentence + "<@" + user + ">\n"
message.direct_reply(sentence)
Comme pour les mentions de groupe d'utilisateurs, spécifiez le groupe d'utilisateurs cible au début du message.
Ensuite, envoyez diff
au thread du message cible pour effectuer l'agrégation.
Tout d'abord, extrayez le groupe d'utilisateurs cible du message et obtenez le tableau de membres.
Ensuite, obtenez une liste d'utilisateurs avec des réactions d'une manière ou d'une autre.
Si vous pouvez obtenir ces deux, extrayez les utilisateurs qui n'existent que dans l'un des deux tableaux.
Organisez-les et envoyez-les par DM.
L'écran d'exécution est illustré ci-dessous.
L'introduction de slackbot peut se faire intuitivement à l'aide de l'interface graphique, et Quant à l'implémentation de la fonction, j'ai eu l'impression qu'il est relativement facile de travailler sur Python car il existe une bonne bibliothèque. Actuellement, il y a encore peu de fonctions, donc je continuerai à coder à l'avenir. Aussi, comme toujours, j'écris le même processus à divers endroits, Le nom du fichier est également mauvais et il est dans un état terrible. Je veux faire le refactoring fermement. Enfin, ce code a été téléchargé sur GitHub, alors jetez un œil si vous le souhaitez. J'ai également écrit sur Docker, donc si vous avez un environnement dans lequel vous pouvez utiliser Docker, je pense que vous pouvez l'utiliser dès que vous définissez le jeton.
Recommended Posts