<commit_before>__author__ = 'chris'

import os
import sqlite3 as lite
from collections import Counter
from config import DATA_FOLDER
from dht.node import Node
from dht.utils import digest
from protos import objects
from protos.objects import Listings, Followers, Following
from os.path import join


class Database(object):

    __slots__ = ['PATH', 'filemap', 'profile', 'listings', 'keys', 'follow', 'messages',
                 'notifications', 'broadcasts', 'vendors', 'moderators', 'purchases', 'sales',
                 'cases', 'ratings', 'settings']

    def __init__(self, testnet=False, filepath=None):
        object.__setattr__(self, 'PATH', self._database_path(testnet, filepath))
        object.__setattr__(self, 'filemap', HashMap(self.PATH))
        object.__setattr__(self, 'profile', ProfileStore(self.PATH))
        object.__setattr__(self, 'listings', ListingsStore(self.PATH))
        object.__setattr__(self, 'keys', KeyStore(self.PATH))
        object.__setattr__(self, 'follow', FollowData(self.PATH))
        object.__setattr__(self, 'messages', MessageStore(self.PATH))
        object.__setattr__(self, 'notifications', NotificationStore(self.PATH))
        object.__setattr__(self, 'broadcasts', BroadcastStore(self.PATH))
        object.__setattr__(self, 'vendors', VendorStore(self.PATH))
        object.__setattr__(self, 'moderators', ModeratorStore(self.PATH))
        object.__setattr__(self, 'purchases', Purchases(self.PATH))
        object.__setattr__(self, 'sales', Sales(self.PATH))
        object.__setattr__(self, 'cases', Cases(self.PATH))
        object.__setattr__(self, 'ratings', Ratings(self.PATH))
        object.__setattr__(self, 'settings', Settings(self.PATH))

        self._initialize_datafolder_tree()
        self._initialize_database(self.PATH)

    def get_database_path(self):
        return self.PATH

    def _initialize_database(self, database_path):
        """
        Create database, if not present, and clear cache.
        """
        if not database_path:
            raise RuntimeError('attempted to initialize empty path')

        if not os.path.isfile(database_path):
            self._create_database(database_path)
            cache = join(DATA_FOLDER, "cache.pickle")
            if os.path.exists(cache):
                os.remove(cache)

    @staticmethod
    def _database_path(testnet, filepath):
        '''
        Get database pathname.

        Args:
          testnet: Boolean
          filename: If provided, overrides testnet
        '''
        path = ''

        if filepath:
            path = filepath
        elif testnet:
            path = join(DATA_FOLDER, "OB-Testnet.db")
        else:
            path = join(DATA_FOLDER, "OB-Mainnet.db")

        return path

    @staticmethod
    def connect_database(path):
        conn = lite.connect(path)
        conn.text_factory = str
        return conn

    @staticmethod
    def _initialize_datafolder_tree():
        """
        Creates, if not present, directory tree in DATA_FOLDER.
        """
        tree = [
            ['cache'],
            ['store', 'contracts', 'listings'],
            ['store', 'contracts', 'in progress'],
            ['store', 'contracts', 'unfunded'],
            ['store', 'contracts', 'trade receipts'],
            ['store', 'media'],
            ['purchases', 'in progress'],
            ['purchases', 'unfunded'],
            ['purchases', 'trade receipts'],
            ['cases']
        ]

        path = ''
        for sub_tree in tree:
            path = DATA_FOLDER
            for directory in sub_tree:
                path = join(path, directory)
            if not os.path.exists(path):
                os.makedirs(path)

    @staticmethod
    def _create_database(database_path):
        conn = lite.connect(database_path)
        cursor = conn.cursor()

        cursor.execute('''PRAGMA user_version = 0''')
        cursor.execute('''CREATE TABLE hashmap(hash TEXT PRIMARY KEY, filepath TEXT)''')

        cursor.execute('''CREATE TABLE profile(id INTEGER PRIMARY KEY, serializedUserInfo BLOB, tempHandle TEXT)''')

        cursor.execute('''CREATE TABLE listings(id INTEGER PRIMARY KEY, serializedListings BLOB)''')

        cursor.execute('''CREATE TABLE keys(type TEXT PRIMARY KEY, privkey BLOB, pubkey BLOB)''')

        cursor.execute('''CREATE TABLE followers(id INTEGER PRIMARY KEY, serializedFollowers BLOB)''')

        cursor.execute('''CREATE TABLE following(id INTEGER PRIMARY KEY, serializedFollowing BLOB)''')

        cursor.execute('''CREATE TABLE messages(msgID TEXT PRIMARY KEY, guid TEXT, handle TEXT, pubkey BLOB,
    subject TEXT, messageType TEXT, message TEXT, timestamp INTEGER, avatarHash BLOB, signature BLOB,
    outgoing INTEGER, read INTEGER)''')
        cursor.execute('''CREATE INDEX index_guid ON messages(guid);''')
        cursor.execute('''CREATE INDEX index_subject ON messages(subject);''')
        cursor.execute('''CREATE INDEX index_messages_read ON messages(read);''')

        cursor.execute('''CREATE TABLE notifications(id TEXT PRIMARY KEY, guid BLOB, handle TEXT, type TEXT,
    orderId TEXT, title TEXT, timestamp INTEGER, imageHash BLOB, read INTEGER)''')

        cursor.execute('''CREATE TABLE broadcasts(id TEXT PRIMARY KEY, guid BLOB, handle TEXT, message TEXT,
    timestamp INTEGER, avatarHash BLOB)''')

        cursor.execute('''CREATE TABLE vendors(guid TEXT PRIMARY KEY, serializedNode BLOB)''')

        cursor.execute('''CREATE TABLE moderators(guid TEXT PRIMARY KEY, pubkey BLOB, bitcoinKey BLOB,
    bitcoinSignature BLOB, handle TEXT, name TEXT, description TEXT, avatar BLOB, fee FLOAT)''')

        cursor.execute('''CREATE TABLE purchases(id TEXT PRIMARY KEY, title TEXT, description TEXT,
    timestamp INTEGER, btc FLOAT, address TEXT, status INTEGER, outpoint BLOB, thumbnail BLOB, vendor TEXT,
    proofSig BLOB, contractType TEXT)''')

        cursor.execute('''CREATE TABLE sales(id TEXT PRIMARY KEY, title TEXT, description TEXT,
    timestamp INTEGER, btc REAL, address TEXT, status INTEGER, thumbnail BLOB, outpoint BLOB, buyer TEXT,
    paymentTX TEXT, contractType TEXT)''')

        cursor.execute('''CREATE TABLE cases(id TEXT PRIMARY KEY, title TEXT, timestamp INTEGER, orderDate TEXT,
    btc REAL, thumbnail BLOB, buyer TEXT, vendor TEXT, validation TEXT, claim TEXT, status INTEGER)''')

        cursor.execute('''CREATE TABLE ratings(listing TEXT, ratingID TEXT,  rating TEXT)''')
        cursor.execute('''CREATE INDEX index_listing ON ratings(listing);''')
        cursor.execute('''CREATE INDEX index_rating_id ON ratings(ratingID);''')

        cursor.execute('''CREATE TABLE settings(id INTEGER PRIMARY KEY, refundAddress TEXT, currencyCode TEXT,
    country TEXT, language TEXT, timeZone TEXT, notifications INTEGER, shippingAddresses BLOB, blocked BLOB,
    termsConditions TEXT, refundPolicy TEXT, moderatorList BLOB, username TEXT, password TEXT)''')

        conn.commit()
        conn.close()


class HashMap(object):
    """
    Creates a table in the database for mapping file hashes (which are sent<commit_msg>Add table for unconfirmed txs to db<commit_after>__author__ = 'chris'

import os
import sqlite3 as lite
from collections import Counter
from config import DATA_FOLDER
from dht.node import Node
from dht.utils import digest
from protos import objects
from protos.objects import Listings, Followers, Following
from os.path import join


class Database(object):

    __slots__ = ['PATH', 'filemap', 'profile', 'listings', 'keys', 'follow', 'messages',
                 'notifications', 'broadcasts', 'vendors', 'moderators', 'purchases', 'sales',
                 'cases', 'ratings', 'settings']

    def __init__(self, testnet=False, filepath=None):
        object.__setattr__(self, 'PATH', self._database_path(testnet, filepath))
        object.__setattr__(self, 'filemap', HashMap(self.PATH))
        object.__setattr__(self, 'profile', ProfileStore(self.PATH))
        object.__setattr__(self, 'listings', ListingsStore(self.PATH))
        object.__setattr__(self, 'keys', KeyStore(self.PATH))
        object.__setattr__(self, 'follow', FollowData(self.PATH))
        object.__setattr__(self, 'messages', MessageStore(self.PATH))
        object.__setattr__(self, 'notifications', NotificationStore(self.PATH))
        object.__setattr__(self, 'broadcasts', BroadcastStore(self.PATH))
        object.__setattr__(self, 'vendors', VendorStore(self.PATH))
        object.__setattr__(self, 'moderators', ModeratorStore(self.PATH))
        object.__setattr__(self, 'purchases', Purchases(self.PATH))
        object.__setattr__(self, 'sales', Sales(self.PATH))
        object.__setattr__(self, 'cases', Cases(self.PATH))
        object.__setattr__(self, 'ratings', Ratings(self.PATH))
        object.__setattr__(self, 'settings', Settings(self.PATH))

        self._initialize_datafolder_tree()
        self._initialize_database(self.PATH)

    def get_database_path(self):
        return self.PATH

    def _initialize_database(self, database_path):
        """
        Create database, if not present, and clear cache.
        """
        if not database_path:
            raise RuntimeError('attempted to initialize empty path')

        if not os.path.isfile(database_path):
            self._create_database(database_path)
            cache = join(DATA_FOLDER, "cache.pickle")
            if os.path.exists(cache):
                os.remove(cache)

    @staticmethod
    def _database_path(testnet, filepath):
        '''
        Get database pathname.

        Args:
          testnet: Boolean
          filename: If provided, overrides testnet
        '''
        path = ''

        if filepath:
            path = filepath
        elif testnet:
            path = join(DATA_FOLDER, "OB-Testnet.db")
        else:
            path = join(DATA_FOLDER, "OB-Mainnet.db")

        return path

    @staticmethod
    def connect_database(path):
        conn = lite.connect(path)
        conn.text_factory = str
        return conn

    @staticmethod
    def _initialize_datafolder_tree():
        """
        Creates, if not present, directory tree in DATA_FOLDER.
        """
        tree = [
            ['cache'],
            ['store', 'contracts', 'listings'],
            ['store', 'contracts', 'in progress'],
            ['store', 'contracts', 'unfunded'],
            ['store', 'contracts', 'trade receipts'],
            ['store', 'media'],
            ['purchases', 'in progress'],
            ['purchases', 'unfunded'],
            ['purchases', 'trade receipts'],
            ['cases']
        ]

        path = ''
        for sub_tree in tree:
            path = DATA_FOLDER
            for directory in sub_tree:
                path = join(path, directory)
            if not os.path.exists(path):
                os.makedirs(path)

    @staticmethod
    def _create_database(database_path):
        conn = lite.connect(database_path)
        cursor = conn.cursor()

        cursor.execute('''PRAGMA user_version = 0''')
        cursor.execute('''CREATE TABLE hashmap(hash TEXT PRIMARY KEY, filepath TEXT)''')

        cursor.execute('''CREATE TABLE profile(id INTEGER PRIMARY KEY, serializedUserInfo BLOB, tempHandle TEXT)''')

        cursor.execute('''CREATE TABLE listings(id INTEGER PRIMARY KEY, serializedListings BLOB)''')

        cursor.execute('''CREATE TABLE keys(type TEXT PRIMARY KEY, privkey BLOB, pubkey BLOB)''')

        cursor.execute('''CREATE TABLE followers(id INTEGER PRIMARY KEY, serializedFollowers BLOB)''')

        cursor.execute('''CREATE TABLE following(id INTEGER PRIMARY KEY, serializedFollowing BLOB)''')

        cursor.execute('''CREATE TABLE messages(msgID TEXT PRIMARY KEY, guid TEXT, handle TEXT, pubkey BLOB,
    subject TEXT, messageType TEXT, message TEXT, timestamp INTEGER, avatarHash BLOB, signature BLOB,
    outgoing INTEGER, read INTEGER)''')
        cursor.execute('''CREATE INDEX index_guid ON messages(guid);''')
        cursor.execute('''CREATE INDEX index_subject ON messages(subject);''')
        cursor.execute('''CREATE INDEX index_messages_read ON messages(read);''')

        cursor.execute('''CREATE TABLE notifications(id TEXT PRIMARY KEY, guid BLOB, handle TEXT, type TEXT,
    orderId TEXT, title TEXT, timestamp INTEGER, imageHash BLOB, read INTEGER)''')

        cursor.execute('''CREATE TABLE broadcasts(id TEXT PRIMARY KEY, guid BLOB, handle TEXT, message TEXT,
    timestamp INTEGER, avatarHash BLOB)''')

        cursor.execute('''CREATE TABLE vendors(guid TEXT PRIMARY KEY, serializedNode BLOB)''')

        cursor.execute('''CREATE TABLE moderators(guid TEXT PRIMARY KEY, pubkey BLOB, bitcoinKey BLOB,
    bitcoinSignature BLOB, handle TEXT, name TEXT, description TEXT, avatar BLOB, fee FLOAT)''')

        cursor.execute('''CREATE TABLE purchases(id TEXT PRIMARY KEY, title TEXT, description TEXT,
    timestamp INTEGER, btc FLOAT, address TEXT, status INTEGER, outpoint BLOB, thumbnail BLOB, vendor TEXT,
    proofSig BLOB, contractType TEXT)''')

        cursor.execute('''CREATE TABLE sales(id TEXT PRIMARY KEY, title TEXT, description TEXT,
    timestamp INTEGER, btc REAL, address TEXT, status INTEGER, thumbnail BLOB, outpoint BLOB, buyer TEXT,
    paymentTX TEXT, contractType TEXT)''')

        cursor.execute('''CREATE TABLE cases(id TEXT PRIMARY KEY, title TEXT, timestamp INTEGER, orderDate TEXT,
    btc REAL, thumbnail BLOB, buyer TEXT, vendor TEXT, validation TEXT, claim TEXT, status INTEGER)''')

        cursor.execute('''CREATE TABLE ratings(listing TEXT, ratingID TEXT,  rating TEXT)''')
        cursor.execute('''CREATE INDEX index_listing ON ratings(listing);''')
        cursor.execute('''CREATE INDEX index_rating_id ON ratings(ratingID);''')

        cursor.execute('''CREATE TABLE transactions(tx BLOB);''')

        cursor.execute('''CREATE TABLE settings(id INTEGER PRIMARY KEY, refundAddress TEXT, currencyCode TEXT,
    country TEXT, language TEXT, timeZone TEXT, notifications INTEGER, shippingAddresses BLOB, blocked BLOB,
    termsConditions TEXT, refundPolicy TEXT, moderatorList BLOB, username TEXT, password TEXT)''')

        conn.commit()
        conn.close()


class HashMap(object):
    """
    Creates a table in the database for mapping file hashes (which are sent
{'fraction_non_alphanumeric': 0.11455780407534487, 'fraction_numerical': 0.0002800924305020657, 'mean_word_length': 3.150537634408602, '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': '5954917', 'n_tokens_mistral': 4076, 'n_tokens_neox': 3892, 'n_words': 1137}