Permalink
Browse files

separate html interface from web layer in both web.py and pylons impl…

…ementations

git-svn-id: http://sword-app.svn.sourceforge.net/svnroot/sword-app/sss/branches/sss-2@450 2bf6ea0f-123d-0410-b71a-f1a21eb24612
  • Loading branch information...
1 parent 08aef1a commit d26e204adc62879f44f6a3ab8ea04fd56428d535 richard-jones committed Jan 15, 2012
Showing with 138 additions and 26 deletions.
  1. +1 −1 sss/__init__.py
  2. +8 −1 sss/config.py
  3. +6 −0 sss/core.py
  4. +4 −12 sss/pylons_sword_controller.py
  5. +116 −1 sss/repository.py
  6. +3 −11 sss/webpy.py
View
@@ -1,6 +1,6 @@
from info import __version__, __author__, __license__
-from core import Auth, AuthException, Authenticator, DeleteRequest, DeleteResponse, DepositRequest, DepositResponse, EntryDocument, SDCollection, SWORDRequest, ServiceDocument, Statement, SwordError, SwordServer
+from core import Auth, AuthException, Authenticator, DeleteRequest, DeleteResponse, DepositRequest, DepositResponse, EntryDocument, SDCollection, SWORDRequest, ServiceDocument, Statement, SwordError, SwordServer, WebUI
from config import Configuration, SSS_CONFIG_FILE
from spec import Errors, HttpHeaders
View
@@ -119,7 +119,8 @@
},
"sword_server" : "sss.repository.SSS",
- "authenticator" : "sss.repository.SSSAuthenticator"
+ "authenticator" : "sss.repository.SSSAuthenticator",
+ "webui" : "sss.repository.WebInterface"
}
"""
@@ -144,6 +145,9 @@ def get_server_implementation(self):
def get_authenticator_implementation(self):
return self._get_class(self.authenticator)
+
+ def get_webui_implementation(self):
+ return self._get_class(self.webui)
def get_container_formats(self):
default_params = self._get_accept_params(self.container_format_default)
@@ -213,6 +217,9 @@ def _load_class(self, modpath, classname):
return self._load_class(modpath, classname)
else:
raise e
+ except AttributeError as e:
+ ssslog.debug("Tried and failed to load " + classname + " from " + modpath)
+ raise e
def _load_json(self):
if not os.path.isfile(self.SSS_CONFIG_FILE):
View
@@ -856,3 +856,9 @@ def get_rdf_xml(self):
return rdf
+class WebUI(object):
+ def __init__(self, config):
+ self.config = config
+
+ def get(self, path=None):
+ return
@@ -7,7 +7,7 @@
from core import Auth, SWORDSpec, SwordError, AuthException, DepositRequest, DeleteRequest
from negotiator import ContentNegotiator, AcceptParameters, ContentType
from spec import Errors, HttpHeaders, ValidationException
-from webui import HomePage, CollectionPage, ItemPage
+
import logging
ssslog = logging.getLogger(__name__)
@@ -17,6 +17,7 @@
config = Configuration()
Authenticator = config.get_authenticator_implementation()
SwordServer = config.get_server_implementation()
+WebInterface = config.get_webui_implementation()
__controller__ = "SwordController"
@@ -336,7 +337,6 @@ def webui(self, path=None):
abort(405, "Method Not Allowed")
return
-
def part(self, path=None):
http_method = request.environ['REQUEST_METHOD']
if http_method == "GET":
@@ -819,16 +819,8 @@ def _GET_aggregation(self, path=None):
return
def _GET_webui(self, path=None):
- if path is not None:
- if path.find("/") >= 0:
- ip = ItemPage(config)
- return ip.get_item_page(path)
- else:
- cp = CollectionPage(config)
- return cp.get_collection_page(path)
- else:
- hp = HomePage(config)
- return hp.get_home_page()
+ w = WebInterface(config)
+ return w.get(path)
def _GET_part(self, path):
ss = SwordServer(config, None)
View
@@ -1,5 +1,5 @@
import os, hashlib, uuid, urllib
-from core import Statement, DepositResponse, MediaResourceResponse, DeleteResponse, SWORDSpec, Auth, AuthException, SwordError, ServiceDocument, SDCollection, EntryDocument, Authenticator, SwordServer
+from core import Statement, DepositResponse, MediaResourceResponse, DeleteResponse, SWORDSpec, Auth, AuthException, SwordError, ServiceDocument, SDCollection, EntryDocument, Authenticator, SwordServer, WebUI
from spec import Namespaces, Errors
from lxml import etree
from datetime import datetime
@@ -10,6 +10,19 @@
from sss_logging import logging
ssslog = logging.getLogger(__name__)
+class WebInterface(WebUI):
+ def get(self, path=None):
+ if path is not None:
+ if path.find("/") >= 0:
+ ip = ItemPage(self.config)
+ return ip.get_item_page(path)
+ else:
+ cp = CollectionPage(self.config)
+ return cp.get_collection_page(path)
+ else:
+ hp = HomePage(self.config)
+ return hp.get_home_page()
+
class SSSAuthenticator(Authenticator):
def __init__(self, config):
Authenticator.__init__(self, config)
@@ -1111,4 +1124,106 @@ def list_content(self, collection, id, exclude=[]):
cfiles = [f for f in os.listdir(odir) if not f.startswith("sss_") and not f in exclude]
return cfiles
+# Basic Web Interface
+#######################################################################
+
+class WebPage(object):
+ def _wrap_html(self, title, frag, head_frag=None):
+ return "<html><head><title>" + title + "</title>" + head_frag + "</head><body>" + frag + "</body></html>"
+
+class HomePage(WebPage):
+ """
+ Welcome / home page
+ """
+ def __init__(self, config):
+ self.config = config
+ self.dao = DAO(self.config)
+ self.um = URIManager(config)
+
+ def get_home_page(self):
+ frag = "<h1>Simple SWORDv2 Server</h1>"
+ frag += "<p><strong>Service Document (SD-IRI)</strong>: <a href=\"" + self.config.base_url + "sd-uri\">" + self.config.base_url + "sd-uri</a></p>"
+ frag += "<p>If prompted, use the username <strong>" + self.config.user + "</strong> and the password <strong>" + self.config.password + "</strong></p>"
+ frag += "<p>The On-Behalf-Of user to use is <strong>" + self.config.obo + "</strong></p>"
+
+ # list the collections
+ frag += "<h2>Collections</h2><ul>"
+ for col in self.dao.get_collection_names():
+ frag += "<li><a href=\"" + self.um.html_url(col) + "\">" + col + "</a></li>"
+ frag += "</ul>"
+
+ head_frag = "<link rel=\"http://purl.org/net/sword/discovery/service-document\" href=\"" + self.config.base_url + "sd-uri\"/>"
+
+ return self._wrap_html("Simple SWORDv2 Server", frag, head_frag)
+
+class CollectionPage(WebPage):
+ def __init__(self, config):
+ self.config = config
+ self.dao = DAO(config)
+ self.um = URIManager(config)
+
+ def get_collection_page(self, id):
+ frag = "<h1>Collection: " + id + "</h1>"
+
+ # list all of the containers in the collection
+ cpath = self.dao.get_store_path(id)
+ containers = os.listdir(cpath)
+ frag += "<h2>Containers</h2><ul>"
+ for container in containers:
+ frag += "<li><a href=\"" + self.um.html_url(id, container) + "\">" + container + "</a></li>"
+ frag += "</ul>"
+
+ head_frag = "<link rel=\"http://purl.org/net/sword/terms/deposit\" href=\"" + self.um.col_uri(id) + "\"/>"
+
+ return self._wrap_html("Collection: " + id, frag, head_frag)
+class ItemPage(WebPage):
+ def __init__(self, config):
+ self.config = config
+ self.dao = DAO(config)
+ self.um = URIManager(config)
+
+ def get_item_page(self, oid):
+ collection, id = self.um.interpret_oid(oid)
+ statement = self.dao.load_statement(collection, id)
+ metadata = self.dao.get_metadata(collection, id)
+
+ state_frag = self._get_state_frag(statement)
+ md_frag = self._layout_metadata(metadata)
+ file_frag = self._layout_files(statement)
+
+ frag = "<h1>Item: " + id + "</h1>"
+ frag += "<strong>State</strong>: " + state_frag
+ frag += self._layout_sections(md_frag, file_frag)
+
+ head_frag = "<link rel=\"http://purl.org/net/sword/terms/edit\" href=\"" + self.um.edit_uri(collection, id) + "\"/>"
+ head_frag += "<link rel=\"http://purl.org/net/sword/terms/statement\" href=\"" + self.um.state_uri(collection, id, "atom") + "\"/>"
+ head_frag += "<link rel=\"http://purl.org/net/sword/terms/statement\" href=\"" + self.um.state_uri(collection, id, "ore") + "\"/>"
+
+ return self._wrap_html("Item: " + id, frag, head_frag)
+
+ def _layout_metadata(self, metadata):
+ frag = "<h2>Metadata</h2>"
+ for key, vals in metadata.iteritems():
+ frag += "<strong>" + key + "</strong>: " + ", ".join(vals) + "<br/>"
+ if len(metadata) == 0:
+ frag += "No metadata associated with this item"
+ return frag
+
+ def _layout_files(self, statement):
+ frag = "<h2>Files</h2>"
+ frag += "<table border=\"1\"><tr><th>URI</th><th>deposited on</th><th>format</th><th>deposited by</th><th>on behalf of</th></tr>"
+ for uri, deposit_time, format, by, obo in statement.original_deposits:
+ frag += "<tr><td><a href=\"" + uri + "\">" + uri + "</a></td><td>" + str(deposit_time) + "</td><td>" + format
+ frag += "</td><td>" + by + "</td><td>" + str(obo) + "</td></tr>"
+ frag += "</table>"
+ return frag
+
+ def _get_state_frag(self, statement):
+ if statement.in_progress:
+ return statement.in_progress_uri
+ else:
+ return statement.archived_uri
+
+ def _layout_sections(self, metadata, files):
+ return "<table border=\"0\"><tr><td valign=\"top\">" + metadata + "</td><td valign=\"top\">" + files + "</td></tr></table>"
View
@@ -2,7 +2,6 @@
from web.wsgiserver import CherryPyWSGIServer
from core import Auth, SWORDSpec, SwordError, AuthException, DepositRequest, DeleteRequest
from negotiator import ContentNegotiator, AcceptParameters, ContentType
-from webui import HomePage, CollectionPage, ItemPage
from spec import Errors, HttpHeaders, ValidationException
from sss_logging import logging
@@ -13,6 +12,7 @@
config = Configuration()
Authenticator = config.get_authenticator_implementation()
SwordServer = config.get_server_implementation()
+WebInterface = config.get_webui_implementation()
# Whether to run using SSL. This uses a default self-signed certificate. Change the paths to
# use an alternative set of keys
@@ -734,16 +734,8 @@ class WebUI(SwordHttpHandler):
Class to provide a basic web interface to the store for convenience
"""
def GET(self, path=None):
- if path is not None:
- if path.find("/") >= 0:
- ip = ItemPage(config)
- return ip.get_item_page(path)
- else:
- cp = CollectionPage(config)
- return cp.get_collection_page(path)
- else:
- hp = HomePage(config)
- return hp.get_home_page()
+ w = WebInterface(config)
+ return w.get(path)
class Part(SwordHttpHandler):
"""

0 comments on commit d26e204

Please sign in to comment.