def run(self, revisionTextA, revisionTextB, revisionDict):
    gdiff = diff_match_patch()
    revisionDiffs = gdiff.diff_main(revisionTextA,
        revisionTextB, False)
    gdiff.diff_cleanupSemantic(revisionDiffs)
    revisionDiffs = filter(self.isRemoveOrAdd, revisionDiffs)
    diffWordCount = map(self.countWords, revisionDiffs)
    addedWordCount = self.getAddWordCount(diffWordCount)
    deletedWordCount = self.getDeletedWordCount(diffWordCount)

    revision = Revision(**revisionDict)
    revision.wordsAdded = addedWordCount
    revision.wordsDeleted = deletedWordCount
    revision.wordCount = self.getWordCount(revisionTextB)
    return revision.to_dict()
Example #2
0
 def is_new(self):
     # today = datetime.date.today()
     # delta = datetime.timedelta(days=settings.BOT_CONSIDERED_NEW)
     # result = today - self.date_added <= delta
     # return result
     return self.revision >= Revision.get_instance(
     ).nr - settings.BOT_CONSIDERED_NEW + 1
Example #3
0
 def many_by_usernames(names: List):
     results = Bot.select(
     ).where((fn.lower(Bot.username) << [n.lower() for n in names]) & (
         Bot.revision <= Revision.get_instance().nr & Bot.approved == True))
     if len(results) > 0:
         return results
     else:
         raise Bot.DoesNotExist()
Example #4
0
def main(cli_args):
    client = TreeherderClient(cli_args.repo, cli_args.csrf_token, cli_args.session_id)
    revision = Revision(client, cli_args.revision)
    results = revision.results
    jobs = [result.get_jobs_for(cli_args.job_type, job_number=cli_args.job_number, job_platform=cli_args.job_platform) for result in results]
    jobs = _flatten_list(jobs)

    for job in jobs:
        for i in range(1, cli_args.repeat + 1):
            print('Repeat #{}'.format(i))
            job.__getattribute__(cli_args.command)()
Example #5
0
    def update_categories(self, categories: List):
        self.notify_admin(
            "Updating BotList categories to Revision {}...".format(
                Revision.get_instance().nr))

        for cat in categories:
            text = _format_category_bots(cat)

            msg = self.send_or_edit(text, cat.current_message_id)
            if msg:
                cat.current_message_id = msg.message_id
                self.sent['category'].append("{} {}".format(
                    'Resent' if self.resend else 'Updated', cat))
            cat.save()

        self._save_channel()

        # Add "share", "up", and "down" buttons
        for i in range(0, len(categories)):
            buttons = list()
            if i > 0:
                # Not first category
                # Add "Up" button
                buttons.append(
                    InlineKeyboardButton(
                        "🔺",
                        url=BotList.create_hyperlink(
                            categories[i - 1].current_message_id)))

            buttons.append(
                InlineKeyboardButton("Share",
                                     url="https://t.me/{}?start={}".format(
                                         settings.SELF_BOT_NAME,
                                         categories[i].id)))

            if i < len(categories) - 1:
                # Not last category
                buttons.append(
                    InlineKeyboardButton(
                        "🔻",
                        url=BotList.create_hyperlink(
                            categories[i + 1].current_message_id)))

            reply_markup = InlineKeyboardMarkup([buttons])
            self.bot.edit_message_reply_markup(
                self.channel.chat_id,
                categories[i].current_message_id,
                reply_markup=reply_markup,
                timeout=60)
Example #6
0
def search_bots(query):
    query = query.lower().strip()
    split = query.split(' ')

    # easter egg
    if query in ('awesome bot', 'great bot', 'superb bot', 'best bot', 'best bot ever'):
        return [Bot.by_username('@botlistbot')]

    # exact results
    where_query = (
        (fn.lower(Bot.username).contains(query) |
         fn.lower(Bot.name) << split |
         fn.lower(Bot.extra) ** query) &
        (Bot.revision <= Revision.get_instance().nr &
         Bot.approved == True)
    )
    results = set(Bot.select().distinct().where(where_query))

    # keyword results
    keyword_results = Bot.select(Bot).join(Keyword).where(
        (fn.lower(Keyword.name) << split) &
        (Bot.revision <= Revision.get_instance().nr) &
        (Bot.approved == True)
    )
    results.update(keyword_results)

    # many @usernames
    usernames = re.findall(settings.REGEX_BOT_ONLY, query)
    if usernames:
        try:
            bots = Bot.many_by_usernames(usernames)
            results.update(bots)
        except Bot.DoesNotExist:
            pass

    return list(results)
Example #7
0
    def run(self, toEmail, documentId, credentialsAsJson):
        credentials = OAuth2Credentials.from_json(credentialsAsJson)
        http = credentials.authorize(httplib2.Http())

        request = config.getService().revisions().list(fileId=documentId)
        response = request.execute(http=http)

        revisions = []
        for item in response.get('items'):
            revision = Revision()
            revision.documentId = documentId
            revision.revisionNumber = item.get('id')
            revision.author = item.get('lastModifyingUserName')
            revision.exportLink = item.get('exportLinks').get('text/plain')
            revision.dateTime = item.get('modifiedDate')
            revisions.append(revision.to_dict())
        return revisions
Example #8
0
    def testRun(self):
        pipeline = RevisionsDiffPipeline('Hello', 'Hello there', {})
        pipeline.start_test()
        result = pipeline.outputs.default.value

        expected = Revision()
        expected.wordsAdded = 1
        expected.wordsDeleted = 0
        expected.wordCount = 2
        self.assertEqual(result, expected.to_dict())
  def run(self, toEmail, documentId, credentialsAsJson):
    credentials = OAuth2Credentials.from_json(credentialsAsJson)
    http = credentials.authorize(httplib2.Http())

    request = config.getService().revisions().list(fileId=documentId)
    response = request.execute(http=http)

    revisions = []
    for item in response.get('items'):
      revision = Revision()
      revision.documentId = documentId
      revision.revisionNumber = item.get('id')
      revision.author = item.get('lastModifyingUserName')
      revision.exportLink = item.get('exportLinks').get('text/plain')
      revision.dateTime = item.get('modifiedDate')
      revisions.append(revision.to_dict())
    return revisions
Example #10
0
    def run(self, revisionTextA, revisionTextB, revisionDict):
        gdiff = diff_match_patch()
        revisionDiffs = gdiff.diff_main(revisionTextA, revisionTextB, False)
        gdiff.diff_cleanupSemantic(revisionDiffs)
        revisionDiffs = filter(self.isRemoveOrAdd, revisionDiffs)
        diffWordCount = map(self.countWords, revisionDiffs)
        addedWordCount = self.getAddWordCount(diffWordCount)
        deletedWordCount = self.getDeletedWordCount(diffWordCount)

        revision = Revision(**revisionDict)
        revision.wordsAdded = addedWordCount
        revision.wordsDeleted = deletedWordCount
        revision.wordCount = self.getWordCount(revisionTextB)
        return revision.to_dict()
Example #11
0
def send_botlist(bot, update, resend=False, silent=False):
    log.info("Re-sending BotList..." if resend else "Updating BotList...")

    channel = helpers.get_channel()
    revision = Revision.get_instance()
    revision.nr += 1
    revision.save()

    all_categories = Category.select_all()

    botlist = BotList(bot, update, channel, resend, silent)
    if resend:
        botlist.delete_full_botlist()
    botlist.update_intro()
    botlist.update_categories(all_categories)
    botlist.update_new_bots_list()
    botlist.update_category_list()
    botlist.send_footer()
    botlist.finish()
    channel.save()
    Statistic.of(update, 'send', 'botlist (resend: {})'.format(str(resend)),
                 Statistic.IMPORTANT)
Example #12
0
  def run(self, toEmail, subject, body, documentsAnalyses):
    # TODO(michaelcupino): Move csv transforms into a service.
    csvFile = tempfile.TemporaryFile()
    writer = csv.writer(csvFile)
    values = [['Date', 'Time', 'Who in doc', 'Word count', 'Words added',
        'Words deleted', 'Punct. cap', 'Words moved', 'Document ID',
        'Document Name']]
    writer.writerows(values)

    for documentAnalyses in documentsAnalyses:
      for documentAnalysis in documentAnalyses:
        revision = Revision(**documentAnalysis)
        values = [[
          revision.dateTime, # Date
          '', # Time
          revision.author,
          revision.wordCount,
          revision.wordsAdded,
          revision.wordsDeleted,
          '', # Punct. cap
          '', # Words moved
          revision.documentId, # Document ID
          '', # Document Name
        ]]
        writer.writerows(values)

    csvFile.seek(0)
    csvFileBytes = csvFile.read()
    csvFile.close()

    message = mail.EmailMessage()
    message.sender = '*****@*****.**'
    message.to = toEmail
    message.subject = subject
    message.body = str(body)
    message.attachments = [('export.csv', csvFileBytes)]
    message.send()
Example #13
0
 def select_pending_update():
     return Bot.select().where(Bot.approved == True,
                               Bot.revision == Revision.get_instance().next)
Example #14
0
 def select_approved():
     return Bot.select().where(Bot.approved == True,
                               Bot.revision <= Revision.get_instance().nr)
Example #15
0
 def select_new_bots():
     return Bot.select().where(
         (Bot.revision >= Revision.get_instance().nr -
          settings.BOT_CONSIDERED_NEW + 1)
         & (Bot.revision < Revision.get_instance().next)
         & Bot.approved == True)
Example #16
0
 def of_category_without_new(category):
     return Bot.select().where(
         Bot.category == category, Bot.approved == True,
         Bot.revision <= Revision.get_instance().nr).order_by(
             fn.Lower(Bot.username))
Example #17
0
 def explorable_bots():
     results = Bot.select().where(
         ~(Bot.description.is_null()), Bot.approved == True,
         Bot.revision <= Revision.get_instance().nr)
     return list(results)
Example #18
0
def new_bot_submission(bot, update, chat_data, args=None):
    tg_user = update.message.from_user
    user = User.from_telegram_object(tg_user)
    if util.stop_banned(update, user):
        return
    reply_to = util.original_reply_id(update)

    if args:
        text = ' '.join(args)
    else:
        text = update.message.text
        command_no_args = len(
            re.findall(r'^/new\s*$',
                       text)) > 0 or text.lower().strip() == '/new@botlistbot'
        if command_no_args:
            update.message.reply_text(util.action_hint(
                "Please use this command with an argument. For example:\n/new @mybot 🔎"
            ),
                                      reply_to_message_id=reply_to)
            return

    # `#new` is already checked by handler
    try:
        username = re.match(settings.REGEX_BOT_IN_TEXT, text).groups()[0]
        if username.lower() == '@' + settings.SELF_BOT_NAME.lower():
            log.info("Ignoring {}".format(text))
            return
    except AttributeError:
        if args:
            update.message.reply_text(util.failure(
                "Sorry, but you didn't send me a bot `@username`."),
                                      quote=True,
                                      parse_mode=ParseMode.MARKDOWN,
                                      reply_to_message_id=reply_to)
        log.info("Ignoring {}".format(text))
        # no bot username, ignore update
        return

    try:
        new_bot = Bot.by_username(username)
        if new_bot.approved:
            update.message.reply_text(util.action_hint(
                "Sorry fool, but {} is already in the @BotList 😉".format(
                    new_bot.username)),
                                      reply_to_message_id=reply_to)
        else:
            update.message.reply_text(util.action_hint(
                "{} has already been submitted. Please have patience...".
                format(new_bot.username)),
                                      reply_to_message_id=reply_to)
        return
    except Bot.DoesNotExist:
        new_bot = Bot(revision=Revision.get_instance().next,
                      approved=False,
                      username=username,
                      submitted_by=user)

    new_bot.inlinequeries = "🔎" in text
    new_bot.official = "🔹" in text

    # find language
    languages = Country.select().execute()
    for lang in languages:
        if lang.emoji in text:
            new_bot.country = lang

    new_bot.date_added = datetime.date.today()

    description_reg = re.match(settings.REGEX_BOT_IN_TEXT + ' -\s?(.*)', text)
    description_notify = ''
    if description_reg:
        description = description_reg.group(2)
        new_bot.description = description
        description_notify = ' Your description was included.'

    new_bot.save()
    if util.is_private_message(update) and util.uid_from_update(
            update) in settings.MODERATORS:
        from components.explore import send_bot_details
        send_bot_details(bot, update, chat_data, new_bot)
    else:
        msg = update.message.reply_text(util.success(
            "You submitted {} for approval.{}".format(new_bot,
                                                      description_notify)),
                                        parse_mode=ParseMode.MARKDOWN,
                                        reply_to_message_id=reply_to)
    return ConversationHandler.END
Example #19
0
  def testRun(self, mockUrlOpenMethod):
    exportLinks = [
      'docs.google.com/123',
      'docs.google.com/456',
      'docs.google.com/789'
    ]
    mockRevisions = [
      Revision(exportLink=exportLinks[0]).to_dict(),
      Revision(exportLink=exportLinks[1]).to_dict(),
      Revision(exportLink=exportLinks[2]).to_dict()
    ]
    exportedText = {
      exportLinks[0]: StringIO('Hello'),
      exportLinks[1]: StringIO('Hello world.'),
      exportLinks[2]: StringIO('Hello.'),
    }
    mockUrlOpenMethod.side_effect = lambda url: exportedText[url]

    # TODO(michaelcupino): Fix tests
    pipeline = RevisionsAnalysisPipeline(mockRevisions, None)
    pipeline.start_test()
    result = pipeline.outputs.default.value

    revision1 = Revision()
    revision1.wordsAdded = 1
    revision1.wordsDeleted = 0
    revision1.wordCount = 1
    revision1.exportLink = 'docs.google.com/123'
    revision2 = Revision()
    revision2.wordsAdded = 1
    revision2.wordsDeleted = 0
    revision2.wordCount = 2
    revision2.exportLink = 'docs.google.com/456'
    revision3 = Revision()
    revision3.wordsAdded = 0
    revision3.wordsDeleted = 1
    revision3.wordCount = 1
    revision3.exportLink = 'docs.google.com/789'
    self.assertEqual([revision1.to_dict(), revision2.to_dict(),
        revision3.to_dict()], result)
Example #20
0
import os

from decouple import config
from playhouse.migrate import SqliteMigrator, IntegerField, migrate
from playhouse.sqlite_ext import SqliteExtDatabase

from model.revision import Revision

db_path = config('DATABASE_URI',
                 default=os.path.expanduser('~/botlistbot.sqlite3'))
db = SqliteExtDatabase(db_path)

migrator = SqliteMigrator(db)

revision = IntegerField(default=100)

with db.transaction():
    migrate(migrator.add_column('bot', 'revision', revision), )

Revision.create_table(fail_silently=True)
Revision.insert({'nr': 101}).execute()
Example #21
0
    def testRun(self, mockOAuth2CredentialsFromJsonMethod, mockUrlOpenMethod):
        http = HttpMockSequence([
            ({
                'status': '200'
            }, open(datafile('test-drive-revisions-list-0.json'),
                    'rb').read()),
        ])
        mockCredentials = MagicMock(name='mockCredentials')
        mockCredentials.authorize = MagicMock(return_value=http)
        mockOAuth2CredentialsFromJsonMethod.return_value = mockCredentials
        exportLinks = [
            ('https://docs.google.com/feeds/download/documents/export/Export?id=1Duz2'
             'yYSTSgdWQhTgEJ3zPELKTHS3WGhPVLQk1PDJm3Q&revision=697&exportFormat=tx'
             't'),
            ('https://docs.google.com/feeds/download/documents/export/Export?id=1Duz2'
             'yYSTSgdWQhTgEJ3zPELKTHS3WGhPVLQk1PDJm3Q&revision=698&exportFormat=tx'
             't'),
            ('https://docs.google.com/feeds/download/documents/export/Export?id=1Duz2'
             'yYSTSgdWQhTgEJ3zPELKTHS3WGhPVLQk1PDJm3Q&revision=868&exportFormat=tx'
             't'),
            ('https://docs.google.com/feeds/download/documents/export/Export?id=1Duz2'
             'yYSTSgdWQhTgEJ3zPELKTHS3WGhPVLQk1PDJm3Q&revision=869&exportFormat=tx'
             't'),
            ('https://docs.google.com/feeds/download/documents/export/Export?id=1Duz2'
             'yYSTSgdWQhTgEJ3zPELKTHS3WGhPVLQk1PDJm3Q&revision=937&exportFormat=tx'
             't'),
            ('https://docs.google.com/feeds/download/documents/export/Export?id=1Duz2'
             'yYSTSgdWQhTgEJ3zPELKTHS3WGhPVLQk1PDJm3Q&revision=939&exportFormat=tx'
             't'),
            ('https://docs.google.com/feeds/download/documents/export/Export?id=1Duz2'
             'yYSTSgdWQhTgEJ3zPELKTHS3WGhPVLQk1PDJm3Q&revision=1035&exportFormat=t'
             'xt'),
            ('https://docs.google.com/feeds/download/documents/export/Export?id=1Duz2'
             'yYSTSgdWQhTgEJ3zPELKTHS3WGhPVLQk1PDJm3Q&revision=1036&exportFormat=t'
             'xt'),
            ('https://docs.google.com/feeds/download/documents/export/Export?id=1Duz2'
             'yYSTSgdWQhTgEJ3zPELKTHS3WGhPVLQk1PDJm3Q&revision=1048&exportFormat=t'
             'xt'),
            ('https://docs.google.com/feeds/download/documents/export/Export?id=1Duz2'
             'yYSTSgdWQhTgEJ3zPELKTHS3WGhPVLQk1PDJm3Q&revision=1049&exportFormat=t'
             'xt'),
            ('https://docs.google.com/feeds/download/documents/export/Export?id=1Duz2'
             'yYSTSgdWQhTgEJ3zPELKTHS3WGhPVLQk1PDJm3Q&revision=1057&exportFormat=t'
             'xt')
        ]
        exportedText = {
            exportLinks[0]:
            StringIO('Hello'),
            exportLinks[1]:
            StringIO('Hello world.'),
            exportLinks[2]:
            StringIO('Hello'),
            exportLinks[3]:
            StringIO(''),
            exportLinks[4]:
            StringIO('Hello again, this is a longer sentence'),
            exportLinks[5]:
            StringIO(('Hello again, this is a longer sentence with '
                      'another word')),
            exportLinks[6]:
            StringIO(('Hello again, this is a longer sentence with '
                      'another word. Here is another sentence')),
            exportLinks[7]:
            StringIO(
                ('Hello again, this is a longer sentence with '
                 'another word. Here is another sentence with another word')),
            exportLinks[8]:
            StringIO(
                ('Hello again, this is a longer sentence with '
                 'another word. Here is another sentence with another word')),
            exportLinks[9]:
            StringIO(('Hello again, this is a longer sentence with '
                      'another word. Here is another sentence.')),
            exportLinks[10]:
            StringIO(('Hello again, this is a longer sentence with '
                      'another word. Here is another sentence. The end.'))
        }
        mockUrlOpenMethod.side_effect = lambda url: exportedText[url]

        # TODO(michaelcupino): Fix tests
        pipeline = DocumentAnalysisPipeline('*****@*****.**', 'abc123', None)
        pipeline.start_test()
        result = pipeline.outputs.default.value

        # TODO(michaelcupino): Updated expected data to match actual result.
        expectedResult = []
        expectedResult.append(
            Revision(
                wordsAdded=1,
                wordsDeleted=0,
                wordCount=1,
                author='Jonathan H',
                dateTime='2014-03-15T17:49:32.768Z',
                exportLink=
                ('https://docs.google.com/feeds/download/documents/export/Ex'
                 'port?id=1Duz2yYSTSgdWQhTgEJ3zPELKTHS3WGhPVLQk1PDJm3Q&revision=697&'
                 'exportFormat=txt'),
                revisionNumber='697',
                documentId='abc123').to_dict())
        expectedResult.append(Revision(wordsAdded=1, wordsDeleted=0).to_dict())
        expectedResult.append(Revision(wordsAdded=0, wordsDeleted=1).to_dict())
        expectedResult.append(Revision(wordsAdded=0, wordsDeleted=1).to_dict())
        expectedResult.append(Revision(wordsAdded=7, wordsDeleted=0).to_dict())
        expectedResult.append(Revision(wordsAdded=3, wordsDeleted=0).to_dict())
        expectedResult.append(Revision(wordsAdded=5, wordsDeleted=0).to_dict())
        expectedResult.append(Revision(wordsAdded=3, wordsDeleted=0).to_dict())
        expectedResult.append(Revision(wordsAdded=0, wordsDeleted=0).to_dict())
        # TODO(michaelcupino): I would have expected there to be no words added.
        # Figure out why this behavior occurrs.
        expectedResult.append(Revision(wordsAdded=1, wordsDeleted=3).to_dict())
        expectedResult.append(Revision(wordsAdded=2, wordsDeleted=0).to_dict())
        self.assertEqual(expectedResult, result)