def __init__(self, ctx, graph, uri, **kw): """ uri is the whole page load (relative) uri """ self.graph, self.uri = graph, uri agent = getUser(ctx) self.desc = ImageSetDesc(graph, agent, uri)
def testAltUrlTurnsStarToAll(self): s = ImageSetDesc(graph1, None, "/set?tag=t") self.assertEqual(s.altUrl(star='all'), "/set?tag=t") s = ImageSetDesc(graph1, None, "/set?tag=t&star=only") self.assertEqual(s.altUrl(star='all'), "/set?tag=t") s = ImageSetDesc(graph1, None, "/set?tag=t&star=all") self.assertEqual(s.altUrl(star='all'), "/set?tag=t")
def agentImageSetCheck(graph, agent, photo): """ does this agent (or one of its classes) have permission to view some imageset that (currently) includes the image? returns an imageset URI or None """ for res in maySee(graph, agent): if 'bigasterisk.com/openidProxySite' in res: # some other statements about permissions got in the # graph; it's wasting time to check them as images continue log.debug("%r can see %r - is the pic in that set?", agent, res) try: imgSet = ImageSetDesc(graph, agent, res) except ValueError: # includes permissions for things that aren't photos at all continue if imgSet.includesPhoto(photo): return maySee return None
def expandPhotos(graph, user, subject): """ returns the set of images that this subject refers to, plus a short description of the set subject can be a photo itself, some search query, a topic, etc """ # this may be redundant with what ImageSetDesc does with one photo? if graph.contains((subject, RDF.type, FOAF.Image)): return [subject], "this photo" #URIRef('http://photo.bigasterisk.com/set?current=http%3A%2F%2Fphoto.bigasterisk.com%2Femail%2F2010-11-15%2FP1010194.JPG&dir=http%3A%2F%2Fphoto.bigasterisk.com%2Femail%2F2010-11-15%2F') pics = ImageSetDesc(graph, user, subject).photos() if len(pics) == 1: return pics, "this photo" else: return pics, "these %s photos" % len(pics)
class ImageSet(rend.Page): """ multiple images, with one currently-featured one. Used for search results """ docFactory = loaders.xmlfile("imageSet.html") @print_timing def __init__(self, ctx, graph, uri, **kw): """ uri is the whole page load (relative) uri """ self.graph, self.uri = graph, uri agent = getUser(ctx) self.desc = ImageSetDesc(graph, agent, uri) @print_timing def renderHTTP(self, ctx): req = inevow.IRequest(ctx) if (req.getHeader('accept') == 'application/json' and not ctx.arg("jsonUpdate") and not ctx.arg('setList')): # approximage parse return self.jsonContent() if req.method == 'POST': if ctx.arg('tagRange'): return self.postTagRange(ctx) raise ValueError("unknown action") if ctx.arg('rss'): # can't use a /rss child, since we're not receiving # segments anymore here. That's probably going to be a # problem later, but rss=1 is ok today. return self.photoRss(ctx) if ctx.arg('archive') == 'zip': request = inevow.IRequest(ctx) ua = request.getHeader('User-agent') if 'Googlebot' in ua or 'Yahoo! Slurp' in ua or 'http://search.msn.com/msnbot.htm' in ua: raise ValueError("bots, you don't want these huge zip files") return self.archiveZip(ctx) view = View(self.graph, self.desc, params=dict(date=ctx.arg('date'), star=ctx.arg('star')), cookie=req.getHeader("cookie") or '', agent=getUser(ctx), openidProxyHeader=req.getHeader('x-openid-proxy'), forwardedFor=req.getHeader('x-forwarded-for')) if ctx.arg("jsonUpdate"): req.setHeader("Content-Type", "application/json") return json.dumps(self.templateData(view)) if ctx.arg("setList"): req.setHeader("Content-Type", "application/json") return json.dumps(view.photosInSetPlus()) ret = Renderer(search_dirs=['template/']).render(view) print "rendered view is %s" % len(ret) # after 65k, this gets truncated somewhere! get a new web server req.setHeader("Content-Type", "text/html") return ret.encode('utf8') def templateData(self, view): def v(keys): return dict((k, getattr(view, k)()) for k in keys) return { 'topBar' : v("setLabel storyModeUrl intro".split()), 'featured' : v("currentLabel currentImgJson prevNextDateButtons stepButtons featured actionsAllowed aclWidget uploadButton publicShareButton otherSizeLinks link debugRdf localPath".split()), 'featuredMeta' : v("facts allowedToWriteMeta currentImgJson".split()), # this one should be omitted when the client already had the right set 'photosInSet' : v(" starLinkAll starLinkOnly photosInSet setAclWidget".split()), 'pageJson' : v(["pageJson"]), # putting comments in here too would be nice # maybe spell out the images that will be needed for this page, for the preload queue? } def jsonContent(self): return json.dumps({'photos' : self.desc.photos()}) def archiveZip(self, ctx): raise NotImplementedError("bitrotted- needs fixing") f = StringIO('') zf = zipfile.ZipFile(f, 'w', zipfile.ZIP_DEFLATED) for photo in self.desc.photos(): data, mtime = thumb(photo, maxSize=Full) zf.writestr(str(photo.split('/')[-1]), data) zf.close() request = inevow.IRequest(ctx) request.setHeader("Content-Type", "multipart/x-zip") downloadFilename = self.desc.topic.split('/')[-1] + ".zip" request.setHeader("Content-Disposition", "attachment; filename=%s" % downloadFilename.encode('ascii')) return f.getvalue() def postTagRange(self, ctx): # security? p = self.desc.photos() i1 = p.index(URIRef(ctx.arg('start'))) i2 = p.index(URIRef(ctx.arg('end'))) newUri = URIRef(ctx.arg('uri')) imgStatements = [(img, FOAF.depicts, newUri) for img in p[i1:i2+1]] if (ctx.arg('label') or '').strip(): imgStatements.append((newUri, RDFS.label, Literal(ctx.arg('label')))) writeStatements([ (newUri, RDF.type, URIRef(ctx.arg('rdfClass'))), #(newUri, DC.created, Literal now ] + imgStatements) return json.dumps({ "msg": "tagged %s images: <a href=\"%s\">view your new set</a>" % (len(imgStatements), newUri) }) def photoRss(self, ctx): request = inevow.IRequest(ctx) # this should be making atom! # it needs to return the most recent pics, with a link to the next set! # copied from what flickr emits request.setHeader("Content-Type", "text/xml; charset=utf-8") items = [T.Tag('title')["bigasterisk %s photos" % self.desc.determineLabel(self.desc.graph, self.desc.topicDict)]] for pic in self.desc.photos()[-50:]: # no plan yet for the range. use paging i guess items.append(T.Tag('item')[ T.Tag('title')[self.graph.label(pic, default=pic.split('/')[-1])], T.Tag('link')[absoluteSite(pic) + '?size=screen'], T.Tag('description')[ '<a href="%s"><img src="%s" /></a>' % (absoluteSite(pic) + '?size=large', absoluteSite(pic) + '?size=thumb')], T.Tag('media:thumbnail')(url=absoluteSite(pic) + '?size=small'), T.Tag('media:content')(url=absoluteSite(pic) + '?size=screen'), ]) return """<?xml version="1.0" encoding="utf-8" standalone="yes"?> <rss version="2.0" xmlns:media="http://search.yahoo.com/mrss" xmlns:atom="http://www.w3.org/2005/Atom"> <channel> """ + flat.flatten(items) + """
class ImageSet(rend.Page): """ multiple images, with one currently-featured one. Used for search results """ docFactory = loaders.xmlfile("imageSet.html") @print_timing def __init__(self, ctx, graph, uri, **kw): """ uri is the whole page load (relative) uri """ self.graph, self.uri = graph, uri agent = getUser(ctx) self.desc = ImageSetDesc(graph, agent, uri) @print_timing def renderHTTP(self, ctx): req = inevow.IRequest(ctx) if (req.getHeader('accept') == 'application/json' and not ctx.arg("jsonUpdate") and not ctx.arg('setList')): # approximage parse return self.jsonContent() if req.method == 'POST': if ctx.arg('tagRange'): return self.postTagRange(ctx) raise ValueError("unknown action") if ctx.arg('rss'): # can't use a /rss child, since we're not receiving # segments anymore here. That's probably going to be a # problem later, but rss=1 is ok today. return self.photoRss(ctx) if ctx.arg('archive') == 'zip': request = inevow.IRequest(ctx) ua = request.getHeader('User-agent') or '' if 'Googlebot' in ua or 'Yahoo! Slurp' in ua or 'http://search.msn.com/msnbot.htm' in ua: raise ValueError("bots, you don't want these huge zip files") return self.archiveZip(ctx) view = View(self.graph, self.desc, params=dict(date=ctx.arg('date'), star=ctx.arg('star')), cookie=req.getHeader("cookie") or '', agent=getUser(ctx), openidProxyHeader=req.getHeader('x-openid-proxy'), forwardedFor=req.getHeader('x-forwarded-for')) if ctx.arg("jsonUpdate"): req.setHeader("Content-Type", "application/json") return json.dumps(self.templateData(view)) if ctx.arg("setList"): req.setHeader("Content-Type", "application/json") return json.dumps(view.photosInSetPlus()) ret = Renderer(search_dirs=['template/']).render(view) print "rendered view is %s" % len(ret) # after 65k, this gets truncated somewhere! get a new web server req.setHeader("Content-Type", "text/html") return ret.encode('utf8') def templateData(self, view): def v(keys): return dict((k, getattr(view, k)()) for k in keys) return { 'topBar': v("setLabel storyModeUrl intro".split()), 'featured': v("currentLabel currentImgJson prevNextDateButtons stepButtons featured actionsAllowed aclWidget uploadButton publicShareButton otherSizeLinks link debugRdf localPath" .split()), 'featuredMeta': v("facts allowedToWriteMeta currentImgJson".split()), # this one should be omitted when the client already had the right set 'photosInSet': v(" starLinkAll starLinkOnly photosInSet setAclWidget".split()), 'pageJson': v(["pageJson"]), # putting comments in here too would be nice # maybe spell out the images that will be needed for this page, for the preload queue? } def jsonContent(self): return json.dumps({'photos': self.desc.photos()}) def archiveZip(self, ctx): raise NotImplementedError("bitrotted- needs fixing") f = StringIO('') zf = zipfile.ZipFile(f, 'w', zipfile.ZIP_DEFLATED) for photo in self.desc.photos(): data, mtime = thumb(photo, maxSize=Full) zf.writestr(str(photo.split('/')[-1]), data) zf.close() request = inevow.IRequest(ctx) request.setHeader("Content-Type", "multipart/x-zip") downloadFilename = self.desc.topic.split('/')[-1] + ".zip" request.setHeader( "Content-Disposition", "attachment; filename=%s" % downloadFilename.encode('ascii')) return f.getvalue() def postTagRange(self, ctx): # security? p = self.desc.photos() i1 = p.index(URIRef(ctx.arg('start'))) i2 = p.index(URIRef(ctx.arg('end'))) newUri = URIRef(ctx.arg('uri')) imgStatements = [(img, FOAF.depicts, newUri) for img in p[i1:i2 + 1]] if (ctx.arg('label') or '').strip(): imgStatements.append( (newUri, RDFS.label, Literal(ctx.arg('label')))) writeStatements([ (newUri, RDF.type, URIRef(ctx.arg('rdfClass'))), #(newUri, DC.created, Literal now ] + imgStatements) return json.dumps({ "msg": "tagged %s images: <a href=\"%s\">view your new set</a>" % (len(imgStatements), newUri) }) def photoRss(self, ctx): request = inevow.IRequest(ctx) # this should be making atom! # it needs to return the most recent pics, with a link to the next set! # copied from what flickr emits request.setHeader("Content-Type", "text/xml; charset=utf-8") items = [ T.Tag('title')["bigasterisk %s photos" % self.desc.determineLabel( self.desc.graph, self.desc.topicDict)] ] for pic in self.desc.photos( )[-50:]: # no plan yet for the range. use paging i guess items.append( T.Tag('item')[ T.Tag('title')[self.graph. label(pic, default=pic.split('/')[-1])], T.Tag('link')[absoluteSite(pic) + '?size=screen'], T.Tag('description')['<a href="%s"><img src="%s" /></a>' % (absoluteSite(pic) + '?size=large', absoluteSite(pic) + '?size=thumb')], T.Tag('media:thumbnail')(url=absoluteSite(pic) + '?size=small'), T.Tag('media:content')(url=absoluteSite(pic) + '?size=screen'), ]) return """<?xml version="1.0" encoding="utf-8" standalone="yes"?> <rss version="2.0" xmlns:media="http://search.yahoo.com/mrss" xmlns:atom="http://www.w3.org/2005/Atom"> <channel> """ + flat.flatten(items) + """
def testCanonicalErrorsOnRandomParam(self): s = ImageSetDesc(graph1, None, "/set?random=10") self.assertRaises(ValueError, s.canonicalSetUri)
def testCanonicalOmitsCurrentParam(self): s = ImageSetDesc(graph1, None, "/set?tag=t¤t=foo") self.assertEqual(s.canonicalSetUri(), SITE["set?tag=t"])
def testCanonicalIncludesStarParam(self): s = ImageSetDesc(graph1, None, "/set?dir=http%3A%2F%2Fexample.com%2Fd1&star=only") self.assertEqual( s.canonicalSetUri(), SITE["set?dir=http%3A%2F%2Fexample.com%2Fd1&star=only"])
def testCanonicalIncludesDateParam(self): s = ImageSetDesc(graph1, None, "/set?date=2010-11-20") self.assertEqual(s.canonicalSetUri(), SITE["set?date=2010-11-20"])
def testCanonicalIncludesDirParam(self): s = ImageSetDesc(graph1, None, "/set?dir=http%3A%2F%2Fexample.com%2Fd1¤t=foo") self.assertEqual(s.canonicalSetUri(), SITE["set?dir=http%3A%2F%2Fexample.com%2Fd1"])
def testCanonicalIncludesStarParam(self): s = ImageSetDesc(graph1, None, "/set?dir=http%3A%2F%2Fexample.com%2Fd1&star=only") self.assertEqual(s.canonicalSetUri(), SITE["set?dir=http%3A%2F%2Fexample.com%2Fd1&star=only"])