Invite User Group to a slack public channel - python

I'm using Python 3.7, and Slack Version 4.1.2 (Production). I want to invite a user group that is already present and has many users in it.
What I have tried in python3:
def invite_user(scid):
# invite_url = 'https://slack.com/api/channels.invite'
# invite_url = 'https://slack.com/api/groups.invite'
invite_url = 'https://slack.com/api/usergroups.update'
invite_url_data = {
'token': auth_token,
'channel': scid,
'usergroup': 'SPXXXXXX',
'name': 'testing'
}
r = requests.post(url=invite_url, data=invite_url_data, headers=header)
print(r.json())
Can someone help me get the right API to invite usergroup to a channel?

Inviting the users of a usergroup to a private channel is indeed just one API call. Before that you need to get the users of the usergroup though, which is another API call. And you can't invite yourself, so you need another API call to get your current user ID.
Here is an example script using the official python library for Slack. Note that this will work for up to 1.000 users. If your usergroups are larger you need to add them in chunks.
import slack
import os
# init slack client with access token
slack_token = os.environ['SLACK_TOKEN']
client = slack.WebClient(token=slack_token)
# get my own user ID
response = client.auth_test()
assert response['ok']
my_user_id = response['user_id']
# get members of usergroup excluding myself
response = client.usergroups_users_list(usergroup='S12345678')
assert response['ok']
users = [x for x in response['users'] if x != my_user_id]
# add members to private channel
response = client.conversations_invite(
channel='G12345678',
users = users
)
assert response['ok']
print(response)

It's not how it works in Slack.
You can get members of group by https://api.slack.com/methods/groups.info
Then you can extract user ids list from group_data["group"]["members"] for a group you want users to invite from.
After you can do the same a group where you can add them.
After you have 2 lists of users for each group, you can merge them and then make a request:
invite_url = 'https://slack.com/api/usergroups.update'
invite_url_data = {
'token': auth_token,
'channel': scid,
'usergroup': 'SPXXXXXX',
'name': 'testing',
'users': [
"U060R4BJ4", # here are your users from a merged lists
"U060RNRCZ"
],
}
r = requests.post(url=invite_url, data=invite_url_data, headers=header)

Related

Not able to fetch discord guild/server/channel members

Tried to get numbers of discord members using discord's API endpoint GET/guilds/{guild.id}/members (see here).
I am using Postman to make a call to it. I set the Authorization header:
Authorization: "Bot ${BOT_TOKEN}"
The response I get is
{ "message": "Missing Access", "code": 50001 }
I also tried with Authorization: DISCORD_CLIENT_ID.
The response is { "message": "401: Unauthorized", "code": 0 }.
Am I missing something? Please help me out with this.
First, you need to make sure you are using the correct guild id and not a channel id. You can enable Developer Mode on Discord through User settings -> Advanced, which allows you to obtain the guild id by right-clicking on a guild (server), and then clicking on Copy ID.
Next, go to your application through Developer Portal, select your application and navigate to the Bot tab on the navigation bar to the left. From there, obtain your bot's authentication token that you need to pass in the headers of your request. On the same tab - since you need to get the list of Guild Members, and since that "endpoint is restricted according to whether the GUILD_MEMBERS Privileged Intent is enabled for your application" - scroll down to the Privileged Gateway Intents section and enable SERVER MEMBERS INTENT.
Below is a working example using the Node.js standard modules. Please note that, as described here, the default limit of maximum number of members to return is 1. Thus, you can adjust the limit in the query parameters, as below, to receive more results per request. The maximum number of results you can get per request is 1000. Therefore, if a guild contains more members than that, you can keep track of the highest user id present in each previous request, and pass it to the after parameter of the next request, as described in the documentation. In this way, you can obtain every member in a guild. Also, make sure you set the properties in options in the proper way, as shown below; otherwise, you might come accross getaddrinfo ENOTFOUND error, as shown here.
Update
If you haven't already, you should add your bot to the server you wish, by generating an invite link for your bot through URL Generator under OAuth2 in your application settings (select bot from scopes). Now, you can access that URL from your browser and add the bot to any of your servers. If you need to, you can share the same invite link with others, so that they can add your bot to their servers.
Example in Node.js
const https = require('https')
const url = require('url');
GUILD_ID = "YOUR_GUILD_ID"
BOT_TOKEN = 'YOUR_BOT_TOKEN'
LIMIT = 10
const requestUrl = url.parse(url.format({
protocol: 'https',
hostname: 'discord.com',
pathname: `/api/guilds/${GUILD_ID}/members`,
query: {
'limit': LIMIT
}
}));
const options = {
hostname: requestUrl.hostname,
path: requestUrl.path,
method: 'GET',
headers: {
'Authorization': `Bot ${BOT_TOKEN}`,
}
}
const req = https.request(options, res => {
res.on('data', d => {
process.stdout.write(d)
})
})
req.on('error', error => {
console.error(error)
})
req.end()
Example in Python
import requests
import json
GUILD_ID = "YOUR_GUILD_ID"
BOT_TOKEN = 'YOUR_BOT_TOKEN'
LIMIT = 10
headers = {'Authorization' : 'Bot {}'.format(BOT_TOKEN)}
base_URL = 'https://discord.com/api/guilds/{}/members'.format(GUILD_ID)
params = {"limit": LIMIT}
r = requests.get(base_URL, headers=headers, params=params)
print(r.status_code)
print(r.text,'\n')
#print(r.raise_for_status())
for obj in r.json():
print(obj,'\n')

How to send direct message to specific user in ms teams using python?

I want to send Send direct message to specific user in ms teams through python with Odoo?
This is a little more complicated task, but definitely doable. Sending an individual message using python is not as easy as using Webhook to send the message in Teams. You have to go through Authentication, get your token and then send the chat. Here are the steps that I used to get this to work using selenium to get the Authentication and then using requests.post to send individual massage.
By the way if you thought getting authentication with Microsoft is easy you are 100% wrong, here is the link to getting access token from microsoft https://learn.microsoft.com/en-us/graph/auth-v2-user
After you register your app with Azure you can use the following cod to get the Authentication token using slenium.
Set up Selenium
import gc
gc.disable() # 03/23/2022 added this one to prevent trash collection and avoide crashing the notebooks
from selenium import webdriver
from selenium.webdriver.firefox.options import Options
from selenium.webdriver.firefox.service import Service
from selenium.common.exceptions import WebDriverException # to catch WebDriverException after changing the host from postman to local
Options.binary_location = "/usr/bin/firefox"
ser = Service("/tmp/geckodriver")
options = Options()
options.binary_location = "location for firefix bynary .. /firefox_binary.py"
options.headless = True
driver = webdriver.Firefox(options=options, service=ser)
Use the following code to go through Authentication. ( You need some selenium skills to code the manual process), I'll share the starting point as an example and you can code yours as it is different than the links that I am using.
import time
import re
import json
import requests
import pandas as pd
Options.binary_location = "/usr/bin/firefox"
ser = Service("/tmp/geckodriver")
options = Options()
options.headless = True
driver = webdriver.Firefox(options=options, service=ser)
tenant_id = 'your tenant id for Microsoft graph'
client_id = "your client id for Microsoft graph"
url = f"http://login.microsoftonline.com/{tenant_id}/oauth2/v2.0/authorize?client_id={client_id}&response_type=code&response_mode=query&scope=user.read%20chat.read&state=12345"
driver.get(url)
print(driver.current_url)
#open_tab
time.sleep(3)
This is the section that you are going to use your selenium skills, I just put the first step that is required by Microsoft, depending on your/your company setup you may need few more steps to sign in.
element_id = webdriver.common.by.By.ID
email_locator=(element_id,"i0116")
driver.find_element(*email_locator).send_keys("your email address")
next_button_locator = (element_id,"idSIButton9")
driver.find_element(*next_button_locator).click()
time.sleep(9)
print(driver.current_url)
I recommend printing driver.current_url after each steps so you can manually check the link and then code it accordingly.
After you logged in, now you can use the following code to get your Authentication token. I used localhost:5000 as return Url, but you can set up any URL that you want in your App registration page.
This authentication tokens are only valid for one hour, so I used the following while loop to refresh the token every 30 minutes
while True:
try:
driver.get(url)
except WebDriverException:
time.sleep(3)
url_pattern = 'http://localhost:5000/\?code=(?P<code>[^&]*)&state=12345.*'
re_match = re.match(url_pattern,driver.current_url)
code = re_match.group('code')
headers = { 'Content-Type': 'application/x-www-form-urlencoded'}
body = {'grant_type': 'authorization_code',
'code': code,
'redirect_url':'your redirect url',
'client_id': 'your client id',
'client_secret':'your client secret'}
response = requests.post('https://login.microsoftonline.com/yor tenant id/oauth2/v2.0/token',headers=headers,data = body)
access_token = json.loads(response.text)['access_token']
pd_response = pd.DataFrame([json.loads(response.text)])
# I am saving the new token in spark dataframe where I can read it with other code, but you can save it different way
sf_response = spark.createDataFrame(pd_response)
sf_response.write.mode("overwrite").saveAsTable('graphTest')
time.sleep(30*60)
Now if you got through all the obstacle that Microsoft throws at you to just authenticate yoursel, you can use the following line to post a message
#used this function to get updated token, but you can pass your token anyway that you want.
def getGraphAccessToken():
"""
Gets access token that is saved in graphTest table
"""
dataFrame = spark.sql("select * from graphTest")
return dataFrame.collect()[0]['access_token']
And Finally you can use the following codes to send the message to anyone or group of people as long as you have their chat id.
def sendIndividualChat(text,chatIdList,contentType="html"):
"""
sends individual chat through Microsoft Teams.
Parameters:
----------
text : str, message content
chatIdList : list, list of chat id(id is in string format) for individual chat messages
"""
headers = {'Content-type':'application/json',
"Authorization": f"Bearer {getGraphAccessToken()}"
}
body = {
"body": {
"contentType": contentType,
"content": text
}}
for chatId in chatIdList:
requests.post(f"https://graph.microsoft.com/v1.0/chats/{chatId}/messages",headers=headers,data =json.dumps(body) )
If you dont know how to get the chat id for the individuals or group chat there are few ways, you can use Graph Explorer https://developer.microsoft.com/en-us/graph/graph-explorer or the following code to get list of your most recent chat with their according chat id. Make sure you send the person/group that you want to get the chat id a message, so it shows up on recent chat messages.
def getCurrentChats():
"""
Gets list of current chats for current user.
Returns:
--------
Pandas DataFrame with information about the current chats
"""
headers = {'Content-type':'application/json',
"Authorization": f"Bearer {getGraphAccessToken()}"}
connection = http.client.HTTPSConnection("graph.microsoft.com")
connection.request("GET","/v1.0/me/chats",headers=headers)
resp = connection.getresponse()
text = resp.read()
return pd.DataFrame(json.loads(text)['value'])
def getCurrentChatMembers(currentChatsDataFrame,idColumn = 'id',debug=False):
"""
Get dictionary of member emails for each chat id
Parameters:
----------
currentChatsDataFrame : Pandas DataFrame returned from getCurrentChats()
idColumn : str, name of column with chat id (default= id)
Returns:
--------
Pandas DataFrame with ['memberName','memberEmail','chatId'] columns
"""
memberList = []
chatIdList = []
emailList = []
headers = {'Content-type':'application/json',
"Authorization": f"Bearer {getGraphAccessToken()}"}
connection = http.client.HTTPSConnection("graph.microsoft.com")
for chat_id in currentChatsDataFrame[idColumn]:
connection.request("GET",f"/v1.0/me/chats/{chat_id}/members",headers=headers)
resp = connection.getresponse()
text = resp.read()
#chatIdList.append(chat_id)
respJson = json.loads(text)['value']
dprint(respJson,debug=debug)
if respJson[1]['email'] =='your email address':# This returns the information about other chat member not the current user.
chatIdList.append(chat_id)
memberList.append(respJson[0]['displayName'])
emailList.append(respJson[0]['email'])
else:
chatIdList.append(chat_id)
memberList.append(respJson[1]['displayName'])
emailList.append(respJson[1]['email'])
dprint(text,debug=debug)
dprint('---------------------------')
#member_list.append(json.loads(text)['value'])
dprint(f"chatIdList is {chatIdList}",debug=debug)
dprint(f"memberlist is {memberList}",debug=debug)
dprint(f"emaillist is {emailList}",debug=debug)
return pd.DataFrame({'memberName':memberList,'memberEmail':emailList,'chatId': chatIdList})
Firstly :
Create a new channel in your Team if desired. A new channel will prevent Python generated notices from taking over other conversation channels.
img1
Add a new connector on your desired channel.
img 2
Find the Webhook connector and configure.
img 3
The configuration required is just a name for the webhook and optionally an image.
img4
img 5
Click create and copy the resulting webhook URL.
img6
Add this code your Python project so that it can write a message to Teams.
Install pymsteams with pip.
pip install pymsteams
Add this code to your Python project to enable writing messages to Teams, substitute the URL for your webhook:
import pymsteams
myTeamsMessage = pymsteams.connectorcard("INSERT WEBHOOK URL HERE")
Use this code to generate messages:
myTeamsMessage.text("This message was generated from Python!")
myTeamsMessage.send()
output

Python and mailchimp integration

So i have been stuck on this for a week or so and could really do this some advice.
I have a basic website which allows people to sign up to an automated newsletter that i want to send out. After adding their email on the site their address is automatically added to an audience.
I have a small python script running that then web scrapes a site and then if that returns a certain criteria it will send an automated email out via mailchimp to all the contacts in the mailchimp audience.
What i am having issue with is actually creating and sending out the email via mail chimp.
I have been through https://mailchimp.com/developer/api/marketing/campaigns/add-campaign/ a few times and can't seem to get it working. I am able to create a new campaign succesfully as well as the audience and subject line. I am unable to workout how to actually send the email with the content i want inside it however. It just saves itself as a draft and thats it.
When i try to preview the email there is nothing in it and when i click edit next to the campaign everything is ticked except for the 'content.
I have excluded th web scraping part of my program but below is the test i am running to create and sent out via the mailchimp api
import mailchimp_marketing as MailchimpMarketing
from mailchimp_marketing.api_client import ApiClientError
from mailchimp3 import MailChimp
data = {
"recipients" :
{
"list_id": 'XXXXXXXX'
},
"settings":
{
"subject_line": 'Subject of email',
"from_name": 'from_name',
"reply_to": 'reply_email',
},
"type": "regular"
}
try:
client = MailchimpMarketing.Client()
#print(client)
client.set_config({
"api_key": "XXXXXXXXXXXXXXXX",
"server": "XXXXXXX"
})
#client = MailChimp(mc_api='XXXXXXXXXXXX', mc_user="XXXXXXXXX")
client.campaigns.create(data)
response = client.campaigns.get('campaign_id')
#client.campaigns.send()
print(response)
except ApiClientError as error:
print("Error: {}".format(error.text))
This succesfully creates the campaign except without the content that i want to add and simply saves the email as a draft without send. So i guess my question is how to i edit the email content and then how do i actually initiate the send.
Thanks for any help
I also didn't find a minimal example on the web. Plus the examples in the mailchimp api documentation are severely lacking for python (only curl seems correct). Here's a minimal example:
from mailchimp_marketing import Client, api_client
# find this out at https://mailchimp.com/en/help/about-api-keys/
API_KEY = '…'
# log into your Mailchimp account and look at the URL in your browser.
# You’ll see something like https://us19.admin.mailchimp.com/
# the us19 part is the server prefix.
SERVER_PREFIX = 'us19'
try:
client = Client()
client.set_config({
"api_key": API_KEY,
"server": SERVER_PREFIX
})
# find out list id: https://mailchimp.com/en/help/find-audience-id/
campaign_data = dict(
type='regular',
recipients=dict(list_id='…'),
settings=dict(
subject_line='lorem ipsum',
from_name='John Doe',
reply_to='john#doe.com',
)
)
campaign = client.campaigns.create(campaign_data)
print(campaign)
campaign_id = campaign['id']
content_data = dict(
plain_text='lorem ipsum',
html='<p><strong>lorem</strong><br />ipsum</p>'
)
response = client.campaigns.set_content(campaign_id, content_data)
print(response)
response = client.campaigns.send(campaign_id)
print(response)
except api_client.ApiClientError as e:
print("Error: {}".format(error.text))

Pulling historical channel messages python

I am attempting to create a small dataset by pulling messages/responses from a slack channel I am a part of. I would like to use python to pull the data from the channel however I am having trouble figuring out my api key. I have created an app on slack but I am not sure how to find my api key. I see my client secret, signing secret, and verification token but can't find my api key
Here is a basic example of what I believe I am trying to accomplish:
import slack
sc = slack.SlackClient("api key")
sc.api_call(
"channels.history",
channel="C0XXXXXX"
)
I am willing to just download the data manually if that is possible as well. Any help is greatly appreciated.
messages
See below for is an example code on how to pull messages from a channel in Python.
It uses the official Python Slack library and calls
conversations_history with paging. It will therefore work with
any type of channel and can fetch large amounts of messages if
needed.
The result will be written to a file as JSON array.
You can specify channel and max message to be retrieved
threads
Note that the conversations.history endpoint will not return thread messages. Those have to be retrieved additionaly with one call to conversations.replies for every thread you want to retrieve messages for.
Threads can be identified in the messages for each channel by checking for the threads_ts property in the message. If it exists there is a thread attached to it. See this page for more details on how threads work.
IDs
This script will not replace IDs with names though. If you need that here are some pointers how to implement it:
You need to replace IDs for users, channels, bots, usergroups (if on a paid plan)
You can fetch the lists for users, channels and usergroups from the API with users_list, conversations_list and usergroups_list respectively, bots need to be fetched one by one with bots_info (if needed)
IDs occur in many places in messages:
user top level property
bot_id top level property
as link in any property that allows text, e.g. <#U12345678> for users or <#C1234567> for channels. Those can occur in the top level text property, but also in attachments and blocks.
Example code
import os
import slack
import json
from time import sleep
CHANNEL = "C12345678"
MESSAGES_PER_PAGE = 200
MAX_MESSAGES = 1000
# init web client
client = slack.WebClient(token=os.environ['SLACK_TOKEN'])
# get first page
page = 1
print("Retrieving page {}".format(page))
response = client.conversations_history(
channel=CHANNEL,
limit=MESSAGES_PER_PAGE,
)
assert response["ok"]
messages_all = response['messages']
# get additional pages if below max message and if they are any
while len(messages_all) + MESSAGES_PER_PAGE <= MAX_MESSAGES and response['has_more']:
page += 1
print("Retrieving page {}".format(page))
sleep(1) # need to wait 1 sec before next call due to rate limits
response = client.conversations_history(
channel=CHANNEL,
limit=MESSAGES_PER_PAGE,
cursor=response['response_metadata']['next_cursor']
)
assert response["ok"]
messages = response['messages']
messages_all = messages_all + messages
print(
"Fetched a total of {} messages from channel {}".format(
len(messages_all),
CHANNEL
))
# write the result to a file
with open('messages.json', 'w', encoding='utf-8') as f:
json.dump(
messages_all,
f,
sort_keys=True,
indent=4,
ensure_ascii=False
)
This is using the slack webapi. You would need to install requests package. This should grab all the messages in channel. You need a token which can be grabbed from apps management page. And you can use the getChannels() function. Once you grab all the messages you will need to see who wrote what message you need to do id matching(map ids to usernames) you can use getUsers() functions. Follow this https://api.slack.com/custom-integrations/legacy-tokens to generate a legacy-token if you do not want to use a token from your app.
def getMessages(token, channelId):
print("Getting Messages")
# this function get all the messages from the slack team-search channel
# it will only get all the messages from the team-search channel
slack_url = "https://slack.com/api/conversations.history?token=" + token + "&channel=" + channelId
messages = requests.get(slack_url).json()
return messages
def getChannels(token):
'''
function returns an object containing a object containing all the
channels in a given workspace
'''
channelsURL = "https://slack.com/api/conversations.list?token=%s" % token
channelList = requests.get(channelsURL).json()["channels"] # an array of channels
channels = {}
# putting the channels and their ids into a dictonary
for channel in channelList:
channels[channel["name"]] = channel["id"]
return {"channels": channels}
def getUsers(token):
# this function get a list of users in workplace including bots
users = []
channelsURL = "https://slack.com/api/users.list?token=%s&pretty=1" % token
members = requests.get(channelsURL).json()["members"]
return members

MS teams bot - create new conversation

I'm using the botbuilder-python to build MS Teams bot.
Following samples I am able to respond to messages. What I'm struggling with is creating completely new message, without existing activity passed from Teams. I modified some code from the tests (https://github.com/Microsoft/botbuilder-python/blob/62b0512a4dd918fa0d3837207012b31213aaedcc/libraries/botframework-connector/tests/test_conversations.py) but I'm getting:
botbuilder.schema.error_response_py3.ErrorResponseException: (BadSyntax) Could not parse tenant id
What is it, where can I find it (I can fish it out from request but it's not ideal) and how do I pass it? Can anyone point me at any Python samples of creating a new conversation?
I figured it out, just in case anybody else is trying to do the same thing and gets stuck:
to = ChannelAccount(id=to_user_id)
bot_channel = ChannelAccount(id=bot_id)
activity_reply = Activity(type=ActivityTypes.message, channel_id='msteams',from_property=bot_channel,recipient=to,text=message)
credentials=MicrosoftAppCredentials(app_id, app_password)
JwtTokenValidation.authenticate_request(activity_reply, "Authorization", credentials)
# That's where you pass the tenant id
reply_conversation_params=ConversationParameters(bot=bot_channel, members=[to], activity=activity_reply, channel_data={ 'tenant': { 'id': tenant_id } })
connector = ConnectorClient(credentials, base_url='https://smba.trafficmanager.net/uk/')
# Create conversation
conversation = connector.conversations.create_conversation(reply_conversation_params)
# And send it
connector.conversations.send_to_conversation(conversation.id, activity_reply)

Categories

Resources