<commit_before>import argparse
import logging

import sqlalchemy
from sqlalchemy import Boolean
from sqlalchemy import Column
from sqlalchemy import Enum
from sqlalchemy import ForeignKey
from sqlalchemy import Integer
from sqlalchemy import String
from sqlalchemy.orm import relationship
from unidecode import unidecode

from pajbot.managers.db import Base
from pajbot.managers.db import DBManager
from pajbot.utils import find

log = logging.getLogger('pajbot')


class Banphrase(Base):
    __tablename__ = 'tb_banphrase'

    id = Column(Integer, primary_key=True)
    name = Column(String(256), nullable=False, default='')
    phrase = Column(String(256), nullable=False)
    length = Column(Integer, nullable=False, default=300)
    permanent = Column(Boolean, nullable=False, default=False)
    warning = Column(Boolean, nullable=False, default=True)
    notify = Column(Boolean, nullable=False, default=True)
    case_sensitive = Column(Boolean, nullable=False, default=False)
    remove_accents = Column(Boolean, nullable=False, default=False)
    enabled = Column(Boolean, nullable=False, default=True)
    sub_immunity = Column(Boolean,
            nullable=False,
            default=False,
            server_default=sqlalchemy.sql.expression.false())
    operator = Column(Enum('contains', 'startswith', 'endswith', 'exact'),
            nullable=False,
            default='contains',
            server_default='contains')

    data = relationship('BanphraseData',
            uselist=False,
            cascade='',
            lazy='joined')

    DEFAULT_TIMEOUT_LENGTH = 300
    DEFAULT_NOTIFY = True

    def __init__(self, **options):
        self.id = None
        self.name = 'No name'
        self.length = self.DEFAULT_TIMEOUT_LENGTH
        self.permanent = False
        self.warning = True
        self.notify = self.DEFAULT_NOTIFY
        self.case_sensitive = False
        self.enabled = True
        self.operator = 'contains'
        self.remove_accents = False

        self.set(**options)

    def set(self, **options):
        self.name = options.get('name', self.name)
        self.phrase = options.get('phrase', self.phrase)
        self.length = options.get('length', self.length)
        self.permanent = options.get('permanent', self.permanent)
        self.warning = options.get('warning', self.warning)
        self.notify = options.get('notify', self.notify)
        self.case_sensitive = options.get('case_sensitive', self.case_sensitive)
        self.sub_immunity = options.get('sub_immunity', self.sub_immunity)
        self.enabled = options.get('enabled', self.enabled)
        self.operator = options.get('operator', self.operator)
        self.remove_accents = options.get('remove_accents', self.remove_accents)

        self.refresh_operator()

    def format_message(self, message):
        if self.case_sensitive is False:
            message = message.lower()
        if self.remove_accents:
            message = unidecode(message)

        return message

    def get_phrase(self):
        if self.case_sensitive is False:
            return self.phrase.lower()
        return self.phrase

    def refresh_operator(self):
        self.predicate = getattr(self, 'predicate_{}'.format(self.operator), None)

    def predicate_contains(self, message):
        return self.get_phrase() in self.format_message(message)

    def predicate_startswith(self, message):
        return self.format_message(message).startswith(self.get_phrase())

    def predicate_endswith(self, message):
        return self.format_message(message).endswith(self.get_phrase())

    def predicate_exact(self, message):
        return self.format_message(message) == self.get_phrase()

    def match(self, message, user):
        """
        Returns True if message matches our banphrase.
        Otherwise it returns False
        Respects case-sensitiveness option
        """
        if user and self.sub_immunity is True and user.subscriber is True:
            return False
        return self.predicate(message)

    def exact_match(self, message):
        """
        Returns True if message exactly matches our banphrase.
        Otherwise it returns False
        Respects case-sensitiveness option
        """
        if self.case_sensitive:
            return self.phrase == message
        else:
            return self.phrase.lower() == message.lower()


@sqlalchemy.event.listens_for(Banphrase, 'load')
def on_banphrase_load(target, context):
    target.refresh_operator()


@sqlalchemy.event.listens_for(Banphrase, 'refresh')
def on_banphrase_refresh(target, context, attrs):
    target.refresh_operator()


class BanphraseData(Base):
    __tablename__ = 'tb_banphrase_data'

    banphrase_id = Column(Integer,
            ForeignKey('tb_banphrase.id'),
            primary_key=True,<commit_msg>Add jsonify method to Banphrase<commit_after>import argparse
import logging

import sqlalchemy
from sqlalchemy import Boolean
from sqlalchemy import Column
from sqlalchemy import Enum
from sqlalchemy import ForeignKey
from sqlalchemy import Integer
from sqlalchemy import String
from sqlalchemy.orm import relationship
from unidecode import unidecode

from pajbot.managers.db import Base
from pajbot.managers.db import DBManager
from pajbot.utils import find

log = logging.getLogger('pajbot')


class Banphrase(Base):
    __tablename__ = 'tb_banphrase'

    id = Column(Integer, primary_key=True)
    name = Column(String(256), nullable=False, default='')
    phrase = Column(String(256), nullable=False)
    length = Column(Integer, nullable=False, default=300)
    permanent = Column(Boolean, nullable=False, default=False)
    warning = Column(Boolean, nullable=False, default=True)
    notify = Column(Boolean, nullable=False, default=True)
    case_sensitive = Column(Boolean, nullable=False, default=False)
    remove_accents = Column(Boolean, nullable=False, default=False)
    enabled = Column(Boolean, nullable=False, default=True)
    sub_immunity = Column(Boolean,
            nullable=False,
            default=False,
            server_default=sqlalchemy.sql.expression.false())
    operator = Column(Enum('contains', 'startswith', 'endswith', 'exact'),
            nullable=False,
            default='contains',
            server_default='contains')

    data = relationship('BanphraseData',
            uselist=False,
            cascade='',
            lazy='joined')

    DEFAULT_TIMEOUT_LENGTH = 300
    DEFAULT_NOTIFY = True

    def __init__(self, **options):
        self.id = None
        self.name = 'No name'
        self.length = self.DEFAULT_TIMEOUT_LENGTH
        self.permanent = False
        self.warning = True
        self.notify = self.DEFAULT_NOTIFY
        self.case_sensitive = False
        self.enabled = True
        self.operator = 'contains'
        self.remove_accents = False

        self.set(**options)

    def set(self, **options):
        self.name = options.get('name', self.name)
        self.phrase = options.get('phrase', self.phrase)
        self.length = options.get('length', self.length)
        self.permanent = options.get('permanent', self.permanent)
        self.warning = options.get('warning', self.warning)
        self.notify = options.get('notify', self.notify)
        self.case_sensitive = options.get('case_sensitive', self.case_sensitive)
        self.sub_immunity = options.get('sub_immunity', self.sub_immunity)
        self.enabled = options.get('enabled', self.enabled)
        self.operator = options.get('operator', self.operator)
        self.remove_accents = options.get('remove_accents', self.remove_accents)

        self.refresh_operator()

    def format_message(self, message):
        if self.case_sensitive is False:
            message = message.lower()
        if self.remove_accents:
            message = unidecode(message)

        return message

    def get_phrase(self):
        if self.case_sensitive is False:
            return self.phrase.lower()
        return self.phrase

    def refresh_operator(self):
        self.predicate = getattr(self, 'predicate_{}'.format(self.operator), None)

    def predicate_contains(self, message):
        return self.get_phrase() in self.format_message(message)

    def predicate_startswith(self, message):
        return self.format_message(message).startswith(self.get_phrase())

    def predicate_endswith(self, message):
        return self.format_message(message).endswith(self.get_phrase())

    def predicate_exact(self, message):
        return self.format_message(message) == self.get_phrase()

    def match(self, message, user):
        """
        Returns True if message matches our banphrase.
        Otherwise it returns False
        Respects case-sensitiveness option
        """
        if user and self.sub_immunity is True and user.subscriber is True:
            return False
        return self.predicate(message)

    def exact_match(self, message):
        """
        Returns True if message exactly matches our banphrase.
        Otherwise it returns False
        Respects case-sensitiveness option
        """
        if self.case_sensitive:
            return self.phrase == message
        else:
            return self.phrase.lower() == message.lower()

    def jsonify(self):
        return {
                'name': self.name,
                'phrase': self.phrase,
                'length': self.length,
                'permanent': self.permanent,
                }


@sqlalchemy.event.listens_for(Banphrase, 'load')
def on_banphrase_load(target, context):
    target.refresh_operator()


@sqlalchemy.event.listens_for(Banphrase, 'refresh')
def on_banphrase_refresh(target, context, attrs):
    target.refresh_operator()


class BanphraseData(Base):
    __tablename__ = 'tb_banphrase_data'

    banphrase_id = Column(Integer,
            ForeignKey('tb_banphrase.id'),
            primary_key=True,
{'fraction_non_alphanumeric': 0.09922277177753104, 'fraction_numerical': 0.0024225295245785807, 'mean_word_length': 2.9711422845691384, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5158461', 'n_tokens_mistral': 2876, 'n_tokens_neox': 2743, 'n_words': 638}