<commit_before>import errno
import inspect
import os
import sqlite3
import yaml
import json

from bottle import PluginError

from mapproxy_webconf import utils, defaults

class YAMLStorePlugin(object):
    name = 'yamlstore'

    def __init__(self, storage_dir, keyword='storage'):
        self.storage = YAMLStore(storage_dir)
        self.keyword = keyword

    def setup(self, app):
        '''
        Make sure that other installed plugins don't affect the same keyword argument.
        '''
        for other in app.plugins:
            if not isinstance(other, YAMLStorePlugin):
                continue
            if other.keyword == self.keyword:
                raise PluginError(_("Found another YAMLStore plugin with conflicting settings (non-unique keyword)."))

    def apply(self, callback, context):
        conf = context['config'].get('yamlstorage') or {}
        keyword = conf.get('keyword', self.keyword)

        # Test if the original callback accepts a 'db' keyword.
        # Ignore it if it does not need a database handle.
        args = inspect.getargspec(context['callback'])[0]
        if keyword not in args:
            return callback

        def wrapper(*args, **kwargs):
            # Add the storage as a keyword argument.
            kwargs[keyword] = self.storage

            return callback(*args, **kwargs)

        # Replace the route callback with the wrapped one.
        return wrapper

DEFAULT_VALUE = object()
class YAMLStore(object):
    def __init__(self, storage_dir):
        self.storage_dir = storage_dir

    def _filename(self, name):
        return os.path.join(self.storage_dir, name + '.yaml')

    def get(self, name, project, default=DEFAULT_VALUE):
        try:
            with open(self._filename(name), 'rb') as f:
                data = yaml.load(f)
                project_data = data.get(project, default)
                if project_data is DEFAULT_VALUE:
                    return {}
                else:
                    return project_data
        except IOError, ex:
            if ex.errno == errno.ENOENT:
                if default is DEFAULT_VALUE:
                    return {}
                return default

    def put(self, name, project, data):
        content = yaml.dump({project: data})
        utils.save_atomic(self._filename(name), content)

class SQLiteStorePlugin(object):
    name = 'sqlitestore'

    def __init__(self, dbfile, keyword='storage'):
        self.storage = SQLiteStore(dbfile)
        self.keyword = keyword

    def setup(self, app):
        '''
        Make sure that other installed plugins don't affect the same keyword argument.
        '''
        for other in app.plugins:
            if not isinstance(other, SQLiteStorePlugin):
                continue
            if other.keyword == self.keyword:
                raise PluginError(_("Found another SQLiteStore plugin with conflicting settings (non-unique keyword)."))

    def apply(self, callback, context):
        conf = context['config'].get('sqlitestore') or {}
        keyword = conf.get('keyword', self.keyword)

        # Test if the original callback accepts a 'storage' keyword.
        # Ignore it if it does not need a database handle.
        args = inspect.getargspec(context['callback'])[0]
        if keyword not in args:
            return callback

        def wrapper(*args, **kwargs):
            # Add the storage as a keyword argument.
            kwargs[keyword] = self.storage

            return callback(*args, **kwargs)

        # Replace the route callback with the wrapped one.
        return wrapper

class SQLiteStore(object):
    def __init__(self, filename):
        self.filename = filename
        self.db = sqlite3.connect(filename)
        self.db.row_factory = sqlite3.Row
        self._init_db()
        self._init_project('base')

    def _init_db(self):
        self.db.execute("""
            PRAGMA foreign_keys = ON;
        """)
        self.db.execute("""
            CREATE TABLE IF NOT EXISTS store (
                id INTEGER PRIMARY KEY,
                section TEXT NOT NULL,
                project TEXT,
                data TEXT NOT NULL,
                rank INTEGER,
                parent INTEGER,
                manual BOOLEAN,
                locked BOOLEAN,
                FOREIGN KEY(parent) REFERENCES store(id) ON DELETE CASCADE
            )
        """)

    def _init_project(self, project):
        defaults_data = json.dumps(defaults.PROJECT_DEFAULTS)
        services_data = json.dumps(defaults.PROJECT_SERVICES)

        cur = self.db.cursor()

        inserts = []

        cur.execute("SELECT * FROM store WHERE section ='defaults' AND project=?", (project,))
        if not len(cur.fetchall()):
            inserts.append({'section': 'defaults', 'project': project, 'data': defaults_data})

        cur.execute("SELECT * FROM store WHERE section ='services' AND project=?", (project,))
        if not len(cur.fetchall()):
            inserts.append({'section': 'services', 'project': project, 'data': services_data})

        cur.executemany("INSERT INTO store (section, project, data) VALUES (:section, :project, :data)", inserts)
        self.db.commit()

    def delete_project(self, project):
        cur = self.db.cursor()
        cur.execute("DELETE FROM store WHERE project=?", (project, ))
        self.db.commit()
        return cur.rowcount >= 1

    def get_projects(self):
        cur = self.db.cursor()
        cur.execute("SELECT DISTINCT project FROM store")
        for row in cur.fetchall():
            yield row['project']

    def get_all(self, section, project, default=DEFAULT_VALUE, with_rank=False, with_id=False, with_manual=False, with_locked=False, with_section=False):
        if default is DEFAULT_VALUE:
            default = {}

        result = default
        if hasattr(result, "append"):
            append_data = True
        else:
            append_data = False

        cur = self.db.cursor()
        cur.execute("SELECT id, data, parent, rank, manual, locked FROM store WHERE section = ? AND project = ?",
            (section, project))
        for row in cur.fetchall():
            data = {}
            data['data'] = json.loads(row['data'])
            if with_manual:
                data['_manual'] = row['manual']
            if with_id:
                data['_id'] = row['id']
            if with_rank:
                data['_parent'] = row['parent']
                data['_rank'] = row['rank']
            if with_locked:
                data['_locked'] = row['locked']
            if with_section:
                data['_section'] = section
            if append_data:
                result.append(data)
            else:
                result[row['id']] = data
        return result

    def get_all_data(self, section, project, default=DEFAULT_VALUE):
        data = self.get_all(section, project, default)
        for i, _data in data.items():
            data[i] = _data['data']
        return data

    def get(self, id, section, project, with_rank=False, with_manual=False, with_locked=False):
        cur = self.db.cursor()
        cur.execute("SELECT data, parent, rank, manual, locked FROM store WHERE id = ? AND section = ? AND project = ?",
            (id, section, project))
        row = cur.fetchone()
        if row:
            data = {}
            data['data'] = json.loads(row[0])
            if row[1] is not None:
                data['_parent'] = row[1]
            if with_rank and row[2] is not None:
                data['_rank'] = row[2]
            if with_manual and row[3] is not None:
                data['_manual'] = row[3]
            if with_locked and row[4] is not None:
                data['_locked'] = row[4]
            return data

    def add(self, section, project, data):
        rank = data.pop('_rank', None)
        parent = data.pop('_parent', None)
        manual = data.pop('_manual', False)
        locked = data.pop('_locked', False)
        data.pop('_id', None)

        data = json.dumps(data['data'])

        cur = self.db.cursor()
        cur.execute("INSERT INTO store (section, project, data, parent, rank, manual, locked) VALUES (?, ?, ?, ?, ?, ?, ?)",
            (section, project, data, parent, rank, manual, locked))
        self.db.commit()
        return cur.lastrowid

    def update(self, id, section, project, data):
        rank = data.pop('_rank', None)
        parent = data.pop('_parent', None)
        manual = data.pop('_manual', False)
        locked = data.pop('_locked', False)
        data.pop('_id', None)
        data.pop('_layers', None)

        data = json.dumps(data['data'])

        cur = self.db.cursor()
        cur.execute("UPDATE store SET data = ?, parent = ?, rank = ?, manual = ?, locked = ? WHERE id = ? AND SECTION = ? AND project = ?",
            (data, parent, rank, manual, locked, id, section, project))
        self.db.commit()

    def updates(self, section, project, data):
        #ensure all needed values are present or None
        data = [{'id': d['_id'], 'rank': d['_rank'] if '_rank' in d else None, 'parent': d['_parent'] if '_parent' in d else None, 'manual': d['_manual'] if '_manual' in d else False, 'locked': d['_locked'] if '_locked' in d else False} for d in data if '_id' in d]
        cur = self.db.cursor()
        cur.executemany("UPDATE store SET parent = :parent, rank = :rank, manual = :manual, locked = :locked WHERE id = :id", data)
        self.db.commit()

    def delete(self, id, section, project):
        cur = self.db.cursor()
        cur.execute("DELETE FROM store WHERE id = ? AND SECTION = ? AND project = ?",
            (id, section, project))
        self.db.commit()
        return cur.rowcount == 1

    def exists_in_data(self, section, project, search):
        cur = self.db.cursor()
        cur.execute("SELECT id FROM store WHERE section = ? AND project = ? AND data LIKE ?", (section, project, search))
        row = cur.fetchone()
        return row[0] if row else False

    def exist_project(self, project):
        cur = self.db.cursor()
        cur.execute("SELECT id FROM store WHERE section = 'defaults' AND project = ?", (project,))
        result = cur.fetchall()
        return len(result) > 0

    def check_dependencies(self, id, project, look_for):
        cur = self.db.cursor()
        cur.execute("SELECT section, data FROM store WHERE project = ? AND section in (%s)" % (', '.join(["'%s'" % section for section in look_for.keys()]), ), (project,))
        result = cur.fetchall()

        response = {}

        for row in result:
            section =  row[0]
            data = json.loads(row[1])
            if look_for[section] in data and id in data[look_for[section]]:
                dependency = {'name': data['name']}
                if data.has_key('title'):
                    dependency['title'] = data['title']
                if response.has_key(section):
                    response[section].append(dependency)
                else:
                    response[section] = [dependency]

        return response
<commit_msg>Data might be empty<commit_after>import errno
import inspect
import os
import sqlite3
import yaml
import json

from bottle import PluginError

from mapproxy_webconf import utils, defaults

class YAMLStorePlugin(object):
    name = 'yamlstore'

    def __init__(self, storage_dir, keyword='storage'):
        self.storage = YAMLStore(storage_dir)
        self.keyword = keyword

    def setup(self, app):
        '''
        Make sure that other installed plugins don't affect the same keyword argument.
        '''
        for other in app.plugins:
            if not isinstance(other, YAMLStorePlugin):
                continue
            if other.keyword == self.keyword:
                raise PluginError(_("Found another YAMLStore plugin with conflicting settings (non-unique keyword)."))

    def apply(self, callback, context):
        conf = context['config'].get('yamlstorage') or {}
        keyword = conf.get('keyword', self.keyword)

        # Test if the original callback accepts a 'db' keyword.
        # Ignore it if it does not need a database handle.
        args = inspect.getargspec(context['callback'])[0]
        if keyword not in args:
            return callback

        def wrapper(*args, **kwargs):
            # Add the storage as a keyword argument.
            kwargs[keyword] = self.storage

            return callback(*args, **kwargs)

        # Replace the route callback with the wrapped one.
        return wrapper

DEFAULT_VALUE = object()
class YAMLStore(object):
    def __init__(self, storage_dir):
        self.storage_dir = storage_dir

    def _filename(self, name):
        return os.path.join(self.storage_dir, name + '.yaml')

    def get(self, name, project, default=DEFAULT_VALUE):
        try:
            with open(self._filename(name), 'rb') as f:
                data = yaml.load(f)
                project_data = data.get(project, default)
                if project_data is DEFAULT_VALUE:
                    return {}
                else:
                    return project_data
        except IOError, ex:
            if ex.errno == errno.ENOENT:
                if default is DEFAULT_VALUE:
                    return {}
                return default

    def put(self, name, project, data):
        content = yaml.dump({project: data})
        utils.save_atomic(self._filename(name), content)

class SQLiteStorePlugin(object):
    name = 'sqlitestore'

    def __init__(self, dbfile, keyword='storage'):
        self.storage = SQLiteStore(dbfile)
        self.keyword = keyword

    def setup(self, app):
        '''
        Make sure that other installed plugins don't affect the same keyword argument.
        '''
        for other in app.plugins:
            if not isinstance(other, SQLiteStorePlugin):
                continue
            if other.keyword == self.keyword:
                raise PluginError(_("Found another SQLiteStore plugin with conflicting settings (non-unique keyword)."))

    def apply(self, callback, context):
        conf = context['config'].get('sqlitestore') or {}
        keyword = conf.get('keyword', self.keyword)

        # Test if the original callback accepts a 'storage' keyword.
        # Ignore it if it does not need a database handle.
        args = inspect.getargspec(context['callback'])[0]
        if keyword not in args:
            return callback

        def wrapper(*args, **kwargs):
            # Add the storage as a keyword argument.
            kwargs[keyword] = self.storage

            return callback(*args, **kwargs)

        # Replace the route callback with the wrapped one.
        return wrapper

class SQLiteStore(object):
    def __init__(self, filename):
        self.filename = filename
        self.db = sqlite3.connect(filename)
        self.db.row_factory = sqlite3.Row
        self._init_db()
        self._init_project('base')

    def _init_db(self):
        self.db.execute("""
            PRAGMA foreign_keys = ON;
        """)
        self.db.execute("""
            CREATE TABLE IF NOT EXISTS store (
                id INTEGER PRIMARY KEY,
                section TEXT NOT NULL,
                project TEXT,
                data TEXT NOT NULL,
                rank INTEGER,
                parent INTEGER,
                manual BOOLEAN,
                locked BOOLEAN,
                FOREIGN KEY(parent) REFERENCES store(id) ON DELETE CASCADE
            )
        """)

    def _init_project(self, project):
        defaults_data = json.dumps(defaults.PROJECT_DEFAULTS)
        services_data = json.dumps(defaults.PROJECT_SERVICES)

        cur = self.db.cursor()

        inserts = []

        cur.execute("SELECT * FROM store WHERE section ='defaults' AND project=?", (project,))
        if not len(cur.fetchall()):
            inserts.append({'section': 'defaults', 'project': project, 'data': defaults_data})

        cur.execute("SELECT * FROM store WHERE section ='services' AND project=?", (project,))
        if not len(cur.fetchall()):
            inserts.append({'section': 'services', 'project': project, 'data': services_data})

        cur.executemany("INSERT INTO store (section, project, data) VALUES (:section, :project, :data)", inserts)
        self.db.commit()

    def delete_project(self, project):
        cur = self.db.cursor()
        cur.execute("DELETE FROM store WHERE project=?", (project, ))
        self.db.commit()
        return cur.rowcount >= 1

    def get_projects(self):
        cur = self.db.cursor()
        cur.execute("SELECT DISTINCT project FROM store")
        for row in cur.fetchall():
            yield row['project']

    def get_all(self, section, project, default=DEFAULT_VALUE, with_rank=False, with_id=False, with_manual=False, with_locked=False, with_section=False):
        if default is DEFAULT_VALUE:
            default = {}

        result = default
        if hasattr(result, "append"):
            append_data = True
        else:
            append_data = False

        cur = self.db.cursor()
        cur.execute("SELECT id, data, parent, rank, manual, locked FROM store WHERE section = ? AND project = ?",
            (section, project))
        for row in cur.fetchall():
            data = {}
            data['data'] = json.loads(row['data'])
            if with_manual:
                data['_manual'] = row['manual']
            if with_id:
                data['_id'] = row['id']
            if with_rank:
                data['_parent'] = row['parent']
                data['_rank'] = row['rank']
            if with_locked:
                data['_locked'] = row['locked']
            if with_section:
                data['_section'] = section
            if append_data:
                result.append(data)
            else:
                result[row['id']] = data
        return result

    def get_all_data(self, section, project, default=DEFAULT_VALUE):
        data = self.get_all(section, project, default)
        for i, _data in data.items():
            data[i] = _data['data']
        return data

    def get(self, id, section, project, with_rank=False, with_manual=False, with_locked=False):
        cur = self.db.cursor()
        cur.execute("SELECT data, parent, rank, manual, locked FROM store WHERE id = ? AND section = ? AND project = ?",
            (id, section, project))
        row = cur.fetchone()
        if row:
            data = {}
            data['data'] = json.loads(row[0])
            if row[1] is not None:
                data['_parent'] = row[1]
            if with_rank and row[2] is not None:
                data['_rank'] = row[2]
            if with_manual and row[3] is not None:
                data['_manual'] = row[3]
            if with_locked and row[4] is not None:
                data['_locked'] = row[4]
            return data

    def add(self, section, project, data):
        rank = data.pop('_rank', None)
        parent = data.pop('_parent', None)
        manual = data.pop('_manual', False)
        locked = data.pop('_locked', False)
        data.pop('_id', None)

        data = json.dumps(data['data'])

        cur = self.db.cursor()
        cur.execute("INSERT INTO store (section, project, data, parent, rank, manual, locked) VALUES (?, ?, ?, ?, ?, ?, ?)",
            (section, project, data, parent, rank, manual, locked))
        self.db.commit()
        return cur.lastrowid

    def update(self, id, section, project, data):
        rank = data.pop('_rank', None)
        parent = data.pop('_parent', None)
        manual = data.pop('_manual', False)
        locked = data.pop('_locked', False)
        data.pop('_id', None)
        data.pop('_layers', None)
        data = json.dumps(data.get('data', {}))

        cur = self.db.cursor()
        cur.execute("UPDATE store SET data = ?, parent = ?, rank = ?, manual = ?, locked = ? WHERE id = ? AND SECTION = ? AND project = ?",
            (data, parent, rank, manual, locked, id, section, project))
        self.db.commit()

    def updates(self, section, project, data):
        #ensure all needed values are present or None
        data = [{'id': d['_id'], 'rank': d['_rank'] if '_rank' in d else None, 'parent': d['_parent'] if '_parent' in d else None, 'manual': d['_manual'] if '_manual' in d else False, 'locked': d['_locked'] if '_locked' in d else False} for d in data if '_id' in d]
        cur = self.db.cursor()
        cur.executemany("UPDATE store SET parent = :parent, rank = :rank, manual = :manual, locked = :locked WHERE id = :id", data)
        self.db.commit()

    def delete(self, id, section, project):
        cur = self.db.cursor()
        cur.execute("DELETE FROM store WHERE id = ? AND SECTION = ? AND project = ?",
            (id, section, project))
        self.db.commit()
        return cur.rowcount == 1

    def exists_in_data(self, section, project, search):
        cur = self.db.cursor()
        cur.execute("SELECT id FROM store WHERE section = ? AND project = ? AND data LIKE ?", (section, project, search))
        row = cur.fetchone()
        return row[0] if row else False

    def exist_project(self, project):
        cur = self.db.cursor()
        cur.execute("SELECT id FROM store WHERE section = 'defaults' AND project = ?", (project,))
        result = cur.fetchall()
        return len(result) > 0

    def check_dependencies(self, id, project, look_for):
        cur = self.db.cursor()
        cur.execute("SELECT section, data FROM store WHERE project = ? AND section in (%s)" % (', '.join(["'%s'" % section for section in look_for.keys()]), ), (project,))
        result = cur.fetchall()

        response = {}

        for row in result:
            section =  row[0]
            data = json.loads(row[1])
            if look_for[section] in data and id in data[look_for[section]]:
                dependency = {'name': data['name']}
                if data.has_key('title'):
                    dependency['title'] = data['title']
                if response.has_key(section):
                    response[section].append(dependency)
                else:
                    response[section] = [dependency]

        return response
<|endoftext|>


<commit_before>import errno
import inspect
import os
import sqlite3
import yaml
import json

from bottle import PluginError

from mapproxy_webconf import utils, defaults

class YAMLStorePlugin(object):
    name = 'yamlstore'

    def __init__(self, storage_dir, keyword='storage'):
        self.storage = YAMLStore(storage_dir)
        self.keyword = keyword

    def setup(self, app):
        '''
        Make sure that other installed plugins don't affect the same keyword argument.
        '''
        for other in app.plugins:
            if not isinstance(other, YAMLStorePlugin):
                continue
            if other.keyword == self.keyword:
                raise PluginError(_("Found another YAMLStore plugin with conflicting settings (non-unique keyword)."))

    def apply(self, callback, context):
        conf = context['config'].get('yamlstorage') or {}
        keyword = conf.get('keyword', self.keyword)

        # Test if the original callback accepts a 'db' keyword.
        # Ignore it if it does not need a database handle.
        args = inspect.getargspec(context['callback'])[0]
        if keyword not in args:
            return callback

        def wrapper(*args, **kwargs):
            # Add the storage as a keyword argument.
            kwargs[keyword] = self.storage

            return callback(*args, **kwargs)

        # Replace the route callback with the wrapped one.
        return wrapper

DEFAULT_VALUE = object()
class YAMLStore(object):
    def __init__(self, storage_dir):
        self.storage_dir = storage_dir

    def _filename(self, name):
        return os.path.join(self.storage_dir, name + '.yaml')

    def get(self, name, project, default=DEFAULT_VALUE):
        try:
            with open(self._filename(name), 'rb') as f:
                data = yaml.load(f)
                project_data = data.get(project, default)
                if project_data is DEFAULT_VALUE:
                    return {}
                else:
                    return project_data
        except IOError, ex:
            if ex.errno == errno.ENOENT:
                if default is DEFAULT_VALUE:
                    return {}
                return default

    def put(self, name, project, data):
        content = yaml.dump({project: data})
        utils.save_atomic(self._filename(name), content)

class SQLiteStorePlugin(object):
    name = 'sqlitestore'

    def __init__(self, dbfile, keyword='storage'):
        self.storage = SQLiteStore(dbfile)
        self.keyword = keyword

    def setup(self, app):
        '''
        Make sure that other installed plugins don't affect the same keyword argument.
        '''
        for other in app.plugins:
            if not isinstance(other, SQLiteStorePlugin):
                continue
            if other.keyword == self.keyword:
                raise PluginError(_("Found another SQLiteStore plugin with conflicting settings (non-unique keyword)."))

    def apply(self, callback, context):
        conf = context['config'].get('sqlitestore') or {}
        keyword = conf.get('keyword', self.keyword)

        # Test if the original callback accepts a 'storage' keyword.
        # Ignore it if it does not need a database handle.
        args = inspect.getargspec(context['callback'])[0]
        if keyword not in args:
            return callback

        def wrapper(*args, **kwargs):
            # Add the storage as a keyword argument.
            kwargs[keyword] = self.storage

            return callback(*args, **kwargs)

        # Replace the route callback with the wrapped one.
        return wrapper

class SQLiteStore(object):
    def __init__(self, filename):
        self.filename = filename
        self.db = sqlite3.connect(filename)
        self.db.row_factory = sqlite3.Row
        self._init_db()
        self._init_project('base')

    def _init_db(self):
        self.db.execute("""
            PRAGMA foreign_keys = ON;
        """)
        self.db.execute("""
            CREATE TABLE IF NOT EXISTS store (
                id INTEGER PRIMARY KEY,
                section TEXT NOT NULL,
                project TEXT,
                data TEXT NOT NULL,
                rank INTEGER,
                parent INTEGER,
                manual BOOLEAN,
                locked BOOLEAN,
                FOREIGN KEY(parent) REFERENCES store(id) ON DELETE CASCADE
            )
        """)

    def _init_project(self, project):
        defaults_data = json.dumps(defaults.PROJECT_DEFAULTS)
        services_data = json.dumps(defaults.PROJECT_SERVICES)

        cur = self.db.cursor()

        inserts = []

        cur.execute("SELECT * FROM store WHERE section ='defaults' AND project=?", (project,))
        if not len(cur.fetchall()):
            inserts.append({'section': 'defaults', 'project': project, 'data': defaults_data})

        cur.execute("SELECT * FROM store WHERE section ='services' AND project=?", (project,))
        if not len(cur.fetchall()):
            inserts.append({'section': 'services', 'project': project, 'data': services_data})

        cur.executemany("INSERT INTO store (section, project, data) VALUES (:section, :project, :data)", inserts)
        self.db.commit()

    def delete_project(self, project):
        cur = self.db.cursor()
        cur.execute("DELETE FROM store WHERE project=?", (project, ))
        self.db.commit()
        return cur.rowcount >= 1

    def get_projects(self):
        cur = self.db.cursor()
        cur.execute("SELECT DISTINCT project FROM store")
        for row in cur.fetchall():
            yield row['project']

    def get_all(self, section, project, default=DEFAULT_VALUE, with_rank=False, with_id=False, with_manual=False, with_locked=False, with_section=False):
        if default is DEFAULT_VALUE:
            default = {}

        result = default
        if hasattr(result, "append"):
            append_data = True
        else:
            append_data = False

        cur = self.db.cursor()
        cur.execute("SELECT id, data, parent, rank, manual, locked FROM store WHERE section = ? AND project = ?",
            (section, project))
        for row in cur.fetchall():
            data = {}
            data['data'] = json.loads(row['data'])
            if with_manual:
                data['_manual'] = row['manual']
            if with_id:
                data['_id'] = row['id']
            if with_rank:
                data['_parent'] = row['parent']
                data['_rank'] = row['rank']
            if with_locked:
                data['_locked'] = row['locked']
            if with_section:
                data['_section'] = section
            if append_data:
                result.append(data)
            else:
                result[row['id']] = data
        return result

    def get_all_data(self, section, project, default=DEFAULT_VALUE):
        data = self.get_all(section, project, default)
        for i, _data in data.items():
            data[i] = _data['data']
        return data

    def get(self, id, section, project, with_rank=False, with_manual=False, with_locked=False):
        cur = self.db.cursor()
        cur.execute("SELECT data, parent, rank, manual, locked FROM store WHERE id = ? AND section = ? AND project = ?",
            (id, section, project))
        row = cur.fetchone()
        if row:
            data = {}
            data['data'] = json.loads(row[0])
            if row[1] is not None:
                data['_parent'] = row[1]
            if with_rank and row[2] is not None:
                data['_rank'] = row[2]
            if with_manual and row[3] is not None:
                data['_manual'] = row[3]
            if with_locked and row[4] is not None:
                data['_locked'] = row[4]
            return data

    def add(self, section, project, data):
        rank = data.pop('_rank', None)
        parent = data.pop('_parent', None)
        manual = data.pop('_manual', False)
        locked = data.pop('_locked', False)
        data.pop('_id', None)

        data = json.dumps(data['data'])

        cur = self.db.cursor()
        cur.execute("INSERT INTO store (section, project, data, parent, rank, manual, locked) VALUES (?, ?, ?, ?, ?, ?, ?)",
            (section, project, data, parent, rank, manual, locked))
        self.db.commit()
        return cur.lastrowid

    def update(self, id, section, project, data):
        rank = data.pop('_rank', None)
        parent = data.pop('_parent', None)
        manual = data.pop('_manual', False)
        locked = data.pop('_locked', False)
        data.pop('_id', None)
        data.pop('_layers', None)
        data = json.dumps(data.get('data', {}))

        cur = self.db.cursor()
        cur.execute("UPDATE store SET data = ?, parent = ?, rank = ?, manual = ?, locked = ? WHERE id = ? AND SECTION = ? AND project = ?",
            (data, parent, rank, manual, locked, id, section, project))
        self.db.commit()

    def updates(self, section, project, data):
        #ensure all needed values are present or None
        data = [{'id': d['_id'], 'rank': d['_rank'] if '_rank' in d else None, 'parent': d['_parent'] if '_parent' in d else None, 'manual': d['_manual'] if '_manual' in d else False, 'locked': d['_locked'] if '_locked' in d else False} for d in data if '_id' in d]
        cur = self.db.cursor()
        cur.executemany("UPDATE store SET parent = :parent, rank = :rank, manual = :manual, locked = :locked WHERE id = :id", data)
        self.db.commit()

    def delete(self, id, section, project):
        cur = self.db.cursor()
        cur.execute("DELETE FROM store WHERE id = ? AND SECTION = ? AND project = ?",
            (id, section, project))
        self.db.commit()
        return cur.rowcount == 1

    def exists_in_data(self, section, project, search):
        cur = self.db.cursor()
        cur.execute("SELECT id FROM store WHERE section = ? AND project = ? AND data LIKE ?", (section, project, search))
        row = cur.fetchone()
        return row[0] if row else False

    def exist_project(self, project):
        cur = self.db.cursor()
        cur.execute("SELECT id FROM store WHERE section = 'defaults' AND project = ?", (project,))
        result = cur.fetchall()
        return len(result) > 0

    def check_dependencies(self, id, project, look_for):
        cur = self.db.cursor()
        cur.execute("SELECT section, data FROM store WHERE project = ? AND section in (%s)" % (', '.join(["'%s'" % section for section in look_for.keys()]), ), (project,))
        result = cur.fetchall()

        response = {}

        for row in result:
            section =  row[0]
            data = json.loads(row[1])
            if look_for[section] in data and id in data[look_for[section]]:
                dependency = {'name': data['name']}
                if data.has_key('title'):
                    dependency['title'] = data['title']
                if response.has_key(section):
                    response[section].append(dependency)
                else:
                    response[section] = [dependency]

        return response
<commit_msg>add section ids for each project<commit_after>import errno
import inspect
import os
import sqlite3
import yaml
import json

from bottle import PluginError

from mapproxy_webconf import utils, defaults

class YAMLStorePlugin(object):
    name = 'yamlstore'

    def __init__(self, storage_dir, keyword='storage'):
        self.storage = YAMLStore(storage_dir)
        self.keyword = keyword

    def setup(self, app):
        '''
        Make sure that other installed plugins don't affect the same keyword argument.
        '''
        for other in app.plugins:
            if not isinstance(other, YAMLStorePlugin):
                continue
            if other.keyword == self.keyword:
                raise PluginError(_("Found another YAMLStore plugin with conflicting settings (non-unique keyword)."))

    def apply(self, callback, context):
        conf = context['config'].get('yamlstorage') or {}
        keyword = conf.get('keyword', self.keyword)

        # Test if the original callback accepts a 'db' keyword.
        # Ignore it if it does not need a database handle.
        args = inspect.getargspec(context['callback'])[0]
        if keyword not in args:
            return callback

        def wrapper(*args, **kwargs):
            # Add the storage as a keyword argument.
            kwargs[keyword] = self.storage

            return callback(*args, **kwargs)

        # Replace the route callback with the wrapped one.
        return wrapper

DEFAULT_VALUE = object()
class YAMLStore(object):
    def __init__(self, storage_dir):
        self.storage_dir = storage_dir

    def _filename(self, name):
        return os.path.join(self.storage_dir, name + '.yaml')

    def get(self, name, project, default=DEFAULT_VALUE):
        try:
            with open(self._filename(name), 'rb') as f:
                data = yaml.load(f)
                project_data = data.get(project, default)
                if project_data is DEFAULT_VALUE:
                    return {}
                else:
                    return project_data
        except IOError, ex:
            if ex.errno == errno.ENOENT:
                if default is DEFAULT_VALUE:
                    return {}
                return default

    def put(self, name, project, data):
        content = yaml.dump({project: data})
        utils.save_atomic(self._filename(name), content)

class SQLiteStorePlugin(object):
    name = 'sqlitestore'

    def __init__(self, dbfile, keyword='storage'):
        self.storage = SQLiteStore(dbfile)
        self.keyword = keyword

    def setup(self, app):
        '''
        Make sure that other installed plugins don't affect the same keyword argument.
        '''
        for other in app.plugins:
            if not isinstance(other, SQLiteStorePlugin):
                continue
            if other.keyword == self.keyword:
                raise PluginError(_("Found another SQLiteStore plugin with conflicting settings (non-unique keyword)."))

    def apply(self, callback, context):
        conf = context['config'].get('sqlitestore') or {}
        keyword = conf.get('keyword', self.keyword)

        # Test if the original callback accepts a 'storage' keyword.
        # Ignore it if it does not need a database handle.
        args = inspect.getargspec(context['callback'])[0]
        if keyword not in args:
            return callback

        def wrapper(*args, **kwargs):
            # Add the storage as a keyword argument.
            kwargs[keyword] = self.storage

            return callback(*args, **kwargs)

        # Replace the route callback with the wrapped one.
        return wrapper

class SQLiteStore(object):
    def __init__(self, filename):
        self.filename = filename
        self.db = sqlite3.connect(filename)
        self.db.row_factory = sqlite3.Row
        self._init_db()
        self._init_project('base')

    def _init_db(self):
        self.db.execute("""
            PRAGMA foreign_keys = ON;
        """)
        self.db.execute("""
            CREATE TABLE IF NOT EXISTS store (
                _id INTEGER PRIMARY KEY,
                id INTEGER NOT NULL,
                section TEXT NOT NULL,
                project TEXT,
                data TEXT NOT NULL,
                rank INTEGER,
                parent INTEGER,
                manual BOOLEAN,
                locked BOOLEAN,
                FOREIGN KEY(parent) REFERENCES store(_id) ON DELETE CASCADE
            )
        """)

    def _init_project(self, project):
        defaults_data = json.dumps(defaults.PROJECT_DEFAULTS)
        services_data = json.dumps(defaults.PROJECT_SERVICES)
        section_id = self.create_section_id(project)

        cur = self.db.cursor()
        inserts = []

        cur.execute("SELECT * FROM store WHERE section ='defaults' AND project=?", (project,))
        if not len(cur.fetchall()):
            inserts.append({'id': section_id, 'section': 'defaults', 'project': project, 'data': defaults_data})
        cur.executemany("INSERT INTO store (id, section, project, data) VALUES (:id, :section, :project, :data)", inserts)
        self.db.commit()

        inserts = []
        section_id = self.create_section_id(project)
        cur.execute("SELECT * FROM store WHERE section ='services' AND project=?", (project,))
        if not len(cur.fetchall()):
            inserts.append({'id': section_id, 'section': 'services', 'project': project, 'data': services_data})

        cur.executemany("INSERT INTO store (id, section, project, data) VALUES (:id, :section, :project, :data)", inserts)
        self.db.commit()

    def create_section_id(self, project):
        section_id = 1

        cur = self.db.cursor()
        cur.execute("SELECT MAX(id) FROM store WHERE project=?", (project,))
        row = cur.fetchone()[0]
        if row:
            section_id = row + 1
        return section_id

    def delete_project(self, project):
        cur = self.db.cursor()
        cur.execute("DELETE FROM store WHERE project=?", (project, ))
        self.db.commit()
        return cur.rowcount >= 1

    def get_projects(self):
        cur = self.db.cursor()
        cur.execute("SELECT DISTINCT project FROM store")
        for row in cur.fetchall():
            yield row['project']

    def get_all(self, section, project, default=DEFAULT_VALUE, with_rank=False, with_id=False, with_manual=False, with_locked=False, with_section=False):
        if default is DEFAULT_VALUE:
            default = {}

        result = default
        if hasattr(result, "append"):
            append_data = True
        else:
            append_data = False

        cur = self.db.cursor()
        cur.execute("SELECT id, data, parent, rank, manual, locked FROM store WHERE section = ? AND project = ?",
            (section, project))
        for row in cur.fetchall():
            data = {}
            data['data'] = json.loads(row['data'])
            if with_manual:
                data['_manual'] = row['manual']
            if with_id:
                data['_id'] = row['id']
            if with_rank:
                data['_parent'] = row['parent']
                data['_rank'] = row['rank']
            if with_locked:
                data['_locked'] = row['locked']
            if with_section:
                data['_section'] = section
            if append_data:
                result.append(data)
            else:
                result[row['id']] = data
        return result

    def get_all_data(self, section, project, default=DEFAULT_VALUE):
        data = self.get_all(section, project, default)
        for i, _data in data.items():
            data[i] = _data['data']
        return data

    def get(self, id, section, project, with_rank=False, with_manual=False, with_locked=False):
        cur = self.db.cursor()
        cur.execute("SELECT data, parent, rank, manual, locked FROM store WHERE id = ? AND section = ? AND project = ?",
            (id, section))
        row = cur.fetchone()
        if row:
            data = {}
            data['data'] = json.loads(row[0])
            if row[1] is not None:
                data['_parent'] = row[1]
            if with_rank and row[2] is not None:
                data['_rank'] = row[2]
            if with_manual and row[3] is not None:
                data['_manual'] = row[3]
            if with_locked and row[4] is not None:
                data['_locked'] = row[4]
            return data

    def add(self, section, project, data, with_id=False):
        if not with_id:
            section_id = self.create_section_id(project)
        else:
            section_id = data.pop('_id')

        rank = data.pop('_rank', None)
        parent = data.pop('_parent', None)
        manual = data.pop('_manual', False)
        locked = data.pop('_locked', False)

        data = json.dumps(data['data'])

        cur = self.db.cursor()
        cur.execute("INSERT INTO store (id, section, project, data, parent, rank, manual, locked) VALUES (?, ?, ?, ?, ?, ?, ?, ?)",
            (section_id, section, project, data, parent, rank, manual, locked))
        self.db.commit()
        return cur.lastrowid

    def update(self, id, section, project, data):
        rank = data.pop('_rank', None)
        parent = data.pop('_parent', None)
        manual = data.pop('_manual', False)
        locked = data.pop('_locked', False)
        data.pop('_id', None)
        data.pop('_layers', None)
        data = json.dumps(data.get('data', {}))

        cur = self.db.cursor()
        cur.execute("UPDATE store SET data = ?, parent = ?, rank = ?, manual = ?, locked = ? WHERE id = ? AND SECTION = ? AND project = ?",
            (data, parent, rank, manual, locked, id, section, project))
        self.db.commit()

    def updates(self, section, project, data):
        #ensure all needed values are present or None
        data = [{'id': d['_id'], 'rank': d['_rank'] if '_rank' in d else None, 'parent': d['_parent'] if '_parent' in d else None, 'manual': d['_manual'] if '_manual' in d else False, 'locked': d['_locked'] if '_locked' in d else False} for d in data if '_id' in d]
        cur = self.db.cursor()
        cur.executemany("UPDATE store SET parent = :parent, rank = :rank, manual = :manual, locked = :locked WHERE id = :id", data)
        self.db.commit()

    def delete(self, id, section, project):
        cur = self.db.cursor()
        cur.execute("DELETE FROM store WHERE id = ? AND SECTION = ? AND project = ?",
            (id, section, project))
        self.db.commit()
        return cur.rowcount == 1

    def exists_in_data(self, section, project, search):
        cur = self.db.cursor()
        cur.execute("SELECT id FROM store WHERE section = ? AND project = ? AND data LIKE ?", (section, project, search))
        row = cur.fetchone()
        return row[0] if row else False

    def exist_project(self, project):
        cur = self.db.cursor()
        cur.execute("SELECT id FROM store WHERE section = 'defaults' AND project = ?", (project,))
        result = cur.fetchall()
        return len(result) > 0

    def check_dependencies(self, id, project, look_for):
        cur = self.db.cursor()
        cur.execute("SELECT section, data FROM store WHERE project = ? AND section in (%s)" % (', '.join(["'%s'" % section for section in look_for.keys()]), ), (project,))
        result = cur.fetchall()

        response = {}

        for row in result:
            section =  row[0]
            data = json.loads(row[1])
            if look_for[section] in data and id in data[look_for[section]]:
                dependency = {'name': data['name']}
                if data.has_key('title'):
                    dependency['title'] = data['title']
                if response.has_key(section):
                    response[section].append(dependency)
                else:
                    response[section] = [dependency]

        return response
<|endoftext|>


<commit_before># Copyright 2009 the Melange authors.
#
# 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.

"""Module containing the GCI Callback.
"""

class Callback(object):
  """Callback object that handles interaction between the core.
  """

  API_VERSION = 1

  def __init__(self, core):
    """Initializes a new Callback object for the specified core.
    """

    self.core = core
    self.views = []

  def registerViews(self):
    """Instantiates all view objects.
    """
    from soc.modules.gci.views import accepted_orgs
    from soc.modules.gci.views import admin
    from soc.modules.gci.views import age_check
    from soc.modules.gci.views import all_tasks
    from soc.modules.gci.views import bulk_create
    from soc.modules.gci.views import dashboard
    from soc.modules.gci.views import delete_account
    from soc.modules.gci.views import document
    from soc.modules.gci.views import homepage
    from soc.modules.gci.views import invite
    from soc.modules.gci.views import leaderboard
    from soc.modules.gci.views import org_app
    from soc.modules.gci.views import org_home
    from soc.modules.gci.views import org_profile
    from soc.modules.gci.views import participants
    from soc.modules.gci.views import profile
    from soc.modules.gci.views import profile_show
    from soc.modules.gci.views import program
    from soc.modules.gci.views import request
    from soc.modules.gci.views import student_forms
    from soc.modules.gci.views import students_info
    from soc.modules.gci.views import task
    from soc.modules.gci.views import task_list
    from soc.modules.gci.views import task_create

    self.views.append(accepted_orgs.AcceptedOrgsPage())
    self.views.append(accepted_orgs.AcceptedOrgsAdminPage())
    self.views.append(admin.DashboardPage())
    self.views.append(admin.LookupLinkIdPage())
    self.views.append(all_tasks.TaskListPage())
    self.views.append(age_check.AgeCheck())
    self.views.append(bulk_create.BulkCreate())
    self.views.append(dashboard.DashboardPage())
    self.views.append(delete_account.DeleteAccountPage())
    self.views.append(document.DocumentPage())
    self.views.append(document.EditDocumentPage())
    self.views.append(document.EventsPage())
    self.views.append(document.DocumentListPage())
    self.views.append(homepage.Homepage())
    self.views.append(invite.InvitePage())
    self.views.append(invite.ManageInvite())
    self.views.append(invite.RespondInvite())
    self.views.append(invite.ListUserInvitesPage())
    self.views.append(leaderboard.LeaderboardPage())
    self.views.append(leaderboard.StudentTasksPage())
    self.views.append(org_app.GCIOrgAppEditPage())
    self.views.append(org_profile.OrgProfilePage())
    self.views.append(org_app.GCIOrgAppPreviewPage())
    self.views.append(org_app.GCIOrgAppRecordsList())
    self.views.append(org_app.GCIOrgAppShowPage())
    self.views.append(org_app.GCIOrgAppTakePage())
    self.views.append(org_home.OrgHomepage())
    self.views.append(participants.MentorsListAdminPage())
    self.views.append(profile.GCIProfilePage())
    self.views.append(profile_show.GCIProfileShowPage())
    self.views.append(program.ProgramPage())
    self.views.append(program.TimelinePage())
    self.views.append(request.SendRequestPage())
    self.views.append(request.ManageRequestPage())
    self.views.append(request.RespondRequestPage())
    self.views.append(student_forms.StudentFormUpload())
    self.views.append(student_forms.StudentFormDownload())
    self.views.append(students_info.StudentsInfoPage())
    self.views.append(task.TaskViewPage())
    self.views.append(task.WorkSubmissionDownload())
    self.views.append(task_list.TaskListPage())
    self.views.append(task_create.TaskCreatePage())

    # Google Appengine Tasks
    from soc.modules.gci.tasks.bulk_create import BulkCreateTask
    from soc.modules.gci.tasks.ranking_update import RankingUpdater
    from soc.modules.gci.tasks.task_update import TaskUpdate

    self.views.append(BulkCreateTask())
    self.views.append(RankingUpdater())
    self.views.append(TaskUpdate())

  def registerWithSitemap(self):
    """Called by the server when sitemap entries should be registered.
    """

    self.core.requireUniqueService('registerWithSitemap')

    # Redesigned view registration
    for view in self.views:
      self.core.registerSitemapEntry(view.djangoURLPatterns())

  def registerWithProgramMap(self):
    """Called by the server when program_map entries should be registered.
    """

    self.core.requireUniqueService('registerWithProgramMap')

    from soc.modules.gci.models.program import GCIProgram
    program_entities = GCIProgram.all().fetch(1000)
    map = ('GCI Programs', [
        (str(e.key()), e.name) for e in program_entities])

    self.core.registerProgramEntry(map)
<commit_msg>List of requests that belong to the current user added to GCI callback.<commit_after># Copyright 2009 the Melange authors.
#
# 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.

"""Module containing the GCI Callback.
"""

class Callback(object):
  """Callback object that handles interaction between the core.
  """

  API_VERSION = 1

  def __init__(self, core):
    """Initializes a new Callback object for the specified core.
    """

    self.core = core
    self.views = []

  def registerViews(self):
    """Instantiates all view objects.
    """
    from soc.modules.gci.views import accepted_orgs
    from soc.modules.gci.views import admin
    from soc.modules.gci.views import age_check
    from soc.modules.gci.views import all_tasks
    from soc.modules.gci.views import bulk_create
    from soc.modules.gci.views import dashboard
    from soc.modules.gci.views import delete_account
    from soc.modules.gci.views import document
    from soc.modules.gci.views import homepage
    from soc.modules.gci.views import invite
    from soc.modules.gci.views import leaderboard
    from soc.modules.gci.views import org_app
    from soc.modules.gci.views import org_home
    from soc.modules.gci.views import org_profile
    from soc.modules.gci.views import participants
    from soc.modules.gci.views import profile
    from soc.modules.gci.views import profile_show
    from soc.modules.gci.views import program
    from soc.modules.gci.views import request
    from soc.modules.gci.views import student_forms
    from soc.modules.gci.views import students_info
    from soc.modules.gci.views import task
    from soc.modules.gci.views import task_list
    from soc.modules.gci.views import task_create

    self.views.append(accepted_orgs.AcceptedOrgsPage())
    self.views.append(accepted_orgs.AcceptedOrgsAdminPage())
    self.views.append(admin.DashboardPage())
    self.views.append(admin.LookupLinkIdPage())
    self.views.append(all_tasks.TaskListPage())
    self.views.append(age_check.AgeCheck())
    self.views.append(bulk_create.BulkCreate())
    self.views.append(dashboard.DashboardPage())
    self.views.append(delete_account.DeleteAccountPage())
    self.views.append(document.DocumentPage())
    self.views.append(document.EditDocumentPage())
    self.views.append(document.EventsPage())
    self.views.append(document.DocumentListPage())
    self.views.append(homepage.Homepage())
    self.views.append(invite.InvitePage())
    self.views.append(invite.ManageInvite())
    self.views.append(invite.RespondInvite())
    self.views.append(invite.ListUserInvitesPage())
    self.views.append(leaderboard.LeaderboardPage())
    self.views.append(leaderboard.StudentTasksPage())
    self.views.append(org_app.GCIOrgAppEditPage())
    self.views.append(org_profile.OrgProfilePage())
    self.views.append(org_app.GCIOrgAppPreviewPage())
    self.views.append(org_app.GCIOrgAppRecordsList())
    self.views.append(org_app.GCIOrgAppShowPage())
    self.views.append(org_app.GCIOrgAppTakePage())
    self.views.append(org_home.OrgHomepage())
    self.views.append(participants.MentorsListAdminPage())
    self.views.append(profile.GCIProfilePage())
    self.views.append(profile_show.GCIProfileShowPage())
    self.views.append(program.ProgramPage())
    self.views.append(program.TimelinePage())
    self.views.append(request.ListUserRequestsPage())
    self.views.append(request.SendRequestPage())
    self.views.append(request.ManageRequestPage())
    self.views.append(request.RespondRequestPage())
    self.views.append(student_forms.StudentFormUpload())
    self.views.append(student_forms.StudentFormDownload())
    self.views.append(students_info.StudentsInfoPage())
    self.views.append(task.TaskViewPage())
    self.views.append(task.WorkSubmissionDownload())
    self.views.append(task_list.TaskListPage())
    self.views.append(task_create.TaskCreatePage())

    # Google Appengine Tasks
    from soc.modules.gci.tasks.bulk_create import BulkCreateTask
    from soc.modules.gci.tasks.ranking_update import RankingUpdater
    from soc.modules.gci.tasks.task_update import TaskUpdate

    self.views.append(BulkCreateTask())
    self.views.append(RankingUpdater())
    self.views.append(TaskUpdate())

  def registerWithSitemap(self):
    """Called by the server when sitemap entries should be registered.
    """

    self.core.requireUniqueService('registerWithSitemap')

    # Redesigned view registration
    for view in self.views:
      self.core.registerSitemapEntry(view.djangoURLPatterns())

  def registerWithProgramMap(self):
    """Called by the server when program_map entries should be registered.
    """

    self.core.requireUniqueService('registerWithProgramMap')

    from soc.modules.gci.models.program import GCIProgram
    program_entities = GCIProgram.all().fetch(1000)
    map = ('GCI Programs', [
        (str(e.key()), e.name) for e in program_entities])

    self.core.registerProgramEntry(map)
<|endoftext|>


<commit_before>"""Abstract collection for experiment and integration of all experiment types."""

from snovault import (
    abstract_collection,
    calculated_property,
    collection,
    load_schema,
)
from .base import (
    Item,
    paths_filtered_by_status
)

@abstract_collection(
    name='experiments',
    unique_key='accession',
    properties={
        'title': "Experiments",
        'description': 'Listing of all types of experiments.',
    })
class Experiment(Item):
    """The main experiment class."""

    base_types = ['Experiment'] + Item.base_types
    schema = load_schema('encoded:schemas/experiment.json')
    rev = {
        'experiment_sets': ('ExperimentSet', 'experiments_in_set'),
    }
    embedded = ["protocol", "protocol_variation", "lab", "award", "experiment_sets",
                "produced_in_pub", "publications_of_exp",
                "biosample", "biosample.biosource", "biosample.modifications",
                "biosample.treatments", "biosample.biosource.individual.organism"]
    name_key = 'accession'

    def generate_mapid(self, experiment_type, num):
        delim = '_'
        mapid = str(type(self).__name__)
        mapid = mapid + delim + ''.join(experiment_type.split())
        return mapid + delim + str(num)

    def find_current_sop_map(self, experiment_type):
        maps = []
        suffnum = 1
        mapid = self.generate_mapid(experiment_type, suffnum)
        sop_coll = self.registry['collections']['SopMap']
        if sop_coll is not None:
            while(True):
                m = sop_coll.get(mapid)
                if not m:
                    break
                maps.append(m)
                suffnum += 1
                mapid = self.generate_mapid(experiment_type, suffnum)

        if len(maps) > 0:
            return maps[-1]
        return None

    def _update(self, properties, sheets=None):
        # if the sop_mapping field is not present see if it should be
        if 'sop_mapping' not in properties.keys():
            sopmap = self.find_current_sop_map(properties['experiment_type'])
            properties['sop_mapping'] = {}
            if sopmap is not None:
                sop_mapping = str(sopmap.uuid)
                properties['sop_mapping']['sop_map'] = sop_mapping
                properties['sop_mapping']['has_sop'] = "Yes"
            else:
                properties['sop_mapping']['has_sop'] = "No"
        # update self first to ensure 'experiment_relation' are stored in self.properties
        super(Experiment, self)._update(properties, sheets)

        DicRefRelation = {
            "controlled by": "control for",
            "derived from": "source for",
            "control for": "controlled by",
            "source for": "derived from"
        }
        acc = str(self.uuid)
        if 'experiment_relation' in properties.keys():
            for relation in properties["experiment_relation"]:
                switch = relation["relationship_type"]
                rev_switch = DicRefRelation[switch]
                related_exp = relation["experiment"]
                relationship_entry = {"relationship_type": rev_switch, "experiment": acc}
                rel_dic = {'experiment_relation': [relationship_entry, ]}

                target_exp = self.collection.get(related_exp)
                # case one we don't have relations
                if 'experiment_relation' not in target_exp.properties.keys():
                    target_exp.properties.update(rel_dic)
                    target_exp.update(target_exp.properties)
                else:
                    # case two we have relations but not the one we need
                    for target_relation in target_exp.properties['experiment_relation']:
                        if target_relation['experiment'] == acc:
                            break
                    else:
                        # make data for new experiemnt_relation
                        target_exp.properties['experiment_relation'].append(relationship_entry)
                        target_exp.update(target_exp.properties)

    @calculated_property(schema={
        "title": "Experiment Sets",
        "description": "Experiment Sets to which this experiment belongs.",
        "type": "array",
        "items": {
            "title": "Experiment Set",
            "type": ["string", "object"],
            "linkFrom": "ExperimentSet.experiments_in_set"
        }
    })
    def experiment_sets(self, request, experiment_sets):
        paths = paths_filtered_by_status(request, experiment_sets)
        return paths

    @calculated_property(schema={
        "title": "Produced in Publication",
        "description": "The Publication in which this Experiment was produced.",
        "type": "string",
        "linkTo": "Publication"
    })
    def produced_in_pub(self, request):
        esets = [request.embed('/', str(uuid), '@@object') for uuid in
                 self.experiment_sets(request, self.get_rev_links("experiment_sets"))]

        # replicate experiment set is the boss
        reps = [eset for eset in esets if 'ExperimentSetReplicate' in eset['@type']]
        if reps:
            return reps[0].get('produced_in_pub')

    @calculated_property(schema={
        "title": "Publications",
        "description": "Publications associated with this Experiment.",
        "type": "array",
        "items": {
            "title": "Publication",
            "type": "string",
            "linkTo": "Publication"
        }
    })
    def publications_of_exp(self, request):
        esets = [request.embed('/', str(uuid), '@@object') for uuid in
                 self.experiment_sets(request, self.get_rev_links("experiment_sets"))]
        import itertools
        pubs = list(itertools.chain.from_iterable([eset.get('publications_of_set',[])
                                                    for eset in esets]))
        import pdb; pdb.set_trace()
        return pubs

@collection(
    name='experiments-hi-c',
    unique_key='accession',
    properties={
        'title': 'Experiments Hi-C',
        'description': 'Listing Hi-C Experiments',
    })
class ExperimentHiC(Experiment):
    """The experiment class for Hi-C experiments."""

    item_type = 'experiment_hi_c'
    schema = load_schema('encoded:schemas/experiment_hi_c.json')
    embedded = Experiment.embedded + ["digestion_enzyme", "submitted_by"]
    name_key = 'accession'

    @calculated_property(schema={
        "title": "Experiment summary",
        "description": "Summary of the experiment, including type, enzyme and biosource.",
        "type": "string",
    })
    def experiment_summary(self, request, experiment_type='Undefined', digestion_enzyme=None, biosample=None):
        sum_str = experiment_type
        if biosample:
            biosamp_props = request.embed(biosample, '@@object')
            biosource = biosamp_props['biosource_summary']
            sum_str += (' on ' + biosource)
        if digestion_enzyme:
            de_props = request.embed(digestion_enzyme, '@@object')
            de_name = de_props['name']
            sum_str += (' with ' + de_name)
        return sum_str

    @calculated_property(schema={
        "title": "Display Title",
        "description": "A calculated title for every object in 4DN",
        "type": "string"
    })
    def display_title(self, request, experiment_type='Undefined', digestion_enzyme=None, biosample=None):
        return self.experiment_summary(request, experiment_type, digestion_enzyme, biosample)

@collection(
    name='experiments-capture-c',
    unique_key='accession',
    properties={
        'title': 'Experiments Capture Hi-C',
        'description': 'Listing Capture Hi-C Experiments',
    })
class ExperimentCaptureC(Experiment):
    """The experiment class for Capture Hi-C experiments."""
    item_type = 'experiment_capture_c'
    schema = load_schema('encoded:schemas/experiment_capture_c.json')
    embedded = Experiment.embedded + ["digestion_enzyme",
                                      "submitted_by",
                                      "targeted_regions",
                                      "targeted_regions.target",
                                      "targeted_regions.oligo_file"]
    name_key = 'accession'

    @calculated_property(schema={
        "title": "Experiment summary",
        "description": "Summary of the experiment, including type, enzyme and biosource.",
        "type": "string",
    })
    def experiment_summary(self, request, experiment_type='Undefined', digestion_enzyme=None, biosample=None):
        sum_str = experiment_type
        if biosample:
            biosamp_props = request.embed(biosample, '@@object')
            biosource = biosamp_props['biosource_summary']

            sum_str += (' on ' + biosource)
        if digestion_enzyme:
            de_props = request.embed(digestion_enzyme, '@@object')
            de_name = de_props['name']
            sum_str += (' with ' + de_name)
        return sum_str

    @calculated_property(schema={
        "title": "Display Title",
        "description": "A calculated title for every object in 4DN",
        "type": "string"
    })
    def display_title(self, request, experiment_type='Undefined', digestion_enzyme=None, biosample=None):
        return self.experiment_summary(request, experiment_type, digestion_enzyme, biosample)

@collection(
    name='experiments-repliseq',
    unique_key='accession',
    properties={
        'title': 'Experiments Repliseq',
        'description': 'Listing of Repliseq Experiments',
    })
class ExperimentRepliseq(Experiment):
    """The experiment class for Repliseq experiments."""
    item_type = 'experiment_repliseq'
    schema = load_schema('encoded:schemas/experiment_repliseq.json')
    embedded = Experiment.embedded + ["submitted_by"]
    name_key = 'accession'

    @calculated_property(schema={
        "title": "Experiment summary",
        "description": "Summary of the experiment, including type, enzyme and biosource.",
        "type": "string",
    })
    def experiment_summary(self, request, experiment_type='Undefined', cell_cycle_stage=None, biosample=None):
        sum_str = experiment_type
        if biosample:
            biosamp_props = request.embed(biosample, '@@object')
            biosource = biosamp_props['biosource_summary']
            sum_str += (' on ' + biosource)
        if cell_cycle_stage:
            sum_str += (' at ' + cell_cycle_stage)
        return sum_str

    @calculated_property(schema={
        "title": "Display Title",
        "description": "A calculated title for every object in 4DN",
        "type": "string"
    })
    def display_title(self, request, experiment_type='Undefined', cell_cycle_stage=None, biosample=None):
        return self.experiment_summary(request, experiment_type, cell_cycle_stage, biosample)

@collection(
    name='experiments-mic',
    unique_key='accession',
    properties={
        'title': 'Microscopy Experiments',
        'description': 'Listing of Microscopy Experiments',
    })
class ExperimentMic(Experiment):
    """The experiment class for Microscopy experiments."""
    item_type = 'experiment_mic'
    schema = load_schema('encoded:schemas/experiment_mic.json')
    embedded = Experiment.embedded + ["submitted_by"]
    name_key = 'accession'

    @calculated_property(schema={
        "title": "Experiment summary",
        "description": "Summary of the experiment, including type, enzyme and biosource.",
        "type": "string",
    })
    def experiment_summary(self, request, experiment_type='Undefined', biosample=None):
        sum_str = experiment_type
        if biosample:
            biosamp_props = request.embed(biosample, '@@object')
            biosource = biosamp_props['biosource_summary']
            sum_str += (' on ' + biosource)
        return sum_str

    @calculated_property(schema={
        "title": "Display Title",
        "description": "A calculated title for every object in 4DN",
        "type": "string"
    })
    def display_title(self, request, experiment_type='Undefined', biosample=None):
        return self.experiment_summary(request, experiment_type, biosample)

@calculated_property(context=Experiment, category='action')
def clone(context, request):
    """If the user submits for any lab, allow them to clone
    This is like creating, but keeps previous fields"""
    if request.has_permission('create'):
        return {
            'name': 'clone',
            'title': 'Clone',
            'profile': '/profiles/{ti.name}.json'.format(ti=context.type_info),
            'href': '{item_uri}#!clone'.format(item_uri=request.resource_path(context)),
        }
<commit_msg>removed pdb<commit_after>"""Abstract collection for experiment and integration of all experiment types."""

from snovault import (
    abstract_collection,
    calculated_property,
    collection,
    load_schema,
)
from .base import (
    Item,
    paths_filtered_by_status
)

@abstract_collection(
    name='experiments',
    unique_key='accession',
    properties={
        'title': "Experiments",
        'description': 'Listing of all types of experiments.',
    })
class Experiment(Item):
    """The main experiment class."""

    base_types = ['Experiment'] + Item.base_types
    schema = load_schema('encoded:schemas/experiment.json')
    rev = {
        'experiment_sets': ('ExperimentSet', 'experiments_in_set'),
    }
    embedded = ["protocol", "protocol_variation", "lab", "award", "experiment_sets",
                "produced_in_pub", "publications_of_exp",
                "biosample", "biosample.biosource", "biosample.modifications",
                "biosample.treatments", "biosample.biosource.individual.organism"]
    name_key = 'accession'

    def generate_mapid(self, experiment_type, num):
        delim = '_'
        mapid = str(type(self).__name__)
        mapid = mapid + delim + ''.join(experiment_type.split())
        return mapid + delim + str(num)

    def find_current_sop_map(self, experiment_type):
        maps = []
        suffnum = 1
        mapid = self.generate_mapid(experiment_type, suffnum)
        sop_coll = self.registry['collections']['SopMap']
        if sop_coll is not None:
            while(True):
                m = sop_coll.get(mapid)
                if not m:
                    break
                maps.append(m)
                suffnum += 1
                mapid = self.generate_mapid(experiment_type, suffnum)

        if len(maps) > 0:
            return maps[-1]
        return None

    def _update(self, properties, sheets=None):
        # if the sop_mapping field is not present see if it should be
        if 'sop_mapping' not in properties.keys():
            sopmap = self.find_current_sop_map(properties['experiment_type'])
            properties['sop_mapping'] = {}
            if sopmap is not None:
                sop_mapping = str(sopmap.uuid)
                properties['sop_mapping']['sop_map'] = sop_mapping
                properties['sop_mapping']['has_sop'] = "Yes"
            else:
                properties['sop_mapping']['has_sop'] = "No"
        # update self first to ensure 'experiment_relation' are stored in self.properties
        super(Experiment, self)._update(properties, sheets)

        DicRefRelation = {
            "controlled by": "control for",
            "derived from": "source for",
            "control for": "controlled by",
            "source for": "derived from"
        }
        acc = str(self.uuid)
        if 'experiment_relation' in properties.keys():
            for relation in properties["experiment_relation"]:
                switch = relation["relationship_type"]
                rev_switch = DicRefRelation[switch]
                related_exp = relation["experiment"]
                relationship_entry = {"relationship_type": rev_switch, "experiment": acc}
                rel_dic = {'experiment_relation': [relationship_entry, ]}

                target_exp = self.collection.get(related_exp)
                # case one we don't have relations
                if 'experiment_relation' not in target_exp.properties.keys():
                    target_exp.properties.update(rel_dic)
                    target_exp.update(target_exp.properties)
                else:
                    # case two we have relations but not the one we need
                    for target_relation in target_exp.properties['experiment_relation']:
                        if target_relation['experiment'] == acc:
                            break
                    else:
                        # make data for new experiemnt_relation
                        target_exp.properties['experiment_relation'].append(relationship_entry)
                        target_exp.update(target_exp.properties)

    @calculated_property(schema={
        "title": "Experiment Sets",
        "description": "Experiment Sets to which this experiment belongs.",
        "type": "array",
        "items": {
            "title": "Experiment Set",
            "type": ["string", "object"],
            "linkFrom": "ExperimentSet.experiments_in_set"
        }
    })
    def experiment_sets(self, request, experiment_sets):
        paths = paths_filtered_by_status(request, experiment_sets)
        return paths

    @calculated_property(schema={
        "title": "Produced in Publication",
        "description": "The Publication in which this Experiment was produced.",
        "type": "string",
        "linkTo": "Publication"
    })
    def produced_in_pub(self, request):
        esets = [request.embed('/', str(uuid), '@@object') for uuid in
                 self.experiment_sets(request, self.get_rev_links("experiment_sets"))]

        # replicate experiment set is the boss
        reps = [eset for eset in esets if 'ExperimentSetReplicate' in eset['@type']]
        if reps:
            return reps[0].get('produced_in_pub')

    @calculated_property(schema={
        "title": "Publications",
        "description": "Publications associated with this Experiment.",
        "type": "array",
        "items": {
            "title": "Publication",
            "type": "string",
            "linkTo": "Publication"
        }
    })
    def publications_of_exp(self, request):
        esets = [request.embed('/', str(uuid), '@@object') for uuid in
                 self.experiment_sets(request, self.get_rev_links("experiment_sets"))]
        import itertools
        pubs = list(itertools.chain.from_iterable([eset.get('publications_of_set',[])
                                                    for eset in esets]))
        return pubs

@collection(
    name='experiments-hi-c',
    unique_key='accession',
    properties={
        'title': 'Experiments Hi-C',
        'description': 'Listing Hi-C Experiments',
    })
class ExperimentHiC(Experiment):
    """The experiment class for Hi-C experiments."""

    item_type = 'experiment_hi_c'
    schema = load_schema('encoded:schemas/experiment_hi_c.json')
    embedded = Experiment.embedded + ["digestion_enzyme", "submitted_by"]
    name_key = 'accession'

    @calculated_property(schema={
        "title": "Experiment summary",
        "description": "Summary of the experiment, including type, enzyme and biosource.",
        "type": "string",
    })
    def experiment_summary(self, request, experiment_type='Undefined', digestion_enzyme=None, biosample=None):
        sum_str = experiment_type
        if biosample:
            biosamp_props = request.embed(biosample, '@@object')
            biosource = biosamp_props['biosource_summary']
            sum_str += (' on ' + biosource)
        if digestion_enzyme:
            de_props = request.embed(digestion_enzyme, '@@object')
            de_name = de_props['name']
            sum_str += (' with ' + de_name)
        return sum_str

    @calculated_property(schema={
        "title": "Display Title",
        "description": "A calculated title for every object in 4DN",
        "type": "string"
    })
    def display_title(self, request, experiment_type='Undefined', digestion_enzyme=None, biosample=None):
        return self.experiment_summary(request, experiment_type, digestion_enzyme, biosample)

@collection(
    name='experiments-capture-c',
    unique_key='accession',
    properties={
        'title': 'Experiments Capture Hi-C',
        'description': 'Listing Capture Hi-C Experiments',
    })
class ExperimentCaptureC(Experiment):
    """The experiment class for Capture Hi-C experiments."""
    item_type = 'experiment_capture_c'
    schema = load_schema('encoded:schemas/experiment_capture_c.json')
    embedded = Experiment.embedded + ["digestion_enzyme",
                                      "submitted_by",
                                      "targeted_regions",
                                      "targeted_regions.target",
                                      "targeted_regions.oligo_file"]
    name_key = 'accession'

    @calculated_property(schema={
        "title": "Experiment summary",
        "description": "Summary of the experiment, including type, enzyme and biosource.",
        "type": "string",
    })
    def experiment_summary(self, request, experiment_type='Undefined', digestion_enzyme=None, biosample=None):
        sum_str = experiment_type
        if biosample:
            biosamp_props = request.embed(biosample, '@@object')
            biosource = biosamp_props['biosource_summary']

            sum_str += (' on ' + biosource)
        if digestion_enzyme:
            de_props = request.embed(digestion_enzyme, '@@object')
            de_name = de_props['name']
            sum_str += (' with ' + de_name)
        return sum_str

    @calculated_property(schema={
        "title": "Display Title",
        "description": "A calculated title for every object in 4DN",
        "type": "string"
    })
    def display_title(self, request, experiment_type='Undefined', digestion_enzyme=None, biosample=None):
        return self.experiment_summary(request, experiment_type, digestion_enzyme, biosample)

@collection(
    name='experiments-repliseq',
    unique_key='accession',
    properties={
        'title': 'Experiments Repliseq',
        'description': 'Listing of Repliseq Experiments',
    })
class ExperimentRepliseq(Experiment):
    """The experiment class for Repliseq experiments."""
    item_type = 'experiment_repliseq'
    schema = load_schema('encoded:schemas/experiment_repliseq.json')
    embedded = Experiment.embedded + ["submitted_by"]
    name_key = 'accession'

    @calculated_property(schema={
        "title": "Experiment summary",
        "description": "Summary of the experiment, including type, enzyme and biosource.",
        "type": "string",
    })
    def experiment_summary(self, request, experiment_type='Undefined', cell_cycle_stage=None, biosample=None):
        sum_str = experiment_type
        if biosample:
            biosamp_props = request.embed(biosample, '@@object')
            biosource = biosamp_props['biosource_summary']
            sum_str += (' on ' + biosource)
        if cell_cycle_stage:
            sum_str += (' at ' + cell_cycle_stage)
        return sum_str

    @calculated_property(schema={
        "title": "Display Title",
        "description": "A calculated title for every object in 4DN",
        "type": "string"
    })
    def display_title(self, request, experiment_type='Undefined', cell_cycle_stage=None, biosample=None):
        return self.experiment_summary(request, experiment_type, cell_cycle_stage, biosample)

@collection(
    name='experiments-mic',
    unique_key='accession',
    properties={
        'title': 'Microscopy Experiments',
        'description': 'Listing of Microscopy Experiments',
    })
class ExperimentMic(Experiment):
    """The experiment class for Microscopy experiments."""
    item_type = 'experiment_mic'
    schema = load_schema('encoded:schemas/experiment_mic.json')
    embedded = Experiment.embedded + ["submitted_by"]
    name_key = 'accession'

    @calculated_property(schema={
        "title": "Experiment summary",
        "description": "Summary of the experiment, including type, enzyme and biosource.",
        "type": "string",
    })
    def experiment_summary(self, request, experiment_type='Undefined', biosample=None):
        sum_str = experiment_type
        if biosample:
            biosamp_props = request.embed(biosample, '@@object')
            biosource = biosamp_props['biosource_summary']
            sum_str += (' on ' + biosource)
        return sum_str

    @calculated_property(schema={
        "title": "Display Title",
        "description": "A calculated title for every object in 4DN",
        "type": "string"
    })
    def display_title(self, request, experiment_type='Undefined', biosample=None):
        return self.experiment_summary(request, experiment_type, biosample)

@calculated_property(context=Experiment, category='action')
def clone(context, request):
    """If the user submits for any lab, allow them to clone
    This is like creating, but keeps previous fields"""
    if request.has_permission('create'):
        return {
            'name': 'clone',
            'title': 'Clone',
            'profile': '/profiles/{ti.name}.json'.format(ti=context.type_info),
            'href': '{item_uri}#!clone'.format(item_uri=request.resource_path(context)),
        }
<|endoftext|>