Skip to content
Snippets Groups Projects
model.py 4.48 KiB
Newer Older
  • Learn to ignore specific revisions
  • # Copyright 2019 PrivateStorage.io, LLC
    #
    # Licensed under the Apache License, Version 2.0 (the "License");
    # you may not use this file except in compliance with the License.
    # You may obtain a copy of the License at
    #
    #     http://www.apache.org/licenses/LICENSE-2.0
    #
    # Unless required by applicable law or agreed to in writing, software
    # distributed under the License is distributed on an "AS IS" BASIS,
    # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    # See the License for the specific language governing permissions and
    # limitations under the License.
    
    """
    This module implements models (in the MVC sense) for the client side of
    the storage plugin.
    """
    
    
    from functools import (
        wraps,
    
    from twisted.python.filepath import (
        FilePath,
    
    class StoreAddError(Exception):
        def __init__(self, reason):
            self.reason = reason
    
    
    class StoreDirectoryError(Exception):
        def __init__(self, reason):
            self.reason = reason
    
    
    
    class SchemaError(TypeError):
        pass
    
    
    CONFIG_DB_NAME = u"privatestorageio-satauthz-v1.sqlite3"
    
    def open_and_initialize(path):
        try:
            path.parent().makedirs(ignoreExistingDirectory=True)
        except OSError as e:
            raise StoreDirectoryError(e)
    
        conn = connect(
            path.asBytesMode().path,
            isolation_level="IMMEDIATE",
        )
        with conn:
            cursor = conn.cursor()
            cursor.execute(
                """
                CREATE TABLE IF NOT EXISTS [version] AS SELECT 1 AS [version]
                """
            )
            cursor.execute(
                """
                SELECT [version] FROM [version]
                """
            )
            expected = [(1,)]
            version = cursor.fetchall()
            if version != expected:
                raise SchemaError(
                    "Unexpected database schema version.  Expected {}.  Got {}.".format(
                        expected,
                        version,
                    ),
                )
    
            cursor.execute(
                """
                CREATE TABLE IF NOT EXISTS [payment-references] (
                    number text,
    
                    PRIMARY KEY(number)
                )
                """,
            )
        return conn
    
    
    def with_cursor(f):
        @wraps(f)
        def with_cursor(self, *a, **kw):
            with self._connection:
                return f(self, self._connection.cursor(), *a, **kw)
        return with_cursor
    
    
    
    @attr.s(frozen=True)
    class PaymentReferenceStore(object):
        """
        This class implements persistence for payment references.
    
    
        :ivar allmydata.node._Config node_config: The Tahoe-LAFS node configuration object for
    
            the node that owns the persisted payment preferences.
        """
    
        database_path = attr.ib(type=FilePath)
        _connection = attr.ib()
    
        @classmethod
        def from_node_config(cls, node_config):
            db_path = FilePath(node_config.get_private_path(CONFIG_DB_NAME))
            conn = open_and_initialize(
                db_path,
            )
            return cls(
                db_path,
                conn,
            )
    
        @with_cursor
        def get(self, cursor, prn):
            cursor.execute(
                """
                SELECT
                    ([number])
                FROM
                    [payment-references]
                WHERE
                    [number] = ?
                """,
                (prn,),
            )
            refs = cursor.fetchall()
            if len(refs) == 0:
    
            return PaymentReference(refs[0][0])
    
        @with_cursor
        def add(self, cursor, prn):
            cursor.execute(
                """
                INSERT OR IGNORE INTO [payment-references] VALUES (?)
                """,
                (prn,)
            )
    
        @with_cursor
        def list(self, cursor):
            cursor.execute(
                """
                SELECT ([number]) FROM [payment-references]
                """,
            )
            refs = cursor.fetchall()
    
                PaymentReference(number)
                for (number,)
                in refs
    
    
    @attr.s
    class PaymentReference(object):
        number = attr.ib()
    
        @classmethod
        def from_json(cls, json):
            values = loads(json)
            version = values.pop(u"version")
            return getattr(cls, "from_json_v{}".format(version))(values)
    
    
        @classmethod
        def from_json_v1(cls, values):
            return cls(**values)
    
    
        def to_json(self):
    
            return dumps(self.marshal())
    
    
        def marshal(self):
            return self.to_json_v1()
    
    
    
        def to_json_v1(self):
            result = attr.asdict(self)
            result[u"version"] = 1
            return result