From 909f88bc809c38d152316864bdbb0861dc966c81 Mon Sep 17 00:00:00 2001 From: Vinod Kurup Date: Tue, 6 Aug 2013 11:53:23 -0400 Subject: [PATCH 01/22] Beginning CHANGELOG for next version --- docs/CHANGELOG.rst | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/CHANGELOG.rst b/docs/CHANGELOG.rst index 4c5854a..889bf05 100644 --- a/docs/CHANGELOG.rst +++ b/docs/CHANGELOG.rst @@ -1,6 +1,12 @@ Raspberry IO Changelog ====================== +Version 0.3 (Unreleased) +------------------------ + +* + + Version 0.2 - Open Source Release (2013-08-06) ---------------------------------------------- From 11f977d41c26bb3252d410c4b5654ee5e9ab95ae Mon Sep 17 00:00:00 2001 From: Vinod Kurup Date: Mon, 12 Aug 2013 10:27:33 -0400 Subject: [PATCH 02/22] Add twitter button May need to be styled better, but will leave that to future optimization --- raspberryio/static/js/site.js | 3 +++ raspberryio/static/less/site.less | 5 ++++- raspberryio/templates/base.html | 5 ++++- 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/raspberryio/static/js/site.js b/raspberryio/static/js/site.js index e3f6c64..960e030 100644 --- a/raspberryio/static/js/site.js +++ b/raspberryio/static/js/site.js @@ -71,3 +71,6 @@ $(function() { } }); }); + +// Twitter button JS +!function(d,s,id){var js,fjs=d.getElementsByTagName(s)[0],p=/^http:/.test(d.location)?'http':'https';if(!d.getElementById(id)){js=d.createElement(s);js.id=id;js.src=p+'://platform.twitter.com/widgets.js';fjs.parentNode.insertBefore(js,fjs);}}(document, 'script', 'twitter-wjs'); diff --git a/raspberryio/static/less/site.less b/raspberryio/static/less/site.less index 34e8e79..3079147 100644 --- a/raspberryio/static/less/site.less +++ b/raspberryio/static/less/site.less @@ -524,7 +524,7 @@ hr { } footer { text-align: center; - font-size: 9px; + font-size: 10px; color: @white; padding: 3px 0; background: url('/static/img/background.jpg'); @@ -533,6 +533,9 @@ hr { a { color: @white !important; } + li { + line-height: 12px; + } } } diff --git a/raspberryio/templates/base.html b/raspberryio/templates/base.html index 35f82b8..22e3b1a 100644 --- a/raspberryio/templates/base.html +++ b/raspberryio/templates/base.html @@ -168,7 +168,10 @@

Raspberry IO

From 21589b6301e4e6bc05c32863a0b1395dc960f860 Mon Sep 17 00:00:00 2001 From: Vinod Kurup Date: Mon, 12 Aug 2013 10:31:02 -0400 Subject: [PATCH 03/22] Update changelog --- docs/CHANGELOG.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/CHANGELOG.rst b/docs/CHANGELOG.rst index 889bf05..3ef7a4a 100644 --- a/docs/CHANGELOG.rst +++ b/docs/CHANGELOG.rst @@ -4,7 +4,7 @@ Raspberry IO Changelog Version 0.3 (Unreleased) ------------------------ -* +* Add link to RaspberryIO Twitter account Version 0.2 - Open Source Release (2013-08-06) From f05c1a147d0938b6d9fb04281c2a39724bb4ed6f Mon Sep 17 00:00:00 2001 From: Vinod Kurup Date: Mon, 12 Aug 2013 10:46:25 -0400 Subject: [PATCH 04/22] Move the secret key Move SECRET_KEY from base.py to local_example.py, where it can be customized Also put a copy in travis.py, so Travis still works --- raspberryio/settings/base.py | 3 --- raspberryio/settings/local.example.py | 6 +++++- raspberryio/settings/travis.py | 6 +++++- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/raspberryio/settings/base.py b/raspberryio/settings/base.py index 024c19d..ef4d4a4 100644 --- a/raspberryio/settings/base.py +++ b/raspberryio/settings/base.py @@ -85,9 +85,6 @@ 'compressor.finders.CompressorFinder', ) -# Make this unique, and don't share it with anybody. -SECRET_KEY = 'yv!hkvt&k8dn^$*$&lif)#ydw8zvk4iz93s8m+$x%eyg-!$n69' - # List of callables that know how to import templates from various sources. TEMPLATE_LOADERS = ( 'django.template.loaders.filesystem.Loader', diff --git a/raspberryio/settings/local.example.py b/raspberryio/settings/local.example.py index 76cad4e..44b464d 100644 --- a/raspberryio/settings/local.example.py +++ b/raspberryio/settings/local.example.py @@ -2,7 +2,11 @@ from raspberryio.settings.dev import * -# Override settings here +## Override settings here + +# Make this unique, and don't share it with anybody. +SECRET_KEY = 'yv!hkvt&k8dn^$*$&lif)#ydw8zvk4iz93s8m+$x%eyg-!$n69' + # Special test settings if 'test' in sys.argv: diff --git a/raspberryio/settings/travis.py b/raspberryio/settings/travis.py index 76cad4e..44b464d 100644 --- a/raspberryio/settings/travis.py +++ b/raspberryio/settings/travis.py @@ -2,7 +2,11 @@ from raspberryio.settings.dev import * -# Override settings here +## Override settings here + +# Make this unique, and don't share it with anybody. +SECRET_KEY = 'yv!hkvt&k8dn^$*$&lif)#ydw8zvk4iz93s8m+$x%eyg-!$n69' + # Special test settings if 'test' in sys.argv: From 9eec6b892fdafef672d23b01c4b20abd56a77176 Mon Sep 17 00:00:00 2001 From: Vinod Kurup Date: Mon, 12 Aug 2013 12:58:25 -0400 Subject: [PATCH 05/22] Get SECRET_KEY from {staging,production}.ini file --- raspberryio/settings/production.py | 1 + raspberryio/settings/staging.py | 1 + 2 files changed, 2 insertions(+) diff --git a/raspberryio/settings/production.py b/raspberryio/settings/production.py index 943654b..e2f4d89 100644 --- a/raspberryio/settings/production.py +++ b/raspberryio/settings/production.py @@ -11,6 +11,7 @@ config = RawConfigParser() config.read(os.path.join(SECRETS_ROOT, 'settings.ini')) SUPERFEEDR_CREDS = json.loads(config.get('secrets', 'SUPERFEEDR_CREDS')) + SECRET_KEY = json.loads(config.get('secrets', 'SECRET_KEY')) DATABASES['default']['NAME'] = config.get('database', 'DATABASE_NAME') DATABASES['default']['HOST'] = config.get('database', 'DATABASE_HOST') DATABASES['default']['USER'] = config.get('database', 'DATABASE_USER') diff --git a/raspberryio/settings/staging.py b/raspberryio/settings/staging.py index 60ffcc5..a581bdd 100644 --- a/raspberryio/settings/staging.py +++ b/raspberryio/settings/staging.py @@ -41,5 +41,6 @@ config = RawConfigParser() config.read(os.path.join(SECRETS_ROOT, 'settings.ini')) SUPERFEEDR_CREDS = json.loads(config.get('secrets', 'SUPERFEEDR_CREDS')) + SECRET_KEY = json.loads(config.get('secrets', 'SECRET_KEY')) except: pass From a547de8f602e3558c37c415b6356e8f4a66afeb8 Mon Sep 17 00:00:00 2001 From: Vinod Kurup Date: Tue, 13 Aug 2013 08:30:29 -0400 Subject: [PATCH 06/22] Sysadmin fixes - on PSF box, users in the `admin` group have sudo privileges - `/etc/sudoers` is automatically regenerated by PSF Chef recipes, so don't alter it --- fabfile.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/fabfile.py b/fabfile.py index fde7abf..40d9851 100644 --- a/fabfile.py +++ b/fabfile.py @@ -88,12 +88,11 @@ def create_users(): user_dir = os.path.join(CONF_ROOT, "users") for username in os.listdir(user_dir): key_file = os.path.normpath(os.path.join(user_dir, username)) - system.create_user(username, groups=['dev', 'login', ], key_file=key_file) + system.create_user(username, groups=['dev', 'login', 'admin', ], key_file=key_file) with open(key_file, 'rt') as f: ssh_key = f.read() # Add ssh key for project user files.append('%s/authorized_keys' % ssh_dir, ssh_key, use_sudo=True) - files.append(u'/etc/sudoers', r'%dev ALL=(ALL) NOPASSWD:ALL', use_sudo=True) sudo('chown -R %s:%s %s' % (env.project_user, env.project_user, ssh_dir)) From 9d7425892452e99adf66edab2d1672c18622f486 Mon Sep 17 00:00:00 2001 From: Vinod Kurup Date: Wed, 14 Aug 2013 08:35:50 -0400 Subject: [PATCH 07/22] Fix production DB name --- fabfile.py | 1 - 1 file changed, 1 deletion(-) diff --git a/fabfile.py b/fabfile.py index 40d9851..7ed55bc 100644 --- a/fabfile.py +++ b/fabfile.py @@ -64,7 +64,6 @@ def production(): # Provided machine uses default port env.ssh_port = 22 setup_path() - env.db = 'psf_rpi' def setup_path(): From 66ad84d00202c8c91323e2967e23dafd0950ecda Mon Sep 17 00:00:00 2001 From: Vinod Kurup Date: Wed, 14 Aug 2013 08:36:48 -0400 Subject: [PATCH 08/22] Update changelog --- docs/CHANGELOG.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/CHANGELOG.rst b/docs/CHANGELOG.rst index 889bf05..7b898f7 100644 --- a/docs/CHANGELOG.rst +++ b/docs/CHANGELOG.rst @@ -4,7 +4,7 @@ Raspberry IO Changelog Version 0.3 (Unreleased) ------------------------ -* +* Fabfile fixes Version 0.2 - Open Source Release (2013-08-06) From d99399490194bb958ee0b30afe82133a737d3b08 Mon Sep 17 00:00:00 2001 From: Vinod Kurup Date: Wed, 28 Aug 2013 16:03:10 -0400 Subject: [PATCH 09/22] Improve pagination * Override bootstrap's @paginationActiveBackground to be darker gray * Improve `includes/pagination.html` so we can use it site-wide * Add pagination to Question list * Add pagination to Followers/Following lists * Use sitewide pagination template for list of users * Use sitewide pagination template for feed aggregator * Use sitewide pagination template for project list * Add username and count of answers to Question list --- docs/CHANGELOG.rst | 2 +- raspberryio/qanda/views.py | 6 ++-- raspberryio/static/less/site.less | 1 + .../accounts/account_profile_related.html | 21 +++++++---- .../templates/accounts/activeusers.html | 36 ++++--------------- .../templates/aggregator/feeditem_list.html | 26 +++----------- .../templates/includes/pagination.html | 28 +++++++-------- .../templates/project/project_list.html | 34 ++---------------- .../templates/qanda/question_list.html | 25 ++++++++++--- raspberryio/userprofile/views.py | 11 ++++++ 10 files changed, 77 insertions(+), 113 deletions(-) diff --git a/docs/CHANGELOG.rst b/docs/CHANGELOG.rst index 889bf05..052776d 100644 --- a/docs/CHANGELOG.rst +++ b/docs/CHANGELOG.rst @@ -4,7 +4,7 @@ Raspberry IO Changelog Version 0.3 (Unreleased) ------------------------ -* +* Improve pagination throughout site Version 0.2 - Open Source Release (2013-08-06) diff --git a/raspberryio/qanda/views.py b/raspberryio/qanda/views.py index 71d5eaf..e5c6fe8 100644 --- a/raspberryio/qanda/views.py +++ b/raspberryio/qanda/views.py @@ -2,6 +2,7 @@ from django.shortcuts import render, redirect, get_object_or_404 from django.contrib.auth.decorators import login_required from django.contrib.sites.models import Site +from django.views.generic.list_detail import object_list from hilbert.decorators import ajax_only from mezzanine.utils.sites import current_site_id @@ -29,9 +30,8 @@ def index(request): @cache_on_auth(60 * 2) def question_list(request): questions = Question.objects.all() - return render(request, 'qanda/question_list.html', { - 'questions': questions, - }) + return object_list(request, queryset=questions, paginate_by=20, + template_object_name='question') def question_detail(request, question_slug): diff --git a/raspberryio/static/less/site.less b/raspberryio/static/less/site.less index 34e8e79..3e5c0e1 100644 --- a/raspberryio/static/less/site.less +++ b/raspberryio/static/less/site.less @@ -31,6 +31,7 @@ @greenMedium: #8FAC3C; @grayLightest: #edebeb; @raspberry: #c03939; +@paginationActiveBackground: #BBBBBB; /* Mixins ================= */ diff --git a/raspberryio/templates/accounts/account_profile_related.html b/raspberryio/templates/accounts/account_profile_related.html index a5cbe22..c932896 100644 --- a/raspberryio/templates/accounts/account_profile_related.html +++ b/raspberryio/templates/accounts/account_profile_related.html @@ -6,16 +6,21 @@ {% block title %}{{ user.username }}{% endblock %} {% block body_id %}user-listing{% endblock %} -{% block main%} +{% block main %}
-
+ +{% if related_users.has_other_pages %} + {% include "includes/pagination.html" with page_obj=related_users %} +{% endif %} + +
    {% for related_user in related_users %} {% if related_user %} @@ -25,8 +30,8 @@ {% avatar profile 150 %} {% endwith %} - -
    + +

    {{ related_user.username }}

    {% include 'includes/relationship-status.html' with profile_user=related_user %}
    @@ -34,9 +39,13 @@ {% endif %} {% endfor %}
-{% endblock %}
+{% if related_users.has_other_pages %} + {% include "includes/pagination.html" with page_obj=related_users %} +{% endif %} +{% endblock %} + {% block extra_js %} {% endblock %} diff --git a/raspberryio/templates/accounts/activeusers.html b/raspberryio/templates/accounts/activeusers.html index db0399d..37087d3 100644 --- a/raspberryio/templates/accounts/activeusers.html +++ b/raspberryio/templates/accounts/activeusers.html @@ -9,21 +9,9 @@ {% block main %}
- + {% if users.has_other_pages %} + {% include "includes/pagination.html" with page_obj=users %} + {% endif %}
{% for user in users %}
@@ -39,21 +27,9 @@
{% endfor %}
- + {% if users.has_other_pages %} + {% include "includes/pagination.html" with page_obj=users %} + {% endif %}
{% endblock %} diff --git a/raspberryio/templates/aggregator/feeditem_list.html b/raspberryio/templates/aggregator/feeditem_list.html index 6fb4404..4f4cc65 100644 --- a/raspberryio/templates/aggregator/feeditem_list.html +++ b/raspberryio/templates/aggregator/feeditem_list.html @@ -18,24 +18,15 @@

Community posts for {{ feed_type.name }} {% if is_paginated %} - + {% include "includes/pagination.html" %} {% endif %} -
+
{% for item in object_list %}
{% if is_paginated %} - + {% include "includes/pagination.html" %} {% endif %} {% endblock %} diff --git a/raspberryio/templates/includes/pagination.html b/raspberryio/templates/includes/pagination.html index e7bc19b..f89d47d 100644 --- a/raspberryio/templates/includes/pagination.html +++ b/raspberryio/templates/includes/pagination.html @@ -1,19 +1,17 @@ {% load i18n %} -{% if current_page.has_previous or current_page.has_next %} -{% endif %} \ No newline at end of file diff --git a/raspberryio/templates/project/project_list.html b/raspberryio/templates/project/project_list.html index caef983..edd805c 100644 --- a/raspberryio/templates/project/project_list.html +++ b/raspberryio/templates/project/project_list.html @@ -12,43 +12,15 @@ {% if is_paginated %} - + {% include "includes/pagination.html" %} {% endif %}
{% include 'includes/project-gallery.html' with projects=object_list %} -
+
{% if is_paginated %} - + {% include "includes/pagination.html" %} {% endif %} {% endcache %} diff --git a/raspberryio/templates/qanda/question_list.html b/raspberryio/templates/qanda/question_list.html index 6bf9ff5..58f7f5d 100644 --- a/raspberryio/templates/qanda/question_list.html +++ b/raspberryio/templates/qanda/question_list.html @@ -12,16 +12,31 @@

Questions & Answers

Have a question about a Raspberry Pi project you are working on? Find or ask questions, plus submit answers too!

Ask a question - -{% if questions %} + +{% if question_list %}

Questions

+ + {% if is_paginated %} + {% include "includes/pagination.html" %} + {% endif %} + + + {% if is_paginated %} + {% include "includes/pagination.html" with current_page=page_obj %} + {% endif %} {% else %}

No questions have been asked :(

{% endif %} + + {% endblock %} diff --git a/raspberryio/userprofile/views.py b/raspberryio/userprofile/views.py index e8a1063..4883e72 100644 --- a/raspberryio/userprofile/views.py +++ b/raspberryio/userprofile/views.py @@ -50,6 +50,17 @@ def profile_related_list(request, username, relation): related_users = models.followers(user) elif relation == 'following': related_users = models.following(user) + + paginator = Paginator(related_users, 20) + page = request.GET.get('page') + try: + related_users = paginator.page(page) + except PageNotAnInteger: + # If page is not an integer, deliver first page. + related_users = paginator.page(1) + except EmptyPage: + # If page is out of range (e.g. 9999), deliver last page of results. + related_users = paginator.page(paginator.num_pages) return render(request, "accounts/account_profile_related.html", { 'user': user, 'profile': profile, From da60ad62d5e16cc8a261321d88f4523db35a4af2 Mon Sep 17 00:00:00 2001 From: Vinod Kurup Date: Wed, 28 Aug 2013 16:10:26 -0400 Subject: [PATCH 10/22] Update test since we changed name for pagination --- raspberryio/qanda/tests/test_views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/raspberryio/qanda/tests/test_views.py b/raspberryio/qanda/tests/test_views.py index e79d2a7..899704c 100644 --- a/raspberryio/qanda/tests/test_views.py +++ b/raspberryio/qanda/tests/test_views.py @@ -19,7 +19,7 @@ def test_results(self): question3 = self.create_question() expected_questions = set([question1, question2, question3]) response = self.client.get(self.url) - result_questions = response.context['questions'] + result_questions = response.context['question_list'] self.assertEqual(set(result_questions), expected_questions) From 14ced850bb2135ba88ffc295306cbecc0267cc3f Mon Sep 17 00:00:00 2001 From: Vinod Kurup Date: Thu, 29 Aug 2013 13:42:46 -0400 Subject: [PATCH 11/22] Implement Disqus comments * Add ':' between meta_title and site_title in base.html template * Add DISQUS_HOSTNAME and DISQUS_SHORTNAME to settings * Add Disqus div and JS to project-detail page * Document settings in Developer docs * Update Changelog --- docs/CHANGELOG.rst | 1 + docs/developer.rst | 13 +++++++++++++ raspberryio/project/views.py | 3 +++ raspberryio/settings/base.py | 4 ++++ raspberryio/settings/production.py | 3 +++ raspberryio/settings/staging.py | 3 +++ raspberryio/templates/base.html | 2 +- .../templates/project/project_detail.html | 19 +++++++++++++++++++ 8 files changed, 47 insertions(+), 1 deletion(-) diff --git a/docs/CHANGELOG.rst b/docs/CHANGELOG.rst index 6114f79..82e10da 100644 --- a/docs/CHANGELOG.rst +++ b/docs/CHANGELOG.rst @@ -4,6 +4,7 @@ Raspberry IO Changelog Version 0.3 (Unreleased) ------------------------ +* Add DISQUS comments to project detail page * Fabfile fixes * Improve pagination throughout site diff --git a/docs/developer.rst b/docs/developer.rst index cd53aea..5593384 100644 --- a/docs/developer.rst +++ b/docs/developer.rst @@ -88,3 +88,16 @@ this flattened representation of the latest revision in its own table, and should be used in the future for any other models with a similar structure. Using something in MPTT or similar might be better than the current "flatten and copy" behavior, but this is what we have for now. + +Comments: +--------- + +We use `Disqus `_ to allow users to comment on +individual projects. The ``DISQUS_HOSTNAME`` (in Django settings) is +set to ``http://raspberry.io` so that non-production sites can see the +commenting functionality. ``DISQUS_SHORTNAME`` is set to +``raspberryio`` for production and ``raspberryio-staging`` for the +staging site. If local developers wish to test commenting for some +reason, then they should create a DISQUS account, set up a new +shortname and use that for ``DISQUS_SHORTNAME`` in +``raspberryio.settings.base``. diff --git a/raspberryio/project/views.py b/raspberryio/project/views.py index 07de157..eaa859b 100644 --- a/raspberryio/project/views.py +++ b/raspberryio/project/views.py @@ -5,6 +5,7 @@ from django.contrib.auth.decorators import login_required from django.views.generic.list_detail import object_list from django.core.cache import cache +from django.conf import settings from actstream import action @@ -39,6 +40,8 @@ def project_detail(request, project_slug): raise Http404('There is no project here') return render(request, 'project/project_detail.html', { 'project': project, + 'DISQUS_SHORTNAME': settings.DISQUS_SHORTNAME, + 'DISQUS_HOSTNAME': settings.DISQUS_HOSTNAME, }) diff --git a/raspberryio/settings/base.py b/raspberryio/settings/base.py index ef4d4a4..11860ee 100644 --- a/raspberryio/settings/base.py +++ b/raspberryio/settings/base.py @@ -346,3 +346,7 @@ pass else: set_dynamic_settings(globals()) + +# Disqus +DISQUS_SHORTNAME = 'raspberryio-dev' +DISQUS_HOSTNAME = 'http://raspberry.io' diff --git a/raspberryio/settings/production.py b/raspberryio/settings/production.py index e2f4d89..7868cf2 100644 --- a/raspberryio/settings/production.py +++ b/raspberryio/settings/production.py @@ -21,3 +21,6 @@ pass EMAIL_SUBJECT_PREFIX = '[Raspberryio Prod] ' + +# Disqus +DISQUS_SHORTNAME = 'raspberryio' diff --git a/raspberryio/settings/staging.py b/raspberryio/settings/staging.py index a581bdd..af8649f 100644 --- a/raspberryio/settings/staging.py +++ b/raspberryio/settings/staging.py @@ -44,3 +44,6 @@ SECRET_KEY = json.loads(config.get('secrets', 'SECRET_KEY')) except: pass + +# Disqus +DISQUS_SHORTNAME = 'raspberryio-staging' diff --git a/raspberryio/templates/base.html b/raspberryio/templates/base.html index 35f82b8..077f3f6 100644 --- a/raspberryio/templates/base.html +++ b/raspberryio/templates/base.html @@ -10,7 +10,7 @@ {% block extra-meta %}{% endblock %} - {% block meta_title %}{% endblock %} {% block site_title %}{{ settings.SITE_TITLE }}{% endblock %} + {% block meta_title %}{% endblock %} : {% block site_title %}{{ settings.SITE_TITLE }}{% endblock %} diff --git a/raspberryio/templates/project/project_detail.html b/raspberryio/templates/project/project_detail.html index 9057fc6..0843d60 100644 --- a/raspberryio/templates/project/project_detail.html +++ b/raspberryio/templates/project/project_detail.html @@ -3,6 +3,7 @@ {% load url from future %} {% load cache %} +{% block meta_title %}{{ project.title }}{% endblock %} {% block body_id %}project-detail{% endblock %} {% block main %} @@ -169,6 +170,11 @@

Step {{ forloop.counter }}: {{ step.title }}

{% endfor %} + +

Comments

+
+ comments powered by Disqus + {% endblock %} {% block extra_js %} @@ -226,4 +232,17 @@

Step {{ forloop.counter }}: {{ step.title }} }); }); + + {% endblock %} From 0c73b691569d5685b2268c3b04c32249a472d94a Mon Sep 17 00:00:00 2001 From: Vinod Kurup Date: Fri, 30 Aug 2013 08:32:37 -0400 Subject: [PATCH 12/22] Add aggregator to list of modules to test --- raspberryio/settings/dev.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/raspberryio/settings/dev.py b/raspberryio/settings/dev.py index ac95789..d8e7580 100644 --- a/raspberryio/settings/dev.py +++ b/raspberryio/settings/dev.py @@ -31,7 +31,7 @@ TEST_RUNNER = 'hilbert.test.CoverageRunner' -DEFAULT_TEST_LABELS = ['project', 'userprofile', 'search', 'qanda'] +DEFAULT_TEST_LABELS = ['project', 'userprofile', 'search', 'qanda', 'aggregator', ] COVERAGE_MODULES = ( 'forms', From d380cb43b07f07534644852c1a02a162848821ac Mon Sep 17 00:00:00 2001 From: Vinod Kurup Date: Fri, 30 Aug 2013 08:34:01 -0400 Subject: [PATCH 13/22] Use now() from django.utils.timezone to suppress warning messages --- raspberryio/aggregator/tests.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/raspberryio/aggregator/tests.py b/raspberryio/aggregator/tests.py index 93112e8..f9aa61a 100644 --- a/raspberryio/aggregator/tests.py +++ b/raspberryio/aggregator/tests.py @@ -2,8 +2,6 @@ # https://docs.djangoproject.com/en/dev/topics/testing/#email-services from __future__ import absolute_import -import datetime - from mock import patch from django.conf import settings @@ -12,7 +10,7 @@ from django.core.urlresolvers import reverse from django.test import TestCase from django.test.client import Client - +from django.utils.timezone import now from django_push.subscriber.models import SubscriptionManager from .management.commands import send_pending_approval_email @@ -60,7 +58,7 @@ def setUp(self): for feed in [self.approved_feed, self.denied_feed, self.pending_feed, self.defunct_feed]: feed.save() feed_item = models.FeedItem(feed=feed, title="%s Item" % feed.title, link=feed.public_url, - date_modified=datetime.datetime.now(), guid=feed.title) + date_modified=now(), guid=feed.title) feed_item.save() self.client = Client() From 4a6096f426c737da5ab95e53f1756a2db8ef5d7f Mon Sep 17 00:00:00 2001 From: Vinod Kurup Date: Fri, 30 Aug 2013 08:35:05 -0400 Subject: [PATCH 14/22] Simple changes to improve coverage * __unicode__ method testing * Test index page of qanda --- raspberryio/qanda/tests/test_models.py | 7 +++++++ raspberryio/qanda/tests/test_views.py | 13 +++++++++++++ raspberryio/userprofile/tests/test_models.py | 7 ++++++- 3 files changed, 26 insertions(+), 1 deletion(-) diff --git a/raspberryio/qanda/tests/test_models.py b/raspberryio/qanda/tests/test_models.py index 658b636..51e32d7 100644 --- a/raspberryio/qanda/tests/test_models.py +++ b/raspberryio/qanda/tests/test_models.py @@ -11,6 +11,13 @@ def setUp(self): question=self.question, user=self.answer_user ) + def test_unicode_method(self): + title = 'My title' + q = self.create_question(title=title) + a = self.create_answer(question=q) + self.assertEqual(q.__unicode__(), title) + self.assertEqual(a.__unicode__(), title) + def test_default_score(self): self.assertEqual(self.answer.score, 0) diff --git a/raspberryio/qanda/tests/test_views.py b/raspberryio/qanda/tests/test_views.py index 899704c..33dd547 100644 --- a/raspberryio/qanda/tests/test_views.py +++ b/raspberryio/qanda/tests/test_views.py @@ -6,6 +6,19 @@ from raspberryio.qanda.models import Question, Answer +class IndexViewTestCase(ViewTestMixin, QandaBaseTestCase): + url_name = 'community-index' + + def setUp(self): + super(IndexViewTestCase, self).setUp() + + def test_index_page(self): + question = self.create_question() + response = self.client.get(self.url) + result = response.context['questions'] + self.assertEqual(set(result), set([question])) + + class QuestionListViewTestCase(ViewTestMixin, QandaBaseTestCase): url_name = 'question-list' diff --git a/raspberryio/userprofile/tests/test_models.py b/raspberryio/userprofile/tests/test_models.py index 17fc2da..8849b59 100644 --- a/raspberryio/userprofile/tests/test_models.py +++ b/raspberryio/userprofile/tests/test_models.py @@ -8,6 +8,12 @@ def setUp(self): self.user = self.create_user() self.profile = self.user.get_profile() + def test_unicode_method(self): + self.assertEqual(self.profile.__unicode__(), self.user.username) + + def test_absolute_url(self): + self.assertEqual(self.profile.get_absolute_url(), '/users/%s/' % self.user.username) + def test_model_clean(self): "Ensure the twitter_id is stripped of the @ symbol during clean" self.profile.twitter_id = '@test' @@ -25,4 +31,3 @@ def test_feed_owner(self): feed_type=self.feed_type, owner=self.profile.user) self.approved_feed.save() self.assertTrue(self.profile.feed_owner) - From 4e81430b349d11a74f8cdb8aff7bf9e75b3fa5d7 Mon Sep 17 00:00:00 2001 From: Vinod Kurup Date: Fri, 30 Aug 2013 14:34:25 -0400 Subject: [PATCH 15/22] Remove code that I think is redundant --- raspberryio/userprofile/views.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/raspberryio/userprofile/views.py b/raspberryio/userprofile/views.py index 4883e72..2188b9b 100644 --- a/raspberryio/userprofile/views.py +++ b/raspberryio/userprofile/views.py @@ -41,8 +41,6 @@ def login(request, template="accounts/account_login.html"): def profile_related_list(request, username, relation): "Render the list of a users folllowers or who the user is following" profile = get_object_or_404(Profile, user__username__iexact=username) - if profile.user.username != username: - return redirect(profile, permanent=True) user = profile.user # get a queryset of users described by this relationship @@ -71,8 +69,6 @@ def profile_related_list(request, username, relation): def profile_actions(request, username): "Custom renderer for user profile activity stream" profile = get_object_or_404(Profile, user__username__iexact=username) - if profile.user.username != username: - return redirect(profile, permanent=True) user = profile.user return render(request, "accounts/account_profile_actions.html", { 'user': user, From c2d9d917fd9d178305f3dae9572408108e739dc6 Mon Sep 17 00:00:00 2001 From: Vinod Kurup Date: Fri, 30 Aug 2013 14:36:05 -0400 Subject: [PATCH 16/22] Improve coverage in userprofile.views --- raspberryio/userprofile/tests/test_views.py | 38 +++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/raspberryio/userprofile/tests/test_views.py b/raspberryio/userprofile/tests/test_views.py index c7fd2d0..68c8cf7 100644 --- a/raspberryio/userprofile/tests/test_views.py +++ b/raspberryio/userprofile/tests/test_views.py @@ -46,6 +46,14 @@ def test_following(self): related_users = len(response.context['related_users']) self.assertEqual(related_users, self.user.follow_set.all().count()) + def test_paginator_out_of_range(self): + # if page# is > max, then show last page + follow(self.user, self.user1) + url = self.get_url_args(self.user, 'following') + response = self.client.get(url, {'page': '9999'}) + related_users = response.context['related_users'] + self.assertEqual(len(related_users), self.user.follow_set.all().count()) + class DashboardTestCase(ProjectBaseTestCase): url_name = 'profile-dashboard' @@ -99,3 +107,33 @@ def test_inactive_users(self): response = self.client.get(self.url) users = response.context['users'] self.assertEqual(len(users), User.objects.filter(is_active=True).count()) + + def test_paginator_out_of_range(self): + # if page# is > max, then show last page + response = self.client.get(self.url, {'page': '9999'}) + users = response.context['users'] + self.assertEqual(len(users), User.objects.all().count()) + + +class ActivityStreamTestCase(RaspberryIOBaseTestCase): + url_name = 'profile-actions' + + def setUp(self): + self.user = self.create_user(data={'username': 'test', 'password': 'pwd'}) + self.user1 = self.create_user(data={'username': 'test1', 'password': 'pwd'}) + + def get_url_args(self, user): + return reverse(self.url_name, args=(user,)) + + def test_empty_activity_stream(self): + url = self.get_url_args(self.user) + response = self.client.get(url) + actions = response.context['actions'] + self.assertEqual(len(actions), 0) + + def test_nonempty_activity_stream(self): + follow(self.user, self.user1) + url = self.get_url_args(self.user) + response = self.client.get(url) + actions = response.context['actions'] + self.assertEqual(len(actions), 1) From 4958506ad2a77b3bb13f8fe2f3141aea2afc11a6 Mon Sep 17 00:00:00 2001 From: Vinod Kurup Date: Fri, 30 Aug 2013 14:36:23 -0400 Subject: [PATCH 17/22] Test our UserProfileForm modification --- raspberryio/userprofile/tests/__init__.py | 1 + raspberryio/userprofile/tests/test_forms.py | 17 +++++++++++++++++ 2 files changed, 18 insertions(+) create mode 100644 raspberryio/userprofile/tests/test_forms.py diff --git a/raspberryio/userprofile/tests/__init__.py b/raspberryio/userprofile/tests/__init__.py index 9b54322..eaca276 100644 --- a/raspberryio/userprofile/tests/__init__.py +++ b/raspberryio/userprofile/tests/__init__.py @@ -1,2 +1,3 @@ from raspberryio.userprofile.tests.test_models import * from raspberryio.userprofile.tests.test_views import * +from raspberryio.userprofile.tests.test_forms import * diff --git a/raspberryio/userprofile/tests/test_forms.py b/raspberryio/userprofile/tests/test_forms.py new file mode 100644 index 0000000..bb5960f --- /dev/null +++ b/raspberryio/userprofile/tests/test_forms.py @@ -0,0 +1,17 @@ +from django.core.urlresolvers import reverse + +from raspberryio.project.tests.base import RaspberryIOBaseTestCase + + +class UserProfileFormTestCase(RaspberryIOBaseTestCase): + url_name = "profile_update" + + def setUp(self): + self.user = self.create_user(data={'username': 'test', 'password': 'pwd'}) + self.url = reverse(self.url_name) + + def test_twitter_handle_on_form(self): + self.client.login(username=self.user.username, password='pwd') + response = self.client.get(self.url) + twitter_el = '' + self.assertContains(response, twitter_el, html=True) From 42dcfcae64c0432156b2cb2288688b16496575d4 Mon Sep 17 00:00:00 2001 From: Vinod Kurup Date: Fri, 30 Aug 2013 16:32:31 -0400 Subject: [PATCH 18/22] Finish up userprofile testing --- raspberryio/userprofile/tests/test_views.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/raspberryio/userprofile/tests/test_views.py b/raspberryio/userprofile/tests/test_views.py index 68c8cf7..5dbdfaf 100644 --- a/raspberryio/userprofile/tests/test_views.py +++ b/raspberryio/userprofile/tests/test_views.py @@ -137,3 +137,21 @@ def test_nonempty_activity_stream(self): response = self.client.get(url) actions = response.context['actions'] self.assertEqual(len(actions), 1) + + +class LoginTestCase(RaspberryIOBaseTestCase): + url_name = 'login' + + def setUp(self): + self.user = self.create_user(data={'username': 'test', 'password': 'right'}) + self.url = reverse(self.url_name) + + def test_login(self): + # try bad password first + response = self.client.post(self.url, {'username': 'test', 'password': 'wrong'}) + self.assertEqual(response.status_code, 200) + self.assertContains(response, 'Invalid') + # now try right password + response = self.client.post(self.url, {'username': 'test', 'password': 'right'}) + self.assertEqual(response.status_code, 302) + self.assertRedirects(response, reverse('profile-dashboard')) From d453b2f3d63501aeab9834371f869a91484be51f Mon Sep 17 00:00:00 2001 From: Vinod Kurup Date: Fri, 30 Aug 2013 16:33:12 -0400 Subject: [PATCH 19/22] Finish up project testing --- raspberryio/project/tests/test_forms.py | 20 +++++++++++++++++ raspberryio/project/tests/test_models.py | 28 ++++++++++++++++++++++++ 2 files changed, 48 insertions(+) diff --git a/raspberryio/project/tests/test_forms.py b/raspberryio/project/tests/test_forms.py index aaf2d5d..a445612 100644 --- a/raspberryio/project/tests/test_forms.py +++ b/raspberryio/project/tests/test_forms.py @@ -7,8 +7,18 @@ class ProjectFormTestCase(ProjectBaseTestCase): def setUp(self): + self.request_factory = RequestFactory() self.project = self.create_project() + def test_placeholder_labels(self): + request = self.request_factory.get('/') + form = ProjectStepForm() + # first assert that label is shown + self.assertEqual(form.fields['title'].label, 'Title') + form.Meta.remove_labels = True + form = ProjectStepForm(request.GET, instance=self.project) + # now assert that Meta attribute removes it + self.assertEqual(form.fields['title'].label, '') class ProjectStepFormTestCase(ProjectBaseTestCase): @@ -99,6 +109,16 @@ def test_multiple_images_valid(self): else: self.fail('Form should be valid') + def test_bad_video_url(self): + post_data = { + 'title': self.get_random_string(), + 'content': self.get_random_string(), + 'video': 'http://example.com/badurl', + } + request = self.request_factory.post('/', post_data) + form = ProjectStepForm(request.POST, instance=self.project_step) + self.assertFalse(form.is_valid()) + class ProjectImageFormTestCase(ProjectBaseTestCase): diff --git a/raspberryio/project/tests/test_models.py b/raspberryio/project/tests/test_models.py index 0eb0cb2..93e5f37 100644 --- a/raspberryio/project/tests/test_models.py +++ b/raspberryio/project/tests/test_models.py @@ -1,5 +1,6 @@ from datetime import timedelta +from django.core.urlresolvers import reverse from django.test.client import RequestFactory from mezzanine.utils.timezone import now @@ -42,6 +43,15 @@ def test_is_published_false(self): def test_default_draft(self): self.assertEqual(self.project.status, CONTENT_STATUS_DRAFT) + def test_video_params(self): + # first test that garbage input doesn't work + self.assertEqual(self.project.embed_url, None) + # now test a real video URL + video_id = "6BbufUp_HNs" + video_url = "http://www.youtube.com/watch?v=%s" % video_id + project = self.create_project(featured_video=video_url) + self.assertEqual(project.video_id, video_id) + self.assertEqual(project.embed_url, 'http://www.youtube.com/embed/%s?wmode=transparent' % video_id) class ProjectStepTestCase(ProjectBaseTestCase): @@ -117,3 +127,21 @@ def test_order_number(self): self.assertEqual(project1_step1._order, 1) self.assertEqual(project2_step0._order, 0) self.assertEqual(project2_step1._order, 1) + + def test_absolute_url(self): + self.assertEqual(self.project_step.get_absolute_url(), + reverse('project-detail', args=[self.project.slug])) + + def test_video_params(self): + # first test that garbage input doesn't work + self.assertEqual(self.project_step.embed_url, None) + # now test a real video URL + video_id = "6BbufUp_HNs" + video_url = "http://www.youtube.com/watch?v=%s" % video_id + project_step = self.create_project_step(video=video_url) + self.assertEqual(project_step.video_id, video_id) + self.assertEqual(project_step.embed_url, 'http://www.youtube.com/embed/%s?wmode=transparent' % video_id) + + def test_unicode_method(self): + unicode = 'Step %d of project %s' % (self.project_step._order, self.project.title) + self.assertEqual(self.project_step.__unicode__(), unicode) From 6ecab67fe56d1a2a574552d537b8a12697f34451 Mon Sep 17 00:00:00 2001 From: Vinod Kurup Date: Fri, 30 Aug 2013 20:40:36 -0400 Subject: [PATCH 20/22] Trivial improvements to aggregator tests --- raspberryio/aggregator/tests.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/raspberryio/aggregator/tests.py b/raspberryio/aggregator/tests.py index f9aa61a..4c08ad3 100644 --- a/raspberryio/aggregator/tests.py +++ b/raspberryio/aggregator/tests.py @@ -15,6 +15,7 @@ from .management.commands import send_pending_approval_email from . import models +from . import utils class MockResponse(object): @@ -78,3 +79,17 @@ def test_management_command_sends_email_with_pending_feeds(self): send_pending_approval_email.Command().handle_noargs() self.assertEqual(1, len(mail.outbox)) self.assertEqual(mail.outbox[0].to, [self.user.email]) + + def test_feed_type_items(self): + # 4 items were created in our default feed_type in setUp + self.assertEqual(len(self.feed_type.items()), 4) + + def test_unicode_method(self): + self.assertEqual(self.approved_feed.__unicode__(), 'Approved') + + +class UtilsTests(TestCase): + + def test_push_credentials(self): + settings.SUPERFEEDR_CREDS = ['testid', 'testsecret'] + self.assertEqual(utils.push_credentials(''), ('testid', 'testsecret')) From e1a07c06fe29557c06e75bd1be7554c19e95c644 Mon Sep 17 00:00:00 2001 From: Vinod Kurup Date: Thu, 5 Sep 2013 12:05:43 -0400 Subject: [PATCH 21/22] Update Changelog and include Caleb's fixes --- docs/CHANGELOG.rst | 1 + docs/developer.rst | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/CHANGELOG.rst b/docs/CHANGELOG.rst index b5f48d8..fad0522 100644 --- a/docs/CHANGELOG.rst +++ b/docs/CHANGELOG.rst @@ -4,6 +4,7 @@ Raspberry IO Changelog Version 0.3 (Unreleased) ------------------------ +* Improve coverage to near 100% (excepting aggregator) * Add DISQUS comments to project detail page * Add link to RaspberryIO Twitter account * Improve pagination throughout site diff --git a/docs/developer.rst b/docs/developer.rst index 5593384..e877b8f 100644 --- a/docs/developer.rst +++ b/docs/developer.rst @@ -100,4 +100,4 @@ commenting functionality. ``DISQUS_SHORTNAME`` is set to staging site. If local developers wish to test commenting for some reason, then they should create a DISQUS account, set up a new shortname and use that for ``DISQUS_SHORTNAME`` in -``raspberryio.settings.base``. +``raspberryio.settings.local``. From 4fcc323cf628571e3e479cf1b9d81264bfd29680 Mon Sep 17 00:00:00 2001 From: Vinod Kurup Date: Thu, 5 Sep 2013 13:03:05 -0400 Subject: [PATCH 22/22] Prepare develop branch for release --- docs/CHANGELOG.rst | 2 +- setup.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/CHANGELOG.rst b/docs/CHANGELOG.rst index fad0522..6d81f1e 100644 --- a/docs/CHANGELOG.rst +++ b/docs/CHANGELOG.rst @@ -1,7 +1,7 @@ Raspberry IO Changelog ====================== -Version 0.3 (Unreleased) +Version 0.3 (2013-09-05) ------------------------ * Improve coverage to near 100% (excepting aggregator) diff --git a/setup.py b/setup.py index d2c08bd..094c5c1 100644 --- a/setup.py +++ b/setup.py @@ -2,7 +2,7 @@ setup( name='raspberryio', - version='0.2', + version='0.3', packages=['raspberryio', 'raspberryio.aggregator', 'raspberryio.project', 'raspberryio.qanda', 'raspberryio.search', 'raspberryio.search_models', 'raspberryio.userprofile'],