From a06ab5c1eb2053d33e15244ea579875aa72c0c1f Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Tue, 16 Aug 2011 15:35:59 -0500 Subject: Tabs -> spaces in templates Signed-off-by: Dan McGee --- templates/public/about.html | 2 +- templates/public/index.html | 4 ++-- templates/public/svn.html | 18 +++++++++--------- 3 files changed, 12 insertions(+), 12 deletions(-) (limited to 'templates/public') diff --git a/templates/public/about.html b/templates/public/about.html index 0e0601e8..bf38e8a1 100644 --- a/templates/public/about.html +++ b/templates/public/about.html @@ -3,7 +3,7 @@ {% block content %}

About Arch Linux

-

+

Arch Linux is an independently developed, i686/x86-64 general purpose GNU/Linux distribution versatile enough to suit any role. Development focuses on simplicity, minimalism, and code elegance. Arch is installed as a diff --git a/templates/public/index.html b/templates/public/index.html index add921d1..e68943c8 100644 --- a/templates/public/index.html +++ b/templates/public/index.html @@ -82,7 +82,7 @@

Recent Updates ( {{ update.pkgbase }} {{ update.version }} - + {% for pkg in update.package_links %}{{ pkg.arch }}{% if not forloop.last %}/{% endif %}{% endfor %} @@ -161,7 +161,7 @@

Development

title="Developer Wiki articles">DeveloperWiki
  • Todo Lists
  • -
  • Releng Testbuild Feedback
  • diff --git a/templates/public/svn.html b/templates/public/svn.html index dd175bcc..aedd9a73 100644 --- a/templates/public/svn.html +++ b/templates/public/svn.html @@ -7,25 +7,25 @@

    SVN Repositories

    The PKGBUILD files can be fetched via the ABS utility. To learn more about ABS, see the ABS wiki page.

    -

    The SVN repositories have been cloned into git repositories and can be - viewed via the cgit interface. - All - packages are available here except for - community - and multilib which are available in a different repository.

    +

    The SVN repositories have been cloned into git repositories and can be + viewed via the cgit interface. + All + packages are available here except for + community + and multilib which are available in a different repository.

    You can also get individual PKGBUILDs directly from SVN. This can be especially useful if you need to compile an older version of a package. DO NOT CHECK OUT THE ENTIRE SVN REPO. Your address may be blocked. Use the following commands to check out a specific package: -

    +

    svn checkout --depth=empty svn://svn.archlinux.org/packages
     cd packages
     svn update <your-package-name>
    - For the community and multilib repositories, use the following commands - instead: + For the community and multilib repositories, use the following commands + instead:
    svn checkout --depth=empty svn://svn.archlinux.org/community
     cd community
     svn update <your-package-name>
    -- cgit v1.2.3-54-g00ecf From a4895f06680beaf447ed43ee326423fcc8232815 Mon Sep 17 00:00:00 2001 From: Olivier Keun Date: Fri, 22 Jul 2011 16:25:57 +0200 Subject: News frontpage layout changes Signed-off-by: Dan McGee --- media/archweb.css | 21 ++++++++++++++++----- public/views.py | 2 +- templates/public/index.html | 31 +++++++++++++++++++++++++++---- 3 files changed, 44 insertions(+), 10 deletions(-) (limited to 'templates/public') diff --git a/media/archweb.css b/media/archweb.css index 85fdb610..ce1ece1d 100644 --- a/media/archweb.css +++ b/media/archweb.css @@ -21,7 +21,7 @@ p { margin: .33em 0 1em; } ol, ul { margin-bottom: 1em; padding-left: 2em; } ul { list-style: square; } code { font: 1.2em monospace; background: #ffd; padding: 0.15em 0.25em; } -pre { font: 1.2em monospace; border: 1px solid #bdb; background: #dfd; padding: 0.5em; margin: 0.25em 2em; } +pre { font: 1.2em monospace; border: 1px solid #bdb; background: #dfd; padding: 0.5em; margin: 1em; } pre code { display: block; background: none; } blockquote { margin: 1.5em 2em; } input { vertical-align: middle; } @@ -44,7 +44,7 @@ a:active { color: #e90; } /* headings */ h2 { font-size: 1.5em; margin-bottom: 0.5em; border-bottom: 1px solid #888; } -h3 { font-size: 1.25em; margin-top: 1em; } +h3 { font-size: 1.25em; margin-top: .5em; } h4 { font-size: 1.15em; margin-top: 1em; } h5 { font-size: 1em; margin-top: 1em; } @@ -76,6 +76,12 @@ table.pretty2 { width: auto; margin-top: 0.25em; margin-bottom: 0.5em; border-co table.pretty2 th { padding: 0.35em; background: #eee; border: 1px solid #bbb; } table.pretty2 td { padding: 0.35em; border: 1px dotted #bbb; } +/* definition lists */ +dl { clear:both; } +dl dt, +dl dd { margin-bottom:4px; padding: 8px 0px 4px; font-weight:bold; border-top:1px solid #888; } +dl dt { color: #333; float:left; padding-right:15px; } + /* forms and input styling */ form p { margin: 0.5em 0; } fieldset { border: 0; } @@ -105,14 +111,19 @@ ul.errorlist { color: red; } /* home: news */ #news { margin-top: 1.5em; } -#news h3 { border-bottom: 1px solid #888; } +#news h3 { float:left; padding-bottom: .5em } #news div { margin-bottom: 1em; } #news div p { margin-bottom: 0.5em; } #news .more { font-weight: normal; } -#news .rss-icon { float: right; margin: -1.6em 0.4em 0 0; } -#news h4 { font-size: 1em; margin-top: 1.5em; border-bottom: 1px dotted #bbb; } +#news .rss-icon { float: right; margin-top: 1em; } +#news h4 { clear:both; font-size: 1em; margin-top: 1.5em; border-bottom: 1px dotted #bbb; } #news .timestamp { float: right; font-size: 0.85em; margin: -1.8em 0.5em 0 0; } +/* home: arrowed headings */ +#news h3 a { display: block; background: #1794D1; font-size: 15px; padding: 2px 10px; color: white; } +#news a:active { color: white; } +h3 span.arrow { display: block; width: 0px; height: 0px; border-left: 6px solid transparent; border-right: 6px solid transparent; border-top: 6px solid #1794D1; margin: 0 auto; font-size: 0px; line-height: 0px; } + /* home: pkgsearch box */ #pkgsearch { padding: 1em 0.75em; background: #3ad; color: #fff; border: 1px solid #08b; } #pkgsearch label { width: auto; padding: 0.1em 0; } diff --git a/public/views.py b/public/views.py index 46291b88..e3f3b02f 100644 --- a/public/views.py +++ b/public/views.py @@ -13,7 +13,7 @@ def index(request): pkgs = utils.get_recent_updates() context = { - 'news_updates': News.objects.order_by('-postdate', '-id')[:10], + 'news_updates': News.objects.order_by('-postdate', '-id')[:15], 'pkg_updates': pkgs, } return direct_to_template(request, 'public/index.html', context) diff --git a/templates/public/index.html b/templates/public/index.html index e68943c8..c8b6def0 100644 --- a/templates/public/index.html +++ b/templates/public/index.html @@ -40,17 +40,40 @@

    A simple, lightweight distribution

    -

    Latest News (more)

    +

    + Latest News + +

    RSS Feed {% for news in news_updates %} -

    {{ news.title }}

    + {% if forloop.counter0 < 5 %} +

    + {{ news.title }} +

    {{ news.postdate|date }}

    {{ news.content|markdown|truncatewords_html:75 }}
    + {% else %} + {% if forloop.counter0 == 5 %} +

    + Older News + +

    +
    + {% endif %} +
    {{ news.postdate|date }}
    +
    + {{ news.title }} +
    + {% if forloop.last %} +
    + {% endif %} + {% endif %} {% endfor %}
    -- cgit v1.2.3-54-g00ecf From 6bc2b84516c93ef84799671c51d9a51d46b5570f Mon Sep 17 00:00:00 2001 From: Thomas Bächler Date: Fri, 19 Aug 2011 19:14:22 +0200 Subject: download: update to new 2011.08.19 release Signed-off-by: Dan McGee --- templates/public/download.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'templates/public') diff --git a/templates/public/download.html b/templates/public/download.html index 8bd2e2db..78a2f964 100644 --- a/templates/public/download.html +++ b/templates/public/download.html @@ -9,7 +9,7 @@

    Arch Linux Downloads

    - {% with "2010.05" as version %} + {% with "2011.08.19" as version %}

    Release Info

    All available images can be burned to a CD, mounted as an ISO file, @@ -19,7 +19,7 @@

    Release Info

    +

    Test ISO Info

    + +

    We provide daily snapshot ISOs. Those are largely untested, + but may be more up to date than the releases.

    +

    HTTP/FTP Direct Downloads

    -- cgit v1.2.3-54-g00ecf From 2ed3676f61af821e71a5c070e65419cd60906cb8 Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Tue, 23 Aug 2011 17:17:30 -0500 Subject: Escape parameter to search AUR link Addresses FS#25732. Signed-off-by: Dan McGee --- templates/packages/search.html | 2 +- templates/public/index.html | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'templates/public') diff --git a/templates/packages/search.html b/templates/packages/search.html index 8a357024..4744aa88 100644 --- a/templates/packages/search.html +++ b/templates/packages/search.html @@ -156,7 +156,7 @@

    Package Search

    We couldn't find any packages matching your query. Try searching again using different criteria, or try {% if search_form.q.data %} - searching the AUR + searching the AUR {% else %}searching the AUR{% endif %} to see if the package can be found there.

    diff --git a/templates/public/index.html b/templates/public/index.html index c8b6def0..bea19e0f 100644 --- a/templates/public/index.html +++ b/templates/public/index.html @@ -20,7 +20,7 @@

    A simple, lightweight distribution

    Currently we have official packages optimized for the i686 and x86-64 architectures. We complement our official package sets with a - + community-operated package repository that grows in size and quality each and every day.

    -- cgit v1.2.3-54-g00ecf From d5063bd1d2cae79df7ce6e826c7413fed61ff9db Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Wed, 5 Oct 2011 15:45:44 -0500 Subject: Add package visualizations page Why the hell not? Have fun clicking all the pretty buttons. Signed-off-by: Dan McGee --- media/archweb.css | 27 ++++++++++ media/visualize.js | 112 +++++++++++++++++++++++++++++++++++++++++ settings.py | 1 + templates/public/index.html | 8 +-- templates/visualize/index.html | 43 ++++++++++++++++ urls.py | 1 + visualize/__init__.py | 0 visualize/models.py | 0 visualize/tests.py | 0 visualize/urls.py | 9 ++++ visualize/views.py | 59 ++++++++++++++++++++++ 11 files changed, 256 insertions(+), 4 deletions(-) create mode 100644 media/visualize.js create mode 100644 templates/visualize/index.html create mode 100644 visualize/__init__.py create mode 100644 visualize/models.py create mode 100644 visualize/tests.py create mode 100644 visualize/urls.py create mode 100644 visualize/views.py (limited to 'templates/public') diff --git a/media/archweb.css b/media/archweb.css index 0cadd7a7..eb0f0ca1 100644 --- a/media/archweb.css +++ b/media/archweb.css @@ -948,3 +948,30 @@ ul.admin-actions { #archnavbar.anb-download ul li#anb-download a { color: white !important; } + +/* visualizations page */ +.visualize-buttons { + margin: 0.5em 0.33em; +} + + .visualize-buttons button.active { + depressed: true; + } + +.visualize-chart { + position: relative; + height: 500px; + margin: 0.33em; +} + +#visualize-archrepo .treemap-cell { + border: solid 1px white; + overflow: hidden; + position: absolute; +} + + #visualize-archrepo .treemap-cell span { + padding: 3px; + font-size: 0.85em; + line-height: 1em; + } diff --git a/media/visualize.js b/media/visualize.js new file mode 100644 index 00000000..c1ea598b --- /dev/null +++ b/media/visualize.js @@ -0,0 +1,112 @@ +function packages_treemap(chart_id, orderings, default_order) { + var jq_div = $(chart_id), + color = d3.scale.category20(); + key_func = function(d) { return d.key; }, + value_package_count = function(d) { return d.count; }; + + var treemap = d3.layout.treemap() + .size([jq_div.width(), jq_div.height()]) + /*.sticky(true)*/ + .value(value_package_count) + .sort(function(a, b) { return a.key < b.key; }) + .children(function(d) { return d.data; }); + + var cell_html = function(d) { + if (d.children) { + return ""; + } + return "" + d.name + ": " + treemap.value()(d) + ""; + }; + + var d3_div = d3.select(jq_div.get(0)); + + var prop_px = function(prop, offset) { + return function(d) { + var dist = d[prop] + offset; + if (dist > 0) return dist + "px"; + else return "0px"; + }; + }; + + var cell = function() { + /* the -1 offset comes from the border width we use in the CSS */ + this.style("left", prop_px("x", 0)).style("top", prop_px("y", 0)) + .style("width", prop_px("dx", -1)).style("height", prop_px("dy", -1)); + }; + + var fetch_for_ordering = function(order) { + d3.json(order.url, function(json) { + var nodes = d3_div.data([json]).selectAll("div").data(treemap.nodes, key_func); + /* start out new nodes in the center of the picture area */ + var w_center = jq_div.width() / 2; + var h_center = jq_div.height() / 2; + nodes.enter().append("div") + .attr("class", "treemap-cell") + .attr("title", function(d) { return d.name; }) + .style("left", w_center + "px").style("top", h_center + "px") + .style("width", "0px").style("height", "0px") + .style("display", function(d) { return d.children ? "none" : null; }) + .html(cell_html); + nodes.transition().duration(1500) + .style("background-color", function(d) { return d.children ? null : color(d[order.color_attr]); }) + .call(cell); + nodes.exit().transition().duration(1500).remove(); + }); + }; + + /* start the callback for the default order */ + fetch_for_ordering(orderings[default_order]); + + var make_scale_button = function(name, valuefunc) { + var button_id = chart_id + "-" + name; + /* upon button click, attach new value function and redraw all boxes + * accordingly */ + d3.select(button_id).on("click", function() { + d3_div.selectAll("div") + .data(treemap.value(valuefunc), key_func) + .html(cell_html) + .transition().duration(1500).call(cell); + + /* drop off the '#' sign to convert id to a class prefix */ + d3.selectAll("." + chart_id.substring(1) + "-scaleby") + .classed("active", false); + d3.select(button_id).classed("active", true); + }); + }; + + /* each scale button tweaks our value, e.g. net size function */ + make_scale_button("count", value_package_count); + make_scale_button("flagged", function(d) { return d.flagged; }); + make_scale_button("csize", function(d) { return d.csize; }); + make_scale_button("isize", function(d) { return d.isize; }); + + var make_group_button = function(name, order) { + var button_id = chart_id + "-" + name; + d3.select(button_id).on("click", function() { + fetch_for_ordering(order); + + /* drop off the '#' sign to convert id to a class prefix */ + d3.selectAll("." + chart_id.substring(1) + "-groupby") + .classed("active", false); + d3.select(button_id).classed("active", true); + }); + }; + + $.each(orderings, function(k, v) { + make_group_button(k, v); + }); + + var resize_timeout = null; + var real_resize = function() { + resize_timeout = null; + d3_div.selectAll("div") + .data(treemap.size([jq_div.width(), jq_div.height()]), key_func) + .call(cell); + }; + $(window).resize(function() { + if (resize_timeout) { + clearTimeout(resize_timeout); + } + resize_timeout = setTimeout(real_resize, 200); + }); +} diff --git a/settings.py b/settings.py index 18437098..51f9fcf6 100644 --- a/settings.py +++ b/settings.py @@ -109,6 +109,7 @@ 'public', 'south', # database migration support 'releng', + 'visualize', ) PGP_SERVER = 'pgp.mit.edu:11371' diff --git a/templates/public/index.html b/templates/public/index.html index bea19e0f..b63876ac 100644 --- a/templates/public/index.html +++ b/templates/public/index.html @@ -26,10 +26,10 @@

    A simple, lightweight distribution

    Our strong community is diverse and helpful, and we pride ourselves on the range of skillsets and uses for Arch that stem from it. Please - check out our forums + check out our forums and mailing lists - to get your feet wet. Also glance through our wiki if you want to learn more about Arch.

    @@ -174,8 +174,8 @@

    Development

    title="View/search the package repository database">Packages
  • Package Groups
  • -
  • Bug Tracker
  • +
  • Visualizations
  • SVN Repositories
  • + +

    Visualizations of Packaging Data

    + +

    Package Treemap

    + +
    +
    + Scale Using: + + + + +
    +
    + Group By: + + +
    +
    +
    + + +{% load cdn %}{% jquery %} + + + + + +{% endblock %} diff --git a/urls.py b/urls.py index c9faf165..cdae51bf 100644 --- a/urls.py +++ b/urls.py @@ -76,6 +76,7 @@ (r'^packages/', include('packages.urls')), (r'^releng/', include('releng.urls')), (r'^todo/', include('todolists.urls')), + (r'^visualize/', include('visualize.urls')), (r'^opensearch/packages/$', 'packages.views.opensearch', {}, 'opensearch-packages'), (r'^todolists/$','todolists.views.public_list'), diff --git a/visualize/__init__.py b/visualize/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/visualize/models.py b/visualize/models.py new file mode 100644 index 00000000..e69de29b diff --git a/visualize/tests.py b/visualize/tests.py new file mode 100644 index 00000000..e69de29b diff --git a/visualize/urls.py b/visualize/urls.py new file mode 100644 index 00000000..57ee0626 --- /dev/null +++ b/visualize/urls.py @@ -0,0 +1,9 @@ +from django.conf.urls.defaults import patterns + +urlpatterns = patterns('visualize.views', + (r'^$', 'index', {}, 'visualize-index'), + (r'^by_arch/$', 'by_arch', {}, 'visualize-byarch'), + (r'^by_repo/$', 'by_repo', {}, 'visualize-byrepo'), +) + +# vim: set ts=4 sw=4 et: diff --git a/visualize/views.py b/visualize/views.py new file mode 100644 index 00000000..68f5d4a5 --- /dev/null +++ b/visualize/views.py @@ -0,0 +1,59 @@ +from django.db.models import Count, Sum +from django.http import HttpResponse +from django.utils import simplejson +from django.views.decorators.cache import cache_page +from django.views.generic.simple import direct_to_template + +from main.models import Package, Arch, Repo + +def index(request): + return direct_to_template(request, 'visualize/index.html', {}) + +def arch_repo_data(): + qs = Package.objects.select_related().values( + 'arch__name', 'repo__name').annotate( + count=Count('pk'), csize=Sum('compressed_size'), + isize=Sum('installed_size'), + flagged=Count('flag_date')).order_by() + arches = Arch.objects.values_list('name', flat=True) + repos = Repo.objects.values_list('name', flat=True) + + # now transform these results into two mappings: one ordered (repo, arch), + # and one ordered (arch, repo). + arch_groups = dict((a, { 'name': a, 'key': ':%s' % a, 'arch': a, 'repo': None, 'data': [] }) for a in arches) + repo_groups = dict((r, { 'name': r, 'key': '%s:' % r, 'arch': None, 'repo': r, 'data': [] }) for r in repos) + for row in qs: + arch = row['arch__name'] + repo = row['repo__name'] + values = { + 'arch': arch, + 'repo': repo, + 'name': '%s (%s)' % (repo, arch), + 'key': '%s:%s' % (repo, arch), + 'csize': row['csize'], + 'isize': row['isize'], + 'count': row['count'], + 'flagged': row['flagged'], + } + arch_groups[arch]['data'].append(values) + repo_groups[repo]['data'].append(values) + + data = { + 'by_arch': { 'name': 'Architectures', 'data': arch_groups.values() }, + 'by_repo': { 'name': 'Repositories', 'data': repo_groups.values() }, + } + return data + +@cache_page(1800) +def by_arch(request): + data = arch_repo_data() + to_json = simplejson.dumps(data['by_arch'], ensure_ascii=False) + return HttpResponse(to_json, mimetype='application/json') + +@cache_page(1800) +def by_repo(request): + data = arch_repo_data() + to_json = simplejson.dumps(data['by_repo'], ensure_ascii=False) + return HttpResponse(to_json, mimetype='application/json') + +# vim: set ts=4 sw=4 et: -- cgit v1.2.3-54-g00ecf From 09ea244420a4f8687c9b0122d867dabc5d7d577c Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Tue, 1 Nov 2011 16:45:12 -0500 Subject: Update donation text and links We are finally set up through SPI and Click&Pledge. Add the necessary text, buttons, and links for our new donation home. Signed-off-by: Dan McGee --- media/donate.gif | Bin 2951 -> 0 bytes templates/public/donate.html | 37 ++++++++++--------------------------- templates/public/index.html | 25 ++++--------------------- 3 files changed, 14 insertions(+), 48 deletions(-) delete mode 100644 media/donate.gif (limited to 'templates/public') diff --git a/media/donate.gif b/media/donate.gif deleted file mode 100644 index d637428b..00000000 Binary files a/media/donate.gif and /dev/null differ diff --git a/templates/public/donate.html b/templates/public/donate.html index b5fc43df..0dcfcf2a 100644 --- a/templates/public/donate.html +++ b/templates/public/donate.html @@ -23,33 +23,16 @@

    Donate to Arch Linux

    Monetary donations

    -{% comment %} -

    Financial contributions are accepted via PayPal. - Funds are used for server hardware upgrades, conventions, schwag giveaways and more.

    - -
    - -
    -

    -

    -

    -

    -

    -

    -

    -

    -

    -

    -

    -
    -
    -{% endcomment %} -

    At the moment, we are currently not taking monetary donations, but we - may accept them again in the future.

    +

    Financial contributions are accepted via Click&Pledge. + Arch Linux is a member project of the + Software in the Public Interest, Inc. + non-profit corporation. Funds are used for hosting costs, server hardware + upgrades, and more. You are encouraged to learn more about the SPI, as well + as how donations work.

    + + + Online donation system by ClickandPledge +

    Commercial sponsors and contributions

    diff --git a/templates/public/index.html b/templates/public/index.html index b63876ac..06a6a0c3 100644 --- a/templates/public/index.html +++ b/templates/public/index.html @@ -206,28 +206,11 @@

    About

    -{% comment %} -
    - -
    -

    -

    -

    -

    -

    -

    -

    -

    -

    -

    -

    -
    - + -{% endcomment %}
    -- cgit v1.2.3-54-g00ecf From f26dcbf7285c62f0baa1c64ee813ad0ceff5c288 Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Tue, 1 Nov 2011 17:19:22 -0500 Subject: Use copy of donate image in /media/ This ensures it gets served over HTTPS if the user was on a secure session to begin with. Signed-off-by: Dan McGee --- templates/public/donate.html | 2 +- templates/public/index.html | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'templates/public') diff --git a/templates/public/donate.html b/templates/public/donate.html index 0dcfcf2a..514c1430 100644 --- a/templates/public/donate.html +++ b/templates/public/donate.html @@ -31,7 +31,7 @@

    Monetary donations

    as how donations work.

    - Online donation system by ClickandPledge + Donate via Click&Pledge to Arch Linux

    Commercial sponsors and contributions

    diff --git a/templates/public/index.html b/templates/public/index.html index 06a6a0c3..854bd447 100644 --- a/templates/public/index.html +++ b/templates/public/index.html @@ -208,7 +208,7 @@

    About

    -- cgit v1.2.3-54-g00ecf From 5b63c29fe1c37ce9d946adedeaf13f5ad94d144a Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Tue, 15 Nov 2011 14:03:36 -0600 Subject: Show full names on developer user list pages The old display format doesn't really make sense. Also fix the invalid HTML generated by the PGP tag link- we need to escape using & inside the generated URLs. Signed-off-by: Dan McGee --- main/templatetags/pgp.py | 2 +- media/archweb.css | 4 ++++ templates/public/developer_list.html | 2 +- templates/public/userlist.html | 2 -- 4 files changed, 6 insertions(+), 4 deletions(-) (limited to 'templates/public') diff --git a/main/templatetags/pgp.py b/main/templatetags/pgp.py index f875c11e..67f5e08d 100644 --- a/main/templatetags/pgp.py +++ b/main/templatetags/pgp.py @@ -21,7 +21,7 @@ def pgp_key_link(key_id): pgp_server = getattr(settings, 'PGP_SERVER', None) if not pgp_server: return format_key(key_id) - url = 'http://%s/pks/lookup?op=vindex&fingerprint=on&exact=on&search=0x%s' % \ + url = 'http://%s/pks/lookup?op=vindex&fingerprint=on&exact=on&search=0x%s' % \ (pgp_server, key_id) values = (url, format_key(key_id), key_id[-8:]) return '0x%s' % values diff --git a/media/archweb.css b/media/archweb.css index c5477422..f4bb92fa 100644 --- a/media/archweb.css +++ b/media/archweb.css @@ -802,6 +802,10 @@ div#arch-bio-toc { text-align: center; } + div#arch-bio-toc a { + white-space: nowrap; + } + table.arch-bio-entry td.pic { vertical-align: top; padding-right: 15px; diff --git a/templates/public/developer_list.html b/templates/public/developer_list.html index 2abbbfe4..0ac444e5 100644 --- a/templates/public/developer_list.html +++ b/templates/public/developer_list.html @@ -4,7 +4,7 @@

    {% for dev in dev_list %} - {{ dev.first_name }}{{ dev.last_name.0|capfirst}}    + {{ dev.first_name }} {{ dev.last_name }}    {% endfor %}

    diff --git a/templates/public/userlist.html b/templates/public/userlist.html index c51215c3..0077f611 100644 --- a/templates/public/userlist.html +++ b/templates/public/userlist.html @@ -6,7 +6,6 @@ {% block content %} {% cache 600 dev-tu-profiles user_type %}
    -

    Arch Linux {{user_type}}

    {{description}}

    @@ -14,7 +13,6 @@

    Arch Linux {{user_type}}

    {% with users as dev_list %} {% include 'public/developer_list.html' %} {% endwith %} -
    {% endcache %} {% endblock %} -- cgit v1.2.3-54-g00ecf From 85657db05d7f65604340699cfcb9967c9e81a0ef Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Mon, 21 Nov 2011 10:08:23 -0600 Subject: Better support for non-latin full names Add a 'latin_name' field to the user profile so we can better support those developers with names in non-Latin scripts, and yet still show a Latin name as necessary on the developer profile page. This field only shows up if populated. Also, use consistent sorting everywhere- rather than using username, always use first_name and last_name fields. Signed-off-by: Dan McGee --- devel/views.py | 2 +- .../0057_auto__add_field_userprofile_latin_name.py | 153 +++++++++++++++++++++ main/models.py | 2 + packages/views/search.py | 3 +- public/views.py | 6 +- templates/devel/clock.html | 2 +- templates/public/developer_list.html | 2 +- 7 files changed, 164 insertions(+), 6 deletions(-) create mode 100644 main/migrations/0057_auto__add_field_userprofile_latin_name.py (limited to 'templates/public') diff --git a/devel/views.py b/devel/views.py index 0002df04..08b19cd7 100644 --- a/devel/views.py +++ b/devel/views.py @@ -83,7 +83,7 @@ def index(request): @never_cache def clock(request): devs = User.objects.filter(is_active=True).order_by( - 'username').select_related('userprofile') + 'first_name', 'last_name').select_related('userprofile') now = datetime.now() utc_now = datetime.utcnow().replace(tzinfo=pytz.utc) diff --git a/main/migrations/0057_auto__add_field_userprofile_latin_name.py b/main/migrations/0057_auto__add_field_userprofile_latin_name.py new file mode 100644 index 00000000..ffde1885 --- /dev/null +++ b/main/migrations/0057_auto__add_field_userprofile_latin_name.py @@ -0,0 +1,153 @@ +# encoding: utf-8 +from south.db import db +from south.v2 import SchemaMigration +from django.db import models + +class Migration(SchemaMigration): + + def forwards(self, orm): + db.add_column('user_profiles', 'latin_name', self.gf('django.db.models.fields.CharField')(max_length=255, null=True, blank=True), keep_default=False) + + def backwards(self, orm): + db.delete_column('user_profiles', 'latin_name') + + models = { + 'auth.group': { + 'Meta': {'object_name': 'Group'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), + 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) + }, + 'auth.permission': { + 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'}, + 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) + }, + 'auth.user': { + 'Meta': {'object_name': 'User'}, + 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), + 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), + 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}), + 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) + }, + 'contenttypes.contenttype': { + 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, + 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) + }, + 'main.arch': { + 'Meta': {'ordering': "['name']", 'object_name': 'Arch', 'db_table': "'arches'"}, + 'agnostic': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}) + }, + 'main.donor': { + 'Meta': {'ordering': "('name',)", 'object_name': 'Donor', 'db_table': "'donors'"}, + 'created': ('django.db.models.fields.DateTimeField', [], {}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}), + 'visible': ('django.db.models.fields.BooleanField', [], {'default': 'True'}) + }, + 'main.package': { + 'Meta': {'ordering': "('pkgname',)", 'unique_together': "(('pkgname', 'repo', 'arch'),)", 'object_name': 'Package', 'db_table': "'packages'"}, + 'arch': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'packages'", 'to': "orm['main.Arch']"}), + 'build_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}), + 'compressed_size': ('main.models.PositiveBigIntegerField', [], {}), + 'epoch': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}), + 'filename': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'files_last_update': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), + 'flag_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'installed_size': ('main.models.PositiveBigIntegerField', [], {}), + 'last_update': ('django.db.models.fields.DateTimeField', [], {}), + 'packager': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True'}), + 'packager_str': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'pgp_signature': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'pkgbase': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), + 'pkgdesc': ('django.db.models.fields.TextField', [], {'null': 'True'}), + 'pkgname': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'pkgrel': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'pkgver': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'repo': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'packages'", 'to': "orm['main.Repo']"}), + 'url': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True'}) + }, + 'main.packagedepend': { + 'Meta': {'object_name': 'PackageDepend', 'db_table': "'package_depends'"}, + 'depname': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), + 'depvcmp': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '255'}), + 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'optional': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"}) + }, + 'main.packagefile': { + 'Meta': {'object_name': 'PackageFile', 'db_table': "'package_files'"}, + 'directory': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'filename': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_directory': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"}) + }, + 'main.repo': { + 'Meta': {'ordering': "['name']", 'object_name': 'Repo', 'db_table': "'repos'"}, + 'bugs_category': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}), + 'bugs_project': ('django.db.models.fields.SmallIntegerField', [], {'default': '1'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}), + 'staging': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'svn_root': ('django.db.models.fields.CharField', [], {'max_length': '64'}), + 'testing': ('django.db.models.fields.BooleanField', [], {'default': 'False'}) + }, + 'main.todolist': { + 'Meta': {'object_name': 'Todolist', 'db_table': "'todolists'"}, + 'creator': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}), + 'date_added': ('django.db.models.fields.DateTimeField', [], {'db_index': 'True'}), + 'description': ('django.db.models.fields.TextField', [], {}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}) + }, + 'main.todolistpkg': { + 'Meta': {'unique_together': "(('list', 'pkg'),)", 'object_name': 'TodolistPkg', 'db_table': "'todolist_pkgs'"}, + 'complete': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'list': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Todolist']"}), + 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"}) + }, + 'main.userprofile': { + 'Meta': {'object_name': 'UserProfile', 'db_table': "'user_profiles'"}, + 'alias': ('django.db.models.fields.CharField', [], {'max_length': '50'}), + 'allowed_repos': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['main.Repo']", 'symmetrical': 'False', 'blank': 'True'}), + 'favorite_distros': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'interests': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), + 'languages': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}), + 'latin_name': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), + 'location': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}), + 'notify': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'occupation': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}), + 'other_contact': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}), + 'pgp_key': ('main.models.PGPKeyField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'}), + 'picture': ('django.db.models.fields.files.FileField', [], {'default': "'devs/silhouette.png'", 'max_length': '100'}), + 'public_email': ('django.db.models.fields.CharField', [], {'max_length': '50'}), + 'roles': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), + 'time_zone': ('django.db.models.fields.CharField', [], {'default': "'UTC'", 'max_length': '100'}), + 'user': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'userprofile'", 'unique': 'True', 'to': "orm['auth.User']"}), + 'website': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}), + 'yob': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}) + } + } + + complete_apps = ['main'] diff --git a/main/models.py b/main/models.py index b37468f9..d7780b91 100644 --- a/main/models.py +++ b/main/models.py @@ -77,6 +77,8 @@ class UserProfile(models.Model): help_text="Ideally 125px by 125px") user = models.OneToOneField(User, related_name='userprofile') allowed_repos = models.ManyToManyField('Repo', blank=True) + latin_name = models.CharField(max_length=255, null=True, blank=True, + help_text="Latin-form name; used only for non-Latin full names") class Meta: db_table = 'user_profiles' diff --git a/packages/views/search.py b/packages/views/search.py index 57481614..65fcddb3 100644 --- a/packages/views/search.py +++ b/packages/views/search.py @@ -60,7 +60,8 @@ def __init__(self, *args, **kwargs): self.fields['arch'].choices = make_choice( [arch.name for arch in Arch.objects.all()]) self.fields['q'].widget.attrs.update({"size": "30"}) - maints = User.objects.filter(is_active=True).order_by('username') + maints = User.objects.filter(is_active=True).order_by( + 'first_name', 'last_name') self.fields['maintainer'].choices = \ [('', 'All'), ('orphan', 'Orphan')] + \ [(m.username, m.get_full_name()) for m in maints] diff --git a/public/views.py b/public/views.py index 14dd6353..c28fd303 100644 --- a/public/views.py +++ b/public/views.py @@ -34,13 +34,15 @@ def index(request): } def userlist(request, user_type='devs'): - users = User.objects.order_by('username').select_related('userprofile') + users = User.objects.order_by( + 'first_name', 'last_name').select_related('userprofile') if user_type == 'devs': users = users.filter(is_active=True, groups__name="Developers") elif user_type == 'tus': users = users.filter(is_active=True, groups__name="Trusted Users") elif user_type == 'fellows': - users = users.filter(is_active=False, groups__name__in=["Developers", "Trusted Users"]) + users = users.filter(is_active=False, + groups__name__in=["Developers", "Trusted Users"]) else: raise Http404 diff --git a/templates/devel/clock.html b/templates/devel/clock.html index 0f0e20c5..d2eb0a8d 100644 --- a/templates/devel/clock.html +++ b/templates/devel/clock.html @@ -45,7 +45,7 @@

    Developer World Clocks

    {% endblock %} diff --git a/templates/public/developer_list.html b/templates/public/developer_list.html index 0ac444e5..5aa4c6b2 100644 --- a/templates/public/developer_list.html +++ b/templates/public/developer_list.html @@ -21,7 +21,7 @@ - + -- cgit v1.2.3-54-g00ecf
    Name:{{ dev.get_full_name }}{{ dev.get_full_name }}{% if prof.latin_name %} ({{ prof.latin_name}}){% endif %}
    Alias: {{ prof.alias }}