[Mpuls-commits] r5321 - base/trunk/mpulsweb/model
scm-commit@wald.intevation.org
scm-commit at wald.intevation.org
Tue Sep 13 13:22:37 CEST 2011
Author: bh
Date: 2011-09-13 13:22:37 +0200 (Tue, 13 Sep 2011)
New Revision: 5321
Added:
base/trunk/mpulsweb/model/meta.py
Log:
Port the meta model implementation from WASKU to mpulsweb.
The code was taken from wasku-web revision 391:e20e98117f34.
The agencysettings module is now imported from mpulsweb, though.
Added: base/trunk/mpulsweb/model/meta.py
===================================================================
--- base/trunk/mpulsweb/model/meta.py 2011-09-13 10:01:01 UTC (rev 5320)
+++ base/trunk/mpulsweb/model/meta.py 2011-09-13 11:22:37 UTC (rev 5321)
@@ -0,0 +1,259 @@
+# -*- coding: utf-8 -*-
+# Authors:
+# Torsten Irländer <torsten.irlaender at intevation.de>
+
+"""Classes reperesenting the connection to the meta-case"""
+
+import logging
+import subprocess
+from datetime import datetime
+from xml.etree import ElementTree
+
+import psycopg2.extras
+
+from pylons import config
+
+from formed.instance.backends.postgres import DBFactory as InstanceFactory
+
+from mpulsweb.lib.db import PostgresDBInterface, db
+from mpulsweb.lib.translation import _
+from mpulsweb.lib.base import g, session
+from mpulsweb.lib.security import get_unmapped_db_name
+from mpulsweb.lib.metaclient import MetaClient, MetaException
+
+from mpulsweb.model.agencysettings import Agency
+
+log = logging.getLogger(__name__)
+
+LOAD_META_SQL = """SELECT * from ka_meta_tbl_view where master_id = %s"""
+UPDATE_META_SQL = """\
+UPDATE ka_meta_tbl_view
+SET meta_uuid = %(meta_uuid)s,
+ project_uuid = %(project_uuid)s,
+ sync_permission = %(sync_permission)s,
+ last_download = %(last_download)s,
+ last_upload = %(last_upload)s
+WHERE id = %(id)s"""
+
+
+def get_meta_client():
+ agency = Agency()
+ user = session['USER_AUTHORIZED']
+ return MetaClient(config["mpuls.meta.host"],
+ int(config["mpuls.meta.port"]), g.ssl_context,
+ get_unmapped_db_name(),
+ agency.getMetaUserName(),
+ agency.getMetaUserPassword(),
+ user.login)
+
+
+def convert_meta_xml(converter, project_xml):
+ proc = subprocess.Popen(["xsltproc", converter, "-"], stdin=subprocess.PIPE,
+ stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+ out, err = proc.communicate(project_xml)
+
+ if proc.returncode != 0:
+ log.error("Error running xsltproc subprocess: %r", err)
+ return None
+ if err:
+ log.warning("Unexpected stderr output of xsltproc: %r", err)
+
+ return out
+
+
+class Meta:
+
+ """Model for the client-side information about the meta-case.
+
+ Instances of this class store basic information about the link to
+ the meta case. The link is established using the UUIDs of the meta
+ case and, once it exists, the project part containing the data from
+ the client-side case this instance belongs to. This class also
+ handles operations like setting permissions to sync data with the
+ metacase, link und unlinking and transfer of data.
+ """
+
+ def __init__(self, master_id):
+ self.id = None
+ self.master_id = master_id
+ self._set_default_values()
+
+ # Load meta data
+ self._load()
+
+ #
+ # Low-level interface for the direct manipulation of the case's meta
+ # settings
+ #
+
+ def _save(self):
+ """Save data of meta class in db"""
+ db.execute(UPDATE_META_SQL,
+ dict(id=self.id,
+ meta_uuid=self.meta_uuid,
+ project_uuid=self.project_uuid,
+ sync_permission=self.sync_permission,
+ last_download=self.last_download,
+ last_upload=self.last_upload))
+
+ def _load(self):
+ """Load data of meta class from db"""
+ result = None
+ conn, cur = None, None
+ try:
+ conn = db.getConnection()
+ cur = conn.cursor(cursor_factory=psycopg2.extras.DictCursor)
+ cur.execute(LOAD_META_SQL, (self.master_id,))
+ result = cur.fetchone()
+ # Set values of meta object.
+ self.id = result.get('id')
+ self.meta_uuid = result.get('meta_uuid')
+ self.project_uuid = result.get('project_uuid')
+ self.sync_permission = result.get('sync_permission')
+ self.last_download = result.get('last_download')
+ self.last_upload = result.get('last_upload')
+ except:
+ log.exception('Error on loading meta data for case %s',
+ self.master_id)
+ raise
+ finally:
+ db.recycleConnection(conn, cur)
+
+ def _set_default_values(self):
+ self.meta_uuid = None
+ self.project_uuid = None
+ self.sync_permission = False
+ self.last_download = None
+ self.last_upload = None
+
+ def reset(self):
+ """Reset the meta information by unlink the case and revoke permission.
+ In fact, all case-specific information stored about the link to
+ the meta-server are set to defaults.
+ """
+ self._set_default_values()
+ self._save()
+
+ # Synchronisation
+ def is_sync_allowed(self):
+ """Returns True if the transfer data to the meta-server is allowed."""
+ return self.sync_permission
+
+ def allow_sync(self):
+ """Set flag to allow synchronisation with meta case."""
+ self.sync_permission = True
+ self._save()
+
+ def disallow_sync(self):
+ """Unset flag to allow synchronisation with meta case.
+ Synchronisation is not allowed anymore afterwards.
+ """
+ self.sync_permission = False
+ self._save()
+
+ # Linking
+ def is_linked(self):
+ """Returns True if a link is set to the meta case, False otherwise."""
+ return self.meta_uuid is not None
+
+ def link(self, uuid, project_uuid=None):
+ """Link the case with a meta case identified with its uuids."""
+ if self.is_sync_allowed():
+ if ((self.meta_uuid is not None and self.meta_uuid != uuid)
+ or (self.project_uuid is not None
+ and self.project_uuid != project_uuid)):
+ raise MetaException(_('Case is already linked'))
+ self.meta_uuid = uuid
+ self.project_uuid = project_uuid
+ self._save()
+ else:
+ raise MetaException(_('Synchronisation is not allowed for this'
+ ' case.'))
+
+ def unlink(self):
+ """Delete link to meta case by setting the UUIDs to None"""
+ if self.meta_uuid is None:
+ raise MetaException(_('Case is not linked'))
+ self.meta_uuid = None
+ self.project_uuid = None
+ self._save()
+
+ def reset_project_uuid(self):
+ self.project_uuid = None
+ self._save()
+
+ #
+ # High-level interface for operations involving the meta-server
+ #
+
+ def delete_projectdata(self):
+ """Delete the project part of the meta-case on the meta-server"""
+ if self.is_linked():
+ if self.project_uuid:
+ get_meta_client().delete_project_data(self.meta_uuid,
+ self.project_uuid)
+ else:
+ raise MetaException(_('Case is not linked with any meta case.'))
+
+ def delete_metacase(self):
+ """Delete the meta-case on the meta-server.
+ More precisely, the meta-case is marked for deletion on the
+ meta-server after deleting the project part corresponding to the
+ client case.
+ """
+ if self.is_linked():
+ get_meta_client().delete_case(self.meta_uuid, self.project_uuid)
+ else:
+ raise MetaException(_('Case is not linked with any meta case.'))
+
+ def get_meta_xml(self):
+ """Return the data to transfer to the meta server as an XML string."""
+ factory = InstanceFactory(g.formedTree, PostgresDBInterface())
+ xmltree = factory.toXML([self.master_id])
+ return convert_meta_xml(g.meta_converter,
+ ElementTree.tostring(xmltree.getroot()))
+
+ def create(self, hash):
+ """Create a new meta case and link the uuid with this case."""
+ uuids = get_meta_client().upload_new_case(hash, self.get_meta_xml())
+ # no need to explicitly save the last_upload change because it
+ # will be done by self.link anyway.
+ self.last_upload = datetime.today()
+ self.link(*uuids)
+
+ def pull(self):
+ """Return the meta-case rendered as HTML as a string."""
+ if self.is_linked():
+ rendered = get_meta_client().meta_case_as_html(self.meta_uuid)
+ self.last_download = datetime.today()
+ self._save()
+ return rendered
+ else:
+ raise MetaException(_('Case is not linked with any meta case.'))
+
+ def push(self):
+ """Upload the case data to the linked meta case."""
+ if self.is_linked():
+ uuids = get_meta_client().upload_project_data(self.meta_uuid,
+ self.project_uuid,
+ self.get_meta_xml())
+ self.last_upload = datetime.today()
+ self._save()
+ self.link(*uuids)
+ else:
+ raise MetaException(_('Case is not linked with any meta case.'))
+
+ def delete_metacase_and_reset(self):
+ """Delete the meta case and afterwards reset the meta settings."""
+ self.delete_metacase()
+ self.reset()
+
+ def delete_projectdata_and_reset(self):
+ """Delete the project part and afterwards reset the meta settings."""
+ self.delete_projectdata()
+ self.reset()
+
+ def delete_projectdata_and_unlink(self):
+ """Delete the project part and afterwards reset the meta UUIDs."""
+ self.delete_projectdata()
+ self.unlink()
Property changes on: base/trunk/mpulsweb/model/meta.py
___________________________________________________________________
Name: svn:keywords
+ Id Revision
Name: svn:eol-style
+ native
More information about the Mpuls-commits
mailing list