diff --git a/pyproject.toml b/pyproject.toml
index b76716562..aad2b4dbc 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -77,7 +77,6 @@ module = [
"slack_sdk.*",
"sleekxmpp.*",
"trac.*",
- "twitter.*",
"wit.*",
]
ignore_missing_imports = true
diff --git a/zulip/integrations/twitter/doc.md b/zulip/integrations/twitter/doc.md
deleted file mode 100644
index 622b0beb6..000000000
--- a/zulip/integrations/twitter/doc.md
+++ /dev/null
@@ -1,82 +0,0 @@
-Fetch tweets from Twitter in Zulip! This is great for seeing and
-discussing who is talking about you, friends, competitors, or
-important topics in real time.
-
-1. {!create-channel.md!}
-
-1. {!create-an-incoming-webhook.md!}
-
- The API keys for "Incoming webhook" bots are limited to only
- sending messages via webhooks. Thus, this bot type lessens
- the security risks associated with exposing the bot's API
- key to third-party services.
-
-1. Download your new bot's `zuliprc` configuration file.
-
-1. {!download-python-bindings.md!}
-
-1. The Twitter bot should be set up on a trusted machine, because your API
- key is visible to local users through the command line or config
- file.
-
-1. Next, install **version 1.0 or later** of the `python-twitter`
- library. If your operating system distribution doesn’t package a new
- enough version, you can install the library from source from
- [the GitHub repository](https://github.com/bear/python-twitter).
-
-1. Next, set up Twitter authentication. This bot uses OAuth to
- authenticate with Twitter, and in order to obtain a consumer key &
- secret, you must register a new application under your Twitter
- account:
-
-1. Log in to .
-
-1. Click on `Create New App` and fill out the form.
-
-1. Click on the application you created and click **create my access
- token**. Fill in the requested values.
-
-1. Create a `~/.zulip_twitterrc` with the following contents:
-
- ```
- [twitter]
- consumer_key =
- consumer_secret =
- access_token_key =
- access_token_secret =
- ```
-
-1. Place your bot's `zuliprc` in a directory of your choice (for the next step,
- `~/zuliprc` is used).
-
-1. Test the script by running it manually:
-
- /usr/local/share/zulip/integrations/twitter/twitter-bot --search="@nprnews,quantum
- physics" --config-file=~/zuliprc
-
- /usr/local/share/zulip/integrations/twitter/twitter-bot --twitter-name="<@your-
- twitter-handle>" --config-file=~/zuliprc
-
- Note: `twitter-bot` may install to a different location on
- your operating system distribution.
-
-1. Configure a crontab entry for this script. A sample crontab entry
- that will process tweets every minute is:
-
- ```
- * * * * * /usr/local/share/zulip/integrations/twitter/twitter-bot --search="@nprnews,
- quantum physics" --config-file=~/zuliprc
- ```
-
-1. When someone tweets a message containing one of your search terms,
- get a Zulip on your specified stream, with the search term as
- the topic.
-
-{!congrats.md!}
-
-
-
-Note that the Twitter search bot integration **just sends links to
-tweets**; the pretty inline previews of tweets are generated by the
-Twitter card rendering integration configured in
-`/etc/zulip/settings.py` on the Zulip server.
diff --git a/zulip/integrations/twitter/requirements.txt b/zulip/integrations/twitter/requirements.txt
deleted file mode 100644
index b67d14b5a..000000000
--- a/zulip/integrations/twitter/requirements.txt
+++ /dev/null
@@ -1 +0,0 @@
-python-twitter >= 1.0
diff --git a/zulip/integrations/twitter/twitter-bot b/zulip/integrations/twitter/twitter-bot
deleted file mode 100755
index ef42ac557..000000000
--- a/zulip/integrations/twitter/twitter-bot
+++ /dev/null
@@ -1,251 +0,0 @@
-#!/usr/bin/env python3
-
-# Twitter integration for Zulip
-
-import argparse
-import os
-import sys
-from configparser import ConfigParser, NoOptionError, NoSectionError
-
-import zulip
-
-VERSION = "0.9"
-CONFIGFILE = os.path.expanduser("~/.zulip_twitterrc")
-INSTRUCTIONS = r"""
-twitter-bot --config-file=~/.zuliprc --search="@nprnews,quantum physics"
-
-Send Twitter tweets to a Zulip stream.
-
-Depends on: https://github.com/bear/python-twitter version 3.1
-
-To use this script:
-
-0. Use `pip install python-twitter` to install `python-twitter`
-1. Set up Twitter authentication, as described below
-2. Set up a Zulip bot user and download its `.zuliprc` config file to e.g. `~/.zuliprc`
-3. Subscribe the bot to the stream that will receive Twitter updates (default stream: twitter)
-4. Test the script by running it manually, like this:
-
-twitter-bot --config-file= --search=""
-or
-twitter-bot --config-file= --twitter-name=""
-
-- optional - Exclude any terms or users by using the flags `--exluded-terms` or `--excluded-users`:
-
-twitter-bot --config-file= --search="" --excluded-users="test-username,other-username"
-or
-twitter-bot --config-file= --twitter-name="" --excluded-terms="test-term,other-term"
-
-5. Configure a crontab entry for this script. A sample crontab entry
-that will process tweets every 5 minutes is:
-
-*/5 * * * * /usr/local/share/zulip/integrations/twitter/twitter-bot [options]
-
-== Setting up Twitter authentications ==
-
-Run this on a personal or trusted machine, because your API key is
-visible to local users through the command line or config file.
-
-This bot uses OAuth to authenticate with Twitter. Please create a
-~/.zulip_twitterrc with the following contents:
-
-[twitter]
-consumer_key =
-consumer_secret =
-access_token_key =
-access_token_secret =
-
-In order to obtain a consumer key & secret, you must register a
-new application under your Twitter account:
-
-1. Go to http://dev.twitter.com
-2. Log in
-3. In the menu under your username, click My Applications
-4. Create a new application
-
-Make sure to go the application you created and click "create my
-access token" as well. Fill in the values displayed.
-"""
-
-
-def write_config(config: ConfigParser, configfile_path: str) -> None:
- with open(configfile_path, "w") as configfile:
- config.write(configfile)
-
-
-parser = zulip.add_default_arguments(argparse.ArgumentParser("Fetch tweets from Twitter."))
-parser.add_argument(
- "--instructions",
- action="store_true",
- help="Show instructions for the twitter bot setup and exit",
-)
-parser.add_argument(
- "--limit-tweets", default=15, type=int, help="Maximum number of tweets to send at once"
-)
-parser.add_argument("--search", dest="search_terms", help="Terms to search on", action="store")
-parser.add_argument(
- "--stream",
- dest="stream",
- help="The stream to which to send tweets",
- default="twitter",
- action="store",
-)
-parser.add_argument(
- "--twitter-name", dest="twitter_name", help='Twitter username to poll new tweets from"'
-)
-parser.add_argument("--excluded-terms", dest="excluded_terms", help="Terms to exclude tweets on")
-parser.add_argument("--excluded-users", dest="excluded_users", help="Users to exclude tweets on")
-
-opts = parser.parse_args()
-
-if opts.instructions:
- print(INSTRUCTIONS)
- sys.exit()
-
-if all([opts.search_terms, opts.twitter_name]):
- parser.error("You must only specify either a search term or a username.")
-if opts.search_terms:
- client_type = "ZulipTwitterSearch/"
- CONFIGFILE_INTERNAL = os.path.expanduser("~/.zulip_twitterrc_fetchsearch")
-elif opts.twitter_name:
- client_type = "ZulipTwitter/"
- CONFIGFILE_INTERNAL = os.path.expanduser("~/.zulip_twitteruserrc_fetchuser")
-else:
- parser.error("You must either specify a search term or a username.")
-
-try:
- config = ConfigParser()
- config.read(CONFIGFILE)
- config_internal = ConfigParser()
- config_internal.read(CONFIGFILE_INTERNAL)
-
- consumer_key = config.get("twitter", "consumer_key")
- consumer_secret = config.get("twitter", "consumer_secret")
- access_token_key = config.get("twitter", "access_token_key")
- access_token_secret = config.get("twitter", "access_token_secret")
-except (NoSectionError, NoOptionError):
- parser.error("Please provide a ~/.zulip_twitterrc")
-
-if not all([consumer_key, consumer_secret, access_token_key, access_token_secret]):
- parser.error("Please provide a ~/.zulip_twitterrc")
-
-try:
- since_id = config_internal.getint("twitter", "since_id")
-except (NoOptionError, NoSectionError):
- since_id = 0
-try:
- previous_twitter_name = config_internal.get("twitter", "twitter_name")
-except (NoOptionError, NoSectionError):
- previous_twitter_name = ""
-try:
- previous_search_terms = config_internal.get("twitter", "search_terms")
-except (NoOptionError, NoSectionError):
- previous_search_terms = ""
-
-try:
- import twitter
-except ImportError:
- parser.error("Please install python-twitter")
-
-api = twitter.Api(
- consumer_key=consumer_key,
- consumer_secret=consumer_secret,
- access_token_key=access_token_key,
- access_token_secret=access_token_secret,
-)
-
-user = api.VerifyCredentials()
-
-if not user.id:
- print(
- "Unable to log in to twitter with supplied credentials. Please double-check and try again"
- )
- sys.exit(1)
-
-client = zulip.init_from_options(opts, client=client_type + VERSION)
-
-if opts.search_terms:
- search_query = " OR ".join(opts.search_terms.split(","))
- if since_id == 0 or opts.search_terms != previous_search_terms:
- # No since id yet, fetch the latest and then start monitoring from next time
- # Or, a different user id is being asked for, so start from scratch
- # Either way, fetch last 5 tweets to start off
- statuses = api.GetSearch(search_query, count=5)
- else:
- # We have a saved last id, so insert all newer tweets into the zulip stream
- statuses = api.GetSearch(search_query, since_id=since_id)
-elif opts.twitter_name:
- if since_id == 0 or opts.twitter_name != previous_twitter_name:
- # Same strategy as for search_terms
- statuses = api.GetUserTimeline(screen_name=opts.twitter_name, count=5)
- else:
- statuses = api.GetUserTimeline(screen_name=opts.twitter_name, since_id=since_id)
-
-excluded_terms = opts.excluded_terms.split(",") if opts.excluded_terms else []
-
-excluded_users = opts.excluded_users.split(",") if opts.excluded_users else []
-
-for status in statuses[::-1][: opts.limit_tweets]:
- # Check if the tweet is from an excluded user
- exclude = False
- for user in excluded_users:
- if user == status.user.screen_name:
- exclude = True
- break
- if exclude:
- continue # Continue with the loop for the next tweet
-
- # https://twitter.com/eatevilpenguins/status/309995853408530432
- composed = f"{status.user.name} ({status.user.screen_name})"
- url = f"https://twitter.com/{status.user.screen_name}/status/{status.id}"
- # This contains all strings that could have caused the tweet to match our query.
- text_to_check = [status.text, status.user.screen_name]
- text_to_check.extend(url.expanded_url for url in status.urls)
-
- text_to_check = [text.lower() for text in text_to_check]
-
- # Check that the tweet doesn't contain any terms that
- # are supposed to be excluded
- for term in excluded_terms:
- if any(term.lower() in text for text in text_to_check):
- exclude = True # Tweet should be excluded
- break
- if exclude:
- continue # Continue with the loop for the next tweet
-
- if opts.search_terms:
- search_term_used = None
- for raw_term in opts.search_terms.split(","):
- # Remove quotes from phrase:
- # "Zulip API" -> Zulip API
- term = raw_term[1:-1] if term.startswith('"') and term.endswith('"') else raw_term
- if any(term.lower() in text for text in text_to_check):
- search_term_used = term
- break
- # For some reason (perhaps encodings or message tranformations we
- # didn't anticipate), we don't know what term was used, so use a
- # default.
- if not search_term_used:
- search_term_used = "mentions"
- subject = search_term_used
- elif opts.twitter_name:
- subject = composed
-
- message = {"type": "stream", "to": [opts.stream], "subject": subject, "content": url}
-
- ret = client.send_message(message)
-
- if ret["result"] == "error":
- # If sending failed (e.g. no such stream), abort and retry next time
- print("Error sending message to zulip: %s" % ret["msg"])
- break
- else:
- since_id = status.id
-
-if "twitter" not in config_internal.sections():
- config_internal.add_section("twitter")
-config_internal.set("twitter", "since_id", str(since_id))
-config_internal.set("twitter", "search_terms", str(opts.search_terms))
-config_internal.set("twitter", "twitter_name", str(opts.twitter_name))
-
-write_config(config_internal, CONFIGFILE_INTERNAL)