Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Loading…

Adjust the 'attachments' property of Documents to find all files. #345

Closed
wants to merge 1 commit into from

4 participants

@darkwing
Owner

This uses pretty simple logic to scan a Document's HTML for both
MindTouch and kuma file URL patterns, and then uses Q objects to build
a correct query to return the corresponding Attachment objects. If no
file URLs are found in the Document, it'll return an empty Attachment
queryset.

fix bug 770397 - Displaying attachments table under document and tags

fix bug 770563 - Show tags and file attachments regardless of TOC

Bugfix: actually wrap the file queries in Q objects.

Changing file URL method

@darkwing
Owner

This is a consolidated, merged PR of:

#339

and:

#343

@darkwing
Owner

Fix file size duplication.

apps/wiki/tests/test_views.py
@@ -1846,4 +1847,111 @@ def test_legacy_redirect(self):
'filename': f['filename']})
resp = self.client.get(mindtouch_url)
eq_(301, resp.status_code)
+<<<<<<< HEAD

Merge markers - bad stuff here! Can't merge with this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
apps/wiki/tests/test_views.py
((5 lines not shown))
ok_(a.get_absolute_url() in resp['Location'])
+=======

Maybe just the conflict marker chunk needs to be removed?

@darkwing Owner
darkwing added a note

Found, fixed. Sorry about that, not sure how that happened.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@darkwing darkwing Adjust the 'attachments' property of Documents to find all files.
This uses pretty simple logic to scan a Document's HTML for both
MindTouch and kuma file URL patterns, and then uses Q objects to build
a correct query to return the corresponding Attachment objects. If no
file URLs are found in the Document, it'll return an empty Attachment
queryset.

fix bug 770397 - Displaying attachments table under document and tags

fix bug 770563 - Show tags and file attachments regardless of TOC

Bugfix: actually wrap the file queries in Q objects.

Changing file URL method

Removing unnecessary filesize() method from AttachmentRevisions model

Fixing merge conflict
fe75794
@groovecoder groovecoder commented on the diff
apps/wiki/forms.py
@@ -392,3 +394,36 @@ def clean_slug(self):
if '/' in self.cleaned_data['slug']:
raise forms.ValidationError(SLUG_INVALID)
return super(RevisionValidationForm, self).clean_slug()
+
+
+class AttachmentRevisionForm(forms.ModelForm):
+ # Unlike the DocumentForm/RevisionForm split, we have only one
+ # form for file attachments. The handling view will determine if
+ # this is a new revision of an existing file, or the first version
+ # of a new file.
+ #
+ # As a result of this, calling save(commit=True) is off-limits.
+ class Meta:
+ model = AttachmentRevision
+ fields = ('file', 'title', 'description', 'comment')
+
+ def save(self, commit=True):
@groovecoder Owner

why do we have commit=True default value if it raises an error?

Mostly because it's the standard API for ModelForm, and toggling the default, or requiring it to be specified explicitly, would break unaware code in ways that doesn't raise the NotImplementedError.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@groovecoder groovecoder commented on the diff
apps/wiki/views.py
((8 lines not shown))
# TODO: For now this just grabs and serves the file in the most
- # naive way, since that ensures compatibility for the most common
- # case where we just want to show the file contents embedded in a
- # document.
- #
- # In the future, this should grow to be multiple views -- one
- # legacy view to support document-embedded file URLs, and then
- # more full-featured views for showing metadata, revision history,
- # uploading new versions, etc.
+ # naive way. This likely has performance and security implications.
@groovecoder Owner

we should use some code like https://github.com/mozilla/kuma/blob/master/apps/demos/models.py#L641 to black-list certain mime-types.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@groovecoder
Owner

We should also add these models to the django admin interface.

@groovecoder groovecoder commented on the diff
((7 lines not shown))
+ # Files.
+ url(r'^files/new/$',
+ 'wiki.views.new_attachment',
+ name='wiki.new_attachment'),
+ url(r'^files/(?P<attachment_id>\d+)/$',
+ 'wiki.views.attachment_detail',
+ name='wiki.attachment_detail'),
+ url(r'^files/(?P<attachment_id>\d+)/edit/$',
+ 'wiki.views.edit_attachment',
+ name='wiki.edit_attachment'),
+ url(r'^files/(?P<attachment_id>\d+)/history/$',
+ 'wiki.views.attachment_history',
+ name='wiki.attachment_history'),
+ url(r'^files/(?P<attachment_id>\d+)/(?P<filename>.+)$',
+ 'wiki.views.raw_file',
+ name='wiki.raw_file'),
@groovecoder Owner

should these be in wiki views? I guess then they'd be /en-US/docs/files/* ?

@groovecoder Owner

in any case, we should exempt these urls from the url prefixer? (I forget how to do this)

They need to be top-level since they don't really want to end up under docs/ and subject to the documentation URL hierarchy. Agree that we need to keep the prefixer off 'em, and I don't actually know how to do that.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@ubernostrum

Closing in favor of PR 353.

@ubernostrum ubernostrum closed this
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Jul 5, 2012
  1. @darkwing

    Adjust the 'attachments' property of Documents to find all files.

    darkwing authored
    This uses pretty simple logic to scan a Document's HTML for both
    MindTouch and kuma file URL patterns, and then uses Q objects to build
    a correct query to return the corresponding Attachment objects. If no
    file URLs are found in the Document, it'll return an empty Attachment
    queryset.
    
    fix bug 770397 - Displaying attachments table under document and tags
    
    fix bug 770563 - Show tags and file attachments regardless of TOC
    
    Bugfix: actually wrap the file queries in Q objects.
    
    Changing file URL method
    
    Removing unnecessary filesize() method from AttachmentRevisions model
    
    Fixing merge conflict
This page is out of date. Refresh to see the latest.
View
35 apps/wiki/forms.py
@@ -1,4 +1,5 @@
import json
+import mimetypes
import re
from django import forms
@@ -17,6 +18,7 @@
import wiki.content
from wiki.models import (Document, Revision, FirefoxVersion, OperatingSystem,
+ AttachmentRevision,
FIREFOX_VERSIONS, OPERATING_SYSTEMS, SIGNIFICANCES,
GROUPED_FIREFOX_VERSIONS, GROUPED_OPERATING_SYSTEMS,
CATEGORIES, REVIEW_FLAG_TAGS, RESERVED_SLUGS)
@@ -392,3 +394,36 @@ def clean_slug(self):
if '/' in self.cleaned_data['slug']:
raise forms.ValidationError(SLUG_INVALID)
return super(RevisionValidationForm, self).clean_slug()
+
+
+class AttachmentRevisionForm(forms.ModelForm):
+ # Unlike the DocumentForm/RevisionForm split, we have only one
+ # form for file attachments. The handling view will determine if
+ # this is a new revision of an existing file, or the first version
+ # of a new file.
+ #
+ # As a result of this, calling save(commit=True) is off-limits.
+ class Meta:
+ model = AttachmentRevision
+ fields = ('file', 'title', 'description', 'comment')
+
+ def save(self, commit=True):
@groovecoder Owner

why do we have commit=True default value if it raises an error?

Mostly because it's the standard API for ModelForm, and toggling the default, or requiring it to be specified explicitly, would break unaware code in ways that doesn't raise the NotImplementedError.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
+ if commit:
+ raise NotImplementedError
+ rev = super(AttachmentRevisionForm, self).save(commit=False)
+
+ uploaded_file = self.cleaned_data['file']
+ rev.slug = uploaded_file.name
+
+ # guess_type() is usually pretty good at coming up with the
+ # right thing, but if it can't give us an answer, we fall back
+ # to a default of application/octet-stream.
+ #
+ # TODO: we probably want a "manually fix the mime-type"
+ # ability in the admin.
+ mime_type = mimetypes.guess_type(uploaded_file.name)[0]
+ if mime_type is None:
+ mime_type = 'application/octet-stream'
+ rev.mime_type = mime_type
+
+ return rev
View
34 apps/wiki/models.py
@@ -198,6 +198,7 @@
DOCUMENT_LAST_MODIFIED_CACHE_KEY_TMPL = u'kuma:document-last-modified:%s'
DEKI_FILE_URL = re.compile(r'@api/deki/files/(?P<file_id>\d+)/=')
+KUMA_FILE_URL = re.compile(r'/files/(?P<file_id>\d+)/.+\..+')
class UniqueCollision(Exception):
@@ -805,17 +806,22 @@ def attachments(self):
# instead, the page just gets appropriate HTML to embed
# whatever type of file it is. So we find them by
# regex-searching over the HTML for URLs that match the
- # MindTouch file URL pattern.
- #
- # TODO: Once we settle kuma's file URL pattern and people
- # start using kuma's file-handling, we'll need to also scan
- # for the kuma file URL pattern. That'll probably just involve
- # setting up a couple Q() objects (one for MindTouch file IDs,
- # one for kuma file IDs) and OR'ing them together to get the
- # file query.
+ # file URL patterns.
mt_files = DEKI_FILE_URL.findall(self.html)
+ kuma_files = KUMA_FILE_URL.findall(self.html)
+ mt_q = kuma_q = params = None
+
if mt_files:
- return Attachment.objects.filter(mindtouch_attachment_id__in=mt_files)
+ # We have at least some MindTouch files.
+ params = models.Q(mindtouch_attachment_id__in=mt_files)
+ if kuma_files:
+ # We also have some kuma files. Use an OR query.
+ params = params | models.Q(id__in=kuma_files)
+ if kuma_files and not params:
+ # We have only kuma files.
+ params = models.Q(id__in=kuma_files)
+ if params:
+ return Attachment.objects.filter(params)
# If no files found, return an empty Attachment queryset.
return Attachment.objects.none()
@@ -1384,8 +1390,12 @@ class Attachment(models.Model):
@models.permalink
def get_absolute_url(self):
- return ('wiki.attachment_detail', (), {'attachment_id': self.id,
- 'filename': self.current_revision.filename()})
+ return ('wiki.attachment_detail', (), {'attachment_id': self.id})
+
+ @models.permalink
+ def get_file_url(self):
+ return ('wiki.raw_file', (), {'attachment_id': self.id,
+ 'filename': self.current_revision.filename()})
class AttachmentRevision(models.Model):
@@ -1397,8 +1407,6 @@ class AttachmentRevision(models.Model):
file = models.FileField(upload_to=rev_upload_to, max_length=500)
- # If not supplied, these get auto-filled from the name of the file
- # as uploaded.
title = models.CharField(max_length=255, null=True, db_index=True)
slug = models.CharField(max_length=255, null=True, db_index=True)
View
1  apps/wiki/templates/wiki/attachment_detail.html
@@ -0,0 +1 @@
+
View
1  apps/wiki/templates/wiki/attachment_history.html
@@ -0,0 +1 @@
+
View
58 apps/wiki/templates/wiki/document.html
@@ -170,6 +170,9 @@ <h1 class="page-title">{{ document.title }}</h1>
</div>
{% endif %}
+ {% set tags = document.tags.all() %}
+ {% set attachments = document.attachments.all() %}
+
<div id="wikiArticle" class="page-content boxed">
{% if toc_html %}
<div id="article-nav">
@@ -180,8 +183,20 @@ <h1 class="page-title">{{ document.title }}</h1>
</ol>
</div>
<ul class="page-anchors">
- <li class="anchor-tags"><a href="#page-tags">Tags</a></li>
- <li class="anchor-files"><a href="#page-files">Files</a></li>
+ <li class="anchor-tags">
+ {% if tags|length %}
+ <a href="#page-tags">Tags</a>
+ {% else %}
+ <span title="{{ _('This document has no tags') }}">Tags</span>
+ {% endif %}
+ </li>
+ <li class="anchor-files">
+ {% if attachments|length %}
+ <a href="#page-file">Files</a>
+ {% else %}
+ <span title="{{ _('This document has no files') }}">Files</span>
+ {% endif %}
+ </li>
</ul>
</div>
{% endif %}
@@ -200,10 +215,10 @@ <h1 class="page-title">{{ document.title }}</h1>
{% endif %}
</div>
<section class="page-meta">
- {% set tags = document.tags.all() %}
+
{% if tags | length %}
<section id="page-tags">
- <h2>{{ _('Tags') }}</h2>
+ <h2>{{ _('Tags') }} ({{ tags | length}})</h2>
<div id="deki-page-tags">
<ul class="tags">
<li>
@@ -215,6 +230,39 @@ <h1 class="page-title">{{ document.title }}</h1>
</div>
</section>
{% endif %}
+
+ {% if attachments | length %}
+ <section id="page-attachments">
+ <h2>{{ _('Attachments') }} ({{ attachments | length}})</h2>
+ <table cellpadding="0" cellspacing="0">
+ <thead>
+ <th>{{ _('File') }}</th>
+ <th>{{ _('Size') }}</th>
+ <th>{{ _('Date') }}</th>
+ <th>{{ _('Attached by') }}</th>
+ <!-- <th>&nbsp;</th> actions will go here -->
+ </thead>
+ <tbody>
+ {% for attachment in attachments %}
+ <tr>
+ <td class="attachment-name-cell">
+ <a href="{{ attachment.get_file_url() }}" title="{{ attachment.get_file_url() }}" target="_blank">{{ attachment.title | safe }}</a>
+ {% if attachment.current_revision.description %}
+ <div class="attachment-description">{{ attachment.current_revision.description }}</div>
+ {% endif %}
+ </td>
+ <td>{{ attachment.current_revision.file.size }} bytes</td>
+ <td>{{ datetimeformat(attachment.current_revision.created, format='datetime') }}</td>
+ <td><a href="{{ url('devmo.views.profile_view', username=attachment.current_revision.creator) }}">{{ attachment.current_revision.creator }}</a></td>
+ <!--<td>&nbsp;</td> actions will go here -->
+ </tr>
+ {% endfor %}
+ </tbody>
+ </table>
+ </section>
+ {% endif %}
+
+
<section id="doc-contributors">
{% trans contributors=user_list(contributors) %}
Contributors to this page: {{ contributors }}
@@ -252,4 +300,4 @@ <h1 class="page-title">{{ document.title }}</h1>
{% block side %}
{% include 'wiki/includes/support_for_selectors.html' %}
-{% endblock %}
+{% endblock %}
View
1  apps/wiki/templates/wiki/edit_attachment.html
@@ -0,0 +1 @@
+
View
1  apps/wiki/templates/wiki/new_attachment.html
@@ -0,0 +1 @@
+
View
106 apps/wiki/tests/test_views.py
@@ -13,6 +13,7 @@
from django.contrib.sites.models import Site
from django.core.cache import cache
from django.core.files.base import ContentFile
+from django.core.files import temp as tempfile
from django.db.models import Q
import mock
@@ -1846,4 +1847,107 @@ def test_legacy_redirect(self):
'filename': f['filename']})
resp = self.client.get(mindtouch_url)
eq_(301, resp.status_code)
- ok_(a.get_absolute_url() in resp['Location'])
+ ok_(a.get_file_url() in resp['Location'])
+
+ def test_new_attachment(self):
+ self.client.login(username='testuser', password='testpass')
+
+ # Shamelessly stolen from Django's own file-upload tests.
+ tdir = tempfile.gettempdir()
+ file_for_upload = tempfile.NamedTemporaryFile(suffix=".txt", dir=tdir)
+ file_for_upload.write('I am a test file for upload.')
+ file_for_upload.seek(0)
+
+ post_data = {
+ 'title': 'Test uploaded file',
+ 'description': 'A test file uploaded into kuma.',
+ 'comment': 'Initial upload',
+ 'file': file_for_upload,
+ }
+
+ resp = self.client.post(reverse('wiki.new_attachment'), data=post_data)
+ eq_(302, resp.status_code)
+
+ attachment = Attachment.objects.get(title='Test uploaded file')
+ eq_(resp['Location'], 'http://testserver%s' % attachment.get_absolute_url())
+
+ rev = attachment.current_revision
+ eq_('testuser', rev.creator.username)
+ eq_('A test file uploaded into kuma.', rev.description)
+ eq_('Initial upload', rev.comment)
+ ok_(rev.is_approved)
+
+ def test_edit_attachment(self):
+ self.client.login(username='testuser', password='testpass')
+
+ tdir = tempfile.gettempdir()
+ file_for_upload = tempfile.NamedTemporaryFile(suffix=".txt", dir=tdir)
+ file_for_upload.write('I am a test file for editing.')
+ file_for_upload.seek(0)
+
+ post_data = {
+ 'title': 'Test editing file',
+ 'description': 'A test file for editing.',
+ 'comment': 'Initial upload',
+ 'file': file_for_upload,
+ }
+
+ resp = self.client.post(reverse('wiki.new_attachment'), data=post_data)
+
+ tdir = tempfile.gettempdir()
+ edited_file_for_upload = tempfile.NamedTemporaryFile(suffix=".txt", dir=tdir)
+ edited_file_for_upload.write('I am a new version of the test file for editing.')
+ edited_file_for_upload.seek(0)
+
+ post_data = {
+ 'title': 'Test editing file',
+ 'description': 'A test file for editing.',
+ 'comment': 'Second revision.',
+ 'file': edited_file_for_upload,
+ }
+
+ attachment = Attachment.objects.get(title='Test editing file')
+
+ resp = self.client.post(reverse('wiki.edit_attachment',
+ kwargs={'attachment_id': attachment.id}),
+ data=post_data)
+
+ eq_(302, resp.status_code)
+
+ # Re-fetch because it's been updated.
+ attachment = Attachment.objects.get(title='Test editing file')
+ eq_(resp['Location'], 'http://testserver%s' % attachment.get_absolute_url())
+
+ eq_(2, attachment.revisions.count())
+
+ rev = attachment.current_revision
+ eq_('testuser', rev.creator.username)
+ eq_('Second revision.', rev.comment)
+ ok_(rev.is_approved)
+
+ resp = self.client.get(attachment.get_file_url())
+ eq_('text/plain', rev.mime_type)
+ ok_('I am a new version of the test file for editing.' in resp.content)
+
+ def test_attachment_detail(self):
+ self.client.login(username='testuser', password='testpass')
+
+ tdir = tempfile.gettempdir()
+ file_for_upload = tempfile.NamedTemporaryFile(suffix=".txt", dir=tdir)
+ file_for_upload.write('I am a test file for attachment detail view.')
+ file_for_upload.seek(0)
+
+ post_data = {
+ 'title': 'Test file for viewing',
+ 'description': 'A test file for viewing.',
+ 'comment': 'Initial upload',
+ 'file': file_for_upload,
+ }
+
+ resp = self.client.post(reverse('wiki.new_attachment'), data=post_data)
+
+ attachment = Attachment.objects.get(title='Test file for viewing')
+
+ resp = self.client.get(reverse('wiki.attachment_detail',
+ kwargs={'attachment_id': attachment.id}))
+ eq_(200, resp.status_code)
View
73 apps/wiki/views.py
@@ -50,7 +50,8 @@
from wiki.decorators import check_readonly
from wiki.events import (EditDocumentEvent, ReviewableRevisionInLocaleEvent,
ApproveRevisionInLocaleEvent)
-from wiki.forms import DocumentForm, RevisionForm, ReviewForm, RevisionValidationForm
+from wiki.forms import (DocumentForm, RevisionForm, ReviewForm, RevisionValidationForm,
+ AttachmentRevisionForm)
from wiki.models import (Document, Revision, HelpfulVote, EditorToolbar,
DocumentTag, ReviewTag, Attachment,
DocumentRenderingInProgress,
@@ -1476,28 +1477,74 @@ def load_documents(request):
context_instance=RequestContext(request))
-def attachment_detail(request, attachment_id, filename):
- """Detail of a file attachment."""
+def raw_file(request, attachment_id, filename):
+ """Serve up an attachment's file."""
# TODO: For now this just grabs and serves the file in the most
- # naive way, since that ensures compatibility for the most common
- # case where we just want to show the file contents embedded in a
- # document.
- #
- # In the future, this should grow to be multiple views -- one
- # legacy view to support document-embedded file URLs, and then
- # more full-featured views for showing metadata, revision history,
- # uploading new versions, etc.
+ # naive way. This likely has performance and security implications.
@groovecoder Owner

we should use some code like https://github.com/mozilla/kuma/blob/master/apps/demos/models.py#L641 to black-list certain mime-types.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
attachment = get_object_or_404(Attachment, pk=attachment_id)
if attachment.current_revision is None:
raise Http404
rev = attachment.current_revision
resp = HttpResponse(rev.file.read(), mimetype=rev.mime_type)
resp["Last-Modified"] = rev.created
- resp["Content-Length"] = rev.size
+ resp["Content-Length"] = rev.file.size
return resp
def mindtouch_file_redirect(request, file_id, filename):
"""Redirect an old MindTouch file URL to a new kuma file URL."""
attachment = get_object_or_404(Attachment, mindtouch_attachment_id=file_id)
- return HttpResponsePermanentRedirect(attachment.get_absolute_url())
+ return HttpResponsePermanentRedirect(attachment.get_file_url())
+
+
+def attachment_detail(request, attachment_id):
+ """Detail view of an attachment."""
+ attachment = get_object_or_404(Attachment, pk=attachment_id)
+ return jingo.render(request, 'wiki/attachment_detail.html',
+ {'attachment': attachment})
+
+
+def attachment_history(request, attachment_id):
+ """Detail view of an attachment."""
+ # For now this is just attachment_detail with a different
+ # template. At some point in the near future, it'd be nice to add
+ # a few extra bits, like the ability to set an arbitrary revision
+ # to be current.
+ attachment = get_object_or_404(Attachment, pk=attachment_id)
+ return jingo.render(request, 'wiki/attachment_history.html',
+ {'attachment': attachment})
+
+@login_required
+def new_attachment(request):
+ """Create a new Attachment object and populate its initial
+ revision."""
+ if request.method == 'POST':
+ form = AttachmentRevisionForm(data=request.POST, files=request.FILES)
+ if form.is_valid():
+ rev = form.save(commit=False)
+ rev.creator = request.user
+ attachment = Attachment.objects.create(title=rev.title,
+ slug=rev.slug)
+ rev.attachment = attachment
+ rev.save()
+ return HttpResponseRedirect(attachment.get_absolute_url())
+ form = AttachmentRevisionForm()
+ return jingo.render(request, 'wiki/new_attachment.html',
+ {'form': form})
+
+
+@login_required
+def edit_attachment(request, attachment_id):
+ attachment = get_object_or_404(Attachment,
+ pk=attachment_id)
+ if request.method == 'POST':
+ form = AttachmentRevisionForm(data=request.POST, files=request.FILES)
+ if form.is_valid():
+ rev = form.save(commit=False)
+ rev.creator = request.user
+ rev.attachment = attachment
+ rev.save()
+ return HttpResponseRedirect(attachment.get_absolute_url())
+ form = AttachmentRevisionForm()
+ return jingo.render(request, 'wiki/edit_attachment.html',
+ {'form': form})
View
12 media/css/wiki-screen.css
@@ -84,6 +84,13 @@ textarea#id_content { width: 96%; padding: 15px; min-height: 300px; }
#page-tags ul.tagit { background: none repeat scroll 0 0 #FFFFFF; border: 1px solid #CBC8B9; padding: 6px 8px; }
#page-tags ul.tagit .tagit-label { color: #333333; font-weight: normal; }
+/* page attachments */
+#page-attachments table { margin: 20px 0 0 0; width: 100%; border: 1px solid #E0E0DC; border-bottom:0; border-right:0; border-collapse: collapse; }
+#page-attachments th, #page-attachments td { padding: 5px; border-bottom: 1px solid #E0E0DC; border-right: 1px solid #E0E0DC; }
+#page-attachments th { font-weight:bold; color: #666; }
+#page-attachments td { font-size: .9em; }
+#page-attachments .attachment-description { font-size: .9em; font-style: italic; }
+#page-attachments .attachment-name-cell { width: 40%; }
/*** @Tools @Nav *********/
#nav-toolbar { font-size: .785em; text-shadow: 1px 1px 0 rgba(255,255,255,.25); padding: 0; border-top: 1px solid #cbc8b9; border-bottom: 1px solid #f8f8f6; background: #e4e4d9; background: rgba(198,198,175,.35); }
@@ -287,9 +294,12 @@ input#id_title { font-size: 1.857em; width: 80%; padding: .1em 6px; margin: 0 0
#article-nav .page-anchors { background: #f1f6fb; margin: 0 0 5px; padding: 6px 18px; border: 1px solid #edf2f7; font-size: .785em; font-style: italic; text-transform: uppercase; }
#article-nav .page-anchors li { display: inline; padding: 0; margin-right: 12px; background: none; }
-#article-nav .page-anchors a { padding-left: 16px; }
+#article-nav .page-anchors a, #article-nav .page-anchors span { padding-left: 16px; }
+#article-nav .page-anchors span { cursor: default; }
#article-nav .anchor-tags a { background: transparent url("../img/wiki/icons/tag-tiny.png") 0 50% no-repeat; }
+#article-nav .anchor-tags span { background: transparent url("../img/wiki/icons/tag-tiny-disabled.png") 0 50% no-repeat; }
#article-nav .anchor-files a { background: transparent url("../img/wiki/icons/attach-tiny.png") 0 50% no-repeat; }
+#article-nav .anchor-files span { background: transparent url("../img/wiki/icons/attach-tiny-disabled.png") 0 50% no-repeat; }
/* @IRC @channels *********/
.suggestchannels { font-size: .857em; padding: 6px 6px 6px 8px; background-color: #f6f6f6; border: 1px solid #f3f3f3; margin-bottom: 5px; }
View
BIN  media/img/wiki/icons/attach-tiny-disabled.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN  media/img/wiki/icons/tag-tiny-disabled.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
19 urls.py
@@ -49,9 +49,22 @@
#url(r'^', include('dashboards.urls')),
- # File detail.
- url(r'^/files/(?P<attachment_id>\d+)/(?P<filename>.+)$',
- 'attachment_detail', name='wiki.attachment_detail'),
+ # Files.
+ url(r'^files/new/$',
+ 'wiki.views.new_attachment',
+ name='wiki.new_attachment'),
+ url(r'^files/(?P<attachment_id>\d+)/$',
+ 'wiki.views.attachment_detail',
+ name='wiki.attachment_detail'),
+ url(r'^files/(?P<attachment_id>\d+)/edit/$',
+ 'wiki.views.edit_attachment',
+ name='wiki.edit_attachment'),
+ url(r'^files/(?P<attachment_id>\d+)/history/$',
+ 'wiki.views.attachment_history',
+ name='wiki.attachment_history'),
+ url(r'^files/(?P<attachment_id>\d+)/(?P<filename>.+)$',
+ 'wiki.views.raw_file',
+ name='wiki.raw_file'),
@groovecoder Owner

should these be in wiki views? I guess then they'd be /en-US/docs/files/* ?

@groovecoder Owner

in any case, we should exempt these urls from the url prefixer? (I forget how to do this)

They need to be top-level since they don't really want to end up under docs/ and subject to the documentation URL hierarchy. Agree that we need to keep the prefixer off 'em, and I don't actually know how to do that.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
# Users
('', include('users.urls')),
Something went wrong with that request. Please try again.