text: #!/usr/bin/python
  # -*- coding: utf-8 -*-
  #
  # (C) 2019 Count Count
  #
  # Distributed under the terms of the MIT license.
  
  import hashlib
  import locale
  import os
  import random
  import re
  import threading
  import time
  import traceback
  from dataclasses import dataclass
  from datetime import datetime, timedelta
  from typing import Dict, Iterator, List, Optional, Set, cast, TypedDict
  
  import pytz
  from redis import Redis
  
  import pywikibot
  from pywikibot.bot import SingleSiteBot
  from pywikibot.comms.eventstreams import site_rc_listener
  
  
  timezone = pytz.timezone("Europe/Berlin")
  
  inProduction = True
  
  
  def getDateString() -> str:
      localizedTime = datetime.now(timezone)
      if os.name == "nt":
          return localizedTime.strftime("%e").replace(" ", "") + localizedTime.strftime(". %B %Y")
      else:
          return localizedTime.strftime("%-d. %B %Y")
  
  
  def ensureDateSectionExists(text: str) -> str:
      currentDateSection = f"=== {getDateString()} ==="
      if not currentDateSection in text:
          text += f"\n<noinclude>\n{currentDateSection}</noinclude>"
      return text
  
  
  def FaultTolerantLiveRCPageGenerator(site: pywikibot.site.BaseSite) -> Iterator[pywikibot.Page]:
      for entry in site_rc_listener(site):
          # The title in a log entry may have been suppressed
          if "title" not in entry and entry["type"] == "log":
              continue
          if "\ufffd" in entry["title"]:
              pywikibot.warning(
                  f"Title '{entry['title']}' contains (\\uFFFD 'REPLACEMENT CHARACTER'), Full entry: {entry!r}"
              )
              continue
          try:
              page = pywikibot.Page(site, entry["title"], entry["namespace"])
          except Exception:
              pywikibot.warning("Exception instantiating page %s: %s" % (entry["title"], traceback.format_exc()))
              continue
          page._rcinfo = entry
          yield page
  
  
  def getUserFromSignature(site: pywikibot.site.BaseSite, text: str) -> Optional[pywikibot.User]:
      for wikilink in pywikibot.link_regex.finditer(text):
          if not wikilink.group("title").strip():
              continue
          try:
              link = pywikibot.Link(wikilink.group("title"), source=site)
              link.parse()
          except pywikibot.Error:
              continue
          if link.namespace in [2, 3] and link.title.find("/") == -1:
              return pywikibot.User(site, link.title)
          if link.namespace == -1 and link.title.startswith("Beiträge/"):
              return pywikibot.User(site, link.title[len("Beiträge/") :])
      return None
  
  
  def getContributionsLogPageTitle(greeter: str) -> str:
      return f"Wikipedia:WikiProjekt Begrüßung von Neulingen/Bearbeitungen von Begrüßten/{greeter}"
  
  
  def ensureHeaderForContributionLogExists(text: str, greeter: str) -> str:
      if text == "":
          text = f"{{{{Wikipedia:WikiProjekt Begrüßung von Neulingen/Vorlage:Kopfzeile Bearbeitungen von Begrüßten|{greeter}}}}}"
      return text
  
  
  def getLogPageTitle(greeter: str) -> str:
      return f"Wikipedia:WikiProjekt Begrüßung von Neulingen/Begrüßungslogbuch/{greeter}"
  
  
  def ensureHeaderForLogExists(text: str, greeter: str) -> str:
      if text == "":
          text = f"{{{{Wikipedia:WikiProjekt Begrüßung von Neulingen/Vorlage:Kopfzeile Begrüßungslogbuch|{greeter}}}}}"
      return text
  
  
  def ensureIncludedAsTemplate(mainLogPage: pywikibot.Page, subLogPageTitle: str) -> None:
      if not f"{{{subLogPageTitle}}}" in mainLogPage.get(force=True):
          mainLogPage.text = mainLogPage.text + f"\n{{{{{subLogPageTitle}}}}}"
          mainLogPage.save(summary=f"Bot: Unterseite [[{subLogPageTitle}]] eingebunden.")
  
  
  GreetedUserInfo = TypedDict("GreetedUserInfo", {"greeter": str, "normalEditSeen": str, "time": str})
  ControlGroupUserInfo = TypedDict("ControlGroupUserInfo", {"time": str})
  
  
  class RedisDb:
      def __init__(self, secret: str) -> None:
          self.secret = secret
          self.redis = Redis(host="tools-redis" if os.name != "nt" else "localhost", decode_responses=True)
  
      def getGreetedUserKey(self, greetedUser: str) -> str:
          return f"{self.secret}:greetedUser:{greetedUser}"
  
      def getControlGroupUserKey(self, greetedUser: str) -> str:
          return f"{self.secret}:controlGroup:{greetedUser}"
  
      def addGreetedUser(self, greeter: str, user: str) -> None:
          key = self.getGreetedUserKey(user)
          p = self.redis.pipeline()  # type: ignore
          p.hset(key, "greeter", greeter)
          p.hset(key, "normalEditSeen", "0")
          p.hset(key, "time", int(datetime.utcnow().timestamp()))
          p.expire(key, timedelta(days=90))
          p.sadd(f"{self.secret}:greetedUsers", user)
          p.execute()
  
      def addControlGroupUser(self, user: str) -> None:
          key = self.getControlGroupUserKey(user)
          if not self.redis.exists(key):  # type: ignore
              p = self.redis.pipeline()  # type: ignore
              p.hset(key, "time", int(datetime.utcnow().timestamp()))
              p.expire(key, timedelta(days=90))
              p.sadd(f"{self.secret}:controlGroup", user)
              p.execute()
  
      def getGreetedUserInfo(self, user: str) -> GreetedUserInfo:
          return self.redis.hgetall(self.getGreetedUserKey(user))  # type: ignore
  
      def setGreetedUserInfo(self, user: str, newUserInfo: GreetedUserInfo) -> None:
          self.redis.hmset(self.getGreetedUserKey(user), newUserInfo)  # type: ignore
  
      def removeGreetedUser(self, user: str) -> None:
          self.redis.delete(self.getGreetedUserKey(user))  # type: ignore
  
      def getControlGroupUserInfo(self, user: str) -> ControlGroupUserInfo:
          return self.redis.hgetall(self.getControlGroupUserKey(user))  # type: ignore
  
      def getAllGreetedUsers(self) -> List[str]:
          return cast(List[str], self.redis.smembers(f"{self.secret}:greetedUsers"))  # type: ignore
  
      def getAllControlGroupUsers(self) -> List[str]:
          return cast(List[str], self.redis.smembers(f"{self.secret}:controlGroup"))  # type: ignore
  
      def deleteUserGroups(self) -> None:
          self.redis.delete(f"{self.secret}:greetedUsers")  # type: ignore
          self.redis.delete(f"{self.secret}:controlGroup")  # type: ignore
  
  
  class TalkPageExistsException(Exception):
      pass
  
  
  @dataclass
  class Greeter:
      user: pywikibot.User
      signatureWithoutTimestamp: str
  
  
  class GreetController:
      def __init__(self, site: pywikibot.site.APISite, redisDb: RedisDb, secret: str) -> None:
          self.greeters: List[Greeter]
          self.allGreetersSet: Set[str]
          self.site = site
          self.redisDb = redisDb
          self.secret = secret
          self.site.login()
  
      def isUserGloballyLocked(self, user: pywikibot.User) -> bool:
          globallyLockedRequest = pywikibot.data.api.Request(
              site=self.site,
              parameters={"action": "query", "format": "json", "meta": "globaluserinfo", "guiuser": user.username,},
          )
          response = globallyLockedRequest.submit()
          return "locked" in response["query"]["globaluserinfo"]
  
      def isEligibleAsGreeter(self, greeter: pywikibot.User) -> bool:
          if not greeter.isRegistered():
              pywikibot.warning(f"Greeter '{greeter.username}' does not exist.")
              return False
          if greeter.isBlocked():
              pywikibot.warning(f"'{greeter.username}' is blocked and thus not eligible as greeter.")
              return False
          if self.isUserGloballyLocked(greeter):
              pywikibot.warning(f"'{greeter.username}' is globally locked and thus not eligible as greeter.")
              return False
          if not "review" in greeter.getprops()["rights"]:
              pywikibot.warning(f"'{greeter.username}' does not have review rights and is thus not eligible as greeter.")
              return False
          if greeter.getUserTalkPage().protection():
              # Talk page is protected, thus not eligible as greeter
              return False
          if not inProduction and greeter.username != "Count Count":
              return False
          cutoffTime = datetime.now() - timedelta(hours=24)
          lastActivityTimestamp = greeter.last_event.timestamp()
          if lastActivityTimestamp < cutoffTime:
              # not active in the last 24 hours and is thus not eligible as greeter
              return False
          return True
  
      def reloadGreeters(self) -> None:
          self.greeters = []
          self.allGreetersSet = set()
          projectPage = pywikibot.Page(self.site, "Wikipedia:WikiProjekt Begrüßung von Neulingen/Begrüßungsteam")
          inSection = False
          greetersSet: Set[str] = set()
          for line in projectPage.get(force=True).split("\n"):
              if inSection:
                  if line.startswith("="):
                      break
                  elif line.startswith("#"):
                      match = re.match(
                          r"#\s*(.+) [0-9]{2}:[0-9]{2}, [123]?[0-9]\. (?:Jan\.|Feb\.|Mär\.|Apr\.|Mai|Jun\.|Jul\.|Aug\.|Sep\.|Okt\.|Nov\.|Dez\.) 2[0-9]{3} \((CES?T|MES?Z)\)",
                          line,
                      )
                      if match:
                          signatureWithoutTimestamp = match.group(1)
                          user = getUserFromSignature(self.site, signatureWithoutTimestamp)
                          if not user:
                              pywikibot.warning(
                                  f"Could not extract greeter name from signature '{signatureWithoutTimestamp}'"
                              )
                          else:
                              if user.username in greetersSet:
                                  pywikibot.warning(f"Duplicate greeter '{user.username}''")
                              elif self.isEligibleAsGreeter(user):
                                  greetersSet.add(user.username)
                                  self.greeters.append(Greeter(user, signatureWithoutTimestamp))
                              self.allGreetersSet.add(user.username)
                      else:
                          pywikibot.warning(f"Could not parse greeter line: '{line}''")
              elif re.match(r"==\s*Begrüßungsteam\s*==\s*", line):
                  inSection = True
  
      def getUsersToGreet(self) -> List[pywikibot.User]:
          logevents = self.site.logevents(
              logtype="newusers",
              start=datetime.utcnow() - timedelta(hours=24),
              end=datetime.utcnow() - timedelta(hours=6),
              reverse=True,
          )
          usersToGreet = []
          for logevent in logevents:
              if logevent.action() == "create":  # only locally registered new users, no SUL
                  try:
                      user = pywikibot.User(self.site, logevent.user())
                  except pywikibot.exceptions.HiddenKeyError:
                      # User name hidden/oversighted
                      continue
  
                  if user.isBlocked():
                      # User is blocked and will not be greeted.
                      pass
                  elif self.isUserGloballyLocked(user):
                      # User is globally locked and will not be greeted.
                      pass
                  elif user.getUserTalkPage().exists():
                      # User talk page exists, will thus not be greeted.
                      pass
                  elif inProduction and not timezone.localize(datetime(2019, 12, 2, 0, 0)) < logevent.timestamp().replace(
                      tzinfo=pytz.utc
                  ).astimezone(timezone) < timezone.localize(datetime(2020, 1, 27, 0, 0)):
                      # only greet users registered in eight week test period
                      pass
                  else:
                      usersToGreet.append(user)
  
          return usersToGreet
  
      def logGreetings(self, greeter: pywikibot.User, users: List[pywikibot.User]) -> None:
          logPageTitle = getLogPageTitle(greeter.username)
          logPage = pywikibot.Page(self.site, logPageTitle)
          text = logPage.get(force=True) if logPage.exists() else ""
          text = ensureHeaderForLogExists(text, greeter.username)
          text = ensureDateSectionExists(text)
          for user in users:
              text += f"\n* {{{{Benutzer|{user.username}}}}}"
          logPage.text = text
          logPage.save(summary="Bot: Logeinträge für neue Begrüßungen hinzugefügt.", watch=False)
          mainLogPage = pywikibot.Page(self.site, f"Wikipedia:WikiProjekt Begrüßung von Neulingen/Begrüßungslogbuch")
          ensureIncludedAsTemplate(mainLogPage, logPageTitle)
          usersWithContribsText = ""
          for user in users:
              if len(list(user.contributions(total=1))) != 0:
                  usersWithContribsText += f"\n{{{{subst:Wikipedia:WikiProjekt Begrüßung von Neulingen/Vorlage:BegrüßterHatBereitsVorherEditiert|1={user.username}}}}}"
          if len(usersWithContribsText) > 0:
              contributionsLogPageTitle = getContributionsLogPageTitle(greeter.username)
              contributionsLogPage = pywikibot.Page(self.site, contributionsLogPageTitle)
              contributionsLogText = contributionsLogPage.get(force=True) if contributionsLogPage.exists() else ""
              contributionsLogText = ensureHeaderForContributionLogExists(contributionsLogText, greeter.username)
              contributionsLogText = ensureDateSectionExists(contributionsLogText)
              summary = "Bot: Bereits erfolgte Bearbeitungen von begrüßten Benutzers protokolliert."
              contributionsLogText += usersWithContribsText
              contributionsLogPage.text = contributionsLogText
              contributionsLogPage.save(summary=summary)
              mainLogPage = pywikibot.Page(
                  self.site, f"Wikipedia:WikiProjekt Begrüßung von Neulingen/Bearbeitungen von Begrüßten"
              )
              ensureIncludedAsTemplate(mainLogPage, contributionsLogPageTitle)
  
      def greet(self, greeter: Greeter, user: pywikibot.User) -> None:
          pywikibot.output(f"Greeting '{user.username}' as '{greeter.user.username}'")
          userTalkPage = user.getUserTalkPage()
          if userTalkPage.exists():
              pywikibot.warning(f"User talk page of {user.username} was created suddenly")
              raise TalkPageExistsException()
          greeterTalkPagePrefix = (
              "Benutzerin Diskussion:" if greeter.user.gender() == "female" else "Benutzer Diskussion:"
          )
          greeterTalkPage = greeterTalkPagePrefix + greeter.user.username
          userTalkPage.text = (
              f"{{{{subst:Wikipedia:WikiProjekt Begrüßung von Neulingen/Vorlage:Willkommen|1="
              f"{greeter.signatureWithoutTimestamp}|2={greeter.user.username}|3={greeterTalkPage}}}}}"
          )
          userTalkPage.save(summary="Bot: Herzlich Willkommen bei Wikipedia!", watch=False)
          self.redisDb.addGreetedUser(greeter.user.username, user.username)
  
      def greetAll(self, users: List[pywikibot.User]) -> List[pywikibot.User]:
          greetings: Dict[pywikibot.User, List[pywikibot.User]] = {}
          greetedUsers: List[pywikibot.User] = []
          for user in users:
              greeter = random.choice(self.greeters)
              try:
                  self.greet(greeter, user)
              except TalkPageExistsException:
                  continue
              except Exception:
                  pywikibot.error(
                      f"Error greeting '{user.username}' as '{greeter.user.username}': {traceback.format_exc()}"
                  )
                  continue
              greetedUsers.append(user)
              if not greeter.user in greetings:
                  greetings[greeter.user] = []
              greetings[greeter.user].append(user)
  
          for (k, v) in greetings.items():
              self.logGreetings(k, v)
  
          return greetedUsers
  
      def isInControlGroup(self, user: pywikibot.User) -> bool:
          digest = hashlib.sha224((self.secret + user.username).encode("utf-8")).digest()
          return digest[0] % 128 < 64
  
      def logGroup(self, page: pywikibot.Page, users: List[pywikibot.User]) -> None:
          text = page.get(force=True) if page.exists() else ""
          for user in users:
              newLine = f"\n* [[Benutzer:{user.username}|{user.username}]]"
              if not newLine in text:
                  text += newLine
          page.text = text
          page.save(summary=f"Bot: Benutzerliste nach Botlauf aktualisiert.")
  
      def logGroups(self, greetedUsers: List[pywikibot.User], controlGroup: List[pywikibot.User]) -> None:
          self.logGroup(
              pywikibot.Page(self.site, "Wikipedia:WikiProjekt Begrüßung von Neulingen/Begrüßte Benutzer"), greetedUsers
          )
          self.logGroup(
              pywikibot.Page(self.site, "Wikipedia:WikiProjekt Begrüßung von Neulingen/Kontrollgruppe"), controlGroup
          )
  
      def createGreeterSpecificPages(self, greeter: str) -> None:
          logPageTitle = getLogPageTitle(greeter)
          logPage = pywikibot.Page(self.site, logPageTitle)
          if not logPage.exists():
              text = ensureHeaderForLogExists("", greeter)
              logPage.text = text
              logPage.save(summary="Bot: Seite für Begrüßer angelegt.", watch=False)
          mainLogPage = pywikibot.Page(self.site, f"Wikipedia:WikiProjekt Begrüßung von Neulingen/Begrüßungslogbuch")
          ensureIncludedAsTemplate(mainLogPage, logPageTitle)
          contributionsLogPageTitle = getContributionsLogPageTitle(greeter)
          contributionsLogPage = pywikibot.Page(self.site, contributionsLogPageTitle)
          if not contributionsLogPage.exists():
              contributionsLogText = ensureHeaderForContributionLogExists("", greeter)
              contributionsLogPage.text = contributionsLogText
              contributionsLogPage.save(summary="Bot: Seite für Begrüßer angelegt.")
          mainLogPage = pywikibot.Page(
              self.site, f"Wikipedia:WikiProjekt Begrüßung von Neulingen/Bearbeitungen von Begrüßten"
          )
          ensureIncludedAsTemplate(mainLogPage, contributionsLogPageTitle)
  
      def createAllGreeterSpecificPages(self) -> None:
          self.reloadGreeters()
          for greeter in self.allGreetersSet:
              self.createGreeterSpecificPages(greeter)
  
      def doGreetRun(self) -> None:
          pywikibot.output("Starting greet run...")
          self.reloadGreeters()
          pywikibot.output(f"Eligible greeters: {sorted(greeter.user.username for greeter in self.greeters)}")
          allUsers = self.getUsersToGreet()
          if not inProduction:
              allUsers = allUsers[:10]
          usersToGreet: List[pywikibot.User] = []
          controlGroup: List[pywikibot.User] = []
          for user in allUsers:
              (controlGroup if self.isInControlGroup(user) else usersToGreet).append(user)
          pywikibot.output(f"Users to greet: {sorted(user.username for user in usersToGreet)}")
          pywikibot.output(f"Users in control group: {sorted(user.username for user in controlGroup)}")
          pywikibot.output(
              f"Greeting {len(usersToGreet)} users with {len(self.greeters)} greeters (control group: {len(controlGroup)} users)..."
          )
          greetedUsers = self.greetAll(usersToGreet)
          for user in controlGroup:
              self.redisDb.addControlGroupUser(user.username)
          self.logGroups(greetedUsers, controlGroup)
          pywikibot.output("Finished greet run.")
  
      def run(self) -> None:
          while True:
              if 8 <= datetime.now(timezone).hour < 22:
                  try:
                      self.doGreetRun()
                  except Exception:
                      pywikibot.error(f"Error during greeting run: {traceback.format_exc()}")
              time.sleep(30 * 60)
  
  
  class GreetedUserWatchBot(SingleSiteBot):
      def __init__(self, site: pywikibot.site.APISite, redisDb: RedisDb) -> None:
          super(GreetedUserWatchBot, self).__init__(site=site)
          self.redisDb = redisDb
          self.generator = FaultTolerantLiveRCPageGenerator(self.site)
  
      def skip_page(self, page: pywikibot.Page) -> bool:
          if page.namespace() < 0:
              return True
          if not page.exists():
              return True
          return super().skip_page(page)
  
      def greeterWantsToBeNotifiedOnTalkPage(self, greeter: str) -> bool:
          projectPage = pywikibot.Page(self.site, "Wikipedia:WikiProjekt Begrüßung von Neulingen/Begrüßungsteam")
          inSection = False
          for line in projectPage.get(force=True).split("\n"):
              if inSection:
                  if line.startswith("="):
                      break
                  elif line.startswith("*"):
                      user = getUserFromSignature(self.site, line)
                      if not user:
                          pywikibot.warning(f"Could not extract greeter name from notify line '{line}'")
                      elif user.username == greeter:
                          return True
              elif re.match(r"===\s*Benachrichtigung über Antworten\s*===\s*", line):
                  inSection = True
          return False
  
      def saveNotificationInProject(self, greeter: str, username: str, newRevision: int, ownTalkPageEdit: bool) -> None:
          contributionsLogPageTitle = getContributionsLogPageTitle(greeter)
          contributionsLogPage = pywikibot.Page(self.site, contributionsLogPageTitle)
          contributionsLogText = contributionsLogPage.get(force=True) if contributionsLogPage.exists() else ""
          contributionsLogText = ensureHeaderForContributionLogExists(contributionsLogText, greeter)
          contributionsLogText = ensureDateSectionExists(contributionsLogText)
          summary = "Bot: Bearbeitung eines begrüßten Benutzers protokolliert."
          contributionsLogText += (
              f"\n{{{{subst:Wikipedia:WikiProjekt Begrüßung von Neulingen/Vorlage:BegrüßterHatEditiert2"
              f"|1={username}|2={newRevision}|3={'1' if ownTalkPageEdit else ''}}}}}"
          )
          contributionsLogPage.text = contributionsLogText
          contributionsLogPage.save(summary=summary)
          mainLogPage = pywikibot.Page(
              self.site, f"Wikipedia:WikiProjekt Begrüßung von Neulingen/Bearbeitungen von Begrüßten"
          )
          ensureIncludedAsTemplate(mainLogPage, contributionsLogPageTitle)
  
      def notifyGreeter(self, greeter: str, username: str, newRevision: int, ownTalkPageEdit: bool) -> None:
          self.saveNotificationInProject(greeter, username, newRevision, ownTalkPageEdit)
  
          if self.greeterWantsToBeNotifiedOnTalkPage(greeter) and ownTalkPageEdit:
              greeterTalkPage = pywikibot.User(self.site, greeter).getUserTalkPage()
              text = greeterTalkPage.get(force=True) if greeterTalkPage.exists() else ""
              text += f"\n\n{{{{subst:Wikipedia:WikiProjekt Begrüßung von Neulingen/Vorlage:BegrüßterHatEditiert|1={username}|2={newRevision}}}}}"
              greeterTalkPage.text = text
              greeterTalkPage.save(
                  summary="Bot: Ein von dir begrüßter Benutzer hat seine Benutzerdiskussionsseite bearbeitet.",
                  minor=False,
              )
  
      def treat(self, page: pywikibot.Page) -> None:
          change = page._rcinfo
          if not (change["type"] == "edit" or change["type"] == "new"):
              return
  
          username = change["user"]
          greetedUserInfo = self.redisDb.getGreetedUserInfo(username)
          if greetedUserInfo:
              title = change["title"]
              newRevision = change["revision"]["new"]
              if change["timestamp"] < float(greetedUserInfo["time"]):
                  # event before greeting
                  pywikibot.warn(f"Received event before greeting for user '{username}', rev id {newRevision}")
                  return
              if page.namespace() == 3 and title[title.index(":") + 1 :] == username:
                  # user edited his own talk page for the first time after being greeted
                  self.redisDb.removeGreetedUser(username)
                  self.notifyGreeter(greetedUserInfo["greeter"], username, newRevision, True)
              elif greetedUserInfo["normalEditSeen"] == "0":
                  # user edited somewhere else for the first time after being greeted
                  greetedUserInfo["normalEditSeen"] = "1"
                  self.redisDb.setGreetedUserInfo(username, greetedUserInfo)
                  self.notifyGreeter(greetedUserInfo["greeter"], username, newRevision, False)
  
  
  def runWatchBot(site: pywikibot.site.APISite, redisDb: RedisDb) -> None:
      while True:
          try:
              GreetedUserWatchBot(site, redisDb).run()
          except Exception:
              pywikibot.error(f"Error watching greeted users: {traceback.format_exc()}")
              time.sleep(60)
  
  
  def startWatchBot(site: pywikibot.site.APISite, redisDb: RedisDb) -> None:
      threading.Thread(target=runWatchBot, args=[site, redisDb]).start()
  
  
  def main() -> None:
      otherArgs = pywikibot.handle_args()
      locale.setlocale(locale.LC_ALL, "de_DE.utf8")
      site = cast(pywikibot.site.APISite, pywikibot.Site("de", "wikipedia"))
      if not inProduction:
          monkey_patch(site)
      secret = os.environ.get("GREETBOT_SECRET") if inProduction else "12345abcdef"
      if not secret:
          raise Exception("Environment variable GREETBOT_SECRET not set")
      redisDb = RedisDb(secret)
      if "--create-pages" in otherArgs:
          GreetController(site, redisDb, secret).createAllGreeterSpecificPages()
      elif "--list-user-groups" in otherArgs:
          print("Greeted users:")
          for user in sorted(redisDb.getAllGreetedUsers()):
              greetedUserInfo = redisDb.getGreetedUserInfo(user)
              print(
                  f"* {user} - {datetime.fromtimestamp(int(greetedUserInfo['time']), tz=timezone)} - "
                  f"{greetedUserInfo['greeter']}"
              )
          print("Control group:")
          for user in sorted(redisDb.getAllControlGroupUsers()):
              controlGroupUserInfo = redisDb.getControlGroupUserInfo(user)
              print(f"* {user} - {datetime.fromtimestamp(int(controlGroupUserInfo['time']), tz=timezone)}")
      elif "--delete-user-groups" in otherArgs:
          redisDb.deleteUserGroups()
      elif "--run-bot" in otherArgs:
          startWatchBot(site, redisDb)
          # GreetController(site, redisDb, secret).run()
      elif otherArgs:
          pywikibot.error(f"Unknown args: {otherArgs}")
      else:
          pywikibot.error(f"Missing mode")
  
  
  if __name__ == "__main__":
      try:
          main()
      finally:
          pywikibot.stopme()
  