Ejemplo n.º 1
0
	def get_comment(self, page, comment):
		if not self.comments_on():
			return None
		if page.type != 'file' or not page.displayable():
			return None
		compath = utils.pjoin(page.path, comment)
		po = self._commentpage(compath)
		if not po or po.type != "file" or not po.displayable():
			raise derrors.IntErr("missing or undisplayable comment '%s' on page '%s'" % (comment, page))
		c = model_comment.loadcomment(po, comment)
		if c is None:
			raise derrors.IntErr("misformatted comment '%s' on '%s'" % (comment, page.path))
		return c
Ejemplo n.º 2
0
	def get_template(self, tname, fail_on_error = True):
		to = self.tstore.get(tname)
		if not to and fail_on_error:
			raise derrors.IntErr("request for fully bogus template: "+tname)
		elif not to:
			return None
		return validate_template(to, fail_on_error, tname)
Ejemplo n.º 3
0
 def newblob(self, where, blobstr):
     if not self.validname(where):
         raise derrors.IntErr("bad commentstore name: '%s'" % where)
     loc = join2(self.root, where)
     try:
         if not os.path.isdir(loc):
             makedirs(loc)
     except EnvironmentError as e:
         raise derrors.IOErr("could not make directory '%s': %s" %
                             (loc, str(e)))
     objname = self.blobname(blobstr)
     pname = join2(loc, objname)
     phase = "create"
     try:
         fd = os.open(pname, os.O_CREAT | os.O_EXCL | os.O_WRONLY, 0644)
         phase = "write"
         os.write(fd, blobstr)
         os.close(fd)
     except EnvironmentError as e:
         # It exists already, so we 'succeeded' as it were.
         if phase == "create" and os.path.exists(pname):
             return True
         raise derrors.IOErr("could not %s file '%s': %s" %
                             (phase, pname, str(e)))
     return True
Ejemplo n.º 4
0
def blogview(context):
    """Generate a Blog rendering of the current directory: all
	descendant real pages, from most recent to oldest, possibly
	truncated at a day boundary if there's 'too many', and sets
	up information for blog navigation renderers. Each
	displayed page is rendered with the _blog/blogentry.tmpl_
	template. Supports VirtualDirectory restrictions."""
    if context.page.type != "dir":
        return ''
    if not context.page.displayable():
        raise derrors.IntErr("undisplayable directory page")

    # This automatically applies restrictions.
    dl = context.cache_page_children(context.page)
    if not dl:
        return ''
    dl = clipDown(context, dl)

    # For each file, clone the context, set the current page to
    # it (!), and render it with the blogentry template.
    to = context.model.get_template("blog/blogentry.tmpl")

    # Set up our rolling storage. We can't hook directly onto
    # the context, because we drop the context after every
    # entry. So we write our own dictionary into the context.
    context.setvar(rollvar, {})
    res = []
    rootpath = context.page.me().path
    dupDict = {}
    for ts, path in dl:
        # Skip redirects and other magic files.
        # We go whole hog and drop anything that is not a real page,
        # which subsumes both redirect pages and non-displayable
        # pages. Since attempting to render a non-displayable page
        # is a fatal internal error, we must drop them before we
        # go to the template.
        np = context.model.get_page(path)
        if not np.realpage() or np.is_util():
            continue
        # Suppress multiple occurrences of the same page as
        # may happen with, eg, hardlinks. Note that this is
        # slightly questionable; macros mean that a file's
        # rendering output may depend on not just its contents
        # but its position in the file hierarchy. We don't
        # care.
        pageid = np.identity()
        if pageid in dupDict:
            continue
        else:
            dupDict[pageid] = True
        # Note: we do not reset the view type, because we do
        # not render through the interface that cares; we go
        # straight to template.
        nc = context.clone_to_page(np)
        nc.setvar('relname', path[len(rootpath) + 1:])
        res.append(template.Template(to).render(nc))
        context.newtime(nc.modtime)
    return ''.join(res)
Ejemplo n.º 5
0
def genScopeRange(ctuple):
	if ctuple[1]:
		sday, daynum = calendar.monthrange(ctuple[0], ctuple[1])
		return [("%d" % x, (ctuple[0], ctuple[1], x)) for x in
			range(1, daynum+1)]
	elif ctuple[0]:
		return [(months[x][:3], (ctuple[0], x+1, None)) for x in
			range(0, 12)]
	else:
		raise derrors.IntErr("genScopeRange doesn't do years")
Ejemplo n.º 6
0
	def subst(self, mo):
		what = mo.group(1)[0]
		if what == '$':
			return self.variable(mo)
		elif what == '@':
			return self.renderer(mo)
		elif what == '%':
			return self.cond_renderer(mo)
		elif what == '#':
			return self.include(mo)
		else:
			raise derrors.IntErr("unknown template operation: "+mo.group(1))
Ejemplo n.º 7
0
 def timeof(self, zone, host, path, key="default"):
     self.validate_quad(zone, host, path, key)
     key = key + '~'
     dname = os.path.sep.join([self.root, zone, host, path])
     fname = join2(dname, key)
     st = self.getStat(fname)
     if not st:
         return None
     elif not stat.S_ISREG(st.st_mode):
         raise derrors.IntErr(
             "not a regular file in cachestore: '%s' '%s' '%s' '%s'" %
             (zone, host, path, key))
     else:
         return st.st_mtime
Ejemplo n.º 8
0
def restrict(context, suffix):
	for k, rex in restMatches.items():
		mo = rex.match(suffix)
		if mo:
			break
	if not mo:
		return False

	# We found something. The only tricky bit is setting up the
	# parameters.
	context.setvar(rest_type, k)

	if k == 'VirtStems':
		context.setvar(rest_type, mo.group(1))
		context.setvar(rest_val, defVals[mo.group(1)])
	elif k == 'latest' or k == 'oldest':
		context.setvar(rest_val, int(mo.group(1)))
	elif k == 'calendar':
		cv = []
		for g in mo.groups():
			if g:
				cv.append(int(g))
			else:
				cv.append(None)
		# reject bad month or days; the latter is approximate.
		# if we don't do this we can run into exceptions in
		# the calendar module later.
		if (cv[1] is not None and (cv[1] == 0 or cv[1] > 12)) or \
		   (cv[2] is not None and (cv[2] == 0 or cv[2] > 31)):
			context.delvar(rest_type)
			return False
		context.setvar(rest_val, tuple(cv))
	elif k == 'range':
		# We're easy on this one; you can specify anything you
		# like.
		one = int(mo.group(1))
		two = int(mo.group(2))
		if one > two:
			two, one = one, two
		if one == 0:
			# This guarantees both one and two are positive,
			# since two is >= one.
			one += 1
			two += 1
		context.setvar(rest_val, (one, two))
	else:
		raise derrors.IntErr("unhandled restriction match: "+k)
	return True
Ejemplo n.º 9
0
	def fromstore(self, fileobj, name):
		blob = fileobj.contents()
		if not blob:
			raise derrors.IntErr("CommentV1 fromstore blob is empty")
		mo = commentv1_re.match(blob)
		if not mo:
			return False
		self.user = mo.group(1)
		self.anon = mo.group(2)
		self.username = mo.group(3).strip()
		self.userurl = mo.group(4).strip()
		self.ip = mo.group(5)
		self.data = mo.group(6)
		self.time = fileobj.timestamp()
		self.name = name
		return True
Ejemplo n.º 10
0
	def get_commentlist(self, page):
		if not self.comments_on():
			return []
		# An undisplayable page turns off its comments.
		if page.type != "file" or not page.displayable():
			return []
		po = self._commentpage(page.path)
		if not po:
			return []
		# Safety check:
		if po.type != "dir":
			raise derrors.IntErr("comment fileobj for '%s' not a directory" % page)
		# This is safe by our axioms; we know that this must be
		# only have files, so we will get a list of comments that
		# the page has.
		return po.contents()
Ejemplo n.º 11
0
def blogdir(context):
    """Generate a BlogDir rendering of the current directory:
	display all real pages in the current directory from most
	recent to oldest, rendering each with the template
	_blog/blogdirpage.tmpl_. Supports VirtualDirectory restrictions."""
    if context.page.type != "dir":
        return ''
    if not context.page.displayable():
        raise derrors.IntErr("undisplayable directory page")
    dl = context.page.children("file")
    if not dl:
        return ''
    # Boil it down to just files, in modtime order.
    # (Technically this is real files: displayable, non-redirect.)
    dl = [z for z in dl if z.realpage() and not z.is_util()]
    # This directory might have nothing.
    if not dl:
        return ''

    # Apply restrictions, backwardly.
    # Because restrictions are designed to be hugely scalable, they
    # want the output we'd get from page.descendants().
    if pageranges.is_restriction(context):
        tl = pageranges.filter_files(context,
                                     [(z.timestamp, z.path) for z in dl])
        if not tl:
            return ''
        dl = [context.model.get_page(z[1]) for z in tl]
    else:
        dl.sort(key=lambda x: x.timestamp, reverse=True)

    # For each file, clone the context, set the current page to
    # it (!), and render it with the blogentry template.
    to = context.model.get_template("blog/blogdirpage.tmpl")
    context.setvar(rollvar, {})
    res = []
    for page in dl:
        # Note: we do not reset the view type, because we do
        # not render through the interface that cares; we go
        # straight to template.
        nc = context.clone_to_page(page)
        res.append(template.Template(to).render(nc))
        context.newtime(nc.modtime)
    return ''.join(res)
Ejemplo n.º 12
0
    def fetch(self, zone, host, path, key="default", TTL=None):
        self.validate_quad(zone, host, path, key)
        key = key + '~'
        fname = os.path.sep.join([self.root, zone, host, path, key])
        st = self.getStat(fname)
        now = time.time()
        if not st:
            return None
        elif not stat.S_ISREG(st.st_mode):
            raise derrors.IntErr(
                "not a regular file in cachestore: '%s' '%s' '%s' '%s'" %
                (zone, host, path, key))
        elif TTL and (st.st_mtime + TTL) < now:
            return None

        # Finally we can get and retrieve the cached file.
        # Cached file objects are always depickled before
        # getting returned. (We use FileObjs because they
        # handle a number of details for us.)
        #
        # Rather than cache the depickled objects, which may
        # be mutated by later people, we cache the file object
        # data and depickle each time.
        if fname not in self.cache:
            fo = FileObj(fname, st, "rb")
            data = fo.contents()
        else:
            data = self.cache[fname]

        if not data:
            # This might be: empty file, no-permissions file,
            # and probably others. None are severe enough to
            # kill us.
            return None

        ro = cPickle.loads(data)
        if self.cache_on:
            self.cache[fname] = data
        return ro
Ejemplo n.º 13
0
def loadcomment(fileobj, name):
	blob = fileobj.contents()
	if not blob:
		return None
	mo = commentver_re.match(blob)
	# might be a version zero comment.
	if not mo:
		mo = commentbody_re.match(blob)
		if mo:
			c = Comment()
		else:
			return None
	elif mo.group(1) == "1":
		c = CommentV1()
	else:
		raise derrors.IntErr("Uknown comment format version: '%s' in %s" %
				     (mo.group(1), name))

	# Load:
	if c.fromstore(fileobj, name):
		return c
	else:
		return None
Ejemplo n.º 14
0
def titleindex(context):
    """Like _blog::blog_, except that instead of rendering entries
	through a template, it just displays a table of dates and entry
	titles (or relative paths for entries without titles), linking
	to entries and to the day pages. Respects VirtualDirectory
	restrictions. Unlike _blog::blog_, it always displays information
	for all applicable entries."""
    if context.page.type != "dir":
        return ''
    if not context.page.displayable():
        raise derrors.IntErr("undisplayable directory page")

    # This automatically applies restrictions.
    dl = context.cache_page_children(context.page)
    if not dl:
        return ''

    # Building a table is unfortunately much more complicated
    # than a <dl> would be, because we have to use <br> to separate
    # multiple entries for the same day instead of <td>, which means
    # that we have to keep track of when we need to generate one and
    # so on.
    rl = [
        '<table class="blogtitles">\n',
    ]
    lday = None
    dupDict = {}
    rootpath = context.page.me().path
    # Rather than directly use a wikirend routine by importing
    # it, we indirect through the renderer registration. Since
    # either way we know a wikirend name, I figure this is no
    # worse.
    rfunc = htmlrends.get_renderer("wikitext:title:nolinks")
    for ts, path in dl:
        # FIXME: this duplication is code smell.
        np = context.model.get_page(path)
        if not np.realpage() or np.is_util() or \
           not np.access_ok(context):
            continue
        pageid = np.identity()
        if pageid in dupDict:
            continue
        else:
            dupDict[pageid] = None

        # Do we need to generate a new row for a new day?
        # Our basic running state is that we are always in
        # a <td> for page links (except right at the start),
        # so we must close it off et cetera and then reopen
        # it.
        t = time.localtime(ts)
        plain = "%d-%02d-%02d" % (t.tm_year, t.tm_mon, t.tm_mday)
        if plain != lday:
            if lday:
                # Not first entry ever, so close off
                # the last day table row.
                rl.append("\n</td> </tr>\n")
            rl.append("<tr> <td> %s: </td> <td>\n" % \
               link_to_tm(context, t, plain))
            lday = plain
        else:
            # If we are the second or later entry for a
            # given day, we must put a <br> between ourselves
            # and the previous entry.
            rl.append("<br>\n")

        # As usual, we must work in a new context.
        nc = context.clone_to_page(np)
        ltitle = rfunc(nc)
        if not ltitle:
            ltitle = httputil.quotehtml(path[len(rootpath) + 1:])
        # We can't use htmlrends.makelink() because that would
        # quote the live HTML in real titles.
        rl.append('    <a href="%s">%s</a>' % \
           (context.nurl(np), ltitle))
        context.newtime(nc.modtime)
    # Done all; close off the <table>
    rl.append('\n</td></tr></table>\n')
    return ''.join(rl)
Ejemplo n.º 15
0
 def get(self, relname, missIsNone=False):
     __pychecker__ = "no-argsused"
     raise derrors.IntErr("using get on a cachestore")