From d009cd0b5c4ba018681942daa59452fe2b1a42c2 Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Tue, 21 Oct 2014 20:33:12 -0500 Subject: Fix error when viewing mirror with no active URLs Signed-off-by: Dan McGee --- mirrors/utils.py | 1 + mirrors/views.py | 2 ++ 2 files changed, 3 insertions(+) diff --git a/mirrors/utils.py b/mirrors/utils.py index 51daf50e..930adb8d 100644 --- a/mirrors/utils.py +++ b/mirrors/utils.py @@ -141,6 +141,7 @@ def get_mirror_statuses(cutoff=DEFAULT_CUTOFF, mirror_id=None, show_all=False): else: check_frequency = None else: + urls = [] last_check = None num_checks = 0 check_frequency = None diff --git a/mirrors/views.py b/mirrors/views.py index c2736da8..cffafbf5 100644 --- a/mirrors/views.py +++ b/mirrors/views.py @@ -193,6 +193,8 @@ def mirror_details(request, name): def mirror_details_json(request, name): authorized = request.user.is_authenticated() mirror = get_object_or_404(Mirror, name=name) + if not authorized and (not mirror.public or not mirror.active): + raise Http404 status_info = get_mirror_statuses(mirror_id=mirror.id, show_all=authorized) data = status_info.copy() -- cgit v1.2.3 From abb3a507a1e8f218b5225d3e00187808e323e48a Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Tue, 21 Oct 2014 21:12:24 -0500 Subject: Move all homepage JavaScript into single file We had two small files plus a handful of inline stuff in the HTML; move as much of it as possible into a single static file. Signed-off-by: Dan McGee --- sitestatic/bootstrap-typeahead.min.js | 1 - sitestatic/homepage.js | 42 +++++++++++++++++++++++++++++++++++ templates/public/index.html | 38 +------------------------------ 3 files changed, 43 insertions(+), 38 deletions(-) delete mode 100644 sitestatic/bootstrap-typeahead.min.js create mode 100644 sitestatic/homepage.js diff --git a/sitestatic/bootstrap-typeahead.min.js b/sitestatic/bootstrap-typeahead.min.js deleted file mode 100644 index 7d555ed9..00000000 --- a/sitestatic/bootstrap-typeahead.min.js +++ /dev/null @@ -1 +0,0 @@ -!function(e){"use strict";var t=function(t,n){this.$element=e(t),this.options=e.extend({},e.fn.typeahead.defaults,n),this.matcher=this.options.matcher||this.matcher,this.sorter=this.options.sorter||this.sorter,this.highlighter=this.options.highlighter||this.highlighter,this.updater=this.options.updater||this.updater,this.$menu=e(this.options.menu).appendTo("body"),this.source=this.options.source,this.shown=!1,this.listen()};t.prototype={constructor:t,select:function(){var e=this.$menu.find(".active").attr("data-value");return e&&this.$element.val(this.updater(e)).change(),this.hide()},updater:function(e){return e},show:function(){var t=e.extend({},this.$element.offset(),{height:this.$element[0].offsetHeight});return this.$menu.css({top:t.top+t.height,left:t.left}),this.$menu.show(),this.shown=!0,this},hide:function(){return this.$menu.hide(),this.shown=!1,this},lookup:function(t){var n;return this.query=this.$element.val(),!this.query||this.query.length"+t+""})},render:function(t){var n=this;return t=e(t).map(function(t,r){return t=e(n.options.item).attr("data-value",r),t.find("a").html(n.highlighter(r)),t[0]}),this.$menu.html(t),this},next:function(t){var n=this.$menu.find(".active").removeClass("active"),r=n.next();r.length||(r=e(this.$menu.find("li")[0])),r.addClass("active")},prev:function(e){var t=this.$menu.find(".active").removeClass("active"),n=t.prev();n.length||(n=this.$menu.find("li").last()),n.addClass("active")},listen:function(){this.$element.on("blur",e.proxy(this.blur,this)).on("keypress",e.proxy(this.keypress,this)).on("keyup",e.proxy(this.keyup,this)),(e.browser.chrome||e.browser.webkit||e.browser.msie)&&this.$element.on("keydown",e.proxy(this.keydown,this)),this.$menu.on("click",e.proxy(this.click,this)).on("mouseenter","li",e.proxy(this.mouseenter,this))},move:function(e){if(!this.shown)return;switch(e.keyCode){case 9:case 13:case 27:e.preventDefault();break;case 38:e.preventDefault(),this.prev();break;case 40:e.preventDefault(),this.next()}e.stopPropagation()},keydown:function(t){this.suppressKeyPressRepeat=!~e.inArray(t.keyCode,[40,38,9,13,27]),this.move(t)},keypress:function(e){if(this.suppressKeyPressRepeat)return;this.move(e)},keyup:function(e){switch(e.keyCode){case 40:case 38:break;case 9:case 13:if(!this.shown)return;this.select();break;case 27:if(!this.shown)return;this.hide();break;default:this.lookup()}e.stopPropagation(),e.preventDefault()},blur:function(e){var t=this;setTimeout(function(){t.hide()},150)},click:function(e){e.stopPropagation(),e.preventDefault(),this.select()},mouseenter:function(t){this.$menu.find(".active").removeClass("active"),e(t.currentTarget).addClass("active")}},e.fn.typeahead=function(n){return this.each(function(){var r=e(this),i=r.data("typeahead"),s=typeof n=="object"&&n;i||r.data("typeahead",i=new t(this,s)),typeof n=="string"&&i[n]()})},e.fn.typeahead.defaults={source:[],items:8,menu:'',item:'
  • ',minLength:1},e.fn.typeahead.Constructor=t,e(function(){e("body").on("focus.typeahead.data-api",'[data-provide="typeahead"]',function(t){var n=e(this);if(n.data("typeahead"))return;t.preventDefault(),n.typeahead(n.data())})})}(window.jQuery) \ No newline at end of file diff --git a/sitestatic/homepage.js b/sitestatic/homepage.js new file mode 100644 index 00000000..48dab93f --- /dev/null +++ b/sitestatic/homepage.js @@ -0,0 +1,42 @@ +!function(e){"use strict";var t=function(t,n){this.$element=e(t),this.options=e.extend({},e.fn.typeahead.defaults,n),this.matcher=this.options.matcher||this.matcher,this.sorter=this.options.sorter||this.sorter,this.highlighter=this.options.highlighter||this.highlighter,this.updater=this.options.updater||this.updater,this.$menu=e(this.options.menu).appendTo("body"),this.source=this.options.source,this.shown=!1,this.listen()};t.prototype={constructor:t,select:function(){var e=this.$menu.find(".active").attr("data-value");return e&&this.$element.val(this.updater(e)).change(),this.hide()},updater:function(e){return e},show:function(){var t=e.extend({},this.$element.offset(),{height:this.$element[0].offsetHeight});return this.$menu.css({top:t.top+t.height,left:t.left}),this.$menu.show(),this.shown=!0,this},hide:function(){return this.$menu.hide(),this.shown=!1,this},lookup:function(t){var n;return this.query=this.$element.val(),!this.query||this.query.length"+t+""})},render:function(t){var n=this;return t=e(t).map(function(t,r){return t=e(n.options.item).attr("data-value",r),t.find("a").html(n.highlighter(r)),t[0]}),this.$menu.html(t),this},next:function(t){var n=this.$menu.find(".active").removeClass("active"),r=n.next();r.length||(r=e(this.$menu.find("li")[0])),r.addClass("active")},prev:function(e){var t=this.$menu.find(".active").removeClass("active"),n=t.prev();n.length||(n=this.$menu.find("li").last()),n.addClass("active")},listen:function(){this.$element.on("blur",e.proxy(this.blur,this)).on("keypress",e.proxy(this.keypress,this)).on("keyup",e.proxy(this.keyup,this)),(e.browser.chrome||e.browser.webkit||e.browser.msie)&&this.$element.on("keydown",e.proxy(this.keydown,this)),this.$menu.on("click",e.proxy(this.click,this)).on("mouseenter","li",e.proxy(this.mouseenter,this))},move:function(e){if(!this.shown)return;switch(e.keyCode){case 9:case 13:case 27:e.preventDefault();break;case 38:e.preventDefault(),this.prev();break;case 40:e.preventDefault(),this.next()}e.stopPropagation()},keydown:function(t){this.suppressKeyPressRepeat=!~e.inArray(t.keyCode,[40,38,9,13,27]),this.move(t)},keypress:function(e){if(this.suppressKeyPressRepeat)return;this.move(e)},keyup:function(e){switch(e.keyCode){case 40:case 38:break;case 9:case 13:if(!this.shown)return;this.select();break;case 27:if(!this.shown)return;this.hide();break;default:this.lookup()}e.stopPropagation(),e.preventDefault()},blur:function(e){var t=this;setTimeout(function(){t.hide()},150)},click:function(e){e.stopPropagation(),e.preventDefault(),this.select()},mouseenter:function(t){this.$menu.find(".active").removeClass("active"),e(t.currentTarget).addClass("active")}},e.fn.typeahead=function(n){return this.each(function(){var r=e(this),i=r.data("typeahead"),s=typeof n=="object"&&n;i||r.data("typeahead",i=new t(this,s)),typeof n=="string"&&i[n]()})},e.fn.typeahead.defaults={source:[],items:8,menu:'',item:'
  • ',minLength:1},e.fn.typeahead.Constructor=t,e(function(){e("body").on("focus.typeahead.data-api",'[data-provide="typeahead"]',function(t){var n=e(this);if(n.data("typeahead"))return;t.preventDefault(),n.typeahead(n.data())})})}(window.jQuery); +var Konami=function(t){var e={addEvent:function(t,e,n,i){t.addEventListener?t.addEventListener(e,n,!1):t.attachEvent&&(t["e"+e+n]=n,t[e+n]=function(){t["e"+e+n](window.event,i)},t.attachEvent("on"+e,t[e+n]))},input:"",pattern:"3838404037393739666513",load:function(t){this.addEvent(document,"keydown",function(n,i){return i&&(e=i),e.input+=n?n.keyCode:event.keyCode,e.input.length>e.pattern.length&&(e.input=e.input.substr(e.input.length-e.pattern.length)),e.input==e.pattern?(e.code(t),e.input="",void 0):void 0},this),this.iphone.load(t)},code:function(t){window.location=t},iphone:{start_x:0,start_y:0,stop_x:0,stop_y:0,tap:!1,capture:!1,orig_keys:"",keys:["UP","UP","DOWN","DOWN","LEFT","RIGHT","LEFT","RIGHT","TAP","TAP","TAP"],code:function(t){e.code(t)},load:function(t){this.orig_keys=this.keys,e.addEvent(document,"touchmove",function(t){if(1==t.touches.length&&e.iphone.capture===!0){var n=t.touches[0] +e.iphone.stop_x=n.pageX,e.iphone.stop_y=n.pageY,e.iphone.tap=!1,e.iphone.capture=!1,e.iphone.check_direction()}}),e.addEvent(document,"touchend",function(){e.iphone.tap===!0&&e.iphone.check_direction(t)},!1),e.addEvent(document,"touchstart",function(t){e.iphone.start_x=t.changedTouches[0].pageX,e.iphone.start_y=t.changedTouches[0].pageY,e.iphone.tap=!0,e.iphone.capture=!0})},check_direction:function(t){var e=Math.abs(this.start_x-this.stop_x),n=Math.abs(this.start_y-this.stop_y),i=0>this.start_x-this.stop_x?"RIGHT":"LEFT",o=0>this.start_y-this.stop_y?"DOWN":"UP",s=e>n?i:o +s=this.tap===!0?"TAP":s,s==this.keys[0]&&(this.keys=this.keys.slice(1,this.keys.length)),0==this.keys.length&&(this.keys=this.orig_keys,this.code(t))}}} +return"string"==typeof t&&e.load(t),"function"==typeof t&&(e.code=t,e.load()),e}; + +function setupTypeahead() { + $('#pkgsearch-field').typeahead({ + source: function(query, callback) { + $.getJSON('/opensearch/packages/suggest', {q: query}, function(data) { + callback(data[1]); + }); + }, + matcher: function(item) { return true; }, + sorter: function(items) { return items; }, + menu: '
      ', + items: 10, + updater: function(item) { + $('#pkgsearch-field').val(item); + $('#pkgsearch-form').submit(); + return item; + } + }).attr('autocomplete', 'off'); + $('#pkgsearch-field').keyup(function(e) { + if (e.keyCode === 13 && + $('ul.pkgsearch-typeahead li.active').size() === 0) { + $('#pkgsearch-form').submit(); + } + }); +} + +function setupKonami(image_src) { + var konami = new Konami(function() { + $('#konami').html(''); + setTimeout(function() { + $('#konami').fadeIn(500); + }, 500); + $('#konami').click(function() { + $('#konami').fadeOut(500); + }); + }); +} diff --git a/templates/public/index.html b/templates/public/index.html index 89486be8..d815363b 100644 --- a/templates/public/index.html +++ b/templates/public/index.html @@ -214,44 +214,8 @@ {% load cdn %}{% jquery %} {% endblock %} -- cgit v1.2.3 From fae6da4d69564f0172d14047b81c0d8a9acc45a5 Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Thu, 23 Oct 2014 07:27:07 -0500 Subject: Bump to Django 1.7.1 Signed-off-by: Dan McGee --- requirements.txt | 2 +- requirements_prod.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/requirements.txt b/requirements.txt index 5d544e3c..4b111f06 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,5 @@ -e git+git://github.com/fredj/cssmin.git@master#egg=cssmin -Django==1.7 +Django==1.7.1 IPy==0.81 Jinja2==2.7.3 Markdown==2.4.1 diff --git a/requirements_prod.txt b/requirements_prod.txt index e3bc0ae2..4f52ce3e 100644 --- a/requirements_prod.txt +++ b/requirements_prod.txt @@ -1,5 +1,5 @@ -e git+git://github.com/fredj/cssmin.git@master#egg=cssmin -Django==1.7 +Django==1.7.1 IPy==0.81 Jinja2==2.7.3 Markdown==2.4.1 -- cgit v1.2.3 From 651678be2b6208cbfb45e11f5f390d66cf3eb8a6 Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Fri, 24 Oct 2014 13:50:38 -0500 Subject: Reorganize sidebar links involving people Signed-off-by: Dan McGee --- templates/public/index.html | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/templates/public/index.html b/templates/public/index.html index d815363b..3b17803c 100644 --- a/templates/public/index.html +++ b/templates/public/index.html @@ -108,7 +108,6 @@ {% cache 115 main-page-right secure %}
      -- cgit v1.2.3 From 15bb0e7101aa9bfa3f63e8ef44f4a8e1e310e3c1 Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Sun, 26 Oct 2014 21:44:11 -0500 Subject: Remove Etag header from feeds We have Last-Modified here, and from what I can tell with some more reading and playing with caching, it isn't necessarily wise to set both of them in the same response. Set the one that we actually trust. Signed-off-by: Dan McGee --- feeds.py | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) diff --git a/feeds.py b/feeds.py index 0bbac270..cb01fbb1 100644 --- a/feeds.py +++ b/feeds.py @@ -1,5 +1,4 @@ from datetime import datetime, time -import hashlib from pytz import utc from django.contrib.sites.models import Site @@ -63,12 +62,6 @@ class GuidNotPermalinkFeed(Rss201rev2Feed): wrapper.flush() -def package_etag(request, *args, **kwargs): - latest = package_last_modified(request) - if latest: - return hashlib.md5(str(kwargs) + str(latest)).hexdigest() - return None - def package_last_modified(request, *args, **kwargs): cursor = connection.cursor() cursor.execute("SELECT MAX(last_update) FROM packages") @@ -81,7 +74,7 @@ class PackageFeed(Feed): link = '/packages/' def __call__(self, request, *args, **kwargs): - wrapper = condition(etag_func=package_etag, last_modified_func=package_last_modified) + wrapper = condition(last_modified_func=package_last_modified) return wrapper(super(PackageFeed, self).__call__)(request, *args, **kwargs) __name__ = 'package_feed' @@ -151,12 +144,6 @@ class PackageFeed(Feed): return (item.repo.name, item.arch.name) -def news_etag(request, *args, **kwargs): - latest = news_last_modified(request) - if latest: - return hashlib.md5(str(latest)).hexdigest() - return None - def news_last_modified(request, *args, **kwargs): cursor = connection.cursor() cursor.execute("SELECT MAX(last_modified) FROM news") @@ -172,7 +159,7 @@ class NewsFeed(Feed): subtitle = description def __call__(self, request, *args, **kwargs): - wrapper = condition(etag_func=news_etag, last_modified_func=news_last_modified) + wrapper = condition(last_modified_func=news_last_modified) return wrapper(super(NewsFeed, self).__call__)(request, *args, **kwargs) __name__ = 'news_feed' -- cgit v1.2.3 From 8e990ca945f4fc5b27c0a81a484a107c83aa69d3 Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Sun, 26 Oct 2014 21:56:24 -0500 Subject: Kill now unneeded workaround for Django issue #9800 Signed-off-by: Dan McGee --- feeds.py | 38 +++++++++++++------------------------- 1 file changed, 13 insertions(+), 25 deletions(-) diff --git a/feeds.py b/feeds.py index cb01fbb1..24611e7e 100644 --- a/feeds.py +++ b/feeds.py @@ -18,38 +18,20 @@ class BatchWritesWrapper(object): self.outfile = outfile self.chunks = chunks self.buf = [] + def write(self, s): buf = self.buf buf.append(s) if len(buf) >= self.chunks: self.outfile.write(''.join(buf)) self.buf = [] + def flush(self): self.outfile.write(''.join(self.buf)) self.outfile.flush() -class GuidNotPermalinkFeed(Rss201rev2Feed): - @staticmethod - def check_for_unique_id(f): - def wrapper(name, contents=None, attrs=None): - if attrs is None: - attrs = {} - if name == 'guid': - attrs['isPermaLink'] = 'false' - return f(name, contents, attrs) - return wrapper - - def write_items(self, handler): - ''' - Totally disgusting. Monkey-patch the handler so if it sees a - 'unique-id' field come through, add an isPermalink="false" attribute. - Workaround for http://code.djangoproject.com/ticket/9800 - ''' - handler.addQuickElement = self.check_for_unique_id( - handler.addQuickElement) - super(GuidNotPermalinkFeed, self).write_items(handler) - +class FasterRssFeed(Rss201rev2Feed): def write(self, outfile, encoding): ''' Batch the underlying 'write' calls on the outfile because Python's @@ -58,7 +40,7 @@ class GuidNotPermalinkFeed(Rss201rev2Feed): '>' closing tags and over 1600 write calls in our package feed. ''' wrapper = BatchWritesWrapper(outfile) - super(GuidNotPermalinkFeed, self).write(wrapper, encoding) + super(FasterRssFeed, self).write(wrapper, encoding) wrapper.flush() @@ -69,7 +51,7 @@ def package_last_modified(request, *args, **kwargs): class PackageFeed(Feed): - feed_type = GuidNotPermalinkFeed + feed_type = FasterRssFeed link = '/packages/' @@ -124,6 +106,8 @@ class PackageFeed(Feed): def items(self, obj): return obj['qs'] + item_guid_is_permalink = False + def item_guid(self, item): # http://diveintomark.org/archives/2004/05/28/howto-atom-id date = item.last_update @@ -151,7 +135,7 @@ def news_last_modified(request, *args, **kwargs): class NewsFeed(Feed): - feed_type = GuidNotPermalinkFeed + feed_type = FasterRssFeed title = 'Arch Linux: Recent news updates' link = '/news/' @@ -168,6 +152,8 @@ class NewsFeed(Feed): return News.objects.select_related('author').order_by( '-postdate', '-id')[:10] + item_guid_is_permalink = False + def item_guid(self, item): return item.guid @@ -185,7 +171,7 @@ class NewsFeed(Feed): class ReleaseFeed(Feed): - feed_type = GuidNotPermalinkFeed + feed_type = FasterRssFeed title = 'Arch Linux: Releases' link = '/download/' @@ -206,6 +192,8 @@ class ReleaseFeed(Feed): def item_pubdate(self, item): return datetime.combine(item.release_date, time()).replace(tzinfo=utc) + item_guid_is_permalink = False + def item_guid(self, item): # http://diveintomark.org/archives/2004/05/28/howto-atom-id date = item.release_date -- cgit v1.2.3 From 9c701ebba1f2ef403aab95354a8ae4efdb7df74c Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Sun, 26 Oct 2014 22:06:08 -0500 Subject: Double batch size in BatchWritesWrapper Signed-off-by: Dan McGee --- feeds.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/feeds.py b/feeds.py index 24611e7e..7247e95c 100644 --- a/feeds.py +++ b/feeds.py @@ -14,15 +14,14 @@ from releng.models import Release class BatchWritesWrapper(object): - def __init__(self, outfile, chunks=20): + def __init__(self, outfile): self.outfile = outfile - self.chunks = chunks self.buf = [] def write(self, s): buf = self.buf buf.append(s) - if len(buf) >= self.chunks: + if len(buf) >= 40: self.outfile.write(''.join(buf)) self.buf = [] -- cgit v1.2.3 From bd2bc6a1c58723502ef6c2e9f49248908a161b13 Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Sun, 26 Oct 2014 22:23:56 -0500 Subject: Add last modified date to releases Signed-off-by: Dan McGee --- feeds.py | 6 ++++++ releng/admin.py | 1 + releng/migrations/0002_release_last_modified.py | 22 ++++++++++++++++++++++ .../0003_release_populate_last_modified.py | 21 +++++++++++++++++++++ releng/models.py | 1 + 5 files changed, 51 insertions(+) create mode 100644 releng/migrations/0002_release_last_modified.py create mode 100644 releng/migrations/0003_release_populate_last_modified.py diff --git a/feeds.py b/feeds.py index 7247e95c..0f7fa5d7 100644 --- a/feeds.py +++ b/feeds.py @@ -159,6 +159,9 @@ class NewsFeed(Feed): def item_pubdate(self, item): return item.postdate + def item_updateddate(self, item): + return item.last_modified + def item_author_name(self, item): return item.author.get_full_name() @@ -191,6 +194,9 @@ class ReleaseFeed(Feed): def item_pubdate(self, item): return datetime.combine(item.release_date, time()).replace(tzinfo=utc) + def item_updateddate(self, item): + return item.last_modified + item_guid_is_permalink = False def item_guid(self, item): diff --git a/releng/admin.py b/releng/admin.py index c7e6396e..9c93c4be 100644 --- a/releng/admin.py +++ b/releng/admin.py @@ -18,6 +18,7 @@ class ReleaseAdmin(admin.ModelAdmin): list_display = ('version', 'release_date', 'kernel_version', 'available', 'created') list_filter = ('available', 'release_date') + readonly_fields = ('created', 'last_modified') SIMPLE_MODELS = (Architecture, BootType, Bootloader, ClockChoice, Filesystem, diff --git a/releng/migrations/0002_release_last_modified.py b/releng/migrations/0002_release_last_modified.py new file mode 100644 index 00000000..58502452 --- /dev/null +++ b/releng/migrations/0002_release_last_modified.py @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import models, migrations +import datetime +from django.utils.timezone import utc + + +class Migration(migrations.Migration): + + dependencies = [ + ('releng', '0001_initial'), + ] + + operations = [ + migrations.AddField( + model_name='release', + name='last_modified', + field=models.DateTimeField(default=datetime.datetime(2001, 1, 1, tzinfo=utc), editable=False), + preserve_default=False, + ), + ] diff --git a/releng/migrations/0003_release_populate_last_modified.py b/releng/migrations/0003_release_populate_last_modified.py new file mode 100644 index 00000000..ec7b6fda --- /dev/null +++ b/releng/migrations/0003_release_populate_last_modified.py @@ -0,0 +1,21 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import models, migrations + +def forwards(apps, schema_editor): + Release = apps.get_model('releng', 'Release') + Release.objects.update(last_modified=models.F('created')) + +def backwards(apps, schema_editor): + pass + +class Migration(migrations.Migration): + + dependencies = [ + ('releng', '0002_release_last_modified'), + ] + + operations = [ + migrations.RunPython(forwards, backwards) + ] diff --git a/releng/models.py b/releng/models.py index c3ffd322..436308f2 100644 --- a/releng/models.py +++ b/releng/models.py @@ -120,6 +120,7 @@ class Release(models.Model): md5_sum = models.CharField('MD5 digest', max_length=32, blank=True) sha1_sum = models.CharField('SHA1 digest', max_length=40, blank=True) created = models.DateTimeField(editable=False) + last_modified = models.DateTimeField(editable=False) available = models.BooleanField(default=True) info = models.TextField('Public information', blank=True) torrent_data = models.TextField(blank=True, -- cgit v1.2.3 From e7449f7063f3f56af118ed8ad703ec3fce6bc39a Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Tue, 28 Oct 2014 14:14:00 -0500 Subject: Bump to django_countries bugfix release Signed-off-by: Dan McGee --- requirements.txt | 2 +- requirements_prod.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/requirements.txt b/requirements.txt index 4b111f06..e1acd2e9 100644 --- a/requirements.txt +++ b/requirements.txt @@ -5,7 +5,7 @@ Jinja2==2.7.3 Markdown==2.4.1 bencode==1.0 django-jinja==1.0.4 -django_countries==3.0 +django_countries==3.0.1 jsmin==2.0.11 pgpdump==1.5 pytz>=2014.7 diff --git a/requirements_prod.txt b/requirements_prod.txt index 4f52ce3e..ef535eb8 100644 --- a/requirements_prod.txt +++ b/requirements_prod.txt @@ -5,7 +5,7 @@ Jinja2==2.7.3 Markdown==2.4.1 bencode==1.0 django-jinja==1.0.4 -django_countries==3.0 +django_countries==3.0.1 jsmin==2.0.11 pgpdump==1.5 psycopg2==2.5.4 -- cgit v1.2.3 From 98e3d3126710a827c1ea1296f38e3e29adf37857 Mon Sep 17 00:00:00 2001 From: Luke Shumaker Date: Wed, 15 Apr 2015 00:37:35 -0400 Subject: Add a Makefile to generate all of the 3rd party or minimized Javascript. The goal here is to generate the files *exactly* as they are currently in the repository, which sometimes means using a specific version of a minifier or other weird things. --- Makefile | 100 ++++++++++++++++++++++ Makefile.d/bootstrap-typeahead.js.patch | 38 ++++++++ Makefile.d/homepage.js.in | 36 ++++++++ Makefile.d/jquery-1.8.3.min.js.preamble | 1 + Makefile.d/jquery.tablesorter-2.7.min.js.preamble | 4 + Makefile.d/konami.js.patch | 46 ++++++++++ 6 files changed, 225 insertions(+) create mode 100644 Makefile create mode 100644 Makefile.d/bootstrap-typeahead.js.patch create mode 100644 Makefile.d/homepage.js.in create mode 100644 Makefile.d/jquery-1.8.3.min.js.preamble create mode 100644 Makefile.d/jquery.tablesorter-2.7.min.js.preamble create mode 100644 Makefile.d/konami.js.patch diff --git a/Makefile b/Makefile new file mode 100644 index 00000000..6b633158 --- /dev/null +++ b/Makefile @@ -0,0 +1,100 @@ +# The idea here is to be able to re-generate the exact Javascript +# files as they exist in git. This means munging whitespace in weird +# ways, using specific versions of various JS minimizers... + +# Where are we? +topdir := $(dir $(lastword $(MAKEFILE_LIST))) +www = $(topdir)/../web-cache/www + +# Where are the Javascript minimizers? +# Any of the 1.3.x or 2.2.x will produce the same output for these +uglifyjs-1.3 = ~/Downloads/UglifyJS/bin/uglifyjs --no-copyright --ascii --max-line-len 0 +uglifyjs-2.2 = ~/Downloads/UglifyJS2/bin/uglifyjs --mangle --compress -- +closure-compiler = java -jar ~/Downloads/compiler-20121212/compiler.jar + +# What versions of 3rd party libraries are we using? +jquery-ver=1.8.3 +bootstrap-ver=2.1.1 +tablesorter-ver=2.7 +d3-ver=3.0.6 +konami-ver=c0f686e647765860ff4d2fcb7b48122785432b75 + +targets = \ + sitestatic/bootstrap-typeahead.js \ + sitestatic/homepage.js \ + sitestatic/jquery-$(jquery-ver).min.js \ + sitestatic/jquery.tablesorter-$(tablesorter-ver).js \ + sitestatic/jquery.tablesorter-$(tablesorter-ver).min.js \ + sitestatic/konami.min.js \ + visualize/static/d3-$(d3-ver).js \ + visualize/static/d3-$(d3-ver).min.js + + +# The base rules + +all: $(targets) +.PHONY: all + +basenames = $(sort $(patsubst %.min,%,$(patsubst %.js,%,$(targets)))) +generated = $(addsuffix .js,$(basenames)) $(addsuffix .min.js,$(basenames)) +clean: + rm -f -- $(generated) +.PHONY: clean + +# Don't have non-minimized .js stick around unless we asked for them. +.INTERMEDIATE: $(filter-out $(targets),$(generated)) + +# Turn on sane error handling +.DELETE_ON_ERROR: + + +# How to download files + +$(www)/http/%: + mkdir -p '$(@D)' + wget 'http://$*' -O '$@' + touch '$@' + +$(www)/https/%: + mkdir -p '$(@D)' + wget 'https://$*' -O '$@' + touch '$@' + + +# Non-minimized .js files +sitestatic/bootstrap-typeahead.js: sitestatic/%: $(www)/https/raw.github.com/twitter/bootstrap/v$(bootstrap-ver)/js/% Makefile.d/%.patch + cp $< $@ + patch -i Makefile.d/$*.patch $@ +sitestatic/jquery-$(jquery-ver).js: sitestatic/%: $(www)/http/code.jquery.com/% + cp $< $@ +sitestatic/jquery.tablesorter-$(tablesorter-ver).js: $(www)/https/raw.github.com/Mottie/tablesorter/v$(tablesorter-ver)/js/jquery.tablesorter.js + cp $< $@ +sitestatic/konami.js: sitestatic/%: $(www)/https/raw.github.com/snaptortoise/konami-js/$(konami-ver)/% Makefile.d/%.patch + cp $< $@ + patch -i Makefile.d/$*.patch $@ +sitestatic/homepage.js: sitestatic/bootstrap-typeahead.min.js sitestatic/konami.min.js Makefile.d/homepage.js.in + { \ + cat sitestatic/bootstrap-typeahead.min.js && \ + echo && \ + sed -e 's,^\s*,,' -e 's,^return.*,&;,' sitestatic/konami.min.js && \ + echo && \ + cat Makefile.d/homepage.js.in ; \ + } > $@ +visualize/static/d3-$(d3-ver).js: %: $(www)/https/raw.github.com/mbostock/d3/v$(d3-ver)/d3.js + cp $< $@ + + +# The crazy minimization processes + +sitestatic/bootstrap-typeahead.min.js: %.min.js: %.js + $(uglifyjs-1.3) $< > $@ +sitestatic/jquery-$(jquery-ver).min.js: sitestatic/%.min.js: sitestatic/%.js Makefile.d/%.min.js.preamble + { cat Makefile.d/$*.min.js.preamble && echo && $(uglifyjs-1.3) $<; } > $@ +sitestatic/jquery.tablesorter-$(tablesorter-ver).min.js: sitestatic/%.min.js: sitestatic/%.js Makefile.d/%.min.js.preamble + @# The tr/sed is to turn all of the newlines except for the last one into spaces + { cat Makefile.d/$*.min.js.preamble && echo && $(closure-compiler) $< | tr '\n' ' ' | sed 's, $$,\n,'; } > $@ +sitestatic/konami.min.js: %.min.js: %.js + @# The sed is to insert newlines and whitespace at the correct places; presumably to match Dan copy/pasting into an editor. + $(uglifyjs-2.2) $< | sed -r -e 's:e\.iphone\.stop_x|s=this\.tap===:\n\t&:g' -e 's,return"string",\n&,' | sed -e 's,;$$,,' -e '$$s,$$,\n,' > $@ +visualize/static/d3-$(d3-ver).min.js: %.min.js: %.js + $(uglifyjs-2.2) $< > $@ diff --git a/Makefile.d/bootstrap-typeahead.js.patch b/Makefile.d/bootstrap-typeahead.js.patch new file mode 100644 index 00000000..dfbab80b --- /dev/null +++ b/Makefile.d/bootstrap-typeahead.js.patch @@ -0,0 +1,38 @@ +commit f3e23371fa0473c82c28932e85570d94e5fc232a +Author: Dan McGee +Date: Mon Sep 24 20:21:15 2012 -0500 + + Don't auto-select the first item in typeahead + + This assumption was baked into the Twitter bootstrap JS; kill it so it + is still easy to do a freeform search if wanted. + + Signed-off-by: Dan McGee + +diff --git a/sitestatic/bootstrap-typeahead.js b/sitestatic/bootstrap-typeahead.js +index c2ccdea..3d355ae 100644 +--- a/sitestatic/bootstrap-typeahead.js ++++ b/sitestatic/bootstrap-typeahead.js +@@ -45,9 +45,11 @@ + + , select: function () { + var val = this.$menu.find('.active').attr('data-value') +- this.$element +- .val(this.updater(val)) +- .change() ++ if (val) { ++ this.$element ++ .val(this.updater(val)) ++ .change() ++ } + return this.hide() + } + +@@ -141,7 +143,6 @@ + return i[0] + }) + +- items.first().addClass('active') + this.$menu.html(items) + return this + } diff --git a/Makefile.d/homepage.js.in b/Makefile.d/homepage.js.in new file mode 100644 index 00000000..2d6f7910 --- /dev/null +++ b/Makefile.d/homepage.js.in @@ -0,0 +1,36 @@ +function setupTypeahead() { + $('#pkgsearch-field').typeahead({ + source: function(query, callback) { + $.getJSON('/opensearch/packages/suggest', {q: query}, function(data) { + callback(data[1]); + }); + }, + matcher: function(item) { return true; }, + sorter: function(items) { return items; }, + menu: '
        ', + items: 10, + updater: function(item) { + $('#pkgsearch-field').val(item); + $('#pkgsearch-form').submit(); + return item; + } + }).attr('autocomplete', 'off'); + $('#pkgsearch-field').keyup(function(e) { + if (e.keyCode === 13 && + $('ul.pkgsearch-typeahead li.active').size() === 0) { + $('#pkgsearch-form').submit(); + } + }); +} + +function setupKonami(image_src) { + var konami = new Konami(function() { + $('#konami').html(''); + setTimeout(function() { + $('#konami').fadeIn(500); + }, 500); + $('#konami').click(function() { + $('#konami').fadeOut(500); + }); + }); +} diff --git a/Makefile.d/jquery-1.8.3.min.js.preamble b/Makefile.d/jquery-1.8.3.min.js.preamble new file mode 100644 index 00000000..ca451d71 --- /dev/null +++ b/Makefile.d/jquery-1.8.3.min.js.preamble @@ -0,0 +1 @@ +/*! jQuery v1.8.3 jquery.com | jquery.org/license */ \ No newline at end of file diff --git a/Makefile.d/jquery.tablesorter-2.7.min.js.preamble b/Makefile.d/jquery.tablesorter-2.7.min.js.preamble new file mode 100644 index 00000000..e57e2d88 --- /dev/null +++ b/Makefile.d/jquery.tablesorter-2.7.min.js.preamble @@ -0,0 +1,4 @@ +/*! +* TableSorter 2.7 min - Client-side table sorting with ease! +* Copyright (c) 2007 Christian Bach +*/ \ No newline at end of file diff --git a/Makefile.d/konami.js.patch b/Makefile.d/konami.js.patch new file mode 100644 index 00000000..f6df91c4 --- /dev/null +++ b/Makefile.d/konami.js.patch @@ -0,0 +1,46 @@ +--- ..//web-cache/www/https/raw.github.com/snaptortoise/konami-js/c0f686e647765860ff4d2fcb7b48122785432b75/konami.js 2015-04-14 17:46:09.372597458 -0400 ++++ sitestatic/konami.js 2015-04-14 22:39:28.549281737 -0400 +@@ -56,7 +56,7 @@ + load: function(link){ + this.orig_keys = this.keys; + konami.addEvent(document,"touchmove",function(e){ +- if(e.touches.length == 1 && konami.iphone.capture==true){ ++ if(e.touches.length == 1 && konami.iphone.capture===true){ + var touch = e.touches[0]; + konami.iphone.stop_x = touch.pageX; + konami.iphone.stop_y = touch.pageY; +@@ -66,7 +66,7 @@ + } + }); + konami.addEvent(document,"touchend",function(evt){ +- if (konami.iphone.tap==true) konami.iphone.check_direction(link); ++ if (konami.iphone.tap===true) konami.iphone.check_direction(link); + },false); + konami.addEvent(document,"touchstart", function(evt){ + konami.iphone.start_x = evt.changedTouches[0].pageX +@@ -76,12 +76,12 @@ + }); + }, + check_direction: function(link){ +- x_magnitude = Math.abs(this.start_x-this.stop_x) +- y_magnitude = Math.abs(this.start_y-this.stop_y) +- x = ((this.start_x-this.stop_x) < 0) ? "RIGHT" : "LEFT"; +- y = ((this.start_y-this.stop_y) < 0) ? "DOWN" : "UP"; +- result = (x_magnitude > y_magnitude) ? x : y; +- result = (this.tap==true) ? "TAP" : result; ++ var x_magnitude = Math.abs(this.start_x-this.stop_x) ++ var y_magnitude = Math.abs(this.start_y-this.stop_y) ++ var x = ((this.start_x-this.stop_x) < 0) ? "RIGHT" : "LEFT"; ++ var y = ((this.start_y-this.stop_y) < 0) ? "DOWN" : "UP"; ++ var result = (x_magnitude > y_magnitude) ? x : y; ++ result = (this.tap===true) ? "TAP" : result; + + if (result==this.keys[0]) this.keys = this.keys.slice(1,this.keys.length) + if (this.keys.length==0) { +@@ -99,4 +99,4 @@ + } + + return konami; +-} +\ No newline at end of file ++} -- cgit v1.2.3