Esempio n. 1
0
class DocFormRenderer(FormMixin, grend.ServiceBasedPage,
                      grend.HTMLResultRenderMixin):
    """A renderer displaying a form and delivering core's result as
	a document.
	
	The core must return a pair of mime-type and content; on errors,
	the form is redisplayed.

	This is mainly useful with custom cores doing weird things.  This
	renderer will not work with dbBasedCores and similar.
	"""
    name = "docform"
    # I actually don't know the result type, since it's determined by the
    # core; I probably should have some way to let the core tell me what
    # it's going to return.
    resultType = "application/octet-stream"
    compute = True

    @classmethod
    def isBrowseable(cls, service):
        return True

    def _formatOutput(self, data, ctx):
        request = inevow.IRequest(ctx)
        mime, payload = data.original
        request.setHeader("content-type", mime)
        request.write(payload)
        return ""

    docFactory = svcs.loadSystemTemplate("defaultresponse.html")
Esempio n. 2
0
class ReloadPage(grend.GavoRenderMixin, rend.Page):
    """A page to clear some caches.

	Right now, we don't use it (e.g., it's not reachable from the web).  There's
	gavo serve reload and reloads of individual RDs, so there may not be much of
	a niche for this.

	If it ever gets resurrected, we probably should use user.server._reload
	as the implementation.
	"""
    modsToReload = []

    def __init__(self, ctx):
        rend.Page.__init__(self)
        self.modulesReloaded = []

    def data_reloadedModules(self, ctx, data):
        return self.modulesReloaded

    def renderHTTP(self, ctx):
        return common.runAuthenticated(ctx, "admin", self._reload, ctx)

    def _reloadModules(self):
        for modPath in self.modsToReload:
            parts = modPath.split(".")
            exec "from %s import %s;reload(%s)" % (".".join(
                parts[:-1]), parts[-1], parts[-1])
            self.modulesReloaded.append(modPath)

    def _reload(self, ctx):
        base.caches.clearCaches()
        self._reloadModules()
        return self._renderHTTP(ctx)

    docFactory = svcs.loadSystemTemplate("reloaded.html")
Esempio n. 3
0
class AuthenticatePage(ErrorPage):
	handles = svcs.Authenticate
	status = 401
	titleMessage = "Authentication Required"

	def renderHTTP(self, ctx):
		request = inevow.IRequest(ctx)
		request.setHeader('WWW-Authenticate', 
			'Basic realm="%s"'%str(self.failure.value.realm))
		return ErrorPage.renderHTTP(self, ctx)
	
	docFactory = svcs.loadSystemTemplate("unauth.html")
Esempio n. 4
0
class LoginPage(rend.Page, grend.GavoRenderMixin):
    """a page that logs people in or out.

	You should usually give a nextURL parameter in the context, the page
	the user is returned to afte login.

	If the user is already authenticated, this will do a logout (by
	sending a 403).
	"""
    def __init__(self, ctx):
        rend.Page.__init__(self)
        self.request = inevow.IRequest(ctx)
        self.nextURL = self.request.args.get("nextURL", ["/"])[0]

    def render_nextURL(self, ctx, data):
        return ctx.tag(href=self.nextURL)

    def render_iflogged(self, ctx, data):
        if self.request.getUser():
            return ctx.tag
        return ""

    def render_ifnotlogged(self, ctx, data):
        if not self.request.getUser():
            return ctx.tag
        return ""

    def data_loggedUser(self, ctx, data):
        return self.request.getUser()

    def renderHTTP(self, ctx):
        relogging = base.parseBooleanLiteral(
            utils.getfirst(self.request.args, "relog", default="False"))
        if self.request.getUser():  # user is logged in...
            if relogging:  # ...and wants to log out: show login dialog...
                raise svcs.Authenticate()
            else:  # ...and has just logged in: forward to destination
                return url.URL.fromContext(ctx).click(self.nextURL)
        else:  # user is not logged in
            if relogging:  #...but was and has just logged out: forward to dest
                return url.URL.fromContext(ctx).click(self.nextURL)
            else:  # ... and wants to log in.
                raise svcs.Authenticate()

    docFactory = svcs.loadSystemTemplate("loginout.html")
Esempio n. 5
0
class ServiceUnavailable(rend.Page):
    """A page to be rendered in emergencies.

	Essentially, this is a 503 with a text taken from stateDir/MAINT.

	Root checks for the presence of that file before returning this
	page, so (ignoring race conditions) this page assumes it's there.
	"""
    def renderHTTP(self, ctx):
        request = inevow.IRequest(ctx)
        request.setResponseCode(503)
        request.setHeader("retry-after", "3600")
        return rend.Page.renderHTTP(self, ctx)

    def data_maintText(self, ctx, data):
        with open(os.path.join(base.getConfig("stateDir"), "MAINT")) as f:
            return f.read().decode("utf-8")

    docFactory = svcs.loadSystemTemplate("maintenance.html")
Esempio n. 6
0
class RDInfoRenderer(grend.CustomTemplateMixin, grend.ServiceBasedPage):
    """A renderer for displaying various properties about a resource descriptor.
	
	This renderer could really be attached to any service since
	it does not call it, but it usually lives on //services/overview.

	By virtue of builtin vanity, you can reach the rdinfo renderer
	at /browse, and thus you can access /browse/foo/q to view the RD infos.
	This is the form used by table registrations.
	"""
    name = "rdinfo"
    customTemplate = svcs.loadSystemTemplate("rdlist.html")

    def data_publishedRDs(self, ctx, data):
        td = base.caches.getRD("//services").getById("resources")
        with base.getTableConn() as conn:
            table = rsc.TableForDef(td, connection=conn)
            try:
                return [
                    row["sourceRD"] for row in table.iterQuery(
                        [td.getColumnByName("sourceRD")],
                        "",
                        distinct=True,
                        limits=("ORDER BY sourceRD", {}))
                ]
            finally:
                table.close()

    def locateChild(self, ctx, segments):
        rdId = "/".join(segments)
        if not rdId:
            raise svcs.WebRedirect("browse")
        clientRD = base.caches.getRD(rdId)
        return RDInfoPage(ctx, clientRD), ()

    defaultDocFactory = common.doctypedStan(T.html[
        T.head[T.title["Missing Template"]], T.
        body[T.
             p["The RD list is only available with an rdlist.html template"]]])
Esempio n. 7
0
class TableInfoRenderer(MetaRenderer):
    """A renderer for displaying table information.

	It really doesn't use the underlying service, but conventionally,
	it is run on __system__/dc_tables/show.
	"""
    name = "tableinfo"
    customTemplate = svcs.loadSystemTemplate("tableinfo.html")

    def renderHTTP(self, ctx):
        if not hasattr(self, "table"):
            # _retrieveTableDef did not run, i.e., no tableName was given
            raise svcs.UnknownURI(
                "You must provide a table name to this renderer.")
        self.metaCarrier = self.table
        return super(TableInfoRenderer, self).renderHTTP(ctx)

    def _retrieveTableDef(self, tableName):
        try:
            self.tableName = tableName
            self.table = registry.getTableDef(tableName)
            self.describingRD = self.table.rd
        except base.NotFoundError, msg:
            raise base.ui.logOldExc(svcs.UnknownURI(str(msg)))
Esempio n. 8
0
class GavoRenderMixin(common.CommonRenderers):
    """A mixin with renderers useful throughout the data center.

	Rendering of meta information:

	* <tag n:render="meta">METAKEY</tag> or
	* <tag n:render="metahtml">METAKEY</tag>

	Rendering the sidebar --
	<body n:render="withsidebar">.  This will only work if the renderer
	has a service attribute that's enough of a service (i.e., carries meta
	and knows how to generate URLs).

	Conditional rendering:

	* ifmeta
	* imownmeta
	* ifdata
	* ifnodata
	* ifslot
	* ifnoslot
	* ifadmin

	Obtaining system info

	* rd <rdId> -- makes the referenced RD the current data (this is
	  not too useful right now, but it lets you check of the existence
	  of RDs already)
	"""
    _sidebar = svcs.loadSystemTemplate("sidebar.html")
    _footer = svcs.loadSystemTemplate("footer.html")

    # macro package to use when expanding macros.  Just set this
    # in the constructor as necessary (ServiceBasedRenderer has the
    # service here)
    macroPackage = None

    def _initGavoRender(self):
        # call this to initialize this mixin.
        # (kept for backward compatibility; don't use this any more)
        pass

    def _doRenderMeta(self, ctx, raiseOnFail=False, plain=False, carrier=None):
        if carrier is None:
            carrier = self.metaCarrier
        if not hasattr(carrier, "_metaRenderCache"):
            carrier._metaRenderCache = {}

        metaKey = "(inaccessible)"
        try:
            metaKey = ctx.tag.children[0].strip()
            if (metaKey, plain) in carrier._metaRenderCache:
                rendered = carrier._metaRenderCache[(metaKey, plain)]

            else:
                htmlBuilder = common.HTMLMetaBuilder(self.macroPackage)

                if plain:
                    rendered = base.getMetaText(carrier,
                                                metaKey,
                                                raiseOnFail=True,
                                                macroPackage=self.macroPackage)

                else:
                    rendered = T.xml(
                        carrier.buildRepr(metaKey,
                                          htmlBuilder,
                                          raiseOnFail=True))

                carrier._metaRenderCache[(metaKey, plain)] = rendered

        except base.NoMetaKey:
            if raiseOnFail:
                raise
            return T.comment["Meta item %s not given." % metaKey]
        except Exception, ex:
            msg = "Meta %s bad (%s)" % (metaKey, str(ex))
            base.ui.notifyError(msg)
            return T.comment[msg]

        ctx.tag.clear()
        return ctx.tag[rendered]
Esempio n. 9
0
class ErrorPage(rend.Page, grend.GavoRenderMixin):
	"""A base for error handling pages.

	The idea is that you set the "handles" class attribute to 
	the exception you handle.  The exception has to match exactly, i.e.,
	no isinstancing is done.

	You also must set status to the HTTP status code the error should
	return.

	All error pages have a failure attribute that's a twisted failure
	with all the related mess (e.g., tracebacks).

	You have the status and message data methods.
	"""
	handles = None
	status = 500
	titleMessage = "Unspecified Error"
	beforeMessage = "We're sorry, but something didn't work out:"
	afterMessage = T.p["This generic text shouldn't be here. The child class should override afterMessage."]
#	_footer = "delete this when done"

	def __init__(self, error):
		self.failure = error

	def data_status(self, ctx, data):
		return str(self.status)

	def data_message(self, ctx, data):
		return self.failure.getErrorMessage()

	def render_beforeMessage(self, ctx, data):
		return ctx.tag[self.beforeMessage]

	def render_afterMessage(self, ctx, data):
		return ctx.tag[self.afterMessage]

	def render_message(self, ctx, data):
		return ctx.tag(class_="errmsg")[self.failure.getErrorMessage()]

	def render_hint(self, ctx, data):
		if (hasattr(self.failure.value, "hint") and self.failure.value.hint):
			return ctx.tag[T.strong["Hint: "], 
				self.failure.value.hint]
		return ""

	def render_rdlink(self, ctx, data):
		if hasattr(self.failure.value, "rd") and self.failure.value.rd:
			rdURL = base.makeAbsoluteURL("/browse/%s"%
				self.failure.value.rd.sourceId)
			return T.p(class_="rdbacklink")["Also see the ",
				T.a(href=rdURL)["resources provided by this RD"],
				"."]
		return ""
	
	def render_titlemessage(self, ctx, data):
		return ctx.tag["%s: %s"%(base.getConfig("web", "sitename"), self.titleMessage)]
	
	def render_footer(self, ctx, data):
		return ctx.tag[
			T.address[
				T.span["Contact us: "],
				T.a(href="mailto:%s"%config.getMeta("contact.email").getContent())[
					config.getMeta("contact.email").getContent()
				]
			]
		]

	def renderHTTP(self, ctx):
		request = inevow.IRequest(ctx)
		request.setResponseCode(self.status)
		return rend.Page.renderHTTP(self, ctx)

	docFactory = svcs.loadSystemTemplate("error.html")
Esempio n. 10
0
class AdminRenderer(formal.ResourceMixin, grend.CustomTemplateMixin,
                    grend.ServiceBasedPage):
    """A renderer allowing to block and/or reload services.

	This renderer could really be attached to any service since
	it does not call it, but it usually lives on //services/overview.  
	It will always require authentication.

	It takes the id of the RD to administer from the path segments
	following the renderer name.

	By virtue of builtin vanity, you can reach the admin renderer
	at /seffe, and thus you can access /seffe/foo/q to administer
	the foo/q RD.
	"""
    name = "admin"
    customTemplate = svcs.loadSystemTemplate("admin.html")
    clientRD = None
    # set below when RD loading failed.
    reloadExc = None
    reloadTB = None

    def form_setDowntime(self, ctx):
        form = formal.Form()
        form.addField(
            "scheduled",
            formal.String(),
            label="Schedule downtime for",
            description="Note that this is purely informative.  The server"
            " will not take down the services at this point in time."
            " Leave empty to cancel.  This will also be cleared on a"
            " reload.")
        form.addAction(self.setDowntime, label="Ok")
        form.data = {
            "scheduled": base.getMetaText(self.clientRD, "_scheduledDowntime")
        }
        return form

    def setDowntime(self, ctx, form, data):
        scheduleFor = data.get("scheduled")
        if scheduleFor is None:
            self.clientRD.delMeta("_scheduledDowntime")
        else:
            try:
                stc.parseISODT(scheduleFor)  # check syntax
                self.clientRD.setMeta("_scheduledDowntime", scheduleFor)
            except stc.STCLiteralError:  # bad date syntax
                raise base.ui.logOldExc(
                    formal.FieldError("Doesn't look like ISO", "scheduleFor"))

    def form_adminOps(self, ctx):
        form = formal.Form()
        if hasattr(self.clientRD, "currently_blocked"):
            label = "Unblock"
        else:
            label = "Block"
        form.addAction(self.toggleBlock, label=label, name="block")
        form.addAction(self.reloadRD, label="Reload RD", name="submit")
        return form

    def toggleBlock(self, ctx, form, data):
        if hasattr(self.clientRD, "currently_blocked"):
            delattr(self.clientRD, "currently_blocked")
        else:
            self.clientRD.currently_blocked = True

    def reloadRD(self, ctx, form, data):
        # XXX TODO: load the supposedly changed RD here and raise errors before
        # booting out the old stuff.
        base.caches.clearForName(self.clientRD.sourceId)

    def data_blockstatus(self, ctx, data):
        if hasattr(self.clientRD, "currently_blocked"):
            return "blocked"
        return "not blocked"

    def data_services(self, ctx, data):
        """returns a sequence of service items belonging to clientRD, sorted
		by id.
		"""
        return sorted(self.clientRD.services)

    def render_svclink(self, ctx, data):
        """renders a link to a service info with a service title.
		
		data must be an item returned from data_services.
		"""
        return ctx.tag(href=data.getURL("info"))[base.getMetaText(
            data, "title")]

    def render_rdId(self, ctx, data):
        return ctx.tag[self.clientRD.sourceId]

    def render_ifexc(self, ctx, data):
        """render children if there was an exception during RD load.
		"""
        if self.reloadExc is None:
            return ""
        else:
            return ctx.tag

    def render_exc(self, ctx, data):
        return ctx.tag[repr(self.reloadExc)]

    def render_traceback(self, ctx, data):
        return ctx.tag[self.reloadTB]

    def renderHTTP(self, ctx):
        # naked renderer means admin services itself
        if self.clientRD is None:
            self.clientRD = base.caches.getRD("__system__/services")
        return common.runAuthenticated(ctx, "admin",
                                       super(AdminRenderer, self).renderHTTP,
                                       ctx)

    def _extractDamageInfo(self):
        """called when reload of RD failed; leaves exc. info in some attributes.
		"""
        type, value = sys.exc_info()[:2]
        self.reloadExc = value
        self.reloadTB = traceback.format_exc()

    # the locateChild here is actually the constructor, as it were --
    # each request gets a new AdminRender by web.root
    def locateChild(self, ctx, segments):
        rdId = "/".join(segments)
        try:
            self.clientRD = base.caches.getRD(rdId)
            if hasattr(self.clientRD, "getRealRD"):
                self.clientRD = self.clientRD.getRealRD()

            self.metaCarrier = self.clientRD
            self.macroPackage = self.clientRD
        except base.RDNotFound:
            raise base.ui.logOldExc(
                svcs.UnknownURI("No such resource descriptor: %s" % rdId))
        except Exception:  # RD is botched.  Clear cache and give an error
            base.caches.clearForName(rdId)
            self._extractDamageInfo()
        return self, ()

    defaultDocFactory = common.doctypedStan(
        T.html[T.head[T.title["Missing Template"]], T.body[T.p[
            "Admin services are only available with a admin.html template"]]])
Esempio n. 11
0
class Form(FormMixin, grend.CustomTemplateMixin, grend.HTMLResultRenderMixin,
           grend.ServiceBasedPage):
    """The "normal" renderer within DaCHS for web-facing services.

	It will display a form and allow outputs in various formats.

	It also does error reporting as long as that is possible within
	the form.
	"""
    name = "form"
    runOnEmptyInputs = False
    compute = True

    def __init__(self, ctx, service):
        grend.ServiceBasedPage.__init__(self, ctx, service)
        if "form" in self.service.templates:
            self.customTemplate = self.service.getTemplate("form")

        # enable special handling if I'm rendering fixed-behaviour services
        # (i.e., ones that never have inputs) XXX TODO: Figure out where I used this and fix that to use the fixed renderer (or whatever)
        if not self.service.getInputKeysFor(self):
            self.runOnEmptyInputs = True
        self.queryResult = None

    @classmethod
    def isBrowseable(self, service):
        return True

    @classmethod
    def isCacheable(self, segments, request):
        return segments == ()

    def renderHTTP(self, ctx):
        if self.runOnEmptyInputs:
            inevow.IRequest(ctx).args[formal.FORMS_KEY] = ["genForm"]
        return FormMixin.renderHTTP(self, ctx)

    def render_commonfoot(self, ctx, data):
        return self._footer

    def _formatOutput(self, res, ctx):
        """actually delivers the whole document.

		This is basically nevow's rend.Page._renderHTTP, changed to
		provide less blocks.
		"""
        request = inevow.IRequest(ctx)

        if isinstance(res.original, tuple):
            # core returned a complete document (mime and string)
            mime, payload = res.original
            request.setHeader("content-type", mime)
            request.setHeader(
                'content-disposition',
                'attachment; filename=result%s' % common.getExtForMime(mime))
            return streaming.streamOut(lambda f: f.write(payload), request)

        self.result = res
        if "response" in self.service.templates:
            self.customTemplate = self.service.getTemplate("response")

        ctx = context.PageContext(parent=ctx, tag=self)
        self.rememberStuff(ctx)
        doc = self.docFactory.load(ctx)
        ctx = context.WovenContext(ctx, T.invisible[doc])

        return deliverYielding(doc, ctx, request)

    defaultDocFactory = svcs.loadSystemTemplate("defaultresponse.html")
Esempio n. 12
0
class RDInfoPage(grend.CustomTemplateMixin, grend.ResourceBasedPage):
    """A page giving infos about an RD.

	This is not a renderer but a helper for RDInfoRenderer.
	"""
    customTemplate = svcs.loadSystemTemplate("rdinfo.html")

    def data_services(self, ctx, data):
        return sorted(self.rd.services,
                      key=lambda s: base.getMetaText(s, "title", default=s.id))

    def data_tables(self, ctx, data):
        return sorted(
            (t for t in self.rd.tables if t.onDisk and not t.temporary),
            key=lambda t: t.id)

    def data_clientRdId(self, ctx, data):
        return self.rd.sourceId

    def _getDescriptionHTML(self, descItem):
        """returns stan for the "description" of a service or a table.

		The RD's description is not picked up.
		"""
        iDesc = descItem.getMeta("description", propagate=False)
        if iDesc is None:
            return ""
        else:
            return T.div(class_="lidescription")[T.xml(
                iDesc.getContent("blockhtml", macroPackage=descItem))]

    def render_rdsvc(self, ctx, service):
        return ctx.tag[T.a(
            href=service.getURL("info")
        )[base.getMetaText(service, "title", default=service.id)],
                       self._getDescriptionHTML(service)]

    def render_rdtable(self, ctx, tableDef):
        qName = tableDef.getQName()

        adqlNote = ""
        if tableDef.adql:
            adqlNote = T.span(class_="adqlnote")[" ", E.ndash,
                                                 " queriable through ",
                                                 T.a(href="/tap")["TAP"],
                                                 " and ",
                                                 T.a(href="/adql")["ADQL"],
                                                 " "]

        return ctx.tag[T.a(href="/tableinfo/%s" % qName)[qName], adqlNote,
                       self._getDescriptionHTML(tableDef)]

    @classmethod
    def makePageTitle(cls, rd):
        """returns a suitable title for the rd info page.

		This is a class method to allow other renderers to generate
		titles for link anchors.
		"""
        return "Information on resource '%s'" % base.getMetaText(
            rd, "title", default="%s" % rd.sourceId)

    def render_title(self, ctx, data):
        return ctx.tag[self.makePageTitle(self.rd)]

    defaultDocFactory = common.doctypedStan(T.html[
        T.head[T.title["Missing Template"]], T.
        body[T.p["RD infos are only available with an rdinfo.html template"]]])
Esempio n. 13
0
class ServiceInfoRenderer(MetaRenderer, utils.IdManagerMixin):
    """A renderer showing all kinds of metadata on a service.

	This renderer produces the default referenceURL page.  To change its
	appearance, override the serviceinfo.html template.
	"""
    name = "info"

    customTemplate = svcs.loadSystemTemplate("serviceinfo.html")

    def __init__(self, *args, **kwargs):
        grend.ServiceBasedPage.__init__(self, *args, **kwargs)
        self.describingRD = self.service.rd
        self.footnotes = set()

    def render_title(self, ctx, data):
        return ctx.tag["Information on Service '%s'" %
                       base.getMetaText(self.service, "title")]

    def render_notebubble(self, ctx, data):
        if not data["note"]:
            return ""
        id = data["note"].tag
        self.footnotes.add(data["note"])
        return ctx.tag(href="#note-%s" % id)["Note %s" % id]

    def render_footnotes(self, ctx, data):
        """renders the footnotes as a definition list.
		"""
        return T.dl(class_="footnotes")[[
            T.xml(note.getContent(targetFormat="html"))
            for note in sorted(self.footnotes, key=lambda n: n.tag)
        ]]

    def data_internalpath(self, ctx, data):
        return "%s/%s" % (self.service.rd.sourceId, self.service.id)

    def data_inputFields(self, ctx, data):
        res = [
            f.asInfoDict() for f in self.service.getInputKeysFor("info") +
            self.service.serviceKeys
        ]
        res.sort(key=lambda val: val["name"].lower())
        return res

    def data_htmlOutputFields(self, ctx, data):
        res = [f.asInfoDict() for f in self.service.getCurOutputFields()]
        res.sort(key=lambda val: val["name"].lower())
        return res

    def data_votableOutputFields(self, ctx, data):
        queryMeta = svcs.QueryMeta({"_FORMAT": "VOTable", "_VERB": 3})
        res = [
            f.asInfoDict() for f in self.service.getCurOutputFields(queryMeta)
        ]
        res.sort(key=lambda val: val["verbLevel"])
        return res

    def data_rendAvail(self, ctx, data):
        return [{
            "rendName": rend,
            "rendExpl": RendExplainer.explain(rend, self.service)
        } for rend in self.service.allowed]

    def data_publications(self, ctx, data):
        res = [{
            "sets": ",".join(p.sets),
            "render": p.render
        } for p in self.service.publications if p.sets]
        return sorted(res, key=lambda v: v["render"])

    def data_browserURL(self, ctx, data):
        return self.service.getBrowserURL()

    def data_service(self, ctx, data):
        return self.service

    defaultDocFactory = common.doctypedStan(
        T.html[T.head[T.title["Missing Template"]], T.body[
            T.p["Infos are only available with a serviceinfo.html template"]]])