diff options
Diffstat (limited to 'misc/dashboard/godashboard')
-rw-r--r-- | misc/dashboard/godashboard/package.py | 184 | ||||
-rw-r--r-- | misc/dashboard/godashboard/project-edit.html | 10 | ||||
-rw-r--r-- | misc/dashboard/godashboard/project-notify.txt | 2 | ||||
-rw-r--r-- | misc/dashboard/godashboard/toutf8.py | 14 |
4 files changed, 153 insertions, 57 deletions
diff --git a/misc/dashboard/godashboard/package.py b/misc/dashboard/godashboard/package.py index 6c3bd9995..cf59bf3e8 100644 --- a/misc/dashboard/godashboard/package.py +++ b/misc/dashboard/godashboard/package.py @@ -17,6 +17,7 @@ from google.appengine.ext.webapp import template from google.appengine.ext.webapp.util import run_wsgi_app from google.appengine.api import users from google.appengine.api import mail +from google.appengine.api import urlfetch import binascii import datetime import hashlib @@ -29,6 +30,11 @@ import time import urllib2 import sets +# local imports +import toutf8 + +template.register_template_library('toutf8') + # Storage model for package info recorded on server. # Just path, count, and time of last install. class Package(db.Model): @@ -50,36 +56,91 @@ re_bitbucket = re.compile(r'^bitbucket\.org/[a-z0-9A-Z_.\-]+/[a-z0-9A-Z_.\-]+$') re_googlecode = re.compile(r'^[a-z0-9\-]+\.googlecode\.com/(svn|hg)$') re_github = re.compile(r'^github\.com/[a-z0-9A-Z_.\-]+/[a-z0-9A-Z_.\-]+$') +def vc_to_web(path): + if re_bitbucket.match(path): + check_url = 'http://' + path + '/?cmd=heads' + web = 'http://' + path + '/' + elif re_github.match(path): + # github doesn't let you fetch the .git directory anymore. + # fetch .git/info/refs instead, like git clone would. + check_url = 'http://'+path+'.git/info/refs' + web = 'http://' + path + elif re_googlecode.match(path): + check_url = 'http://'+path + web = 'http://code.google.com/p/' + path[:path.index('.')] + else: + return False, False + return web, check_url + +re_bitbucket_web = re.compile(r'bitbucket\.org/([a-z0-9A-Z_.\-]+)/([a-z0-9A-Z_.\-]+)') +re_googlecode_web = re.compile(r'code.google.com/p/([a-z0-9\-]+)') +re_github_web = re.compile(r'github\.com/([a-z0-9A-Z_.\-]+)/([a-z0-9A-Z_.\-]+)') +re_striphttp = re.compile(r'http://(www\.)?') + +def web_to_vc(url): + url = re_striphttp.sub('', url) + m = re_bitbucket_web.match(url) + if m: + return 'bitbucket.org/'+m.group(1)+'/'+m.group(2) + m = re_github_web.match(url) + if m: + return 'github.com/'+m.group(1)+'/'+m.group(2) + m = re_googlecode_web.match(url) + if m: + path = m.group(1)+'.googlecode.com/' + # perform http request to path/hg to check if they're using mercurial + vcs = 'svn' + try: + response = urlfetch.fetch('http://'+path+'hg', deadline=1) + if response.status_code == 200: + vcs = 'hg' + except: pass + return path + vcs + return False + MaxPathLength = 100 +CacheTimeout = 3600 class PackagePage(webapp.RequestHandler): def get(self): if self.request.get('fmt') == 'json': return self.json() - q = Package.all() - q.order('-last_install') - by_time = q.fetch(100) + html = memcache.get('view-package') + if not html: + q = Package.all() + q.order('-last_install') + by_time = q.fetch(100) - q = Package.all() - q.order('-count') - by_count = q.fetch(100) + q = Package.all() + q.order('-count') + by_count = q.fetch(100) - self.response.headers['Content-Type'] = 'text/html; charset=utf-8' - path = os.path.join(os.path.dirname(__file__), 'package.html') - self.response.out.write(template.render(path, {"by_time": by_time, "by_count": by_count})) + self.response.headers['Content-Type'] = 'text/html; charset=utf-8' + path = os.path.join(os.path.dirname(__file__), 'package.html') + html = template.render( + path, + {"by_time": by_time, "by_count": by_count} + ) + memcache.set('view-package', html, time=CacheTimeout) + + self.response.out.write(html) def json(self): - self.response.set_status(200) - self.response.headers['Content-Type'] = 'text/plain; charset=utf-8' - q = Package.all() - s = '{"packages": [' - sep = '' - for r in q.fetch(1000): - s += '%s\n\t{"path": "%s", "last_install": "%s", "count": "%s"}' % (sep, r.path, r.last_install, r.count) - sep = ',' - s += '\n]}\n' - self.response.out.write(s) + json = memcache.get('view-package-json') + if not json: + self.response.set_status(200) + self.response.headers['Content-Type'] = 'text/plain; charset=utf-8' + q = Package.all() + s = '{"packages": [' + sep = '' + for r in q.fetch(1000): + s += '%s\n\t{"path": "%s", "last_install": "%s", "count": "%s"}' % (sep, r.path, r.last_install, r.count) + sep = ',' + s += '\n]}\n' + json = s + memcache.set('view-package-json', json, time=CacheTimeoout) + self.response.out.write(json) def can_get_url(self, url): try: @@ -104,18 +165,8 @@ class PackagePage(webapp.RequestHandler): p = Package.get_by_key_name(key) if p is None: # not in datastore - verify URL before creating - if re_bitbucket.match(path): - check_url = 'http://' + path + '/?cmd=heads' - web = 'http://' + path + '/' - elif re_github.match(path): - # github doesn't let you fetch the .git directory anymore. - # fetch .git/info/refs instead, like git clone would. - check_url = 'http://'+path+'.git/info/refs' - web = 'http://' + path - elif re_googlecode.match(path): - check_url = 'http://'+path - web = 'http://code.google.com/p/' + path[:path.index('.')] - else: + web, check_url = vc_to_web(path) + if not web: logging.error('unrecognized path: %s', path) return False if not self.can_get_url(check_url): @@ -150,9 +201,27 @@ class ProjectPage(webapp.RequestHandler): self.redirect(users.create_logout_url("/project")) elif self.request.path == "/project/edit" and admin: self.edit() + elif self.request.path == "/project/assoc" and admin: + self.assoc() else: self.list() + def assoc(self): + projects = Project.all() + for p in projects: + if p.package: + continue + path = web_to_vc(p.web_url) + if not path: + continue + pkg = Package.get_by_key_name("pkg-"+path) + if not pkg: + self.response.out.write('no: %s %s<br>' % (p.web_url, path)) + continue + p.package = pkg + p.put() + self.response.out.write('yes: %s %s<br>' % (p.web_url, path)) + def post(self): if self.request.path == "/project/edit": self.edit(True) @@ -177,30 +246,40 @@ class ProjectPage(webapp.RequestHandler): self.list({"submitMsg": "Your project has been submitted."}) - def list(self, data={}): - projects = Project.all().order('category').order('name') - - admin = users.is_current_user_admin() - if not admin: - projects = projects.filter('approved =', True) - - projects = list(projects) - - tags = sets.Set() - for p in projects: - for t in p.tags: - tags.add(t) - - tag = self.request.get("tag", None) + def list(self, additional_data={}): + cache_key = 'view-project-data' + tag = self.request.get('tag', None) if tag: - projects = filter(lambda x: tag in x.tags, projects) + cache_key += '-'+tag + data = memcache.get(cache_key) + admin = users.is_current_user_admin() + if admin or not data: + projects = Project.all().order('category').order('name') + if not admin: + projects = projects.filter('approved =', True) + projects = list(projects) + + tags = sets.Set() + for p in projects: + for t in p.tags: + tags.add(t) + + if tag: + projects = filter(lambda x: tag in x.tags, projects) + + data = {} + data['tag'] = tag + data['tags'] = tags + data['projects'] = projects + data['admin']= admin + if not admin: + memcache.set(cache_key, data, time=CacheTimeout) + + for k, v in additional_data.items(): + data[k] = v self.response.headers['Content-Type'] = 'text/html; charset=utf-8' path = os.path.join(os.path.dirname(__file__), 'project.html') - data["tag"] = tag - data["tags"] = tags - data["projects"] = projects - data["admin"] = admin self.response.out.write(template.render(path, data)) def edit(self, save=False): @@ -228,7 +307,8 @@ class ProjectPage(webapp.RequestHandler): p.approved = self.request.get("approved") == "1" p.tags = filter(lambda x: x, self.request.get("tags", "").split(",")) p.put() - self.redirect("/project") + memcache.delete('view-project-data') + self.redirect('/project') return # get all project categories and tags diff --git a/misc/dashboard/godashboard/project-edit.html b/misc/dashboard/godashboard/project-edit.html index 5f1ca3b11..ce18fb3fb 100644 --- a/misc/dashboard/godashboard/project-edit.html +++ b/misc/dashboard/godashboard/project-edit.html @@ -1,11 +1,11 @@ <html> <head> +<link href="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8/themes/base/jquery-ui.css" rel="stylesheet" type="text/css"/> <script type="text/javascript" src="http://www.google.com/jsapi"></script> <script> google.load("jquery", "1"); +google.load("jqueryui", "1.8.2"); </script> -<script type="text/javascript" src="/static/jquery.autocomplete.min.js"></script> -<link rel="stylesheet" type="text/css" href="/static/jquery.autocomplete.css" /> </head> <body> <form action="/project/edit?orig_name={{p.name}}" method="POST"> @@ -38,8 +38,10 @@ var cats = [ {% endfor %} ]; -$('#tags').autocomplete(tags); -$('#cats').autocomplete(cats); +google.setOnLoadCallback(function() { + $('#tags').autocomplete({source:tags}); + $('#cats').autocomplete({source:cats}); +}); </script> </body> </html> diff --git a/misc/dashboard/godashboard/project-notify.txt b/misc/dashboard/godashboard/project-notify.txt index 3a165908c..f55bf6421 100644 --- a/misc/dashboard/godashboard/project-notify.txt +++ b/misc/dashboard/godashboard/project-notify.txt @@ -5,5 +5,5 @@ Description: {{project.descr}} URL: {{project.web_url}} To edit/approve/delete: -http://godashboard.appspot.com/project/edit?name={{project.name|urlencode}} +http://godashboard.appspot.com/project/edit?name={{project.name|toutf8|urlencode}} diff --git a/misc/dashboard/godashboard/toutf8.py b/misc/dashboard/godashboard/toutf8.py new file mode 100644 index 000000000..544c681b6 --- /dev/null +++ b/misc/dashboard/godashboard/toutf8.py @@ -0,0 +1,14 @@ +# Copyright 2010 The Go Authors. All rights reserved. +# Use of this source code is governed by a BSD-style +# license that can be found in the LICENSE file. + +# This is a Django custom template filter to work around the +# fact that GAE's urlencode filter doesn't handle unicode strings. + +from google.appengine.ext import webapp + +register = webapp.template.create_template_register() + +@register.filter +def toutf8(value): + return value.encode("utf-8") |