Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Loading…

Closes #73 - allowing for projects to be hidden from public view #114

Open
wants to merge 1 commit into from

1 participant

@rossbruniges

The hope for this PR is to make getting projects live a bit easier, at least with a bit less copy and pasting...

  • projects are set as not public by default (they are still available for users given the URL to review)
  • when a project is not public we include the URL in the robots.txt to disallow
  • there is now an epic robots.txt
  • when we want a project to go live we flip the switch in the admin
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Mar 14, 2013
  1. @rossbruniges
This page is out of date. Refresh to see the latest.
View
10 make_mozilla/base/templates/robots.txt
@@ -0,0 +1,10 @@
+{% if DEBUG %}
+User-agent: *
+Disallow: /
+{% else %}
+User-agent: *
+
+{% for p in hidden_projects %}
+Disallow: {{ p.get_absolute_url() }}
+{% endfor %}
+{% endif %}
View
16 make_mozilla/base/views/root.py
@@ -1,6 +1,9 @@
import jingo
from datetime import datetime
+from django.conf import settings
+from django.http import HttpResponse
+
from make_mozilla.news.models import Article
from make_mozilla.projects.models import Project
from make_mozilla.events.models import Event
@@ -8,7 +11,7 @@
def index(request):
news = Article.objects.filter(featured=True).order_by('-updated')[0:3]
- projects = Project.objects.filter(featured=True).order_by('?')[0:5]
+ projects = Project.objects.public_projects().filter(featured=True).order_by('?')[0:5]
now = datetime.utcnow()
events = Event.objects.filter(
official=True
@@ -24,6 +27,17 @@ def index(request):
})
+def robots(request):
+ hidden_projects = Project.objects.filter(public=False)
+ context = {
+ 'DEBUG': settings.DEBUG,
+ 'hidden_projects': hidden_projects,
+ }
+ template = jingo.render(request, 'robots.txt', context)
+
+ return HttpResponse(template, mimetype="text/plain")
+
+
def fail(request):
return jingo.render(request, 'base/404.html', {}, status=404)
View
8 make_mozilla/projects/admin.py
@@ -7,16 +7,16 @@ class ProjectStepInline(admin.TabularInline):
class ProjectAdmin(admin.ModelAdmin):
- list_display = ('name', 'featured', 'contributor', )
- list_editable = ('featured', )
+ list_display = ('name', 'featured', 'contributor', 'public',)
+ list_editable = ('featured', 'public', )
list_filter = ('contributor', 'difficulties', 'topics', 'tools', 'skills', )
exclude = ('url_hash',)
- prepopulated_fields = {'slug': ('name',),}
+ prepopulated_fields = {'slug': ('name',), }
# inlines = [ProjectStepInline,]
class TagAdmin(admin.ModelAdmin):
- prepopulated_fields = {'value':('label',),}
+ prepopulated_fields = {'value': ('label',), }
fieldsets = (
(None, {
'fields': ('label', 'value', ),
View
8 make_mozilla/projects/managers.py
@@ -0,0 +1,8 @@
+from django.db import models
+
+
+class ProjectsManager(models.Manager):
+
+ # only return projects that are set to be visible
+ def public_projects(self):
+ return self.filter(public=True)
View
107 make_mozilla/projects/migrations/0004_auto__add_field_project_public.py
@@ -0,0 +1,107 @@
+# -*- coding: utf-8 -*-
+import datetime
+from south.db import db
+from south.v2 import SchemaMigration
+from django.db import models
+
+
+class Migration(SchemaMigration):
+
+ def forwards(self, orm):
+ # Adding field 'Project.public'
+ db.add_column('projects_project', 'public',
+ self.gf('django.db.models.fields.BooleanField')(default=False),
+ keep_default=False)
+
+ def backwards(self, orm):
+ # Deleting field 'Project.public'
+ db.delete_column('projects_project', 'public')
+
+ models = {
+ 'events.campaign': {
+ 'Meta': {'object_name': 'Campaign'},
+ 'description': ('django.db.models.fields.TextField', [], {}),
+ 'end': ('django.db.models.fields.DateField', [], {}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'logo': ('django.db.models.fields.files.ImageField', [], {'max_length': '100'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'slug': ('django.db.models.fields.SlugField', [], {'max_length': '50'}),
+ 'start': ('django.db.models.fields.DateField', [], {})
+ },
+ 'events.partner': {
+ 'Meta': {'ordering': "('name',)", 'object_name': 'Partner'},
+ 'featured': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'for_campaign': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['events.Campaign']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'logo': ('django.db.models.fields.files.ImageField', [], {'max_length': '100'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'website': ('django.db.models.fields.URLField', [], {'max_length': '200'})
+ },
+ 'projects.contributor': {
+ 'Meta': {'object_name': 'Contributor'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'local_name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'partner': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['events.Partner']", 'null': 'True', 'blank': 'True'})
+ },
+ 'projects.difficulty': {
+ 'Meta': {'ordering': "['index', 'label', 'id']", 'object_name': 'Difficulty'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'index': ('django.db.models.fields.IntegerField', [], {'default': '1', 'max_length': '2'}),
+ 'label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'value': ('django.db.models.fields.SlugField', [], {'max_length': '50'})
+ },
+ 'projects.project': {
+ 'Meta': {'ordering': "['-added']", 'object_name': 'Project'},
+ 'added': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+ 'body': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'contributor': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['projects.Contributor']", 'null': 'True', 'blank': 'True'}),
+ 'difficulties': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': "orm['projects.Difficulty']", 'null': 'True', 'blank': 'True'}),
+ 'featured': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'image': ('make_mozilla.core.fields.SizedImageField', [], {'max_length': '100'}),
+ 'link': ('django.db.models.fields.URLField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'public': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'skills': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': "orm['projects.Skill']", 'null': 'True', 'blank': 'True'}),
+ 'slug': ('django.db.models.fields.SlugField', [], {'default': "''", 'unique': 'True', 'max_length': '50'}),
+ 'teaser': ('django.db.models.fields.TextField', [], {}),
+ 'tools': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': "orm['tools.Tool']", 'null': 'True', 'blank': 'True'}),
+ 'topics': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': "orm['projects.Topic']", 'null': 'True', 'blank': 'True'}),
+ 'url_hash': ('django.db.models.fields.CharField', [], {'max_length': '20', 'null': 'True', 'blank': 'True'})
+ },
+ 'projects.projectstep': {
+ 'Meta': {'object_name': 'ProjectStep'},
+ 'content': ('django.db.models.fields.TextField', [], {}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'project': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'steps'", 'to': "orm['projects.Project']"})
+ },
+ 'projects.skill': {
+ 'Meta': {'ordering': "['index', 'label', 'id']", 'object_name': 'Skill'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'index': ('django.db.models.fields.IntegerField', [], {'default': '1', 'max_length': '2'}),
+ 'label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'value': ('django.db.models.fields.SlugField', [], {'max_length': '50'})
+ },
+ 'projects.topic': {
+ 'Meta': {'ordering': "['index', 'label', 'id']", 'object_name': 'Topic'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'index': ('django.db.models.fields.IntegerField', [], {'default': '1', 'max_length': '2'}),
+ 'label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'value': ('django.db.models.fields.SlugField', [], {'max_length': '50'})
+ },
+ 'tools.tool': {
+ 'Meta': {'ordering': "['name']", 'object_name': 'Tool'},
+ 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'featured': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'logo': ('django.db.models.fields.files.ImageField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'new': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'slug': ('django.db.models.fields.SlugField', [], {'max_length': '50'}),
+ 'status': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+ 'strapline': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'})
+ }
+ }
+
+ complete_apps = ['projects']
View
108 make_mozilla/projects/migrations/0005_make_public.py
@@ -0,0 +1,108 @@
+# -*- coding: utf-8 -*-
+import datetime
+from south.db import db
+from south.v2 import DataMigration
+from django.db import models
+
+
+class Migration(DataMigration):
+
+ def forwards(self, orm):
+ for project in orm.Project.objects.all():
+ project.public = True
+ project.save()
+
+ def backwards(self, orm):
+ for project in orm.Project.objects.all():
+ project.public = False
+ project.save()
+
+ models = {
+ 'events.campaign': {
+ 'Meta': {'object_name': 'Campaign'},
+ 'description': ('django.db.models.fields.TextField', [], {}),
+ 'end': ('django.db.models.fields.DateField', [], {}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'logo': ('django.db.models.fields.files.ImageField', [], {'max_length': '100'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'slug': ('django.db.models.fields.SlugField', [], {'max_length': '50'}),
+ 'start': ('django.db.models.fields.DateField', [], {})
+ },
+ 'events.partner': {
+ 'Meta': {'ordering': "('name',)", 'object_name': 'Partner'},
+ 'featured': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'for_campaign': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['events.Campaign']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'logo': ('django.db.models.fields.files.ImageField', [], {'max_length': '100'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'website': ('django.db.models.fields.URLField', [], {'max_length': '200'})
+ },
+ 'projects.contributor': {
+ 'Meta': {'object_name': 'Contributor'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'local_name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'partner': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['events.Partner']", 'null': 'True', 'blank': 'True'})
+ },
+ 'projects.difficulty': {
+ 'Meta': {'ordering': "['index', 'label', 'id']", 'object_name': 'Difficulty'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'index': ('django.db.models.fields.IntegerField', [], {'default': '1', 'max_length': '2'}),
+ 'label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'value': ('django.db.models.fields.SlugField', [], {'max_length': '50'})
+ },
+ 'projects.project': {
+ 'Meta': {'ordering': "['-added']", 'object_name': 'Project'},
+ 'added': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+ 'body': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'contributor': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['projects.Contributor']", 'null': 'True', 'blank': 'True'}),
+ 'difficulties': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': "orm['projects.Difficulty']", 'null': 'True', 'blank': 'True'}),
+ 'featured': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'image': ('make_mozilla.core.fields.SizedImageField', [], {'max_length': '100'}),
+ 'link': ('django.db.models.fields.URLField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'public': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'skills': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': "orm['projects.Skill']", 'null': 'True', 'blank': 'True'}),
+ 'slug': ('django.db.models.fields.SlugField', [], {'default': "''", 'unique': 'True', 'max_length': '50'}),
+ 'teaser': ('django.db.models.fields.TextField', [], {}),
+ 'tools': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': "orm['tools.Tool']", 'null': 'True', 'blank': 'True'}),
+ 'topics': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': "orm['projects.Topic']", 'null': 'True', 'blank': 'True'}),
+ 'url_hash': ('django.db.models.fields.CharField', [], {'max_length': '20', 'null': 'True', 'blank': 'True'})
+ },
+ 'projects.projectstep': {
+ 'Meta': {'object_name': 'ProjectStep'},
+ 'content': ('django.db.models.fields.TextField', [], {}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'project': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'steps'", 'to': "orm['projects.Project']"})
+ },
+ 'projects.skill': {
+ 'Meta': {'ordering': "['index', 'label', 'id']", 'object_name': 'Skill'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'index': ('django.db.models.fields.IntegerField', [], {'default': '1', 'max_length': '2'}),
+ 'label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'value': ('django.db.models.fields.SlugField', [], {'max_length': '50'})
+ },
+ 'projects.topic': {
+ 'Meta': {'ordering': "['index', 'label', 'id']", 'object_name': 'Topic'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'index': ('django.db.models.fields.IntegerField', [], {'default': '1', 'max_length': '2'}),
+ 'label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'value': ('django.db.models.fields.SlugField', [], {'max_length': '50'})
+ },
+ 'tools.tool': {
+ 'Meta': {'ordering': "['name']", 'object_name': 'Tool'},
+ 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'featured': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'logo': ('django.db.models.fields.files.ImageField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'new': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'slug': ('django.db.models.fields.SlugField', [], {'max_length': '50'}),
+ 'status': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+ 'strapline': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'})
+ }
+ }
+
+ complete_apps = ['projects']
+ symmetrical = True
View
12 make_mozilla/projects/models.py
@@ -8,9 +8,13 @@
from make_mozilla import tools
from make_mozilla import events
from make_mozilla.core import fields
+from make_mozilla.projects.managers import ProjectsManager
class Project(models.Model):
+
+ objects = ProjectsManager()
+
name = models.CharField(max_length=255)
slug = models.SlugField(unique=True, default='')
teaser = models.TextField()
@@ -34,9 +38,11 @@ class Project(models.Model):
topics = models.ManyToManyField('Topic', blank=True, null=True)
tools = models.ManyToManyField(tools.models.Tool, blank=True, null=True)
skills = models.ManyToManyField('Skill', blank=True, null=True)
+ public = models.BooleanField(default=False,
+ help_text="Check this box when you're happy with the project content and want users to see it")
class Meta:
- ordering = ['-added',]
+ ordering = ['-added', ]
def __init__(self, *args, **kwargs):
super(Project, self).__init__(*args, **kwargs)
@@ -147,10 +153,10 @@ def name(self):
def website(self):
if self.partner:
return self.partner.website
- return none
+ return None
@property
def logo(self):
if self.partner:
return self.partner.logo
- return None
+ return None
View
8 make_mozilla/projects/views.py
@@ -46,7 +46,7 @@ def results(self, difficulty=None, topic=None, tool=None, skill=None):
if skill is not None:
query['skills'] = skill
- return models.Project.objects.filter(**query)
+ return models.Project.objects.public_projects().filter(**query)
def paginated_results(self, page=1, difficulty=None, topic=None, tool=None, skill=None, results_per_page=8):
@@ -69,7 +69,7 @@ def __call__(self, request):
tool = self.extract_tool(request)
skill = self.extract_skill(request)
- featured = models.Project.objects.filter(featured=True)
+ featured = models.Project.objects.public_projects().filter(featured=True)
pagination = self.paginated_results(page, difficulty, topic, tool, skill)
invitation = models.Project(
@@ -114,7 +114,7 @@ def __call__(self, request):
def submit(request):
- return jingo.render(request, 'projects/submit.html');
+ return jingo.render(request, 'projects/submit.html')
def details(request, slug):
@@ -126,4 +126,4 @@ def details(request, slug):
return jingo.render(request, 'projects/detail.html', {
'project': project
- });
+ })
View
2  make_mozilla/settings/base.py
@@ -51,6 +51,8 @@
# Defines the views served for root URLs.
ROOT_URLCONF = 'make_mozilla.urls'
+SUPPORTED_NONLOCALES += ['robots.txt', ]
+
INSTALLED_APPS = list(INSTALLED_APPS) + [
'django.contrib.admin',
'django.contrib.gis',
View
6 make_mozilla/tools/views.py
@@ -6,13 +6,13 @@
def index_static(request):
thimble_qs = models.Tool.objects.filter(slug='thimble')
- thimble_projects = projects.models.Project.objects.filter(tools__in=thimble_qs).order_by('?')[:3]
+ thimble_projects = projects.models.Project.objects.public_projects().filter(tools__in=thimble_qs).order_by('?')[:3]
goggles_qs = models.Tool.objects.filter(slug='x-ray-goggles')
- goggles_projects = projects.models.Project.objects.filter(tools__in=goggles_qs).order_by('?')[:3]
+ goggles_projects = projects.models.Project.objects.public_projects().filter(tools__in=goggles_qs).order_by('?')[:3]
popcorn_qs = models.Tool.objects.filter(slug='popcorn')
- popcorn_projects = projects.models.Project.objects.filter(tools__in=popcorn_qs).order_by('?')[:3]
+ popcorn_projects = projects.models.Project.objects.public_projects().filter(tools__in=popcorn_qs).order_by('?')[:3]
return jingo.render(request, 'tools/index_static.html', {
'projects': {
View
2  make_mozilla/urls.py
@@ -30,6 +30,8 @@
# Uncomment the next line to enable the admin:
(r'^admin/', include(admin.site.urls)),
+ (r'^robots.txt$', 'make_mozilla.base.views.root.robots'),
+
(r'', include(make_mozilla.pages.urls)),
)
Something went wrong with that request. Please try again.