Remove simplewiki from the codebase
This commit is contained in:
@@ -122,11 +122,6 @@ In production, the django `collectstatic` command recompiles everything and puts
|
||||
|
||||
In development, we don't use collectstatic, instead accessing the files in place. The auto-compilation is run via `common/djangoapps/pipeline_mako/templates/static_content.html`. Details: templates include `<%namespace name='static' file='static_content.html'/>`, then something like `<%static:css group='application'/>` to call the functions in `common/djangoapps/pipeline_mako/__init__.py`, which call the `django-pipeline` compilers.
|
||||
|
||||
### Other modules
|
||||
|
||||
- Wiki -- in `lms/djangoapps/simplewiki`. Has some markdown extentions for embedding circuits, videos, etc.
|
||||
|
||||
|
||||
## Testing
|
||||
|
||||
See `testing.md`.
|
||||
|
||||
@@ -314,34 +314,6 @@ Psychoanalyze
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
||||
Simple wiki
|
||||
===========
|
||||
|
||||
.. automodule:: simplewiki
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
||||
Models
|
||||
------
|
||||
|
||||
.. automodule:: simplewiki.models
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
||||
Views
|
||||
-----
|
||||
|
||||
.. automodule:: simplewiki.views
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
||||
Tests
|
||||
-----
|
||||
|
||||
.. automodule:: simplewiki.tests
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
||||
|
||||
Static template view
|
||||
====================
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
# keys being the COURSE_NAME (spaces ok), and the value being a dict of
|
||||
# parameter,value pairs. The required parameters are:
|
||||
#
|
||||
# - number : course number (used in the simplewiki pages)
|
||||
# - number : course number (used in the wiki pages)
|
||||
# - title : humanized descriptive course title
|
||||
#
|
||||
# Optional parameters:
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
# Source: django-simplewiki. GPL license.
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
# allow mdx_* parsers to be just dropped in the simplewiki folder
|
||||
module_path = os.path.abspath(os.path.dirname(__file__))
|
||||
if module_path not in sys.path:
|
||||
sys.path.append(module_path)
|
||||
@@ -1,70 +0,0 @@
|
||||
# Source: django-simplewiki. GPL license.
|
||||
|
||||
from django import forms
|
||||
from django.contrib import admin
|
||||
from django.utils.translation import ugettext as _
|
||||
|
||||
from .models import Article, Revision, Permission, ArticleAttachment
|
||||
|
||||
|
||||
class RevisionInline(admin.TabularInline):
|
||||
model = Revision
|
||||
extra = 1
|
||||
|
||||
|
||||
class RevisionAdmin(admin.ModelAdmin):
|
||||
list_display = ('article', '__unicode__', 'revision_date', 'revision_user', 'revision_text')
|
||||
search_fields = ('article', 'counter')
|
||||
|
||||
|
||||
class AttachmentAdmin(admin.ModelAdmin):
|
||||
list_display = ('article', '__unicode__', 'uploaded_on', 'uploaded_by')
|
||||
|
||||
|
||||
class ArticleAdminForm(forms.ModelForm):
|
||||
def clean(self):
|
||||
cleaned_data = self.cleaned_data
|
||||
if cleaned_data.get("slug").startswith('_'):
|
||||
raise forms.ValidationError(_('Slug cannot start with _ character.'
|
||||
'Reserved for internal use.'))
|
||||
if not self.instance.pk:
|
||||
parent = cleaned_data.get("parent")
|
||||
slug = cleaned_data.get("slug")
|
||||
if Article.objects.filter(slug__exact=slug, parent__exact=parent):
|
||||
raise forms.ValidationError(_('Article slug and parent must be '
|
||||
'unique together.'))
|
||||
return cleaned_data
|
||||
|
||||
class Meta:
|
||||
model = Article
|
||||
|
||||
|
||||
class ArticleAdmin(admin.ModelAdmin):
|
||||
list_display = ('created_by', 'slug', 'modified_on', 'namespace')
|
||||
search_fields = ('slug',)
|
||||
prepopulated_fields = {'slug': ('title',)}
|
||||
inlines = [RevisionInline]
|
||||
form = ArticleAdminForm
|
||||
save_on_top = True
|
||||
|
||||
def formfield_for_foreignkey(self, db_field, request, **kwargs):
|
||||
if db_field.name == 'current_revision':
|
||||
# Try to determine the id of the article being edited
|
||||
id = request.path.split('/')
|
||||
import re
|
||||
if len(id) > 0 and re.match(r"\d+", id[-2]):
|
||||
kwargs["queryset"] = Revision.objects.filter(article=id[-2])
|
||||
return db_field.formfield(**kwargs)
|
||||
else:
|
||||
db_field.editable = False
|
||||
return db_field.formfield(**kwargs)
|
||||
return super(ArticleAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
|
||||
|
||||
|
||||
class PermissionAdmin(admin.ModelAdmin):
|
||||
search_fields = ('article', 'counter')
|
||||
|
||||
admin.site.register(Article, ArticleAdmin)
|
||||
admin.site.register(Revision, RevisionAdmin)
|
||||
admin.site.register(Permission, PermissionAdmin)
|
||||
admin.site.register(ArticleAttachment, AttachmentAdmin)
|
||||
@@ -1,72 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
'''
|
||||
Image Circuit Extension for Python-Markdown
|
||||
======================================
|
||||
|
||||
|
||||
Any single line beginning with circuit-schematic: and followed by data (which should be json data, but this
|
||||
is not enforced at this level) will be displayed as a circuit schematic. This is simply an input element with
|
||||
the value set to the data. It is left to javascript on the page to render that input as a circuit schematic.
|
||||
|
||||
ex:
|
||||
circuit-schematic:[["r",[128,48,0],{"r":"1","_json_":0},["2","1"]],["view",0,0,2,null,null,null,null,null,null,null],["dc",{"0":0,"1":1,"I(_3)":-1}]]
|
||||
|
||||
(This is a schematic with a single one-ohm resistor. Note that this data is not meant to be user-editable.)
|
||||
|
||||
'''
|
||||
import markdown
|
||||
import re
|
||||
|
||||
from django.utils.html import escape
|
||||
|
||||
try:
|
||||
# Markdown 2.1.0 changed from 2.0.3. We try importing the new version first,
|
||||
# but import the 2.0.3 version if it fails
|
||||
from markdown.util import etree
|
||||
except:
|
||||
from markdown import etree
|
||||
|
||||
|
||||
class CircuitExtension(markdown.Extension):
|
||||
def __init__(self, configs):
|
||||
for key, value in configs:
|
||||
self.setConfig(key, value)
|
||||
|
||||
def extendMarkdown(self, md, md_globals):
|
||||
## Because Markdown treats contigous lines as one block of text, it is hard to match
|
||||
## a regex that must occupy the whole line (like the circuit regex). This is why we have
|
||||
## a preprocessor that inspects the lines and replaces the matched lines with text that is
|
||||
## easier to match
|
||||
md.preprocessors.add('circuit', CircuitPreprocessor(md), "_begin")
|
||||
|
||||
pattern = CircuitLink(r'processed-schematic:(?P<data>.*?)processed-schematic-end')
|
||||
pattern.md = md
|
||||
pattern.ext = self
|
||||
md.inlinePatterns.add('circuit', pattern, "<reference")
|
||||
|
||||
|
||||
class CircuitPreprocessor(markdown.preprocessors.Preprocessor):
|
||||
preRegex = re.compile(r'^circuit-schematic:(?P<data>.*)$')
|
||||
|
||||
def run(self, lines):
|
||||
def convertLine(line):
|
||||
m = self.preRegex.match(line)
|
||||
if m:
|
||||
return 'processed-schematic:{0}processed-schematic-end'.format(m.group('data'))
|
||||
else:
|
||||
return line
|
||||
|
||||
return [convertLine(line) for line in lines]
|
||||
|
||||
|
||||
class CircuitLink(markdown.inlinepatterns.Pattern):
|
||||
def handleMatch(self, m):
|
||||
data = m.group('data')
|
||||
data = escape(data)
|
||||
return etree.fromstring("<div align='center'><input type='hidden' parts='' value='" + data + "' analyses='' class='schematic ctrls' width='640' height='480'/></div>")
|
||||
|
||||
|
||||
def makeExtension(configs=None):
|
||||
to_return = CircuitExtension(configs=configs)
|
||||
print "circuit returning ", to_return
|
||||
return to_return
|
||||
@@ -1,71 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
'''
|
||||
Image Embedding Extension for Python-Markdown
|
||||
======================================
|
||||
|
||||
Converts lone links to embedded images, provided the file extension is allowed.
|
||||
|
||||
Ex:
|
||||
http://www.ericfehse.net/media/img/ef/blog/django-pony.jpg
|
||||
becomes
|
||||
<img src="http://www.ericfehse.net/media/img/ef/blog/django-pony.jpg">
|
||||
|
||||
mypic.jpg becomes <img src="/MEDIA_PATH/mypic.jpg">
|
||||
|
||||
Requires Python-Markdown 1.6+
|
||||
'''
|
||||
|
||||
import simplewiki.settings as settings
|
||||
|
||||
import markdown
|
||||
try:
|
||||
# Markdown 2.1.0 changed from 2.0.3. We try importing the new version first,
|
||||
# but import the 2.0.3 version if it fails
|
||||
from markdown.util import etree
|
||||
except:
|
||||
from markdown import etree
|
||||
|
||||
|
||||
class ImageExtension(markdown.Extension):
|
||||
def __init__(self, configs):
|
||||
for key, value in configs:
|
||||
self.setConfig(key, value)
|
||||
|
||||
def add_inline(self, md, name, klass, re):
|
||||
pattern = klass(re)
|
||||
pattern.md = md
|
||||
pattern.ext = self
|
||||
md.inlinePatterns.add(name, pattern, "<reference")
|
||||
|
||||
def extendMarkdown(self, md, md_globals):
|
||||
self.add_inline(md, 'image', ImageLink,
|
||||
r'^(?P<proto>([^:/?#])+://)?(?P<domain>([^/?#]*)/)?(?P<path>[^?#]*\.(?P<ext>[^?#]{3,4}))(?:\?([^#]*))?(?:#(.*))?$')
|
||||
|
||||
|
||||
class ImageLink(markdown.inlinepatterns.Pattern):
|
||||
def handleMatch(self, m):
|
||||
img = etree.Element('img')
|
||||
proto = m.group('proto') or "http://"
|
||||
domain = m.group('domain')
|
||||
path = m.group('path')
|
||||
ext = m.group('ext')
|
||||
|
||||
# A fixer upper
|
||||
if ext.lower() in settings.WIKI_IMAGE_EXTENSIONS:
|
||||
if domain:
|
||||
src = proto + domain + path
|
||||
elif path:
|
||||
# We need a nice way to source local attachments...
|
||||
src = "/wiki/media/" + path + ".upload"
|
||||
else:
|
||||
src = ''
|
||||
img.set('src', src)
|
||||
return img
|
||||
|
||||
|
||||
def makeExtension(configs=None):
|
||||
return ImageExtension(configs=configs)
|
||||
|
||||
if __name__ == "__main__":
|
||||
import doctest
|
||||
doctest.testmod()
|
||||
@@ -1,30 +0,0 @@
|
||||
# Source: https://github.com/mayoff/python-markdown-mathjax
|
||||
|
||||
import markdown
|
||||
try:
|
||||
# Markdown 2.1.0 changed from 2.0.3. We try importing the new version first,
|
||||
# but import the 2.0.3 version if it fails
|
||||
from markdown.util import etree, AtomicString
|
||||
except:
|
||||
from markdown import etree, AtomicString
|
||||
|
||||
|
||||
class MathJaxPattern(markdown.inlinepatterns.Pattern):
|
||||
|
||||
def __init__(self):
|
||||
markdown.inlinepatterns.Pattern.__init__(self, r'(?<!\\)(\$\$?)(.+?)\2')
|
||||
|
||||
def handleMatch(self, m):
|
||||
el = etree.Element('span')
|
||||
el.text = AtomicString(m.group(2) + m.group(3) + m.group(2))
|
||||
return el
|
||||
|
||||
|
||||
class MathJaxExtension(markdown.Extension):
|
||||
def extendMarkdown(self, md, md_globals):
|
||||
# Needs to come before escape matching because \ is pretty important in LaTeX
|
||||
md.inlinePatterns.add('mathjax', MathJaxPattern(), '<escape')
|
||||
|
||||
|
||||
def makeExtension(configs=None):
|
||||
return MathJaxExtension(configs)
|
||||
@@ -1,289 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
"""
|
||||
Embeds web videos using URLs. For instance, if a URL to an youtube video is
|
||||
found in the text submitted to markdown and it isn't enclosed in parenthesis
|
||||
like a normal link in markdown, then the URL will be swapped with a embedded
|
||||
youtube video.
|
||||
|
||||
All resulting HTML is XHTML Strict compatible.
|
||||
|
||||
>>> import markdown
|
||||
|
||||
Test Metacafe
|
||||
|
||||
>>> s = "http://www.metacafe.com/watch/yt-tZMsrrQCnx8/pycon_2008_django_sprint_room/"
|
||||
>>> markdown.markdown(s, ['video'])
|
||||
u'<p><object data="http://www.metacafe.com/fplayer/yt-tZMsrrQCnx8/pycon_2008_django_sprint_room.swf" height="423" type="application/x-shockwave-flash" width="498"><param name="movie" value="http://www.metacafe.com/fplayer/yt-tZMsrrQCnx8/pycon_2008_django_sprint_room.swf" /><param name="allowFullScreen" value="true" /></object></p>'
|
||||
|
||||
|
||||
Test Metacafe with arguments
|
||||
|
||||
>>> markdown.markdown(s, ['video(metacafe_width=500,metacafe_height=425)'])
|
||||
u'<p><object data="http://www.metacafe.com/fplayer/yt-tZMsrrQCnx8/pycon_2008_django_sprint_room.swf" height="425" type="application/x-shockwave-flash" width="500"><param name="movie" value="http://www.metacafe.com/fplayer/yt-tZMsrrQCnx8/pycon_2008_django_sprint_room.swf" /><param name="allowFullScreen" value="true" /></object></p>'
|
||||
|
||||
|
||||
Test Link To Metacafe
|
||||
|
||||
>>> s = "[Metacafe link](http://www.metacafe.com/watch/yt-tZMsrrQCnx8/pycon_2008_django_sprint_room/)"
|
||||
>>> markdown.markdown(s, ['video'])
|
||||
u'<p><a href="http://www.metacafe.com/watch/yt-tZMsrrQCnx8/pycon_2008_django_sprint_room/">Metacafe link</a></p>'
|
||||
|
||||
|
||||
Test Markdown Escaping
|
||||
|
||||
>>> s = "\\http://www.metacafe.com/watch/yt-tZMsrrQCnx8/pycon_2008_django_sprint_room/"
|
||||
>>> markdown.markdown(s, ['video'])
|
||||
u'<p>http://www.metacafe.com/watch/yt-tZMsrrQCnx8/pycon_2008_django_sprint_room/</p>'
|
||||
>>> s = "`http://www.metacafe.com/watch/yt-tZMsrrQCnx8/pycon_2008_django_sprint_room/`"
|
||||
>>> markdown.markdown(s, ['video'])
|
||||
u'<p><code>http://www.metacafe.com/watch/yt-tZMsrrQCnx8/pycon_2008_django_sprint_room/</code></p>'
|
||||
|
||||
|
||||
Test Youtube
|
||||
|
||||
>>> s = "http://www.youtube.com/watch?v=u1mA-0w8XPo&hd=1&fs=1&feature=PlayList&p=34C6046F7FEACFD3&playnext=1&playnext_from=PL&index=1"
|
||||
>>> markdown.markdown(s, ['video'])
|
||||
u'<p><object data="http://www.youtube.com/v/u1mA-0w8XPo&hd=1&fs=1&feature=PlayList&p=34C6046F7FEACFD3&playnext=1&playnext_from=PL&index=1" height="344" type="application/x-shockwave-flash" width="425"><param name="movie" value="http://www.youtube.com/v/u1mA-0w8XPo&hd=1&fs=1&feature=PlayList&p=34C6046F7FEACFD3&playnext=1&playnext_from=PL&index=1" /><param name="allowFullScreen" value="true" /></object></p>'
|
||||
|
||||
|
||||
Test Youtube with argument
|
||||
|
||||
>>> markdown.markdown(s, ['video(youtube_width=200,youtube_height=100)'])
|
||||
u'<p><object data="http://www.youtube.com/v/u1mA-0w8XPo&hd=1&fs=1&feature=PlayList&p=34C6046F7FEACFD3&playnext=1&playnext_from=PL&index=1" height="100" type="application/x-shockwave-flash" width="200"><param name="movie" value="http://www.youtube.com/v/u1mA-0w8XPo&hd=1&fs=1&feature=PlayList&p=34C6046F7FEACFD3&playnext=1&playnext_from=PL&index=1" /><param name="allowFullScreen" value="true" /></object></p>'
|
||||
|
||||
|
||||
Test Youtube Link
|
||||
|
||||
>>> s = "[Youtube link](http://www.youtube.com/watch?v=u1mA-0w8XPo&feature=PlayList&p=34C6046F7FEACFD3&playnext=1&playnext_from=PL&index=1)"
|
||||
>>> markdown.markdown(s, ['video'])
|
||||
u'<p><a href="http://www.youtube.com/watch?v=u1mA-0w8XPo&feature=PlayList&p=34C6046F7FEACFD3&playnext=1&playnext_from=PL&index=1">Youtube link</a></p>'
|
||||
|
||||
|
||||
Test Dailymotion
|
||||
|
||||
>>> s = "http://www.dailymotion.com/relevance/search/ut2004/video/x3kv65_ut2004-ownage_videogames"
|
||||
>>> markdown.markdown(s, ['video'])
|
||||
u'<p><object data="http://www.dailymotion.com/swf/x3kv65_ut2004-ownage_videogames" height="405" type="application/x-shockwave-flash" width="480"><param name="movie" value="http://www.dailymotion.com/swf/x3kv65_ut2004-ownage_videogames" /><param name="allowFullScreen" value="true" /></object></p>'
|
||||
|
||||
|
||||
Test Dailymotion again (Dailymotion and their crazy URLs)
|
||||
|
||||
>>> s = "http://www.dailymotion.com/us/video/x8qak3_iron-man-vs-bruce-lee_fun"
|
||||
>>> markdown.markdown(s, ['video'])
|
||||
u'<p><object data="http://www.dailymotion.com/swf/x8qak3_iron-man-vs-bruce-lee_fun" height="405" type="application/x-shockwave-flash" width="480"><param name="movie" value="http://www.dailymotion.com/swf/x8qak3_iron-man-vs-bruce-lee_fun" /><param name="allowFullScreen" value="true" /></object></p>'
|
||||
|
||||
|
||||
Test Yahoo! Video
|
||||
|
||||
>>> s = "http://video.yahoo.com/watch/1981791/4769603"
|
||||
>>> markdown.markdown(s, ['video'])
|
||||
u'<p><object data="http://d.yimg.com/static.video.yahoo.com/yep/YV_YEP.swf?ver=2.2.40" height="322" type="application/x-shockwave-flash" width="512"><param name="movie" value="http://d.yimg.com/static.video.yahoo.com/yep/YV_YEP.swf?ver=2.2.40" /><param name="allowFullScreen" value="true" /><param name="flashVars" value="id=4769603&vid=1981791" /></object></p>'
|
||||
|
||||
|
||||
Test Veoh Video
|
||||
|
||||
>>> s = "http://www.veoh.com/search/videos/q/mario#watch%3De129555XxCZanYD"
|
||||
>>> markdown.markdown(s, ['video'])
|
||||
u'<p><object data="http://www.veoh.com/videodetails2.swf?permalinkId=e129555XxCZanYD" height="341" type="application/x-shockwave-flash" width="410"><param name="movie" value="http://www.veoh.com/videodetails2.swf?permalinkId=e129555XxCZanYD" /><param name="allowFullScreen" value="true" /></object></p>'
|
||||
|
||||
|
||||
Test Veoh Video Again (More fun URLs)
|
||||
|
||||
>>> s = "http://www.veoh.com/group/BigCatRescuers#watch%3Dv16771056hFtSBYEr"
|
||||
>>> markdown.markdown(s, ['video'])
|
||||
u'<p><object data="http://www.veoh.com/videodetails2.swf?permalinkId=v16771056hFtSBYEr" height="341" type="application/x-shockwave-flash" width="410"><param name="movie" value="http://www.veoh.com/videodetails2.swf?permalinkId=v16771056hFtSBYEr" /><param name="allowFullScreen" value="true" /></object></p>'
|
||||
|
||||
|
||||
Test Veoh Video Yet Again (Even more fun URLs)
|
||||
|
||||
>>> s = "http://www.veoh.com/browse/videos/category/anime/watch/v181645607JyXPWcQ"
|
||||
>>> markdown.markdown(s, ['video'])
|
||||
u'<p><object data="http://www.veoh.com/videodetails2.swf?permalinkId=v181645607JyXPWcQ" height="341" type="application/x-shockwave-flash" width="410"><param name="movie" value="http://www.veoh.com/videodetails2.swf?permalinkId=v181645607JyXPWcQ" /><param name="allowFullScreen" value="true" /></object></p>'
|
||||
|
||||
|
||||
Test Vimeo Video
|
||||
|
||||
>>> s = "http://www.vimeo.com/1496152"
|
||||
>>> markdown.markdown(s, ['video'])
|
||||
u'<p><object data="http://vimeo.com/moogaloop.swf?clip_id=1496152&amp;server=vimeo.com" height="321" type="application/x-shockwave-flash" width="400"><param name="movie" value="http://vimeo.com/moogaloop.swf?clip_id=1496152&amp;server=vimeo.com" /><param name="allowFullScreen" value="true" /></object></p>'
|
||||
|
||||
Test Vimeo Video with some GET values
|
||||
|
||||
>>> s = "http://vimeo.com/1496152?test=test"
|
||||
>>> markdown.markdown(s, ['video'])
|
||||
u'<p><object data="http://vimeo.com/moogaloop.swf?clip_id=1496152&amp;server=vimeo.com" height="321" type="application/x-shockwave-flash" width="400"><param name="movie" value="http://vimeo.com/moogaloop.swf?clip_id=1496152&amp;server=vimeo.com" /><param name="allowFullScreen" value="true" /></object></p>'
|
||||
|
||||
Test Blip.tv
|
||||
|
||||
>>> s = "http://blip.tv/file/get/Pycon-PlenarySprintIntro563.flv"
|
||||
>>> markdown.markdown(s, ['video'])
|
||||
u'<p><object data="http://blip.tv/scripts/flash/showplayer.swf?file=http://blip.tv/file/get/Pycon-PlenarySprintIntro563.flv" height="300" type="application/x-shockwave-flash" width="480"><param name="movie" value="http://blip.tv/scripts/flash/showplayer.swf?file=http://blip.tv/file/get/Pycon-PlenarySprintIntro563.flv" /><param name="allowFullScreen" value="true" /></object></p>'
|
||||
|
||||
Test Gametrailers
|
||||
|
||||
>>> s = "http://www.gametrailers.com/video/console-comparison-borderlands/58079"
|
||||
>>> markdown.markdown(s, ['video'])
|
||||
u'<p><object data="http://www.gametrailers.com/remote_wrap.php?mid=58079" height="392" type="application/x-shockwave-flash" width="480"><param name="movie" value="http://www.gametrailers.com/remote_wrap.php?mid=58079" /><param name="allowFullScreen" value="true" /></object></p>'
|
||||
"""
|
||||
|
||||
import markdown
|
||||
try:
|
||||
# Markdown 2.1.0 changed from 2.0.3. We try importing the new version first,
|
||||
# but import the 2.0.3 version if it fails
|
||||
from markdown.util import etree
|
||||
except:
|
||||
from markdown import etree
|
||||
|
||||
|
||||
version = "0.1.6"
|
||||
|
||||
|
||||
class VideoExtension(markdown.Extension):
|
||||
def __init__(self, configs):
|
||||
self.config = {
|
||||
'bliptv_width': ['480', 'Width for Blip.tv videos'],
|
||||
'bliptv_height': ['300', 'Height for Blip.tv videos'],
|
||||
'dailymotion_width': ['480', 'Width for Dailymotion videos'],
|
||||
'dailymotion_height': ['405', 'Height for Dailymotion videos'],
|
||||
'gametrailers_width': ['480', 'Width for Gametrailers videos'],
|
||||
'gametrailers_height': ['392', 'Height for Gametrailers videos'],
|
||||
'metacafe_width': ['498', 'Width for Metacafe videos'],
|
||||
'metacafe_height': ['423', 'Height for Metacafe videos'],
|
||||
'veoh_width': ['410', 'Width for Veoh videos'],
|
||||
'veoh_height': ['341', 'Height for Veoh videos'],
|
||||
'vimeo_width': ['400', 'Width for Vimeo videos'],
|
||||
'vimeo_height': ['321', 'Height for Vimeo videos'],
|
||||
'yahoo_width': ['512', 'Width for Yahoo! videos'],
|
||||
'yahoo_height': ['322', 'Height for Yahoo! videos'],
|
||||
'youtube_width': ['425', 'Width for Youtube videos'],
|
||||
'youtube_height': ['344', 'Height for Youtube videos'],
|
||||
}
|
||||
|
||||
# Override defaults with user settings
|
||||
for key, value in configs:
|
||||
self.setConfig(key, value)
|
||||
|
||||
def add_inline(self, md, name, klass, re):
|
||||
pattern = klass(re)
|
||||
pattern.md = md
|
||||
pattern.ext = self
|
||||
md.inlinePatterns.add(name, pattern, "<reference")
|
||||
|
||||
def extendMarkdown(self, md, md_globals):
|
||||
self.add_inline(md, 'bliptv', Bliptv,
|
||||
r'([^(]|^)http://(\w+\.|)blip.tv/file/get/(?P<bliptvfile>\S+.flv)')
|
||||
self.add_inline(md, 'dailymotion', Dailymotion,
|
||||
r'([^(]|^)http://www\.dailymotion\.com/(?P<dailymotionid>\S+)')
|
||||
self.add_inline(md, 'gametrailers', Gametrailers,
|
||||
r'([^(]|^)http://www.gametrailers.com/video/[a-z0-9-]+/(?P<gametrailersid>\d+)')
|
||||
self.add_inline(md, 'metacafe', Metacafe,
|
||||
r'([^(]|^)http://www\.metacafe\.com/watch/(?P<metacafeid>\S+)/')
|
||||
self.add_inline(md, 'veoh', Veoh,
|
||||
r'([^(]|^)http://www\.veoh\.com/\S*(#watch%3D|watch/)(?P<veohid>\w+)')
|
||||
self.add_inline(md, 'vimeo', Vimeo,
|
||||
r'([^(]|^)http://(www.|)vimeo\.com/(?P<vimeoid>\d+)\S*')
|
||||
self.add_inline(md, 'yahoo', Yahoo,
|
||||
r'([^(]|^)http://video\.yahoo\.com/watch/(?P<yahoovid>\d+)/(?P<yahooid>\d+)')
|
||||
self.add_inline(md, 'youtube', Youtube,
|
||||
r'([^(]|^)http://www\.youtube\.com/watch\?\S*v=(?P<youtubeargs>[A-Za-z0-9_&=-]+)\S*')
|
||||
|
||||
|
||||
class Bliptv(markdown.inlinepatterns.Pattern):
|
||||
def handleMatch(self, m):
|
||||
url = 'http://blip.tv/scripts/flash/showplayer.swf?file=http://blip.tv/file/get/%s' % m.group('bliptvfile')
|
||||
width = self.ext.config['bliptv_width'][0]
|
||||
height = self.ext.config['bliptv_height'][0]
|
||||
return flash_object(url, width, height)
|
||||
|
||||
|
||||
class Dailymotion(markdown.inlinepatterns.Pattern):
|
||||
def handleMatch(self, m):
|
||||
url = 'http://www.dailymotion.com/swf/%s' % m.group('dailymotionid').split('/')[-1]
|
||||
width = self.ext.config['dailymotion_width'][0]
|
||||
height = self.ext.config['dailymotion_height'][0]
|
||||
return flash_object(url, width, height)
|
||||
|
||||
|
||||
class Gametrailers(markdown.inlinepatterns.Pattern):
|
||||
def handleMatch(self, m):
|
||||
url = 'http://www.gametrailers.com/remote_wrap.php?mid=%s' % \
|
||||
m.group('gametrailersid').split('/')[-1]
|
||||
width = self.ext.config['gametrailers_width'][0]
|
||||
height = self.ext.config['gametrailers_height'][0]
|
||||
return flash_object(url, width, height)
|
||||
|
||||
|
||||
class Metacafe(markdown.inlinepatterns.Pattern):
|
||||
def handleMatch(self, m):
|
||||
url = 'http://www.metacafe.com/fplayer/%s.swf' % m.group('metacafeid')
|
||||
width = self.ext.config['metacafe_width'][0]
|
||||
height = self.ext.config['metacafe_height'][0]
|
||||
return flash_object(url, width, height)
|
||||
|
||||
|
||||
class Veoh(markdown.inlinepatterns.Pattern):
|
||||
def handleMatch(self, m):
|
||||
url = 'http://www.veoh.com/videodetails2.swf?permalinkId=%s' % m.group('veohid')
|
||||
width = self.ext.config['veoh_width'][0]
|
||||
height = self.ext.config['veoh_height'][0]
|
||||
return flash_object(url, width, height)
|
||||
|
||||
|
||||
class Vimeo(markdown.inlinepatterns.Pattern):
|
||||
def handleMatch(self, m):
|
||||
url = 'http://vimeo.com/moogaloop.swf?clip_id=%s&server=vimeo.com' % m.group('vimeoid')
|
||||
width = self.ext.config['vimeo_width'][0]
|
||||
height = self.ext.config['vimeo_height'][0]
|
||||
return flash_object(url, width, height)
|
||||
|
||||
|
||||
class Yahoo(markdown.inlinepatterns.Pattern):
|
||||
def handleMatch(self, m):
|
||||
url = "http://d.yimg.com/static.video.yahoo.com/yep/YV_YEP.swf?ver=2.2.40"
|
||||
width = self.ext.config['yahoo_width'][0]
|
||||
height = self.ext.config['yahoo_height'][0]
|
||||
obj = flash_object(url, width, height)
|
||||
param = etree.Element('param')
|
||||
param.set('name', 'flashVars')
|
||||
param.set('value', "id=%s&vid=%s" % (m.group('yahooid'),
|
||||
m.group('yahoovid')))
|
||||
obj.append(param)
|
||||
return obj
|
||||
|
||||
|
||||
class Youtube(markdown.inlinepatterns.Pattern):
|
||||
def handleMatch(self, m):
|
||||
url = 'http://www.youtube.com/v/%s' % m.group('youtubeargs')
|
||||
width = self.ext.config['youtube_width'][0]
|
||||
height = self.ext.config['youtube_height'][0]
|
||||
return flash_object(url, width, height)
|
||||
|
||||
|
||||
def flash_object(url, width, height):
|
||||
obj = etree.Element('object')
|
||||
obj.set('type', 'application/x-shockwave-flash')
|
||||
obj.set('width', width)
|
||||
obj.set('height', height)
|
||||
obj.set('data', url)
|
||||
param = etree.Element('param')
|
||||
param.set('name', 'movie')
|
||||
param.set('value', url)
|
||||
obj.append(param)
|
||||
param = etree.Element('param')
|
||||
param.set('name', 'allowFullScreen')
|
||||
param.set('value', 'true')
|
||||
obj.append(param)
|
||||
#param = etree.Element('param')
|
||||
#param.set('name', 'allowScriptAccess')
|
||||
#param.set('value', 'sameDomain')
|
||||
#obj.append(param)
|
||||
return obj
|
||||
|
||||
|
||||
def makeExtension(configs=None):
|
||||
return VideoExtension(configs=configs)
|
||||
|
||||
if __name__ == "__main__":
|
||||
import doctest
|
||||
doctest.testmod()
|
||||
@@ -1,96 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
'''
|
||||
Wikipath Extension for Python-Markdown
|
||||
======================================
|
||||
|
||||
Converts [Link Name](wiki:ArticleName) to relative links pointing to article. Requires Python-Markdown 2.0+
|
||||
|
||||
Basic usage:
|
||||
|
||||
>>> import markdown
|
||||
>>> text = "Some text with a [Link Name](wiki:ArticleName)."
|
||||
>>> html = markdown.markdown(text, ['wikipath(base_url="/wiki/view/")'])
|
||||
>>> html
|
||||
u'<p>Some text with a <a class="wikipath" href="/wiki/view/ArticleName/">Link Name</a>.</p>'
|
||||
|
||||
Dependencies:
|
||||
* [Python 2.3+](http://python.org)
|
||||
* [Markdown 2.0+](http://www.freewisdom.org/projects/python-markdown/)
|
||||
'''
|
||||
|
||||
|
||||
import markdown
|
||||
try:
|
||||
# Markdown 2.1.0 changed from 2.0.3. We try importing the new version first,
|
||||
# but import the 2.0.3 version if it fails
|
||||
from markdown.util import etree
|
||||
except:
|
||||
from markdown import etree
|
||||
|
||||
|
||||
class WikiPathExtension(markdown.Extension):
|
||||
def __init__(self, configs):
|
||||
# set extension defaults
|
||||
self.config = {
|
||||
'default_namespace': ['edX', 'Default namespace for when one isn\'t specified.'],
|
||||
'html_class': ['wikipath', 'CSS hook. Leave blank for none.']
|
||||
}
|
||||
|
||||
# Override defaults with user settings
|
||||
for key, value in configs:
|
||||
# self.config[key][0] = value
|
||||
self.setConfig(key, value)
|
||||
|
||||
def extendMarkdown(self, md, md_globals):
|
||||
self.md = md
|
||||
|
||||
# append to end of inline patterns
|
||||
WIKI_RE = r'\[(?P<linkTitle>.+?)\]\(wiki:(?P<wikiTitle>[a-zA-Z\d/_-]*)\)'
|
||||
wikiPathPattern = WikiPath(WIKI_RE, self.config)
|
||||
wikiPathPattern.md = md
|
||||
md.inlinePatterns.add('wikipath', wikiPathPattern, "<reference")
|
||||
|
||||
|
||||
class WikiPath(markdown.inlinepatterns.Pattern):
|
||||
def __init__(self, pattern, config):
|
||||
markdown.inlinepatterns.Pattern.__init__(self, pattern)
|
||||
self.config = config
|
||||
|
||||
def handleMatch(self, m):
|
||||
article_title = m.group('wikiTitle')
|
||||
if article_title.startswith("/"):
|
||||
article_title = article_title[1:]
|
||||
|
||||
if not "/" in article_title:
|
||||
article_title = self.config['default_namespace'][0] + "/" + article_title
|
||||
|
||||
url = "../" + article_title
|
||||
label = m.group('linkTitle')
|
||||
a = etree.Element('a')
|
||||
a.set('href', url)
|
||||
a.text = label
|
||||
|
||||
if self.config['html_class'][0]:
|
||||
a.set('class', self.config['html_class'][0])
|
||||
|
||||
return a
|
||||
|
||||
def _getMeta(self):
|
||||
""" Return meta data or config data. """
|
||||
base_url = self.config['base_url'][0]
|
||||
html_class = self.config['html_class'][0]
|
||||
if hasattr(self.md, 'Meta'):
|
||||
if self.md.Meta.has_key('wiki_base_url'):
|
||||
base_url = self.md.Meta['wiki_base_url'][0]
|
||||
if self.md.Meta.has_key('wiki_html_class'):
|
||||
html_class = self.md.Meta['wiki_html_class'][0]
|
||||
return base_url, html_class
|
||||
|
||||
|
||||
def makeExtension(configs=None):
|
||||
return WikiPathExtension(configs=configs)
|
||||
|
||||
if __name__ == "__main__":
|
||||
import doctest
|
||||
doctest.testmod()
|
||||
@@ -1,216 +0,0 @@
|
||||
# -*- 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 model 'Article'
|
||||
db.create_table('simplewiki_article', (
|
||||
('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
|
||||
('title', self.gf('django.db.models.fields.CharField')(max_length=512)),
|
||||
('slug', self.gf('django.db.models.fields.SlugField')(max_length=100, blank=True)),
|
||||
('created_by', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['auth.User'], null=True, blank=True)),
|
||||
('created_on', self.gf('django.db.models.fields.DateTimeField')(auto_now_add=1, blank=True)),
|
||||
('modified_on', self.gf('django.db.models.fields.DateTimeField')(auto_now_add=1, blank=True)),
|
||||
('parent', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['simplewiki.Article'], null=True, blank=True)),
|
||||
('locked', self.gf('django.db.models.fields.BooleanField')(default=False)),
|
||||
('permissions', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['simplewiki.Permission'], null=True, blank=True)),
|
||||
('current_revision', self.gf('django.db.models.fields.related.OneToOneField')(blank=True, related_name='current_rev', unique=True, null=True, to=orm['simplewiki.Revision'])),
|
||||
))
|
||||
db.send_create_signal('simplewiki', ['Article'])
|
||||
|
||||
# Adding unique constraint on 'Article', fields ['slug', 'parent']
|
||||
db.create_unique('simplewiki_article', ['slug', 'parent_id'])
|
||||
|
||||
# Adding M2M table for field related on 'Article'
|
||||
db.create_table('simplewiki_article_related', (
|
||||
('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)),
|
||||
('from_article', models.ForeignKey(orm['simplewiki.article'], null=False)),
|
||||
('to_article', models.ForeignKey(orm['simplewiki.article'], null=False))
|
||||
))
|
||||
db.create_unique('simplewiki_article_related', ['from_article_id', 'to_article_id'])
|
||||
|
||||
# Adding model 'ArticleAttachment'
|
||||
db.create_table('simplewiki_articleattachment', (
|
||||
('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
|
||||
('article', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['simplewiki.Article'])),
|
||||
('file', self.gf('django.db.models.fields.files.FileField')(max_length=255)),
|
||||
('uploaded_by', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['auth.User'], null=True, blank=True)),
|
||||
('uploaded_on', self.gf('django.db.models.fields.DateTimeField')(auto_now_add=True, blank=True)),
|
||||
))
|
||||
db.send_create_signal('simplewiki', ['ArticleAttachment'])
|
||||
|
||||
# Adding model 'Revision'
|
||||
db.create_table('simplewiki_revision', (
|
||||
('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
|
||||
('article', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['simplewiki.Article'])),
|
||||
('revision_text', self.gf('django.db.models.fields.CharField')(max_length=255, null=True, blank=True)),
|
||||
('revision_user', self.gf('django.db.models.fields.related.ForeignKey')(blank=True, related_name='wiki_revision_user', null=True, to=orm['auth.User'])),
|
||||
('revision_date', self.gf('django.db.models.fields.DateTimeField')(auto_now_add=True, blank=True)),
|
||||
('contents', self.gf('django.db.models.fields.TextField')()),
|
||||
('contents_parsed', self.gf('django.db.models.fields.TextField')(null=True, blank=True)),
|
||||
('counter', self.gf('django.db.models.fields.IntegerField')(default=1)),
|
||||
('previous_revision', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['simplewiki.Revision'], null=True, blank=True)),
|
||||
('deleted', self.gf('django.db.models.fields.IntegerField')(default=0)),
|
||||
))
|
||||
db.send_create_signal('simplewiki', ['Revision'])
|
||||
|
||||
# Adding model 'Permission'
|
||||
db.create_table('simplewiki_permission', (
|
||||
('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
|
||||
('permission_name', self.gf('django.db.models.fields.CharField')(max_length=255)),
|
||||
))
|
||||
db.send_create_signal('simplewiki', ['Permission'])
|
||||
|
||||
# Adding M2M table for field can_write on 'Permission'
|
||||
db.create_table('simplewiki_permission_can_write', (
|
||||
('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)),
|
||||
('permission', models.ForeignKey(orm['simplewiki.permission'], null=False)),
|
||||
('user', models.ForeignKey(orm['auth.user'], null=False))
|
||||
))
|
||||
db.create_unique('simplewiki_permission_can_write', ['permission_id', 'user_id'])
|
||||
|
||||
# Adding M2M table for field can_read on 'Permission'
|
||||
db.create_table('simplewiki_permission_can_read', (
|
||||
('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)),
|
||||
('permission', models.ForeignKey(orm['simplewiki.permission'], null=False)),
|
||||
('user', models.ForeignKey(orm['auth.user'], null=False))
|
||||
))
|
||||
db.create_unique('simplewiki_permission_can_read', ['permission_id', 'user_id'])
|
||||
|
||||
def backwards(self, orm):
|
||||
# Removing unique constraint on 'Article', fields ['slug', 'parent']
|
||||
db.delete_unique('simplewiki_article', ['slug', 'parent_id'])
|
||||
|
||||
# Deleting model 'Article'
|
||||
db.delete_table('simplewiki_article')
|
||||
|
||||
# Removing M2M table for field related on 'Article'
|
||||
db.delete_table('simplewiki_article_related')
|
||||
|
||||
# Deleting model 'ArticleAttachment'
|
||||
db.delete_table('simplewiki_articleattachment')
|
||||
|
||||
# Deleting model 'Revision'
|
||||
db.delete_table('simplewiki_revision')
|
||||
|
||||
# Deleting model 'Permission'
|
||||
db.delete_table('simplewiki_permission')
|
||||
|
||||
# Removing M2M table for field can_write on 'Permission'
|
||||
db.delete_table('simplewiki_permission_can_write')
|
||||
|
||||
# Removing M2M table for field can_read on 'Permission'
|
||||
db.delete_table('simplewiki_permission_can_read')
|
||||
|
||||
models = {
|
||||
'auth.group': {
|
||||
'Meta': {'object_name': 'Group'},
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
|
||||
'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
|
||||
},
|
||||
'auth.permission': {
|
||||
'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
|
||||
'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
|
||||
},
|
||||
'auth.user': {
|
||||
'Meta': {'object_name': 'User'},
|
||||
'about': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'avatar_type': ('django.db.models.fields.CharField', [], {'default': "'n'", 'max_length': '1'}),
|
||||
'bronze': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
|
||||
'consecutive_days_visit_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||
'country': ('django_countries.fields.CountryField', [], {'max_length': '2', 'blank': 'True'}),
|
||||
'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'date_of_birth': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'display_tag_filter_strategy': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
|
||||
'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
|
||||
'email_isvalid': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'email_key': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True'}),
|
||||
'email_tag_filter_strategy': ('django.db.models.fields.SmallIntegerField', [], {'default': '1'}),
|
||||
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
|
||||
'gold': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
|
||||
'gravatar': ('django.db.models.fields.CharField', [], {'max_length': '32'}),
|
||||
'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'ignored_tags': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'interesting_tags': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
|
||||
'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
|
||||
'last_seen': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'location': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
|
||||
'new_response_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||
'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
|
||||
'questions_per_page': ('django.db.models.fields.SmallIntegerField', [], {'default': '10'}),
|
||||
'real_name': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
|
||||
'reputation': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1'}),
|
||||
'seen_response_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||
'show_country': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'silver': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
|
||||
'status': ('django.db.models.fields.CharField', [], {'default': "'w'", 'max_length': '2'}),
|
||||
'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
|
||||
'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}),
|
||||
'website': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'})
|
||||
},
|
||||
'contenttypes.contenttype': {
|
||||
'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
|
||||
'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
|
||||
},
|
||||
'simplewiki.article': {
|
||||
'Meta': {'unique_together': "(('slug', 'parent'),)", 'object_name': 'Article'},
|
||||
'created_by': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True', 'blank': 'True'}),
|
||||
'created_on': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': '1', 'blank': 'True'}),
|
||||
'current_revision': ('django.db.models.fields.related.OneToOneField', [], {'blank': 'True', 'related_name': "'current_rev'", 'unique': 'True', 'null': 'True', 'to': "orm['simplewiki.Revision']"}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'locked': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'modified_on': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': '1', 'blank': 'True'}),
|
||||
'parent': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['simplewiki.Article']", 'null': 'True', 'blank': 'True'}),
|
||||
'permissions': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['simplewiki.Permission']", 'null': 'True', 'blank': 'True'}),
|
||||
'related': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'related_rel_+'", 'null': 'True', 'to': "orm['simplewiki.Article']"}),
|
||||
'slug': ('django.db.models.fields.SlugField', [], {'max_length': '100', 'blank': 'True'}),
|
||||
'title': ('django.db.models.fields.CharField', [], {'max_length': '512'})
|
||||
},
|
||||
'simplewiki.articleattachment': {
|
||||
'Meta': {'object_name': 'ArticleAttachment'},
|
||||
'article': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['simplewiki.Article']"}),
|
||||
'file': ('django.db.models.fields.files.FileField', [], {'max_length': '255'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'uploaded_by': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True', 'blank': 'True'}),
|
||||
'uploaded_on': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'})
|
||||
},
|
||||
'simplewiki.permission': {
|
||||
'Meta': {'object_name': 'Permission'},
|
||||
'can_read': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'read'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['auth.User']"}),
|
||||
'can_write': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'write'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['auth.User']"}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'permission_name': ('django.db.models.fields.CharField', [], {'max_length': '255'})
|
||||
},
|
||||
'simplewiki.revision': {
|
||||
'Meta': {'object_name': 'Revision'},
|
||||
'article': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['simplewiki.Article']"}),
|
||||
'contents': ('django.db.models.fields.TextField', [], {}),
|
||||
'contents_parsed': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'counter': ('django.db.models.fields.IntegerField', [], {'default': '1'}),
|
||||
'deleted': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'previous_revision': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['simplewiki.Revision']", 'null': 'True', 'blank': 'True'}),
|
||||
'revision_date': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
|
||||
'revision_text': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
|
||||
'revision_user': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'wiki_revision_user'", 'null': 'True', 'to': "orm['auth.User']"})
|
||||
}
|
||||
}
|
||||
|
||||
complete_apps = ['simplewiki']
|
||||
@@ -1,136 +0,0 @@
|
||||
# -*- 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):
|
||||
# We collect every article slug in a set. Any time we see a duplicate, we change the duplicate's name
|
||||
unique_slugs = set()
|
||||
for article in orm.Article.objects.all():
|
||||
if article.slug in unique_slugs:
|
||||
i = 2
|
||||
new_name = article.slug + str(i)
|
||||
while new_name in unique_slugs:
|
||||
i += 1
|
||||
new_name = article.slug + str(i)
|
||||
print "Changing", article.slug, "to", new_name
|
||||
article.slug = new_name
|
||||
article.save()
|
||||
|
||||
unique_slugs.add(article.slug)
|
||||
|
||||
def backwards(self, orm):
|
||||
"Write your backwards methods here."
|
||||
|
||||
models = {
|
||||
'auth.group': {
|
||||
'Meta': {'object_name': 'Group'},
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
|
||||
'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
|
||||
},
|
||||
'auth.permission': {
|
||||
'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
|
||||
'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
|
||||
},
|
||||
'auth.user': {
|
||||
'Meta': {'object_name': 'User'},
|
||||
'about': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'avatar_type': ('django.db.models.fields.CharField', [], {'default': "'n'", 'max_length': '1'}),
|
||||
'bronze': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
|
||||
'consecutive_days_visit_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||
'country': ('django_countries.fields.CountryField', [], {'max_length': '2', 'blank': 'True'}),
|
||||
'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'date_of_birth': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'display_tag_filter_strategy': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
|
||||
'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
|
||||
'email_isvalid': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'email_key': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True'}),
|
||||
'email_tag_filter_strategy': ('django.db.models.fields.SmallIntegerField', [], {'default': '1'}),
|
||||
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
|
||||
'gold': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
|
||||
'gravatar': ('django.db.models.fields.CharField', [], {'max_length': '32'}),
|
||||
'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'ignored_tags': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'interesting_tags': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
|
||||
'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
|
||||
'last_seen': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'location': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
|
||||
'new_response_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||
'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
|
||||
'questions_per_page': ('django.db.models.fields.SmallIntegerField', [], {'default': '10'}),
|
||||
'real_name': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
|
||||
'reputation': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1'}),
|
||||
'seen_response_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||
'show_country': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'silver': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
|
||||
'status': ('django.db.models.fields.CharField', [], {'default': "'w'", 'max_length': '2'}),
|
||||
'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
|
||||
'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}),
|
||||
'website': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'})
|
||||
},
|
||||
'contenttypes.contenttype': {
|
||||
'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
|
||||
'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
|
||||
},
|
||||
'simplewiki.article': {
|
||||
'Meta': {'unique_together': "(('slug', 'parent'),)", 'object_name': 'Article'},
|
||||
'created_by': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True', 'blank': 'True'}),
|
||||
'created_on': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': '1', 'blank': 'True'}),
|
||||
'current_revision': ('django.db.models.fields.related.OneToOneField', [], {'blank': 'True', 'related_name': "'current_rev'", 'unique': 'True', 'null': 'True', 'to': "orm['simplewiki.Revision']"}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'locked': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'modified_on': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': '1', 'blank': 'True'}),
|
||||
'parent': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['simplewiki.Article']", 'null': 'True', 'blank': 'True'}),
|
||||
'permissions': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['simplewiki.Permission']", 'null': 'True', 'blank': 'True'}),
|
||||
'related': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'related_rel_+'", 'null': 'True', 'to': "orm['simplewiki.Article']"}),
|
||||
'slug': ('django.db.models.fields.SlugField', [], {'max_length': '100', 'blank': 'True'}),
|
||||
'title': ('django.db.models.fields.CharField', [], {'max_length': '512'})
|
||||
},
|
||||
'simplewiki.articleattachment': {
|
||||
'Meta': {'object_name': 'ArticleAttachment'},
|
||||
'article': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['simplewiki.Article']"}),
|
||||
'file': ('django.db.models.fields.files.FileField', [], {'max_length': '255'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'uploaded_by': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True', 'blank': 'True'}),
|
||||
'uploaded_on': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'})
|
||||
},
|
||||
'simplewiki.permission': {
|
||||
'Meta': {'object_name': 'Permission'},
|
||||
'can_read': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'read'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['auth.User']"}),
|
||||
'can_write': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'write'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['auth.User']"}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'permission_name': ('django.db.models.fields.CharField', [], {'max_length': '255'})
|
||||
},
|
||||
'simplewiki.revision': {
|
||||
'Meta': {'object_name': 'Revision'},
|
||||
'article': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['simplewiki.Article']"}),
|
||||
'contents': ('django.db.models.fields.TextField', [], {}),
|
||||
'contents_parsed': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'counter': ('django.db.models.fields.IntegerField', [], {'default': '1'}),
|
||||
'deleted': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'previous_revision': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['simplewiki.Revision']", 'null': 'True', 'blank': 'True'}),
|
||||
'revision_date': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
|
||||
'revision_text': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
|
||||
'revision_user': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'wiki_revision_user'", 'null': 'True', 'to': "orm['auth.User']"})
|
||||
}
|
||||
}
|
||||
|
||||
complete_apps = ['simplewiki']
|
||||
symmetrical = True
|
||||
@@ -1,161 +0,0 @@
|
||||
# -*- 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):
|
||||
# Removing unique constraint on 'Article', fields ['slug', 'parent']
|
||||
db.delete_unique('simplewiki_article', ['slug', 'parent_id'])
|
||||
|
||||
# Adding model 'Namespace'
|
||||
db.create_table('simplewiki_namespace', (
|
||||
('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
|
||||
('name', self.gf('django.db.models.fields.CharField')(max_length=30)),
|
||||
))
|
||||
db.send_create_signal('simplewiki', ['Namespace'])
|
||||
|
||||
# Deleting field 'Article.parent'
|
||||
db.delete_column('simplewiki_article', 'parent_id')
|
||||
|
||||
# Adding field 'Article.namespace'
|
||||
db.add_column('simplewiki_article', 'namespace',
|
||||
self.gf('django.db.models.fields.related.ForeignKey')(default=1, to=orm['simplewiki.Namespace']),
|
||||
keep_default=False)
|
||||
|
||||
# Adding unique constraint on 'Article', fields ['namespace', 'slug']
|
||||
db.create_unique('simplewiki_article', ['namespace_id', 'slug'])
|
||||
|
||||
def backwards(self, orm):
|
||||
# Removing unique constraint on 'Article', fields ['namespace', 'slug']
|
||||
db.delete_unique('simplewiki_article', ['namespace_id', 'slug'])
|
||||
|
||||
# Deleting model 'Namespace'
|
||||
db.delete_table('simplewiki_namespace')
|
||||
|
||||
# Adding field 'Article.parent'
|
||||
db.add_column('simplewiki_article', 'parent',
|
||||
self.gf('django.db.models.fields.related.ForeignKey')(to=orm['simplewiki.Article'], null=True, blank=True),
|
||||
keep_default=False)
|
||||
|
||||
# Deleting field 'Article.namespace'
|
||||
db.delete_column('simplewiki_article', 'namespace_id')
|
||||
|
||||
# Adding unique constraint on 'Article', fields ['slug', 'parent']
|
||||
db.create_unique('simplewiki_article', ['slug', 'parent_id'])
|
||||
|
||||
models = {
|
||||
'auth.group': {
|
||||
'Meta': {'object_name': 'Group'},
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
|
||||
'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
|
||||
},
|
||||
'auth.permission': {
|
||||
'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
|
||||
'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
|
||||
},
|
||||
'auth.user': {
|
||||
'Meta': {'object_name': 'User'},
|
||||
'about': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'avatar_type': ('django.db.models.fields.CharField', [], {'default': "'n'", 'max_length': '1'}),
|
||||
'bronze': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
|
||||
'consecutive_days_visit_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||
'country': ('django_countries.fields.CountryField', [], {'max_length': '2', 'blank': 'True'}),
|
||||
'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'date_of_birth': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'display_tag_filter_strategy': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
|
||||
'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
|
||||
'email_isvalid': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'email_key': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True'}),
|
||||
'email_tag_filter_strategy': ('django.db.models.fields.SmallIntegerField', [], {'default': '1'}),
|
||||
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
|
||||
'gold': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
|
||||
'gravatar': ('django.db.models.fields.CharField', [], {'max_length': '32'}),
|
||||
'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'ignored_tags': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'interesting_tags': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
|
||||
'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
|
||||
'last_seen': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'location': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
|
||||
'new_response_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||
'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
|
||||
'questions_per_page': ('django.db.models.fields.SmallIntegerField', [], {'default': '10'}),
|
||||
'real_name': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
|
||||
'reputation': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1'}),
|
||||
'seen_response_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||
'show_country': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'silver': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
|
||||
'status': ('django.db.models.fields.CharField', [], {'default': "'w'", 'max_length': '2'}),
|
||||
'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
|
||||
'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}),
|
||||
'website': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'})
|
||||
},
|
||||
'contenttypes.contenttype': {
|
||||
'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
|
||||
'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
|
||||
},
|
||||
'simplewiki.article': {
|
||||
'Meta': {'unique_together': "(('slug', 'namespace'),)", 'object_name': 'Article'},
|
||||
'created_by': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True', 'blank': 'True'}),
|
||||
'created_on': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': '1', 'blank': 'True'}),
|
||||
'current_revision': ('django.db.models.fields.related.OneToOneField', [], {'blank': 'True', 'related_name': "'current_rev'", 'unique': 'True', 'null': 'True', 'to': "orm['simplewiki.Revision']"}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'locked': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'modified_on': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': '1', 'blank': 'True'}),
|
||||
'namespace': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['simplewiki.Namespace']"}),
|
||||
'permissions': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['simplewiki.Permission']", 'null': 'True', 'blank': 'True'}),
|
||||
'related': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'related_rel_+'", 'null': 'True', 'to': "orm['simplewiki.Article']"}),
|
||||
'slug': ('django.db.models.fields.SlugField', [], {'max_length': '100', 'blank': 'True'}),
|
||||
'title': ('django.db.models.fields.CharField', [], {'max_length': '512'})
|
||||
},
|
||||
'simplewiki.articleattachment': {
|
||||
'Meta': {'object_name': 'ArticleAttachment'},
|
||||
'article': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['simplewiki.Article']"}),
|
||||
'file': ('django.db.models.fields.files.FileField', [], {'max_length': '255'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'uploaded_by': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True', 'blank': 'True'}),
|
||||
'uploaded_on': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'})
|
||||
},
|
||||
'simplewiki.namespace': {
|
||||
'Meta': {'object_name': 'Namespace'},
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '30'})
|
||||
},
|
||||
'simplewiki.permission': {
|
||||
'Meta': {'object_name': 'Permission'},
|
||||
'can_read': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'read'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['auth.User']"}),
|
||||
'can_write': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'write'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['auth.User']"}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'permission_name': ('django.db.models.fields.CharField', [], {'max_length': '255'})
|
||||
},
|
||||
'simplewiki.revision': {
|
||||
'Meta': {'object_name': 'Revision'},
|
||||
'article': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['simplewiki.Article']"}),
|
||||
'contents': ('django.db.models.fields.TextField', [], {}),
|
||||
'contents_parsed': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'counter': ('django.db.models.fields.IntegerField', [], {'default': '1'}),
|
||||
'deleted': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'previous_revision': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['simplewiki.Revision']", 'null': 'True', 'blank': 'True'}),
|
||||
'revision_date': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
|
||||
'revision_text': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
|
||||
'revision_user': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'wiki_revision_user'", 'null': 'True', 'to': "orm['auth.User']"})
|
||||
}
|
||||
}
|
||||
|
||||
complete_apps = ['simplewiki']
|
||||
@@ -1,134 +0,0 @@
|
||||
# -*- 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):
|
||||
namespace6002x, created = orm.Namespace.objects.get_or_create(name="6.002xS12")
|
||||
if created:
|
||||
namespace6002x.save()
|
||||
|
||||
for article in orm.Article.objects.all():
|
||||
article.namespace = namespace6002x
|
||||
article.save()
|
||||
|
||||
def backwards(self, orm):
|
||||
raise RuntimeError("Cannot reverse this migration.")
|
||||
|
||||
models = {
|
||||
'auth.group': {
|
||||
'Meta': {'object_name': 'Group'},
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
|
||||
'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
|
||||
},
|
||||
'auth.permission': {
|
||||
'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
|
||||
'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
|
||||
},
|
||||
'auth.user': {
|
||||
'Meta': {'object_name': 'User'},
|
||||
'about': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'avatar_type': ('django.db.models.fields.CharField', [], {'default': "'n'", 'max_length': '1'}),
|
||||
'bronze': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
|
||||
'consecutive_days_visit_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||
'country': ('django_countries.fields.CountryField', [], {'max_length': '2', 'blank': 'True'}),
|
||||
'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'date_of_birth': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'display_tag_filter_strategy': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
|
||||
'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
|
||||
'email_isvalid': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'email_key': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True'}),
|
||||
'email_tag_filter_strategy': ('django.db.models.fields.SmallIntegerField', [], {'default': '1'}),
|
||||
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
|
||||
'gold': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
|
||||
'gravatar': ('django.db.models.fields.CharField', [], {'max_length': '32'}),
|
||||
'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'ignored_tags': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'interesting_tags': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
|
||||
'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
|
||||
'last_seen': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'location': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
|
||||
'new_response_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||
'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
|
||||
'questions_per_page': ('django.db.models.fields.SmallIntegerField', [], {'default': '10'}),
|
||||
'real_name': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
|
||||
'reputation': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1'}),
|
||||
'seen_response_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||
'show_country': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'silver': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
|
||||
'status': ('django.db.models.fields.CharField', [], {'default': "'w'", 'max_length': '2'}),
|
||||
'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
|
||||
'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}),
|
||||
'website': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'})
|
||||
},
|
||||
'contenttypes.contenttype': {
|
||||
'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
|
||||
'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
|
||||
},
|
||||
'simplewiki.article': {
|
||||
'Meta': {'unique_together': "(('slug', 'namespace'),)", 'object_name': 'Article'},
|
||||
'created_by': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True', 'blank': 'True'}),
|
||||
'created_on': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': '1', 'blank': 'True'}),
|
||||
'current_revision': ('django.db.models.fields.related.OneToOneField', [], {'blank': 'True', 'related_name': "'current_rev'", 'unique': 'True', 'null': 'True', 'to': "orm['simplewiki.Revision']"}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'locked': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'modified_on': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': '1', 'blank': 'True'}),
|
||||
'namespace': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['simplewiki.Namespace']"}),
|
||||
'permissions': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['simplewiki.Permission']", 'null': 'True', 'blank': 'True'}),
|
||||
'related': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'related_rel_+'", 'null': 'True', 'to': "orm['simplewiki.Article']"}),
|
||||
'slug': ('django.db.models.fields.SlugField', [], {'max_length': '100', 'blank': 'True'}),
|
||||
'title': ('django.db.models.fields.CharField', [], {'max_length': '512'})
|
||||
},
|
||||
'simplewiki.articleattachment': {
|
||||
'Meta': {'object_name': 'ArticleAttachment'},
|
||||
'article': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['simplewiki.Article']"}),
|
||||
'file': ('django.db.models.fields.files.FileField', [], {'max_length': '255'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'uploaded_by': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True', 'blank': 'True'}),
|
||||
'uploaded_on': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'})
|
||||
},
|
||||
'simplewiki.namespace': {
|
||||
'Meta': {'object_name': 'Namespace'},
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '30'})
|
||||
},
|
||||
'simplewiki.permission': {
|
||||
'Meta': {'object_name': 'Permission'},
|
||||
'can_read': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'read'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['auth.User']"}),
|
||||
'can_write': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'write'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['auth.User']"}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'permission_name': ('django.db.models.fields.CharField', [], {'max_length': '255'})
|
||||
},
|
||||
'simplewiki.revision': {
|
||||
'Meta': {'object_name': 'Revision'},
|
||||
'article': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['simplewiki.Article']"}),
|
||||
'contents': ('django.db.models.fields.TextField', [], {}),
|
||||
'contents_parsed': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'counter': ('django.db.models.fields.IntegerField', [], {'default': '1'}),
|
||||
'deleted': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'previous_revision': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['simplewiki.Revision']", 'null': 'True', 'blank': 'True'}),
|
||||
'revision_date': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
|
||||
'revision_text': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
|
||||
'revision_user': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'wiki_revision_user'", 'null': 'True', 'to': "orm['auth.User']"})
|
||||
}
|
||||
}
|
||||
|
||||
complete_apps = ['simplewiki']
|
||||
symmetrical = True
|
||||
@@ -1,129 +0,0 @@
|
||||
# -*- 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 unique constraint on 'Namespace', fields ['name']
|
||||
db.create_unique('simplewiki_namespace', ['name'])
|
||||
|
||||
def backwards(self, orm):
|
||||
# Removing unique constraint on 'Namespace', fields ['name']
|
||||
db.delete_unique('simplewiki_namespace', ['name'])
|
||||
|
||||
models = {
|
||||
'auth.group': {
|
||||
'Meta': {'object_name': 'Group'},
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
|
||||
'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
|
||||
},
|
||||
'auth.permission': {
|
||||
'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
|
||||
'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
|
||||
},
|
||||
'auth.user': {
|
||||
'Meta': {'object_name': 'User'},
|
||||
'about': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'avatar_type': ('django.db.models.fields.CharField', [], {'default': "'n'", 'max_length': '1'}),
|
||||
'bronze': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
|
||||
'consecutive_days_visit_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||
'country': ('django_countries.fields.CountryField', [], {'max_length': '2', 'blank': 'True'}),
|
||||
'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'date_of_birth': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'display_tag_filter_strategy': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
|
||||
'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
|
||||
'email_isvalid': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'email_key': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True'}),
|
||||
'email_tag_filter_strategy': ('django.db.models.fields.SmallIntegerField', [], {'default': '1'}),
|
||||
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
|
||||
'gold': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
|
||||
'gravatar': ('django.db.models.fields.CharField', [], {'max_length': '32'}),
|
||||
'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'ignored_tags': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'interesting_tags': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
|
||||
'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
|
||||
'last_seen': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'location': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
|
||||
'new_response_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||
'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
|
||||
'questions_per_page': ('django.db.models.fields.SmallIntegerField', [], {'default': '10'}),
|
||||
'real_name': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
|
||||
'reputation': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1'}),
|
||||
'seen_response_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||
'show_country': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'silver': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
|
||||
'status': ('django.db.models.fields.CharField', [], {'default': "'w'", 'max_length': '2'}),
|
||||
'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
|
||||
'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}),
|
||||
'website': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'})
|
||||
},
|
||||
'contenttypes.contenttype': {
|
||||
'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
|
||||
'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
|
||||
},
|
||||
'simplewiki.article': {
|
||||
'Meta': {'unique_together': "(('slug', 'namespace'),)", 'object_name': 'Article'},
|
||||
'created_by': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True', 'blank': 'True'}),
|
||||
'created_on': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': '1', 'blank': 'True'}),
|
||||
'current_revision': ('django.db.models.fields.related.OneToOneField', [], {'blank': 'True', 'related_name': "'current_rev'", 'unique': 'True', 'null': 'True', 'to': "orm['simplewiki.Revision']"}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'locked': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'modified_on': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': '1', 'blank': 'True'}),
|
||||
'namespace': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['simplewiki.Namespace']"}),
|
||||
'permissions': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['simplewiki.Permission']", 'null': 'True', 'blank': 'True'}),
|
||||
'related': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'related_rel_+'", 'null': 'True', 'to': "orm['simplewiki.Article']"}),
|
||||
'slug': ('django.db.models.fields.SlugField', [], {'max_length': '100', 'blank': 'True'}),
|
||||
'title': ('django.db.models.fields.CharField', [], {'max_length': '512'})
|
||||
},
|
||||
'simplewiki.articleattachment': {
|
||||
'Meta': {'object_name': 'ArticleAttachment'},
|
||||
'article': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['simplewiki.Article']"}),
|
||||
'file': ('django.db.models.fields.files.FileField', [], {'max_length': '255'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'uploaded_by': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True', 'blank': 'True'}),
|
||||
'uploaded_on': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'})
|
||||
},
|
||||
'simplewiki.namespace': {
|
||||
'Meta': {'object_name': 'Namespace'},
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
|
||||
},
|
||||
'simplewiki.permission': {
|
||||
'Meta': {'object_name': 'Permission'},
|
||||
'can_read': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'read'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['auth.User']"}),
|
||||
'can_write': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'write'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['auth.User']"}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'permission_name': ('django.db.models.fields.CharField', [], {'max_length': '255'})
|
||||
},
|
||||
'simplewiki.revision': {
|
||||
'Meta': {'object_name': 'Revision'},
|
||||
'article': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['simplewiki.Article']"}),
|
||||
'contents': ('django.db.models.fields.TextField', [], {}),
|
||||
'contents_parsed': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'counter': ('django.db.models.fields.IntegerField', [], {'default': '1'}),
|
||||
'deleted': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'previous_revision': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['simplewiki.Revision']", 'null': 'True', 'blank': 'True'}),
|
||||
'revision_date': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
|
||||
'revision_text': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
|
||||
'revision_user': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'wiki_revision_user'", 'null': 'True', 'to': "orm['auth.User']"})
|
||||
}
|
||||
}
|
||||
|
||||
complete_apps = ['simplewiki']
|
||||
@@ -1,129 +0,0 @@
|
||||
# -*- 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 index on 'Namespace', fields ['name']
|
||||
db.create_index('simplewiki_namespace', ['name'])
|
||||
|
||||
def backwards(self, orm):
|
||||
# Removing index on 'Namespace', fields ['name']
|
||||
db.delete_index('simplewiki_namespace', ['name'])
|
||||
|
||||
models = {
|
||||
'auth.group': {
|
||||
'Meta': {'object_name': 'Group'},
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
|
||||
'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
|
||||
},
|
||||
'auth.permission': {
|
||||
'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
|
||||
'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
|
||||
},
|
||||
'auth.user': {
|
||||
'Meta': {'object_name': 'User'},
|
||||
'about': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'avatar_type': ('django.db.models.fields.CharField', [], {'default': "'n'", 'max_length': '1'}),
|
||||
'bronze': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
|
||||
'consecutive_days_visit_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||
'country': ('django_countries.fields.CountryField', [], {'max_length': '2', 'blank': 'True'}),
|
||||
'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'date_of_birth': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'display_tag_filter_strategy': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
|
||||
'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
|
||||
'email_isvalid': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'email_key': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True'}),
|
||||
'email_tag_filter_strategy': ('django.db.models.fields.SmallIntegerField', [], {'default': '1'}),
|
||||
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
|
||||
'gold': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
|
||||
'gravatar': ('django.db.models.fields.CharField', [], {'max_length': '32'}),
|
||||
'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'ignored_tags': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'interesting_tags': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
|
||||
'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
|
||||
'last_seen': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'location': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
|
||||
'new_response_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||
'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
|
||||
'questions_per_page': ('django.db.models.fields.SmallIntegerField', [], {'default': '10'}),
|
||||
'real_name': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
|
||||
'reputation': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1'}),
|
||||
'seen_response_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||
'show_country': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'silver': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
|
||||
'status': ('django.db.models.fields.CharField', [], {'default': "'w'", 'max_length': '2'}),
|
||||
'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
|
||||
'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}),
|
||||
'website': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'})
|
||||
},
|
||||
'contenttypes.contenttype': {
|
||||
'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
|
||||
'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
|
||||
},
|
||||
'simplewiki.article': {
|
||||
'Meta': {'unique_together': "(('slug', 'namespace'),)", 'object_name': 'Article'},
|
||||
'created_by': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True', 'blank': 'True'}),
|
||||
'created_on': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': '1', 'blank': 'True'}),
|
||||
'current_revision': ('django.db.models.fields.related.OneToOneField', [], {'blank': 'True', 'related_name': "'current_rev'", 'unique': 'True', 'null': 'True', 'to': "orm['simplewiki.Revision']"}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'locked': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'modified_on': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': '1', 'blank': 'True'}),
|
||||
'namespace': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['simplewiki.Namespace']"}),
|
||||
'permissions': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['simplewiki.Permission']", 'null': 'True', 'blank': 'True'}),
|
||||
'related': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'related_rel_+'", 'null': 'True', 'to': "orm['simplewiki.Article']"}),
|
||||
'slug': ('django.db.models.fields.SlugField', [], {'max_length': '100', 'blank': 'True'}),
|
||||
'title': ('django.db.models.fields.CharField', [], {'max_length': '512'})
|
||||
},
|
||||
'simplewiki.articleattachment': {
|
||||
'Meta': {'object_name': 'ArticleAttachment'},
|
||||
'article': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['simplewiki.Article']"}),
|
||||
'file': ('django.db.models.fields.files.FileField', [], {'max_length': '255'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'uploaded_by': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True', 'blank': 'True'}),
|
||||
'uploaded_on': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'})
|
||||
},
|
||||
'simplewiki.namespace': {
|
||||
'Meta': {'object_name': 'Namespace'},
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30', 'db_index': 'True'})
|
||||
},
|
||||
'simplewiki.permission': {
|
||||
'Meta': {'object_name': 'Permission'},
|
||||
'can_read': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'read'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['auth.User']"}),
|
||||
'can_write': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'write'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['auth.User']"}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'permission_name': ('django.db.models.fields.CharField', [], {'max_length': '255'})
|
||||
},
|
||||
'simplewiki.revision': {
|
||||
'Meta': {'object_name': 'Revision'},
|
||||
'article': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['simplewiki.Article']"}),
|
||||
'contents': ('django.db.models.fields.TextField', [], {}),
|
||||
'contents_parsed': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'counter': ('django.db.models.fields.IntegerField', [], {'default': '1'}),
|
||||
'deleted': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'previous_revision': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['simplewiki.Revision']", 'null': 'True', 'blank': 'True'}),
|
||||
'revision_date': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
|
||||
'revision_text': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
|
||||
'revision_user': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'wiki_revision_user'", 'null': 'True', 'to': "orm['auth.User']"})
|
||||
}
|
||||
}
|
||||
|
||||
complete_apps = ['simplewiki']
|
||||
@@ -1,129 +0,0 @@
|
||||
# -*- 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):
|
||||
# Removing index on 'Namespace', fields ['name']
|
||||
db.delete_index('simplewiki_namespace', ['name'])
|
||||
|
||||
def backwards(self, orm):
|
||||
# Adding index on 'Namespace', fields ['name']
|
||||
db.create_index('simplewiki_namespace', ['name'])
|
||||
|
||||
models = {
|
||||
'auth.group': {
|
||||
'Meta': {'object_name': 'Group'},
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
|
||||
'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
|
||||
},
|
||||
'auth.permission': {
|
||||
'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
|
||||
'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
|
||||
},
|
||||
'auth.user': {
|
||||
'Meta': {'object_name': 'User'},
|
||||
'about': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'avatar_type': ('django.db.models.fields.CharField', [], {'default': "'n'", 'max_length': '1'}),
|
||||
'bronze': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
|
||||
'consecutive_days_visit_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||
'country': ('django_countries.fields.CountryField', [], {'max_length': '2', 'blank': 'True'}),
|
||||
'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'date_of_birth': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'display_tag_filter_strategy': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
|
||||
'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
|
||||
'email_isvalid': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'email_key': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True'}),
|
||||
'email_tag_filter_strategy': ('django.db.models.fields.SmallIntegerField', [], {'default': '1'}),
|
||||
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
|
||||
'gold': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
|
||||
'gravatar': ('django.db.models.fields.CharField', [], {'max_length': '32'}),
|
||||
'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'ignored_tags': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'interesting_tags': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
|
||||
'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
|
||||
'last_seen': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'location': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
|
||||
'new_response_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||
'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
|
||||
'questions_per_page': ('django.db.models.fields.SmallIntegerField', [], {'default': '10'}),
|
||||
'real_name': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
|
||||
'reputation': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1'}),
|
||||
'seen_response_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||
'show_country': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'silver': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
|
||||
'status': ('django.db.models.fields.CharField', [], {'default': "'w'", 'max_length': '2'}),
|
||||
'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
|
||||
'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}),
|
||||
'website': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'})
|
||||
},
|
||||
'contenttypes.contenttype': {
|
||||
'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
|
||||
'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
|
||||
},
|
||||
'simplewiki.article': {
|
||||
'Meta': {'unique_together': "(('slug', 'namespace'),)", 'object_name': 'Article'},
|
||||
'created_by': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True', 'blank': 'True'}),
|
||||
'created_on': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': '1', 'blank': 'True'}),
|
||||
'current_revision': ('django.db.models.fields.related.OneToOneField', [], {'blank': 'True', 'related_name': "'current_rev'", 'unique': 'True', 'null': 'True', 'to': "orm['simplewiki.Revision']"}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'locked': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'modified_on': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': '1', 'blank': 'True'}),
|
||||
'namespace': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['simplewiki.Namespace']"}),
|
||||
'permissions': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['simplewiki.Permission']", 'null': 'True', 'blank': 'True'}),
|
||||
'related': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'related_rel_+'", 'null': 'True', 'to': "orm['simplewiki.Article']"}),
|
||||
'slug': ('django.db.models.fields.SlugField', [], {'max_length': '100', 'blank': 'True'}),
|
||||
'title': ('django.db.models.fields.CharField', [], {'max_length': '512'})
|
||||
},
|
||||
'simplewiki.articleattachment': {
|
||||
'Meta': {'object_name': 'ArticleAttachment'},
|
||||
'article': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['simplewiki.Article']"}),
|
||||
'file': ('django.db.models.fields.files.FileField', [], {'max_length': '255'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'uploaded_by': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True', 'blank': 'True'}),
|
||||
'uploaded_on': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'})
|
||||
},
|
||||
'simplewiki.namespace': {
|
||||
'Meta': {'object_name': 'Namespace'},
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
|
||||
},
|
||||
'simplewiki.permission': {
|
||||
'Meta': {'object_name': 'Permission'},
|
||||
'can_read': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'read'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['auth.User']"}),
|
||||
'can_write': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'write'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['auth.User']"}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'permission_name': ('django.db.models.fields.CharField', [], {'max_length': '255'})
|
||||
},
|
||||
'simplewiki.revision': {
|
||||
'Meta': {'object_name': 'Revision'},
|
||||
'article': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['simplewiki.Article']"}),
|
||||
'contents': ('django.db.models.fields.TextField', [], {}),
|
||||
'contents_parsed': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'counter': ('django.db.models.fields.IntegerField', [], {'default': '1'}),
|
||||
'deleted': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'previous_revision': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['simplewiki.Revision']", 'null': 'True', 'blank': 'True'}),
|
||||
'revision_date': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
|
||||
'revision_text': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
|
||||
'revision_user': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'wiki_revision_user'", 'null': 'True', 'to': "orm['auth.User']"})
|
||||
}
|
||||
}
|
||||
|
||||
complete_apps = ['simplewiki']
|
||||
@@ -1,387 +0,0 @@
|
||||
import difflib
|
||||
import os
|
||||
|
||||
from django import forms
|
||||
from django.contrib.auth.models import User
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.db import models
|
||||
from django.db.models import signals
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from markdown import markdown
|
||||
|
||||
from .wiki_settings import *
|
||||
from util.cache import cache
|
||||
from pytz import UTC
|
||||
|
||||
|
||||
class ShouldHaveExactlyOneRootSlug(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class Namespace(models.Model):
|
||||
name = models.CharField(max_length=30, unique=True, verbose_name=_('namespace'))
|
||||
# TODO: We may want to add permissions, etc later
|
||||
|
||||
@classmethod
|
||||
def ensure_namespace(cls, name):
|
||||
try:
|
||||
namespace = Namespace.objects.get(name__exact=name)
|
||||
except Namespace.DoesNotExist:
|
||||
new_namespace = Namespace(name=name)
|
||||
new_namespace.save()
|
||||
|
||||
|
||||
class Article(models.Model):
|
||||
"""Wiki article referring to Revision model for actual content.
|
||||
'slug' and 'title' field should be maintained centrally, since users
|
||||
aren't allowed to change them, anyways.
|
||||
"""
|
||||
|
||||
title = models.CharField(max_length=512, verbose_name=_('Article title'),
|
||||
blank=False)
|
||||
slug = models.SlugField(max_length=100, verbose_name=_('slug'),
|
||||
help_text=_('Letters, numbers, underscore and hyphen.'),
|
||||
blank=True)
|
||||
namespace = models.ForeignKey(Namespace, verbose_name=_('Namespace'))
|
||||
created_by = models.ForeignKey(User, verbose_name=_('Created by'), blank=True, null=True)
|
||||
created_on = models.DateTimeField(auto_now_add=1)
|
||||
modified_on = models.DateTimeField(auto_now_add=1)
|
||||
locked = models.BooleanField(default=False, verbose_name=_('Locked for editing'))
|
||||
permissions = models.ForeignKey('Permission', verbose_name=_('Permissions'),
|
||||
blank=True, null=True,
|
||||
help_text=_('Permission group'))
|
||||
current_revision = models.OneToOneField('Revision', related_name='current_rev',
|
||||
blank=True, null=True, editable=True)
|
||||
related = models.ManyToManyField('self', verbose_name=_('Related articles'), symmetrical=True,
|
||||
help_text=_('Sets a symmetrical relation other articles'),
|
||||
blank=True, null=True)
|
||||
|
||||
def attachments(self):
|
||||
return ArticleAttachment.objects.filter(article__exact=self)
|
||||
|
||||
def get_path(self):
|
||||
return self.namespace.name + "/" + self.slug
|
||||
|
||||
@classmethod
|
||||
def get_article(cls, article_path):
|
||||
"""
|
||||
Given an article_path like namespace/slug, this returns the article. It may raise
|
||||
a Article.DoesNotExist if no matching article is found or ValueError if the
|
||||
article_path is not constructed properly.
|
||||
"""
|
||||
#TODO: Verify the path, throw a meaningful error?
|
||||
namespace, slug = article_path.split("/")
|
||||
return Article.objects.get(slug__exact=slug, namespace__name__exact=namespace)
|
||||
|
||||
@classmethod
|
||||
def get_root(cls, namespace):
|
||||
"""Return the root article, which should ALWAYS exist..
|
||||
except the very first time the wiki is loaded, in which
|
||||
case the user is prompted to create this article."""
|
||||
try:
|
||||
return Article.objects.filter(slug__exact="", namespace__name__exact=namespace)[0]
|
||||
except:
|
||||
raise ShouldHaveExactlyOneRootSlug()
|
||||
|
||||
# @classmethod
|
||||
# def get_url_reverse(cls, path, article, return_list=[]):
|
||||
# """Lookup a URL and return the corresponding set of articles
|
||||
# in the path."""
|
||||
# if path == []:
|
||||
# return return_list + [article]
|
||||
# # Lookup next child in path
|
||||
# try:
|
||||
# a = Article.objects.get(parent__exact = article, slug__exact=str(path[0]))
|
||||
# return cls.get_url_reverse(path[1:], a, return_list+[article])
|
||||
# except Exception, e:
|
||||
# return None
|
||||
|
||||
def can_read(self, user):
|
||||
""" Check read permissions and return True/False."""
|
||||
if user.is_superuser:
|
||||
return True
|
||||
if self.permissions:
|
||||
perms = self.permissions.can_read.all()
|
||||
return perms.count() == 0 or (user in perms)
|
||||
else:
|
||||
# TODO: We can inherit namespace permissions here
|
||||
return True
|
||||
|
||||
def can_write(self, user):
|
||||
""" Check write permissions and return True/False."""
|
||||
if user.is_superuser:
|
||||
return True
|
||||
if self.permissions:
|
||||
perms = self.permissions.can_write.all()
|
||||
return perms.count() == 0 or (user in perms)
|
||||
else:
|
||||
# TODO: We can inherit namespace permissions here
|
||||
return True
|
||||
|
||||
def can_write_l(self, user):
|
||||
"""Check write permissions and locked status"""
|
||||
if user.is_superuser:
|
||||
return True
|
||||
return not self.locked and self.can_write(user)
|
||||
|
||||
def can_attach(self, user):
|
||||
return self.can_write_l(user) and (WIKI_ALLOW_ANON_ATTACHMENTS or not user.is_anonymous())
|
||||
|
||||
def __unicode__(self):
|
||||
if self.slug == '':
|
||||
return unicode(_('Root article'))
|
||||
else:
|
||||
return self.slug
|
||||
|
||||
class Meta:
|
||||
unique_together = (('slug', 'namespace'),)
|
||||
verbose_name = _('Article')
|
||||
verbose_name_plural = _('Articles')
|
||||
|
||||
|
||||
def get_attachment_filepath(instance, filename):
|
||||
"""Store file, appending new extension for added security"""
|
||||
dir_ = WIKI_ATTACHMENTS + instance.article.get_url()
|
||||
dir_ = '/'.join(filter(lambda x: x != '', dir_.split('/')))
|
||||
if not os.path.exists(WIKI_ATTACHMENTS_ROOT + dir_):
|
||||
os.makedirs(WIKI_ATTACHMENTS_ROOT + dir_)
|
||||
return dir_ + '/' + filename + '.upload'
|
||||
|
||||
|
||||
class ArticleAttachment(models.Model):
|
||||
article = models.ForeignKey(Article, verbose_name=_('Article'))
|
||||
file = models.FileField(max_length=255, upload_to=get_attachment_filepath, verbose_name=_('Attachment'))
|
||||
uploaded_by = models.ForeignKey(User, blank=True, verbose_name=_('Uploaded by'), null=True)
|
||||
uploaded_on = models.DateTimeField(auto_now_add=True, verbose_name=_('Upload date'))
|
||||
|
||||
def download_url(self):
|
||||
return reverse('wiki_view_attachment', args=(self.article.get_url(), self.filename()))
|
||||
|
||||
def filename(self):
|
||||
return '.'.join(self.file.name.split('/')[-1].split('.')[:-1])
|
||||
|
||||
def get_size(self):
|
||||
try:
|
||||
size = self.file.size
|
||||
except OSError:
|
||||
size = 0
|
||||
return size
|
||||
|
||||
def filename(self):
|
||||
return '.'.join(self.file.name.split('/')[-1].split('.')[:-1])
|
||||
|
||||
def is_image(self):
|
||||
fname = self.filename().split('.')
|
||||
if len(fname) > 1 and fname[-1].lower() in WIKI_IMAGE_EXTENSIONS:
|
||||
return True
|
||||
return False
|
||||
|
||||
def get_thumb(self):
|
||||
return self.get_thumb_impl(*WIKI_IMAGE_THUMB_SIZE)
|
||||
|
||||
def get_thumb_small(self):
|
||||
return self.get_thumb_impl(*WIKI_IMAGE_THUMB_SIZE_SMALL)
|
||||
|
||||
def mk_thumbs(self):
|
||||
self.mk_thumb(*WIKI_IMAGE_THUMB_SIZE, **{'force': True})
|
||||
self.mk_thumb(*WIKI_IMAGE_THUMB_SIZE_SMALL, **{'force': True})
|
||||
|
||||
def mk_thumb(self, width, height, force=False):
|
||||
"""Requires Python Imaging Library (PIL)"""
|
||||
if not self.get_size():
|
||||
return False
|
||||
|
||||
if not self.is_image():
|
||||
return False
|
||||
|
||||
base_path = os.path.dirname(self.file.path)
|
||||
orig_name = self.filename().split('.')
|
||||
thumb_filename = "%s__thumb__%d_%d.%s" % ('.'.join(orig_name[:-1]), width, height, orig_name[-1])
|
||||
thumb_filepath = "%s%s%s" % (base_path, os.sep, thumb_filename)
|
||||
|
||||
if force or not os.path.exists(thumb_filepath):
|
||||
try:
|
||||
import Image
|
||||
img = Image.open(self.file.path)
|
||||
img.thumbnail((width, height), Image.ANTIALIAS)
|
||||
img.save(thumb_filepath)
|
||||
except IOError:
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
def get_thumb_impl(self, width, height):
|
||||
"""Requires Python Imaging Library (PIL)"""
|
||||
|
||||
if not self.get_size():
|
||||
return False
|
||||
|
||||
if not self.is_image():
|
||||
return False
|
||||
|
||||
self.mk_thumb(width, height)
|
||||
|
||||
orig_name = self.filename().split('.')
|
||||
thumb_filename = "%s__thumb__%d_%d.%s" % ('.'.join(orig_name[:-1]), width, height, orig_name[-1])
|
||||
thumb_url = settings.MEDIA_URL + WIKI_ATTACHMENTS + self.article.get_url() + '/' + thumb_filename
|
||||
|
||||
return thumb_url
|
||||
|
||||
def __unicode__(self):
|
||||
return self.filename()
|
||||
|
||||
|
||||
class Revision(models.Model):
|
||||
|
||||
article = models.ForeignKey(Article, verbose_name=_('Article'))
|
||||
revision_text = models.CharField(max_length=255, blank=True, null=True,
|
||||
verbose_name=_('Description of change'))
|
||||
revision_user = models.ForeignKey(User, verbose_name=_('Modified by'),
|
||||
blank=True, null=True, related_name='wiki_revision_user')
|
||||
revision_date = models.DateTimeField(auto_now_add=True, verbose_name=_('Revision date'))
|
||||
contents = models.TextField(verbose_name=_('Contents (Use MarkDown format)'))
|
||||
contents_parsed = models.TextField(editable=False, blank=True, null=True)
|
||||
counter = models.IntegerField(verbose_name=_('Revision#'), default=1, editable=False)
|
||||
previous_revision = models.ForeignKey('self', blank=True, null=True, editable=False)
|
||||
|
||||
# Deleted has three values. 0 is normal, non-deleted. 1 is if it was deleted by a normal user. It should
|
||||
# be a NEW revision, so that it appears in the history. 2 is a special flag that can be applied or removed
|
||||
# from a normal revision. It means it has been admin-deleted, and can only been seen by an admin. It doesn't
|
||||
# show up in the history.
|
||||
deleted = models.IntegerField(verbose_name=_('Deleted group'), default=0)
|
||||
|
||||
def get_user(self):
|
||||
return self.revision_user if self.revision_user else _('Anonymous')
|
||||
|
||||
# Called after the deleted fied has been changed (between 0 and 2). This bypasses the normal checks put in
|
||||
# save that update the revision or reject the save if contents haven't changed
|
||||
def adminSetDeleted(self, deleted):
|
||||
self.deleted = deleted
|
||||
super(Revision, self).save()
|
||||
|
||||
def save(self, **kwargs):
|
||||
# Check if contents have changed... if not, silently ignore save
|
||||
if self.article and self.article.current_revision:
|
||||
if self.deleted == 0 and self.article.current_revision.contents == self.contents:
|
||||
return
|
||||
else:
|
||||
import datetime
|
||||
self.article.modified_on = datetime.datetime.now(UTC)
|
||||
self.article.save()
|
||||
|
||||
# Increment counter according to previous revision
|
||||
previous_revision = Revision.objects.filter(article=self.article).order_by('-counter')
|
||||
if previous_revision.count() > 0:
|
||||
if previous_revision.count() > previous_revision[0].counter:
|
||||
self.counter = previous_revision.count() + 1
|
||||
else:
|
||||
self.counter = previous_revision[0].counter + 1
|
||||
else:
|
||||
self.counter = 1
|
||||
if (self.article.current_revision and self.article.current_revision.deleted == 0):
|
||||
self.previous_revision = self.article.current_revision
|
||||
|
||||
# Create pre-parsed contents - no need to parse on-the-fly
|
||||
ext = WIKI_MARKDOWN_EXTENSIONS
|
||||
ext += ["wikipath(default_namespace=%s)" % self.article.namespace.name]
|
||||
self.contents_parsed = markdown(self.contents,
|
||||
extensions=ext,
|
||||
safe_mode='escape',)
|
||||
super(Revision, self).save(**kwargs)
|
||||
|
||||
def delete(self, **kwargs):
|
||||
"""If a current revision is deleted, then regress to the previous
|
||||
revision or insert a stub, if no other revisions are available"""
|
||||
article = self.article
|
||||
if article.current_revision == self:
|
||||
prev_revision = Revision.objects.filter(article__exact=article,
|
||||
pk__not=self.pk).order_by('-counter')
|
||||
if prev_revision:
|
||||
article.current_revision = prev_revision[0]
|
||||
article.save()
|
||||
else:
|
||||
r = Revision(article=article,
|
||||
revision_user=article.created_by)
|
||||
r.contents = unicode(_('Auto-generated stub'))
|
||||
r.revision_text = unicode(_('Auto-generated stub'))
|
||||
r.save()
|
||||
article.current_revision = r
|
||||
article.save()
|
||||
super(Revision, self).delete(**kwargs)
|
||||
|
||||
def get_diff(self):
|
||||
if (self.deleted == 1):
|
||||
yield "Article Deletion"
|
||||
return
|
||||
|
||||
if self.previous_revision:
|
||||
previous = self.previous_revision.contents.splitlines(1)
|
||||
else:
|
||||
previous = []
|
||||
|
||||
# Todo: difflib.HtmlDiff would look pretty for our history pages!
|
||||
diff = difflib.unified_diff(previous, self.contents.splitlines(1))
|
||||
# let's skip the preamble
|
||||
diff.next(); diff.next(); diff.next()
|
||||
|
||||
for d in diff:
|
||||
yield d
|
||||
|
||||
def __unicode__(self):
|
||||
return "r%d" % self.counter
|
||||
|
||||
class Meta:
|
||||
verbose_name = _('article revision')
|
||||
verbose_name_plural = _('article revisions')
|
||||
|
||||
|
||||
class Permission(models.Model):
|
||||
permission_name = models.CharField(max_length=255, verbose_name=_('Permission name'))
|
||||
can_write = models.ManyToManyField(User, blank=True, null=True, related_name='write',
|
||||
help_text=_('Select none to grant anonymous access.'))
|
||||
can_read = models.ManyToManyField(User, blank=True, null=True, related_name='read',
|
||||
help_text=_('Select none to grant anonymous access.'))
|
||||
|
||||
def __unicode__(self):
|
||||
return self.permission_name
|
||||
|
||||
class Meta:
|
||||
verbose_name = _('Article permission')
|
||||
verbose_name_plural = _('Article permissions')
|
||||
|
||||
|
||||
class RevisionForm(forms.ModelForm):
|
||||
contents = forms.CharField(label=_('Contents'), widget=forms.Textarea(attrs={'rows': 8, 'cols': 50}))
|
||||
|
||||
class Meta:
|
||||
model = Revision
|
||||
fields = ['contents', 'revision_text']
|
||||
|
||||
|
||||
class RevisionFormWithTitle(forms.ModelForm):
|
||||
title = forms.CharField(label=_('Title'))
|
||||
|
||||
class Meta:
|
||||
model = Revision
|
||||
fields = ['title', 'contents', 'revision_text']
|
||||
|
||||
|
||||
class CreateArticleForm(RevisionForm):
|
||||
title = forms.CharField(label=_('Title'))
|
||||
|
||||
class Meta:
|
||||
model = Revision
|
||||
fields = ['title', 'contents', ]
|
||||
|
||||
|
||||
def set_revision(sender, *args, **kwargs):
|
||||
"""Signal handler to ensure that a new revision is always chosen as the
|
||||
current revision - automatically. It simplifies stuff greatly. Also
|
||||
stores previous revision for diff-purposes"""
|
||||
instance = kwargs['instance']
|
||||
created = kwargs['created']
|
||||
if created and instance.article:
|
||||
instance.article.current_revision = instance
|
||||
instance.article.save()
|
||||
|
||||
signals.post_save.connect(set_revision, Revision)
|
||||
@@ -1,20 +0,0 @@
|
||||
from django import template
|
||||
from django.conf import settings
|
||||
from django.template.defaultfilters import stringfilter
|
||||
from django.utils.http import urlquote as django_urlquote
|
||||
|
||||
from simplewiki.wiki_settings import *
|
||||
|
||||
register = template.Library()
|
||||
|
||||
|
||||
@register.filter()
|
||||
def prepend_media_url(value):
|
||||
"""Prepend user defined media root to url"""
|
||||
return settings.MEDIA_URL + value
|
||||
|
||||
|
||||
@register.filter()
|
||||
def urlquote(value):
|
||||
"""Prepend user defined media root to url"""
|
||||
return django_urlquote(value)
|
||||
@@ -1,23 +0,0 @@
|
||||
"""
|
||||
This file demonstrates two different styles of tests (one doctest and one
|
||||
unittest). These will both pass when you run "manage.py test".
|
||||
|
||||
Replace these with more appropriate tests for your application.
|
||||
"""
|
||||
|
||||
from django.test import TestCase
|
||||
|
||||
|
||||
class SimpleTest(TestCase):
|
||||
def test_basic_addition(self):
|
||||
"""
|
||||
Tests that 1 + 1 always equals 2.
|
||||
"""
|
||||
self.failUnlessEqual(1 + 1, 2)
|
||||
|
||||
__test__ = {"doctest": """
|
||||
Another way to test that 1 + 1 is equal to 2.
|
||||
|
||||
>>> 1 + 1 == 2
|
||||
True
|
||||
"""}
|
||||
@@ -1,19 +0,0 @@
|
||||
from django.conf.urls import patterns, url
|
||||
|
||||
namespace_regex = r"[a-zA-Z\d._-]+"
|
||||
article_slug = r'/(?P<article_path>' + namespace_regex + r'/[a-zA-Z\d_-]*)'
|
||||
namespace = r'/(?P<namespace>' + namespace_regex + r')'
|
||||
|
||||
urlpatterns = patterns('', # nopep8
|
||||
url(r'^$', 'simplewiki.views.root_redirect', name='wiki_root'),
|
||||
url(r'^view' + article_slug, 'simplewiki.views.view', name='wiki_view'),
|
||||
url(r'^view_revision/(?P<revision_number>[0-9]+)' + article_slug, 'simplewiki.views.view_revision', name='wiki_view_revision'),
|
||||
url(r'^edit' + article_slug, 'simplewiki.views.edit', name='wiki_edit'),
|
||||
url(r'^create' + article_slug, 'simplewiki.views.create', name='wiki_create'),
|
||||
url(r'^history' + article_slug + r'(?:/(?P<page>[0-9]+))?$', 'simplewiki.views.history', name='wiki_history'),
|
||||
url(r'^search_related' + article_slug, 'simplewiki.views.search_add_related', name='search_related'),
|
||||
url(r'^random/?$', 'simplewiki.views.random_article', name='wiki_random'),
|
||||
url(r'^revision_feed' + namespace + r'/(?P<page>[0-9]+)?$', 'simplewiki.views.revision_feed', name='wiki_revision_feed'),
|
||||
url(r'^search' + namespace + r'?$', 'simplewiki.views.search_articles', name='wiki_search_articles'),
|
||||
url(r'^list' + namespace + r'?$', 'simplewiki.views.search_articles', name='wiki_list_articles'), # Just an alias for the search, but you usually don't submit a search term
|
||||
)
|
||||
@@ -1,800 +0,0 @@
|
||||
# Markdown: Syntax
|
||||
|
||||
[TOC]
|
||||
|
||||
## Overview
|
||||
|
||||
### Philosophy
|
||||
|
||||
Markdown is intended to be as easy-to-read and easy-to-write as is feasible.
|
||||
|
||||
Readability, however, is emphasized above all else. A Markdown-formatted
|
||||
document should be publishable as-is, as plain text, without looking
|
||||
like it's been marked up with tags or formatting instructions. While
|
||||
Markdown's syntax has been influenced by several existing text-to-HTML
|
||||
filters -- including [Setext] [1], [atx] [2], [Textile] [3], [reStructuredText] [4],
|
||||
[Grutatext] [5], and [EtText] [6] -- the single biggest source of
|
||||
inspiration for Markdown's syntax is the format of plain text email.
|
||||
|
||||
[1]: http://docutils.sourceforge.net/mirror/setext.html
|
||||
[2]: http://www.aaronsw.com/2002/atx/
|
||||
[3]: http://textism.com/tools/textile/
|
||||
[4]: http://docutils.sourceforge.net/rst.html
|
||||
[5]: http://www.triptico.com/software/grutatxt.html
|
||||
[6]: http://ettext.taint.org/doc/
|
||||
|
||||
To this end, Markdown's syntax is comprised entirely of punctuation
|
||||
characters, which punctuation characters have been carefully chosen so
|
||||
as to look like what they mean. E.g., asterisks around a word actually
|
||||
look like \*emphasis\*. Markdown lists look like, well, lists. Even
|
||||
blockquotes look like quoted passages of text, assuming you've ever
|
||||
used email.
|
||||
|
||||
### Automatic Escaping for Special Characters
|
||||
|
||||
In HTML, there are two characters that demand special treatment: `<`
|
||||
and `&`. Left angle brackets are used to start tags; ampersands are
|
||||
used to denote HTML entities. If you want to use them as literal
|
||||
characters, you must escape them as entities, e.g. `<`, and
|
||||
`&`.
|
||||
|
||||
Ampersands in particular are bedeviling for web writers. If you want to
|
||||
write about 'AT&T', you need to write '`AT&T`'. You even need to
|
||||
escape ampersands within URLs. Thus, if you want to link to:
|
||||
|
||||
http://images.google.com/images?num=30&q=larry+bird
|
||||
|
||||
you need to encode the URL as:
|
||||
|
||||
http://images.google.com/images?num=30&q=larry+bird
|
||||
|
||||
in your anchor tag `href` attribute. Needless to say, this is easy to
|
||||
forget, and is probably the single most common source of HTML validation
|
||||
errors in otherwise well-marked-up web sites.
|
||||
|
||||
Markdown allows you to use these characters naturally, taking care of
|
||||
all the necessary escaping for you. If you use an ampersand as part of
|
||||
an HTML entity, it remains unchanged; otherwise it will be translated
|
||||
into `&`.
|
||||
|
||||
So, if you want to include a copyright symbol in your article, you can write:
|
||||
|
||||
©
|
||||
|
||||
and Markdown will leave it alone. But if you write:
|
||||
|
||||
AT&T
|
||||
|
||||
Markdown will translate it to:
|
||||
|
||||
AT&T
|
||||
|
||||
Similarly, because Markdown supports [inline HTML](#html), if you use
|
||||
angle brackets as delimiters for HTML tags, Markdown will treat them as
|
||||
such. But if you write:
|
||||
|
||||
4 < 5
|
||||
|
||||
Markdown will translate it to:
|
||||
|
||||
4 < 5
|
||||
|
||||
However, inside Markdown code spans and blocks, angle brackets and
|
||||
ampersands are *always* encoded automatically. This makes it easy to use
|
||||
Markdown to write about HTML code. (As opposed to raw HTML, which is a
|
||||
terrible format for writing about HTML syntax, because every single `<`
|
||||
and `&` in your example code needs to be escaped.)
|
||||
|
||||
|
||||
* * *
|
||||
|
||||
|
||||
## Block Elements
|
||||
|
||||
### Paragraphs and Line Breaks
|
||||
|
||||
A paragraph is simply one or more consecutive lines of text, separated
|
||||
by one or more blank lines. (A blank line is any line that looks like a
|
||||
blank line -- a line containing nothing but spaces or tabs is considered
|
||||
blank.) Normal paragraphs should not be indented with spaces or tabs.
|
||||
|
||||
The implication of the "one or more consecutive lines of text" rule is
|
||||
that Markdown supports "hard-wrapped" text paragraphs. This differs
|
||||
significantly from most other text-to-HTML formatters (including Movable
|
||||
Type's "Convert Line Breaks" option) which translate every line break
|
||||
character in a paragraph into a `<br />` tag.
|
||||
|
||||
When you *do* want to insert a `<br />` break tag using Markdown, you
|
||||
end a line with two or more spaces, then type return.
|
||||
|
||||
Yes, this takes a tad more effort to create a `<br />`, but a simplistic
|
||||
"every line break is a `<br />`" rule wouldn't work for Markdown.
|
||||
Markdown's email-style [blockquoting][bq] and multi-paragraph [list items][l]
|
||||
work best -- and look better -- when you format them with hard breaks.
|
||||
|
||||
[bq]: #blockquote
|
||||
[l]: #list
|
||||
|
||||
### Headers
|
||||
|
||||
Markdown supports two styles of headers, [Setext] [1] and [atx] [2].
|
||||
|
||||
Setext-style headers are "underlined" using equal signs (for first-level
|
||||
headers) and dashes (for second-level headers). For example:
|
||||
|
||||
This is an H1
|
||||
=============
|
||||
|
||||
This is an H2
|
||||
-------------
|
||||
|
||||
This is an H3
|
||||
_____________
|
||||
|
||||
Any number of underlining `=`'s or `-`'s will work.
|
||||
|
||||
Atx-style headers use 1-6 hash characters at the start of the line,
|
||||
corresponding to header levels 1-6. For example:
|
||||
|
||||
# This is an H1
|
||||
|
||||
## This is an H2
|
||||
|
||||
###### This is an H6
|
||||
|
||||
Optionally, you may "close" atx-style headers. This is purely
|
||||
cosmetic -- you can use this if you think it looks better. The
|
||||
closing hashes don't even need to match the number of hashes
|
||||
used to open the header. (The number of opening hashes
|
||||
determines the header level.) :
|
||||
|
||||
# This is an H1 #
|
||||
|
||||
## This is an H2 ##
|
||||
|
||||
### This is an H3 ######
|
||||
|
||||
|
||||
### Blockquotes
|
||||
|
||||
Markdown uses email-style `>` characters for blockquoting. If you're
|
||||
familiar with quoting passages of text in an email message, then you
|
||||
know how to create a blockquote in Markdown. It looks best if you hard
|
||||
wrap the text and put a `>` before every line:
|
||||
|
||||
> This is a blockquote with two paragraphs. Lorem ipsum dolor sit amet,
|
||||
> consectetuer adipiscing elit. Aliquam hendrerit mi posuere lectus.
|
||||
> Vestibulum enim wisi, viverra nec, fringilla in, laoreet vitae, risus.
|
||||
>
|
||||
> Donec sit amet nisl. Aliquam semper ipsum sit amet velit. Suspendisse
|
||||
> id sem consectetuer libero luctus adipiscing.
|
||||
|
||||
Markdown allows you to be lazy and only put the `>` before the first
|
||||
line of a hard-wrapped paragraph:
|
||||
|
||||
> This is a blockquote with two paragraphs. Lorem ipsum dolor sit amet,
|
||||
consectetuer adipiscing elit. Aliquam hendrerit mi posuere lectus.
|
||||
Vestibulum enim wisi, viverra nec, fringilla in, laoreet vitae, risus.
|
||||
|
||||
> Donec sit amet nisl. Aliquam semper ipsum sit amet velit. Suspendisse
|
||||
id sem consectetuer libero luctus adipiscing.
|
||||
|
||||
Blockquotes can be nested (i.e. a blockquote-in-a-blockquote) by
|
||||
adding additional levels of `>`:
|
||||
|
||||
> This is the first level of quoting.
|
||||
>
|
||||
> > This is nested blockquote.
|
||||
>
|
||||
> Back to the first level.
|
||||
|
||||
Blockquotes can contain other Markdown elements, including headers, lists,
|
||||
and code blocks:
|
||||
|
||||
> ## This is a header.
|
||||
>
|
||||
> 1. This is the first list item.
|
||||
> 2. This is the second list item.
|
||||
>
|
||||
> Here's some example code:
|
||||
>
|
||||
> return shell_exec("echo $input | $markdown_script");
|
||||
|
||||
Any decent text editor should make email-style quoting easy. For
|
||||
example, with BBEdit, you can make a selection and choose Increase
|
||||
Quote Level from the Text menu.
|
||||
|
||||
|
||||
### Lists
|
||||
|
||||
Markdown supports ordered (numbered) and unordered (bulleted) lists.
|
||||
|
||||
Unordered lists use asterisks, pluses, and hyphens -- interchangably
|
||||
-- as list markers:
|
||||
|
||||
* Red
|
||||
* Green
|
||||
* Blue
|
||||
|
||||
is equivalent to:
|
||||
|
||||
+ Red
|
||||
+ Green
|
||||
+ Blue
|
||||
|
||||
and:
|
||||
|
||||
- Red
|
||||
- Green
|
||||
- Blue
|
||||
|
||||
Ordered lists use numbers followed by periods:
|
||||
|
||||
1. Bird
|
||||
2. McHale
|
||||
3. Parish
|
||||
|
||||
It's important to note that the actual numbers you use to mark the
|
||||
list have no effect on the HTML output Markdown produces. The HTML
|
||||
Markdown produces from the above list is:
|
||||
|
||||
<ol>
|
||||
<li>Bird</li>
|
||||
<li>McHale</li>
|
||||
<li>Parish</li>
|
||||
</ol>
|
||||
|
||||
If you instead wrote the list in Markdown like this:
|
||||
|
||||
1. Bird
|
||||
1. McHale
|
||||
1. Parish
|
||||
|
||||
or even:
|
||||
|
||||
3. Bird
|
||||
1. McHale
|
||||
8. Parish
|
||||
|
||||
you'd get the exact same HTML output. The point is, if you want to,
|
||||
you can use ordinal numbers in your ordered Markdown lists, so that
|
||||
the numbers in your source match the numbers in your published HTML.
|
||||
But if you want to be lazy, you don't have to.
|
||||
|
||||
If you do use lazy list numbering, however, you should still start the
|
||||
list with the number 1. At some point in the future, Markdown may support
|
||||
starting ordered lists at an arbitrary number.
|
||||
|
||||
List markers typically start at the left margin, but may be indented by
|
||||
up to three spaces. List markers must be followed by one or more spaces
|
||||
or a tab.
|
||||
|
||||
To make lists look nice, you can wrap items with hanging indents:
|
||||
|
||||
* Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
|
||||
Aliquam hendrerit mi posuere lectus. Vestibulum enim wisi,
|
||||
viverra nec, fringilla in, laoreet vitae, risus.
|
||||
* Donec sit amet nisl. Aliquam semper ipsum sit amet velit.
|
||||
Suspendisse id sem consectetuer libero luctus adipiscing.
|
||||
|
||||
But if you want to be lazy, you don't have to:
|
||||
|
||||
* Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
|
||||
Aliquam hendrerit mi posuere lectus. Vestibulum enim wisi,
|
||||
viverra nec, fringilla in, laoreet vitae, risus.
|
||||
* Donec sit amet nisl. Aliquam semper ipsum sit amet velit.
|
||||
Suspendisse id sem consectetuer libero luctus adipiscing.
|
||||
|
||||
If list items are separated by blank lines, Markdown will wrap the
|
||||
items in `<p>` tags in the HTML output. For example, this input:
|
||||
|
||||
* Bird
|
||||
* Magic
|
||||
|
||||
will turn into:
|
||||
|
||||
<ul>
|
||||
<li>Bird</li>
|
||||
<li>Magic</li>
|
||||
</ul>
|
||||
|
||||
But this:
|
||||
|
||||
* Bird
|
||||
|
||||
* Magic
|
||||
|
||||
will turn into:
|
||||
|
||||
<ul>
|
||||
<li><p>Bird</p></li>
|
||||
<li><p>Magic</p></li>
|
||||
</ul>
|
||||
|
||||
List items may consist of multiple paragraphs. Each subsequent
|
||||
paragraph in a list item must be indented by either 4 spaces
|
||||
or one tab:
|
||||
|
||||
1. This is a list item with two paragraphs. Lorem ipsum dolor
|
||||
sit amet, consectetuer adipiscing elit. Aliquam hendrerit
|
||||
mi posuere lectus.
|
||||
|
||||
Vestibulum enim wisi, viverra nec, fringilla in, laoreet
|
||||
vitae, risus. Donec sit amet nisl. Aliquam semper ipsum
|
||||
sit amet velit.
|
||||
|
||||
2. Suspendisse id sem consectetuer libero luctus adipiscing.
|
||||
|
||||
It looks nice if you indent every line of the subsequent
|
||||
paragraphs, but here again, Markdown will allow you to be
|
||||
lazy:
|
||||
|
||||
* This is a list item with two paragraphs.
|
||||
|
||||
This is the second paragraph in the list item. You're
|
||||
only required to indent the first line. Lorem ipsum dolor
|
||||
sit amet, consectetuer adipiscing elit.
|
||||
|
||||
* Another item in the same list.
|
||||
|
||||
To put a blockquote within a list item, the blockquote's `>`
|
||||
delimiters need to be indented:
|
||||
|
||||
* A list item with a blockquote:
|
||||
|
||||
> This is a blockquote
|
||||
> inside a list item.
|
||||
|
||||
To put a code block within a list item, the code block needs
|
||||
to be indented *twice* -- 8 spaces or two tabs:
|
||||
|
||||
* A list item with a code block:
|
||||
|
||||
<code goes here>
|
||||
|
||||
|
||||
It's worth noting that it's possible to trigger an ordered list by
|
||||
accident, by writing something like this:
|
||||
|
||||
1986. What a great season.
|
||||
|
||||
In other words, a *number-period-space* sequence at the beginning of a
|
||||
line. To avoid this, you can backslash-escape the period:
|
||||
|
||||
1986\. What a great season.
|
||||
|
||||
|
||||
|
||||
### Code Blocks
|
||||
|
||||
Pre-formatted code blocks are used for writing about programming or
|
||||
markup source code. Rather than forming normal paragraphs, the lines
|
||||
of a code block are interpreted literally. Markdown wraps a code block
|
||||
in both `<pre>` and `<code>` tags.
|
||||
|
||||
To produce a code block in Markdown, simply indent every line of the
|
||||
block by at least 4 spaces or 1 tab. For example, given this input:
|
||||
|
||||
This is a normal paragraph:
|
||||
|
||||
This is a code block.
|
||||
|
||||
Markdown will generate:
|
||||
|
||||
<p>This is a normal paragraph:</p>
|
||||
|
||||
<pre><code>This is a code block.
|
||||
</code></pre>
|
||||
|
||||
One level of indentation -- 4 spaces or 1 tab -- is removed from each
|
||||
line of the code block. For example, this:
|
||||
|
||||
Here is an example of AppleScript:
|
||||
|
||||
tell application "Foo"
|
||||
beep
|
||||
end tell
|
||||
|
||||
will turn into:
|
||||
|
||||
<p>Here is an example of AppleScript:</p>
|
||||
|
||||
<pre><code>tell application "Foo"
|
||||
beep
|
||||
end tell
|
||||
</code></pre>
|
||||
|
||||
A code block continues until it reaches a line that is not indented
|
||||
(or the end of the article).
|
||||
|
||||
Within a code block, ampersands (`&`) and angle brackets (`<` and `>`)
|
||||
are automatically converted into HTML entities. This makes it very
|
||||
easy to include example HTML source code using Markdown -- just paste
|
||||
it and indent it, and Markdown will handle the hassle of encoding the
|
||||
ampersands and angle brackets. For example, this:
|
||||
|
||||
<div class="footer">
|
||||
© 2004 Foo Corporation
|
||||
</div>
|
||||
|
||||
will turn into:
|
||||
|
||||
<pre><code><div class="footer">
|
||||
&copy; 2004 Foo Corporation
|
||||
</div>
|
||||
</code></pre>
|
||||
|
||||
Regular Markdown syntax is not processed within code blocks. E.g.,
|
||||
asterisks are just literal asterisks within a code block. This means
|
||||
it's also easy to use Markdown to write about Markdown's own syntax.
|
||||
|
||||
|
||||
|
||||
### Horizontal Rules
|
||||
|
||||
You can produce a horizontal rule tag (`<hr />`) by placing three or
|
||||
more hyphens, asterisks, or underscores on a line by themselves. If you
|
||||
wish, you may use spaces between the hyphens or asterisks. Each of the
|
||||
following lines will produce a horizontal rule:
|
||||
|
||||
* * *
|
||||
|
||||
***
|
||||
|
||||
*****
|
||||
|
||||
- - -
|
||||
|
||||
---------------------------------------
|
||||
|
||||
|
||||
## Span Elements
|
||||
|
||||
### Links
|
||||
|
||||
Markdown supports two style of links: *inline* and *reference*.
|
||||
|
||||
In both styles, the link text is delimited by [square brackets].
|
||||
|
||||
To create an inline link, use a set of regular parentheses immediately
|
||||
after the link text's closing square bracket. Inside the parentheses,
|
||||
put the URL where you want the link to point, along with an *optional*
|
||||
title for the link, surrounded in quotes. For example:
|
||||
|
||||
This is [an example](http://example.com/ "Title") inline link.
|
||||
|
||||
[This link](http://example.net/) has no title attribute.
|
||||
|
||||
Will produce:
|
||||
|
||||
<p>This is <a href="http://example.com/" title="Title">
|
||||
an example</a> inline link.</p>
|
||||
|
||||
<p><a href="http://example.net/">This link</a> has no
|
||||
title attribute.</p>
|
||||
|
||||
If you're referring to a local resource on the same server, you can
|
||||
use relative paths:
|
||||
|
||||
See my [About](/about/) page for details.
|
||||
|
||||
Reference-style links use a second set of square brackets, inside
|
||||
which you place a label of your choosing to identify the link:
|
||||
|
||||
This is [an example][id] reference-style link.
|
||||
|
||||
You can optionally use a space to separate the sets of brackets:
|
||||
|
||||
This is [an example] [id] reference-style link.
|
||||
|
||||
Then, anywhere in the document, you define your link label like this,
|
||||
on a line by itself:
|
||||
|
||||
[id]: http://example.com/ "Optional Title Here"
|
||||
|
||||
That is:
|
||||
|
||||
* Square brackets containing the link identifier (optionally
|
||||
indented from the left margin using up to three spaces);
|
||||
* followed by a colon;
|
||||
* followed by one or more spaces (or tabs);
|
||||
* followed by the URL for the link;
|
||||
* optionally followed by a title attribute for the link, enclosed
|
||||
in double or single quotes, or enclosed in parentheses.
|
||||
|
||||
The following three link definitions are equivalent:
|
||||
|
||||
[foo]: http://example.com/ "Optional Title Here"
|
||||
[foo]: http://example.com/ 'Optional Title Here'
|
||||
[foo]: http://example.com/ (Optional Title Here)
|
||||
|
||||
**Note:** There is a known bug in Markdown.pl 1.0.1 which prevents
|
||||
single quotes from being used to delimit link titles.
|
||||
|
||||
The link URL may, optionally, be surrounded by angle brackets:
|
||||
|
||||
[id]: <http://example.com/> "Optional Title Here"
|
||||
|
||||
You can put the title attribute on the next line and use extra spaces
|
||||
or tabs for padding, which tends to look better with longer URLs:
|
||||
|
||||
[id]: http://example.com/longish/path/to/resource/here
|
||||
"Optional Title Here"
|
||||
|
||||
Link definitions are only used for creating links during Markdown
|
||||
processing, and are stripped from your document in the HTML output.
|
||||
|
||||
Link definition names may consist of letters, numbers, spaces, and
|
||||
punctuation -- but they are *not* case sensitive. E.g. these two
|
||||
links:
|
||||
|
||||
[link text][a]
|
||||
[link text][A]
|
||||
|
||||
are equivalent.
|
||||
|
||||
The *implicit link name* shortcut allows you to omit the name of the
|
||||
link, in which case the link text itself is used as the name.
|
||||
Just use an empty set of square brackets -- e.g., to link the word
|
||||
"Google" to the google.com web site, you could simply write:
|
||||
|
||||
[Google][]
|
||||
|
||||
And then define the link:
|
||||
|
||||
[Google]: http://google.com/
|
||||
|
||||
Because link names may contain spaces, this shortcut even works for
|
||||
multiple words in the link text:
|
||||
|
||||
Visit [Daring Fireball][] for more information.
|
||||
|
||||
And then define the link:
|
||||
|
||||
[Daring Fireball]: http://daringfireball.net/
|
||||
|
||||
Link definitions can be placed anywhere in your Markdown document. I
|
||||
tend to put them immediately after each paragraph in which they're
|
||||
used, but if you want, you can put them all at the end of your
|
||||
document, sort of like footnotes.
|
||||
|
||||
Here's an example of reference links in action:
|
||||
|
||||
I get 10 times more traffic from [Google] [1] than from
|
||||
[Yahoo] [2] or [MSN] [3].
|
||||
|
||||
[1]: http://google.com/ "Google"
|
||||
[2]: http://search.yahoo.com/ "Yahoo Search"
|
||||
[3]: http://search.msn.com/ "MSN Search"
|
||||
|
||||
Using the implicit link name shortcut, you could instead write:
|
||||
|
||||
I get 10 times more traffic from [Google][] than from
|
||||
[Yahoo][] or [MSN][].
|
||||
|
||||
[google]: http://google.com/ "Google"
|
||||
[yahoo]: http://search.yahoo.com/ "Yahoo Search"
|
||||
[msn]: http://search.msn.com/ "MSN Search"
|
||||
|
||||
Both of the above examples will produce the following HTML output:
|
||||
|
||||
<p>I get 10 times more traffic from <a href="http://google.com/"
|
||||
title="Google">Google</a> than from
|
||||
<a href="http://search.yahoo.com/" title="Yahoo Search">Yahoo</a>
|
||||
or <a href="http://search.msn.com/" title="MSN Search">MSN</a>.</p>
|
||||
|
||||
For comparison, here is the same paragraph written using
|
||||
Markdown's inline link style:
|
||||
|
||||
I get 10 times more traffic from [Google](http://google.com/ "Google")
|
||||
than from [Yahoo](http://search.yahoo.com/ "Yahoo Search") or
|
||||
[MSN](http://search.msn.com/ "MSN Search").
|
||||
|
||||
The point of reference-style links is not that they're easier to
|
||||
write. The point is that with reference-style links, your document
|
||||
source is vastly more readable. Compare the above examples: using
|
||||
reference-style links, the paragraph itself is only 81 characters
|
||||
long; with inline-style links, it's 176 characters; and as raw HTML,
|
||||
it's 234 characters. In the raw HTML, there's more markup than there
|
||||
is text.
|
||||
|
||||
With Markdown's reference-style links, a source document much more
|
||||
closely resembles the final output, as rendered in a browser. By
|
||||
allowing you to move the markup-related metadata out of the paragraph,
|
||||
you can add links without interrupting the narrative flow of your
|
||||
prose.
|
||||
|
||||
### Emphasis
|
||||
|
||||
Markdown treats asterisks (`*`) and underscores (`_`) as indicators of
|
||||
emphasis. Text wrapped with one `*` or `_` will be wrapped with an
|
||||
HTML `<em>` tag; double `*`'s or `_`'s will be wrapped with an HTML
|
||||
`<strong>` tag. E.g., this input:
|
||||
|
||||
*single asterisks*
|
||||
|
||||
_single underscores_
|
||||
|
||||
**double asterisks**
|
||||
|
||||
__double underscores__
|
||||
|
||||
will produce:
|
||||
|
||||
<em>single asterisks</em>
|
||||
|
||||
<em>single underscores</em>
|
||||
|
||||
<strong>double asterisks</strong>
|
||||
|
||||
<strong>double underscores</strong>
|
||||
|
||||
You can use whichever style you prefer; the lone restriction is that
|
||||
the same character must be used to open and close an emphasis span.
|
||||
|
||||
Emphasis can be used in the middle of a word:
|
||||
|
||||
un*frigging*believable
|
||||
|
||||
But if you surround an `*` or `_` with spaces, it'll be treated as a
|
||||
literal asterisk or underscore.
|
||||
|
||||
To produce a literal asterisk or underscore at a position where it
|
||||
would otherwise be used as an emphasis delimiter, you can backslash
|
||||
escape it:
|
||||
|
||||
\*this text is surrounded by literal asterisks\*
|
||||
|
||||
|
||||
### Code
|
||||
|
||||
To indicate a span of code, wrap it with backtick quotes (`` ` ``).
|
||||
Unlike a pre-formatted code block, a code span indicates code within a
|
||||
normal paragraph. For example:
|
||||
|
||||
Use the `printf()` function.
|
||||
|
||||
will produce:
|
||||
|
||||
<p>Use the <code>printf()</code> function.</p>
|
||||
|
||||
To include a literal backtick character within a code span, you can use
|
||||
multiple backticks as the opening and closing delimiters:
|
||||
|
||||
``There is a literal backtick (`) here.``
|
||||
|
||||
which will produce this:
|
||||
|
||||
<p><code>There is a literal backtick (`) here.</code></p>
|
||||
|
||||
The backtick delimiters surrounding a code span may include spaces --
|
||||
one after the opening, one before the closing. This allows you to place
|
||||
literal backtick characters at the beginning or end of a code span:
|
||||
|
||||
A single backtick in a code span: `` ` ``
|
||||
|
||||
A backtick-delimited string in a code span: `` `foo` ``
|
||||
|
||||
will produce:
|
||||
|
||||
<p>A single backtick in a code span: <code>`</code></p>
|
||||
|
||||
<p>A backtick-delimited string in a code span: <code>`foo`</code></p>
|
||||
|
||||
With a code span, ampersands and angle brackets are encoded as HTML
|
||||
entities automatically, which makes it easy to include example HTML
|
||||
tags. Markdown will turn this:
|
||||
|
||||
Please don't use any `<blink>` tags.
|
||||
|
||||
into:
|
||||
|
||||
<p>Please don't use any <code><blink></code> tags.</p>
|
||||
|
||||
You can write this:
|
||||
|
||||
`—` is the decimal-encoded equivalent of `—`.
|
||||
|
||||
to produce:
|
||||
|
||||
<p><code>&#8212;</code> is the decimal-encoded
|
||||
equivalent of <code>&mdash;</code>.</p>
|
||||
|
||||
|
||||
### Images
|
||||
|
||||
Admittedly, it's fairly difficult to devise a "natural" syntax for
|
||||
placing images into a plain text document format.
|
||||
|
||||
Markdown uses an image syntax that is intended to resemble the syntax
|
||||
for links, allowing for two styles: *inline* and *reference*.
|
||||
|
||||
Inline image syntax looks like this:
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
That is:
|
||||
|
||||
* An exclamation mark: `!`;
|
||||
* followed by a set of square brackets, containing the `alt`
|
||||
attribute text for the image;
|
||||
* followed by a set of parentheses, containing the URL or path to
|
||||
the image, and an optional `title` attribute enclosed in double
|
||||
or single quotes.
|
||||
|
||||
Reference-style image syntax looks like this:
|
||||
|
||||
![Alt text][id]
|
||||
|
||||
Where "id" is the name of a defined image reference. Image references
|
||||
are defined using syntax identical to link references:
|
||||
|
||||
[id]: url/to/image "Optional title attribute"
|
||||
|
||||
As of this writing, Markdown has no syntax for specifying the
|
||||
dimensions of an image; if this is important to you, you can simply
|
||||
use regular HTML `<img>` tags.
|
||||
|
||||
|
||||
## Miscellaneous
|
||||
|
||||
### Automatic Links
|
||||
|
||||
Markdown supports a shortcut style for creating "automatic" links for URLs and email addresses: simply surround the URL or email address with angle brackets. What this means is that if you want to show the actual text of a URL or email address, and also have it be a clickable link, you can do this:
|
||||
|
||||
<http://example.com/>
|
||||
|
||||
Markdown will turn this into:
|
||||
|
||||
<a href="http://example.com/">http://example.com/</a>
|
||||
|
||||
Automatic links for email addresses work similarly, except that
|
||||
Markdown will also perform a bit of randomized decimal and hex
|
||||
entity-encoding to help obscure your address from address-harvesting
|
||||
spambots. For example, Markdown will turn this:
|
||||
|
||||
<address@example.com>
|
||||
|
||||
into something like this:
|
||||
|
||||
<a href="mailto:addre
|
||||
ss@example.co
|
||||
m">address@exa
|
||||
mple.com</a>
|
||||
|
||||
which will render in a browser as a clickable link to "address@example.com".
|
||||
|
||||
(This sort of entity-encoding trick will indeed fool many, if not
|
||||
most, address-harvesting bots, but it definitely won't fool all of
|
||||
them. It's better than nothing, but an address published in this way
|
||||
will probably eventually start receiving spam.)
|
||||
|
||||
|
||||
|
||||
### Backslash Escapes
|
||||
|
||||
Markdown allows you to use backslash escapes to generate literal
|
||||
characters which would otherwise have special meaning in Markdown's
|
||||
formatting syntax. For example, if you wanted to surround a word
|
||||
with literal asterisks (instead of an HTML `<em>` tag), you can use
|
||||
backslashes before the asterisks, like this:
|
||||
|
||||
\*literal asterisks\*
|
||||
|
||||
Markdown provides backslash escapes for the following characters:
|
||||
|
||||
\ backslash
|
||||
` backtick
|
||||
* asterisk
|
||||
_ underscore
|
||||
{} curly braces
|
||||
[] square brackets
|
||||
() parentheses
|
||||
# hash mark
|
||||
+ plus sign
|
||||
- minus sign (hyphen)
|
||||
. dot
|
||||
! exclamation mark
|
||||
|
||||
@@ -1,552 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from django.conf import settings as settings
|
||||
from django.contrib.auth.decorators import login_required
|
||||
from django.core.context_processors import csrf
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.db.models import Q
|
||||
from django.http import HttpResponse, HttpResponseRedirect, Http404
|
||||
from django.utils import simplejson
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from mitxmako.shortcuts import render_to_response
|
||||
|
||||
from courseware.courses import get_opt_course_with_access
|
||||
from courseware.access import has_access
|
||||
from xmodule.course_module import CourseDescriptor
|
||||
from xmodule.modulestore.django import modulestore
|
||||
|
||||
from .models import Revision, Article, Namespace, CreateArticleForm, RevisionFormWithTitle, RevisionForm
|
||||
import wiki_settings
|
||||
|
||||
|
||||
def wiki_reverse(wiki_page, article=None, course=None, namespace=None, args=[], kwargs={}):
|
||||
kwargs = dict(kwargs) # TODO: Figure out why if I don't do this kwargs sometimes contains {'article_path'}
|
||||
if not 'course_id' in kwargs and course:
|
||||
kwargs['course_id'] = course.id
|
||||
if not 'article_path' in kwargs and article:
|
||||
kwargs['article_path'] = article.get_path()
|
||||
if not 'namespace' in kwargs and namespace:
|
||||
kwargs['namespace'] = namespace
|
||||
return reverse(wiki_page, kwargs=kwargs, args=args)
|
||||
|
||||
|
||||
def update_template_dictionary(dictionary, request=None, course=None, article=None, revision=None):
|
||||
if article:
|
||||
dictionary['wiki_article'] = article
|
||||
dictionary['wiki_title'] = article.title # TODO: What is the title when viewing the article in a course?
|
||||
if not course and 'namespace' not in dictionary:
|
||||
dictionary['namespace'] = article.namespace.name
|
||||
|
||||
if course:
|
||||
dictionary['course'] = course
|
||||
if 'namespace' not in dictionary:
|
||||
dictionary['namespace'] = "edX"
|
||||
else:
|
||||
dictionary['course'] = None
|
||||
|
||||
if revision:
|
||||
dictionary['wiki_article_revision'] = revision
|
||||
dictionary['wiki_current_revision_deleted'] = not (revision.deleted == 0)
|
||||
|
||||
if request:
|
||||
dictionary.update(csrf(request))
|
||||
|
||||
if request and course:
|
||||
dictionary['staff_access'] = has_access(request.user, course, 'staff')
|
||||
else:
|
||||
dictionary['staff_access'] = False
|
||||
|
||||
|
||||
def view(request, article_path, course_id=None):
|
||||
course = get_opt_course_with_access(request.user, course_id, 'load')
|
||||
|
||||
(article, err) = get_article(request, article_path, course)
|
||||
if err:
|
||||
return err
|
||||
|
||||
perm_err = check_permissions(request, article, course, check_read=True, check_deleted=True)
|
||||
if perm_err:
|
||||
return perm_err
|
||||
|
||||
d = {}
|
||||
update_template_dictionary(d, request, course, article, article.current_revision)
|
||||
return render_to_response('simplewiki/simplewiki_view.html', d)
|
||||
|
||||
|
||||
def view_revision(request, revision_number, article_path, course_id=None):
|
||||
course = get_opt_course_with_access(request.user, course_id, 'load')
|
||||
|
||||
(article, err) = get_article(request, article_path, course)
|
||||
if err:
|
||||
return err
|
||||
|
||||
try:
|
||||
revision = Revision.objects.get(counter=int(revision_number), article=article)
|
||||
except:
|
||||
d = {'wiki_err_norevision': revision_number}
|
||||
update_template_dictionary(d, request, course, article)
|
||||
return render_to_response('simplewiki/simplewiki_error.html', d)
|
||||
|
||||
perm_err = check_permissions(request, article, course, check_read=True, check_deleted=True, revision=revision)
|
||||
if perm_err:
|
||||
return perm_err
|
||||
|
||||
d = {}
|
||||
update_template_dictionary(d, request, course, article, revision)
|
||||
|
||||
return render_to_response('simplewiki/simplewiki_view.html', d)
|
||||
|
||||
|
||||
def root_redirect(request, course_id=None):
|
||||
course = get_opt_course_with_access(request.user, course_id, 'load')
|
||||
|
||||
#TODO: Add a default namespace to settings.
|
||||
namespace = "edX"
|
||||
|
||||
try:
|
||||
root = Article.get_root(namespace)
|
||||
return HttpResponseRedirect(reverse('wiki_view', kwargs={'course_id': course_id, 'article_path': root.get_path()}))
|
||||
except:
|
||||
# If the root is not found, we probably are loading this class for the first time
|
||||
# We should make sure the namespace exists so the root article can be created.
|
||||
Namespace.ensure_namespace(namespace)
|
||||
|
||||
err = not_found(request, namespace + '/', course)
|
||||
return err
|
||||
|
||||
|
||||
def create(request, article_path, course_id=None):
|
||||
course = get_opt_course_with_access(request.user, course_id, 'load')
|
||||
|
||||
article_path_components = article_path.split('/')
|
||||
|
||||
# Ensure the namespace exists
|
||||
if not len(article_path_components) >= 1 or len(article_path_components[0]) == 0:
|
||||
d = {'wiki_err_no_namespace': True}
|
||||
update_template_dictionary(d, request, course)
|
||||
return render_to_response('simplewiki/simplewiki_error.html', d)
|
||||
|
||||
namespace = None
|
||||
try:
|
||||
namespace = Namespace.objects.get(name__exact=article_path_components[0])
|
||||
except Namespace.DoesNotExist, ValueError:
|
||||
d = {'wiki_err_bad_namespace': True}
|
||||
update_template_dictionary(d, request, course)
|
||||
return render_to_response('simplewiki/simplewiki_error.html', d)
|
||||
|
||||
# See if the article already exists
|
||||
article_slug = article_path_components[1] if len(article_path_components) >= 2 else ''
|
||||
#TODO: Make sure the slug only contains legal characters (which is already done a bit by the url regex)
|
||||
|
||||
try:
|
||||
existing_article = Article.objects.get(namespace=namespace, slug__exact=article_slug)
|
||||
#It already exists, so we just redirect to view the article
|
||||
return HttpResponseRedirect(wiki_reverse("wiki_view", existing_article, course))
|
||||
except Article.DoesNotExist:
|
||||
#This is good. The article doesn't exist
|
||||
pass
|
||||
|
||||
#TODO: Once we have permissions for namespaces, we should check for create permissions
|
||||
#check_permissions(request, #namespace#, check_locked=False, check_write=True, check_deleted=True)
|
||||
|
||||
if request.method == 'POST':
|
||||
f = CreateArticleForm(request.POST)
|
||||
if f.is_valid():
|
||||
article = Article()
|
||||
article.slug = article_slug
|
||||
if not request.user.is_anonymous():
|
||||
article.created_by = request.user
|
||||
article.title = f.cleaned_data.get('title')
|
||||
article.namespace = namespace
|
||||
a = article.save()
|
||||
new_revision = f.save(commit=False)
|
||||
if not request.user.is_anonymous():
|
||||
new_revision.revision_user = request.user
|
||||
new_revision.article = article
|
||||
new_revision.save()
|
||||
|
||||
return HttpResponseRedirect(wiki_reverse("wiki_view", article, course))
|
||||
else:
|
||||
f = CreateArticleForm(initial={'title': request.GET.get('wiki_article_name', article_slug),
|
||||
'contents': _('Headline\n===\n\n')})
|
||||
|
||||
d = {'wiki_form': f, 'create_article': True, 'namespace': namespace.name}
|
||||
update_template_dictionary(d, request, course)
|
||||
|
||||
return render_to_response('simplewiki/simplewiki_edit.html', d)
|
||||
|
||||
|
||||
def edit(request, article_path, course_id=None):
|
||||
course = get_opt_course_with_access(request.user, course_id, 'load')
|
||||
|
||||
(article, err) = get_article(request, article_path, course)
|
||||
if err:
|
||||
return err
|
||||
|
||||
# Check write permissions
|
||||
perm_err = check_permissions(request, article, course, check_write=True, check_locked=True, check_deleted=False)
|
||||
if perm_err:
|
||||
return perm_err
|
||||
|
||||
if wiki_settings.WIKI_ALLOW_TITLE_EDIT:
|
||||
EditForm = RevisionFormWithTitle
|
||||
else:
|
||||
EditForm = RevisionForm
|
||||
|
||||
if request.method == 'POST':
|
||||
f = EditForm(request.POST)
|
||||
if f.is_valid():
|
||||
new_revision = f.save(commit=False)
|
||||
new_revision.article = article
|
||||
|
||||
if request.POST.__contains__('delete'):
|
||||
if (article.current_revision.deleted == 1): # This article has already been deleted. Redirect
|
||||
return HttpResponseRedirect(wiki_reverse('wiki_view', article, course))
|
||||
new_revision.contents = ""
|
||||
new_revision.deleted = 1
|
||||
elif not new_revision.get_diff():
|
||||
return HttpResponseRedirect(wiki_reverse('wiki_view', article, course))
|
||||
|
||||
if not request.user.is_anonymous():
|
||||
new_revision.revision_user = request.user
|
||||
new_revision.save()
|
||||
if wiki_settings.WIKI_ALLOW_TITLE_EDIT:
|
||||
new_revision.article.title = f.cleaned_data['title']
|
||||
new_revision.article.save()
|
||||
return HttpResponseRedirect(wiki_reverse('wiki_view', article, course))
|
||||
else:
|
||||
startContents = article.current_revision.contents if (article.current_revision.deleted == 0) else 'Headline\n===\n\n'
|
||||
|
||||
f = EditForm({'contents': startContents, 'title': article.title})
|
||||
|
||||
d = {'wiki_form': f}
|
||||
update_template_dictionary(d, request, course, article)
|
||||
return render_to_response('simplewiki/simplewiki_edit.html', d)
|
||||
|
||||
|
||||
def history(request, article_path, page=1, course_id=None):
|
||||
course = get_opt_course_with_access(request.user, course_id, 'load')
|
||||
|
||||
(article, err) = get_article(request, article_path, course)
|
||||
if err:
|
||||
return err
|
||||
|
||||
perm_err = check_permissions(request, article, course, check_read=True, check_deleted=False)
|
||||
if perm_err:
|
||||
return perm_err
|
||||
|
||||
page_size = 10
|
||||
|
||||
if page is None:
|
||||
page = 1
|
||||
try:
|
||||
p = int(page)
|
||||
except ValueError:
|
||||
p = 1
|
||||
|
||||
history = Revision.objects.filter(article__exact=article).order_by('-counter').select_related('previous_revision__counter', 'revision_user', 'wiki_article')
|
||||
|
||||
if request.method == 'POST':
|
||||
if request.POST.__contains__('revision'): # They selected a version, but they can be either deleting or changing the version
|
||||
perm_err = check_permissions(request, article, course, check_write=True, check_locked=True)
|
||||
if perm_err:
|
||||
return perm_err
|
||||
|
||||
redirectURL = wiki_reverse('wiki_view', article, course)
|
||||
try:
|
||||
r = int(request.POST['revision'])
|
||||
revision = Revision.objects.get(id=r)
|
||||
if request.POST.__contains__('change'):
|
||||
article.current_revision = revision
|
||||
article.save()
|
||||
elif request.POST.__contains__('view'):
|
||||
redirectURL = wiki_reverse('wiki_view_revision', course=course,
|
||||
kwargs={'revision_number': revision.counter, 'article_path': article.get_path()})
|
||||
#The rese of these are admin functions
|
||||
elif request.POST.__contains__('delete') and request.user.is_superuser:
|
||||
if (revision.deleted == 0):
|
||||
revision.adminSetDeleted(2)
|
||||
elif request.POST.__contains__('restore') and request.user.is_superuser:
|
||||
if (revision.deleted == 2):
|
||||
revision.adminSetDeleted(0)
|
||||
elif request.POST.__contains__('delete_all') and request.user.is_superuser:
|
||||
Revision.objects.filter(article__exact=article, deleted=0).update(deleted=2)
|
||||
elif request.POST.__contains__('lock_article'):
|
||||
article.locked = not article.locked
|
||||
article.save()
|
||||
except Exception as e:
|
||||
print str(e)
|
||||
pass
|
||||
finally:
|
||||
return HttpResponseRedirect(redirectURL)
|
||||
#
|
||||
#
|
||||
# <input type="submit" name="delete" value="Delete revision"/>
|
||||
# <input type="submit" name="restore" value="Restore revision"/>
|
||||
# <input type="submit" name="delete_all" value="Delete all revisions">
|
||||
# %else:
|
||||
# <input type="submit" name="delete_article" value="Delete all revisions">
|
||||
#
|
||||
|
||||
page_count = (history.count() + (page_size - 1)) / page_size
|
||||
if p > page_count:
|
||||
p = 1
|
||||
beginItem = (p - 1) * page_size
|
||||
|
||||
next_page = p + 1 if page_count > p else None
|
||||
prev_page = p - 1 if p > 1 else None
|
||||
|
||||
d = {'wiki_page': p,
|
||||
'wiki_next_page': next_page,
|
||||
'wiki_prev_page': prev_page,
|
||||
'wiki_history': history[beginItem:beginItem + page_size],
|
||||
'show_delete_revision': request.user.is_superuser}
|
||||
update_template_dictionary(d, request, course, article)
|
||||
|
||||
return render_to_response('simplewiki/simplewiki_history.html', d)
|
||||
|
||||
|
||||
def revision_feed(request, page=1, namespace=None, course_id=None):
|
||||
course = get_opt_course_with_access(request.user, course_id, 'load')
|
||||
|
||||
page_size = 10
|
||||
|
||||
if page is None:
|
||||
page = 1
|
||||
try:
|
||||
p = int(page)
|
||||
except ValueError:
|
||||
p = 1
|
||||
|
||||
history = Revision.objects.order_by('-revision_date').select_related('revision_user', 'article', 'previous_revision')
|
||||
|
||||
page_count = (history.count() + (page_size - 1)) / page_size
|
||||
if p > page_count:
|
||||
p = 1
|
||||
beginItem = (p - 1) * page_size
|
||||
|
||||
next_page = p + 1 if page_count > p else None
|
||||
prev_page = p - 1 if p > 1 else None
|
||||
|
||||
d = {'wiki_page': p,
|
||||
'wiki_next_page': next_page,
|
||||
'wiki_prev_page': prev_page,
|
||||
'wiki_history': history[beginItem:beginItem + page_size],
|
||||
'show_delete_revision': request.user.is_superuser,
|
||||
'namespace': namespace}
|
||||
update_template_dictionary(d, request, course)
|
||||
|
||||
return render_to_response('simplewiki/simplewiki_revision_feed.html', d)
|
||||
|
||||
|
||||
def search_articles(request, namespace=None, course_id=None):
|
||||
course = get_opt_course_with_access(request.user, course_id, 'load')
|
||||
|
||||
# blampe: We should check for the presence of other popular django search
|
||||
# apps and use those if possible. Only fall back on this as a last resort.
|
||||
# Adding some context to results (eg where matches were) would also be nice.
|
||||
|
||||
# todo: maybe do some perm checking here
|
||||
|
||||
if request.method == 'GET':
|
||||
querystring = request.GET.get('value', '').strip()
|
||||
else:
|
||||
querystring = ""
|
||||
|
||||
results = Article.objects.all()
|
||||
if namespace:
|
||||
results = results.filter(namespace__name__exact=namespace)
|
||||
|
||||
if request.user.is_superuser:
|
||||
results = results.order_by('current_revision__deleted')
|
||||
else:
|
||||
results = results.filter(current_revision__deleted=0)
|
||||
|
||||
if querystring:
|
||||
for queryword in querystring.split():
|
||||
# Basic negation is as fancy as we get right now
|
||||
if queryword[0] == '-' and len(queryword) > 1:
|
||||
results._search = lambda x: results.exclude(x)
|
||||
queryword = queryword[1:]
|
||||
else:
|
||||
results._search = lambda x: results.filter(x)
|
||||
|
||||
results = results._search(Q(current_revision__contents__icontains=queryword) | \
|
||||
Q(title__icontains=queryword))
|
||||
|
||||
results = results.select_related('current_revision__deleted', 'namespace')
|
||||
|
||||
results = sorted(results, key=lambda article: (article.current_revision.deleted, article.get_path().lower()))
|
||||
|
||||
if len(results) == 1 and querystring:
|
||||
return HttpResponseRedirect(wiki_reverse('wiki_view', article=results[0], course=course))
|
||||
else:
|
||||
d = {'wiki_search_results': results,
|
||||
'wiki_search_query': querystring,
|
||||
'namespace': namespace}
|
||||
update_template_dictionary(d, request, course)
|
||||
return render_to_response('simplewiki/simplewiki_searchresults.html', d)
|
||||
|
||||
|
||||
def search_add_related(request, course_id, slug, namespace):
|
||||
course = get_opt_course_with_access(request.user, course_id, 'load')
|
||||
|
||||
(article, err) = get_article(request, slug, namespace if namespace else course_id)
|
||||
if err:
|
||||
return err
|
||||
|
||||
perm_err = check_permissions(request, article, course, check_read=True)
|
||||
if perm_err:
|
||||
return perm_err
|
||||
|
||||
search_string = request.GET.get('query', None)
|
||||
self_pk = request.GET.get('self', None)
|
||||
if search_string:
|
||||
results = []
|
||||
related = Article.objects.filter(title__istartswith=search_string)
|
||||
others = article.related.all()
|
||||
if self_pk:
|
||||
related = related.exclude(pk=self_pk)
|
||||
if others:
|
||||
related = related.exclude(related__in=others)
|
||||
related = related.order_by('title')[:10]
|
||||
for item in related:
|
||||
results.append({'id': str(item.id),
|
||||
'value': item.title,
|
||||
'info': item.get_url()})
|
||||
else:
|
||||
results = []
|
||||
|
||||
json = simplejson.dumps({'results': results})
|
||||
return HttpResponse(json, mimetype='application/json')
|
||||
|
||||
|
||||
def add_related(request, course_id, slug, namespace):
|
||||
course = get_opt_course_with_access(request.user, course_id, 'load')
|
||||
|
||||
(article, err) = get_article(request, slug, namespace if namespace else course_id)
|
||||
if err:
|
||||
return err
|
||||
|
||||
perm_err = check_permissions(request, article, course, check_write=True, check_locked=True)
|
||||
if perm_err:
|
||||
return perm_err
|
||||
|
||||
try:
|
||||
related_id = request.POST['id']
|
||||
rel = Article.objects.get(id=related_id)
|
||||
has_already = article.related.filter(id=related_id).count()
|
||||
if has_already == 0 and not rel == article:
|
||||
article.related.add(rel)
|
||||
article.save()
|
||||
except:
|
||||
pass
|
||||
finally:
|
||||
return HttpResponseRedirect(reverse('wiki_view', args=(article.get_url(),)))
|
||||
|
||||
|
||||
def remove_related(request, course_id, namespace, slug, related_id):
|
||||
course = get_opt_course_with_access(request.user, course_id, 'load')
|
||||
|
||||
(article, err) = get_article(request, slug, namespace if namespace else course_id)
|
||||
|
||||
if err:
|
||||
return err
|
||||
|
||||
perm_err = check_permissions(request, article, course, check_write=True, check_locked=True)
|
||||
if perm_err:
|
||||
return perm_err
|
||||
|
||||
try:
|
||||
rel_id = int(related_id)
|
||||
rel = Article.objects.get(id=rel_id)
|
||||
article.related.remove(rel)
|
||||
article.save()
|
||||
except:
|
||||
pass
|
||||
finally:
|
||||
return HttpResponseRedirect(reverse('wiki_view', args=(article.get_url(),)))
|
||||
|
||||
|
||||
def random_article(request, course_id=None):
|
||||
course = get_opt_course_with_access(request.user, course_id, 'load')
|
||||
|
||||
from random import randint
|
||||
num_arts = Article.objects.count()
|
||||
article = Article.objects.all()[randint(0, num_arts - 1)]
|
||||
return HttpResponseRedirect(wiki_reverse('wiki_view', article, course))
|
||||
|
||||
|
||||
def not_found(request, article_path, course):
|
||||
"""Generate a NOT FOUND message for some URL"""
|
||||
d = {'wiki_err_notfound': True,
|
||||
'article_path': article_path,
|
||||
'namespace': "edX"}
|
||||
update_template_dictionary(d, request, course)
|
||||
return render_to_response('simplewiki/simplewiki_error.html', d)
|
||||
|
||||
|
||||
def get_article(request, article_path, course):
|
||||
err = None
|
||||
article = None
|
||||
|
||||
try:
|
||||
article = Article.get_article(article_path)
|
||||
except Article.DoesNotExist, ValueError:
|
||||
err = not_found(request, article_path, course)
|
||||
|
||||
return (article, err)
|
||||
|
||||
|
||||
def check_permissions(request, article, course, check_read=False, check_write=False, check_locked=False, check_deleted=False, revision=None):
|
||||
read_err = check_read and not article.can_read(request.user)
|
||||
|
||||
write_err = check_write and not article.can_write(request.user)
|
||||
|
||||
locked_err = check_locked and article.locked
|
||||
|
||||
if revision is None:
|
||||
revision = article.current_revision
|
||||
deleted_err = check_deleted and not (revision.deleted == 0)
|
||||
if (request.user.is_superuser):
|
||||
deleted_err = False
|
||||
locked_err = False
|
||||
|
||||
if read_err or write_err or locked_err or deleted_err:
|
||||
d = {'wiki_article': article,
|
||||
'wiki_err_noread': read_err,
|
||||
'wiki_err_nowrite': write_err,
|
||||
'wiki_err_locked': locked_err,
|
||||
'wiki_err_deleted': deleted_err, }
|
||||
update_template_dictionary(d, request, course)
|
||||
# TODO: Make this a little less jarring by just displaying an error
|
||||
# on the current page? (no such redirect happens for an anon upload yet)
|
||||
# benjaoming: I think this is the nicest way of displaying an error, but
|
||||
# these errors shouldn't occur, but rather be prevented on the other pages.
|
||||
return render_to_response('simplewiki/simplewiki_error.html', d)
|
||||
else:
|
||||
return None
|
||||
|
||||
####################
|
||||
# LOGIN PROTECTION #
|
||||
####################
|
||||
|
||||
|
||||
if wiki_settings.WIKI_REQUIRE_LOGIN_VIEW:
|
||||
view = login_required(view)
|
||||
history = login_required(history)
|
||||
search_articles = login_required(search_articles)
|
||||
root_redirect = login_required(root_redirect)
|
||||
revision_feed = login_required(revision_feed)
|
||||
random_article = login_required(random_article)
|
||||
search_add_related = login_required(search_add_related)
|
||||
not_found = login_required(not_found)
|
||||
view_revision = login_required(view_revision)
|
||||
|
||||
if wiki_settings.WIKI_REQUIRE_LOGIN_EDIT:
|
||||
create = login_required(create)
|
||||
edit = login_required(edit)
|
||||
add_related = login_required(add_related)
|
||||
remove_related = login_required(remove_related)
|
||||
|
||||
if wiki_settings.WIKI_CONTEXT_PREPROCESSORS:
|
||||
settings.TEMPLATE_CONTEXT_PROCESSORS += wiki_settings.WIKI_CONTEXT_PREPROCESSORS
|
||||
@@ -1,111 +0,0 @@
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.conf import settings
|
||||
|
||||
# Default settings.. overwrite in your own settings.py
|
||||
|
||||
# Planned feature.
|
||||
WIKI_USE_MARKUP_WIDGET = True
|
||||
|
||||
####################
|
||||
# LOGIN PROTECTION #
|
||||
####################
|
||||
# Before setting the below parameters, please note that permissions can
|
||||
# be set in the django permission system on individual articles and their
|
||||
# child articles. In this way you can add a user group and give them
|
||||
# special permissions, be it on the root article or some other. Permissions
|
||||
# are inherited on lower levels.
|
||||
|
||||
# Adds standard django login protection for viewing
|
||||
WIKI_REQUIRE_LOGIN_VIEW = getattr(settings, 'SIMPLE_WIKI_REQUIRE_LOGIN_VIEW',
|
||||
True)
|
||||
|
||||
# Adds standard django login protection for editing
|
||||
WIKI_REQUIRE_LOGIN_EDIT = getattr(settings, 'SIMPLE_WIKI_REQUIRE_LOGIN_EDIT',
|
||||
True)
|
||||
|
||||
####################
|
||||
# ATTACHMENTS #
|
||||
####################
|
||||
|
||||
# This should be a directory that's writable for the web server.
|
||||
# It's relative to the MEDIA_ROOT.
|
||||
WIKI_ATTACHMENTS = getattr(settings, 'SIMPLE_WIKI_ATTACHMENTS',
|
||||
'simplewiki/attachments/')
|
||||
|
||||
# If false, attachments will completely disappear
|
||||
WIKI_ALLOW_ATTACHMENTS = getattr(settings, 'SIMPLE_WIKI_ALLOW_ATTACHMENTS',
|
||||
False)
|
||||
|
||||
# If WIKI_REQUIRE_LOGIN_EDIT is False, then attachments can still be disallowed
|
||||
WIKI_ALLOW_ANON_ATTACHMENTS = getattr(settings, 'SIMPLE_WIKI_ALLOW_ANON_ATTACHMENTS', False)
|
||||
|
||||
# Attachments are automatically stored with a dummy extension and delivered
|
||||
# back to the user with their original extension.
|
||||
# This setting does not add server security, but might add user security
|
||||
# if set -- or force users to use standard formats, which might also
|
||||
# be a good idea.
|
||||
# Example: ('pdf', 'doc', 'gif', 'jpeg', 'jpg', 'png')
|
||||
WIKI_ATTACHMENTS_ALLOWED_EXTENSIONS = getattr(settings, 'SIMPLE_WIKI_ATTACHMENTS_ALLOWED_EXTENSIONS',
|
||||
None)
|
||||
|
||||
# At the moment this variable should not be modified, because
|
||||
# it breaks compatibility with the normal Django FileField and uploading
|
||||
# from the admin interface.
|
||||
WIKI_ATTACHMENTS_ROOT = settings.MEDIA_ROOT
|
||||
|
||||
# Bytes! Default: 1 MB.
|
||||
WIKI_ATTACHMENTS_MAX = getattr(settings, 'SIMPLE_WIKI_ATTACHMENTS_MAX',
|
||||
1 * 1024 * 1024)
|
||||
|
||||
# Allow users to edit titles of pages
|
||||
# (warning! titles are not maintained in the revision system.)
|
||||
WIKI_ALLOW_TITLE_EDIT = getattr(settings, 'SIMPLE_WIKI_ALLOW_TITLE_EDIT', False)
|
||||
|
||||
# Global context processors
|
||||
# These are appended to TEMPLATE_CONTEXT_PROCESSORS in your Django settings
|
||||
# whenever the wiki is in use. It can be used as a simple, but effective
|
||||
# way of extending simplewiki without touching original code (and thus keeping
|
||||
# everything easily maintainable)
|
||||
WIKI_CONTEXT_PREPROCESSORS = getattr(settings, 'SIMPLE_WIKI_CONTEXT_PREPROCESSORS',
|
||||
())
|
||||
|
||||
####################
|
||||
# AESTHETICS #
|
||||
####################
|
||||
|
||||
# List of extensions to be used by Markdown. Custom extensions (i.e., with file
|
||||
# names of mdx_*.py) can be dropped into the simplewiki (or project) directory
|
||||
# and then added to this list to be utilized. Wiki is enabled automatically.
|
||||
#
|
||||
# For more information, see
|
||||
# http://www.freewisdom.org/projects/python-markdown/Available_Extensions
|
||||
WIKI_MARKDOWN_EXTENSIONS = getattr(settings, 'SIMPLE_WIKI_MARKDOWN_EXTENSIONS',
|
||||
['footnotes',
|
||||
'tables',
|
||||
'headerid',
|
||||
'fenced_code',
|
||||
'def_list',
|
||||
#'codehilite', #This was throwing errors
|
||||
'abbr',
|
||||
'toc',
|
||||
'mathjax',
|
||||
'video', # In-line embedding for YouTube, etc.
|
||||
'circuit',
|
||||
])
|
||||
|
||||
|
||||
WIKI_IMAGE_EXTENSIONS = getattr(settings,
|
||||
'SIMPLE_WIKI_IMAGE_EXTENSIONS',
|
||||
('jpg', 'jpeg', 'gif', 'png', 'tiff', 'bmp'))
|
||||
# Planned features
|
||||
WIKI_PAGE_WIDTH = getattr(settings,
|
||||
'SIMPLE_WIKI_PAGE_WIDTH', "100%")
|
||||
|
||||
WIKI_PAGE_ALIGN = getattr(settings,
|
||||
'SIMPLE_WIKI_PAGE_ALIGN', "center")
|
||||
|
||||
WIKI_IMAGE_THUMB_SIZE = getattr(settings,
|
||||
'SIMPLE_WIKI_IMAGE_THUMB_SIZE', (200, 150))
|
||||
|
||||
WIKI_IMAGE_THUMB_SIZE_SMALL = getattr(settings,
|
||||
'SIMPLE_WIKI_IMAGE_THUMB_SIZE_SMALL', (100, 100))
|
||||
@@ -689,7 +689,6 @@ INSTALLED_APPS = (
|
||||
'student',
|
||||
'static_template_view',
|
||||
'staticbook',
|
||||
'simplewiki',
|
||||
'track',
|
||||
'util',
|
||||
'certificates',
|
||||
|
||||
@@ -1,164 +0,0 @@
|
||||
##This file is based on the template from the SimpleWiki source which carries the GPL license
|
||||
|
||||
<%inherit file="../main.html"/>
|
||||
<%namespace name='static' file='../static_content.html'/>
|
||||
|
||||
<%block name="headextra">
|
||||
<%static:css group='course'/>
|
||||
</%block>
|
||||
|
||||
<%!
|
||||
from django.core.urlresolvers import reverse
|
||||
from simplewiki.views import wiki_reverse
|
||||
%>
|
||||
|
||||
<%block name="js_extra">
|
||||
<script type="text/javascript" src="${static.url('js/simplewiki-AutoSuggest_c_2.0.js')}"></script>
|
||||
|
||||
## TODO (cpennington): Remove this when we have a good way for modules to specify js to load on the page
|
||||
## and in the wiki
|
||||
<script type="text/javascript" src="${static.url('js/schematic.js')}"></script>
|
||||
|
||||
<script type="text/javascript">
|
||||
function set_related_article_id(s) {
|
||||
document.getElementById('wiki_related_input_id').value = s.id;
|
||||
document.getElementById('wiki_related_input_submit').disabled=false;
|
||||
}
|
||||
%if wiki_article is not UNDEFINED:
|
||||
var x = window.onload;
|
||||
window.onload = function(){
|
||||
var options = {
|
||||
script: "${ wiki_reverse('search_related', wiki_article, course)}/?self=${wiki_article.pk}&",
|
||||
json: true,
|
||||
varname: "query",
|
||||
maxresults: 35,
|
||||
callback: set_related_article_id,
|
||||
noresults: "Nothing found!"
|
||||
};
|
||||
var as = new AutoSuggest('wiki_related_input', options);
|
||||
if (typeof x == 'function')
|
||||
x();
|
||||
}
|
||||
%endif
|
||||
</script>
|
||||
<script type="text/x-mathjax-config">
|
||||
MathJax.Hub.Config({
|
||||
tex2jax: {inlineMath: [ ['$','$'], ["\\(","\\)"]],
|
||||
displayMath: [ ['$$','$$'], ["\\[","\\]"]]}
|
||||
});
|
||||
</script>
|
||||
<script>
|
||||
$(function(){
|
||||
$.ajaxSetup ({
|
||||
// Disable caching of AJAX responses
|
||||
cache: false
|
||||
});
|
||||
|
||||
$(".div_wiki_circuit").each(function(d,e) {
|
||||
id = $(this).attr("id");
|
||||
name = id.substring(17);
|
||||
//alert(name);
|
||||
$("#"+id).load("/edit_circuit/"+name, function(){update_schematics();});
|
||||
f=this;
|
||||
});
|
||||
|
||||
$("#wiki_create_form").hide();
|
||||
|
||||
$("#create-article").click(function() {
|
||||
$("#wiki_create_form").slideToggle();
|
||||
$(this).parent().toggleClass("active");
|
||||
});
|
||||
|
||||
});
|
||||
</script>
|
||||
|
||||
<%block name="wiki_head"/>
|
||||
|
||||
</%block>
|
||||
|
||||
<%block name="bodyextra">
|
||||
|
||||
%if course:
|
||||
<%include file="/courseware/course_navigation.html" args="active_page='wiki'" />
|
||||
%endif
|
||||
|
||||
<section class="container">
|
||||
<div class="wiki-wrapper">
|
||||
<%block name="wiki_panel">
|
||||
<div aria-label="Wiki Navigation" id="wiki_panel">
|
||||
<h2>Course Wiki</h2>
|
||||
<ul class="action">
|
||||
<li>
|
||||
<h3>
|
||||
<a href="${wiki_reverse("wiki_list_articles", course=course, namespace=namespace)}">All Articles</a>
|
||||
</h3>
|
||||
</li>
|
||||
|
||||
<li class="create-article">
|
||||
<h3>
|
||||
<a href="#" id="create-article"/>Create Article</a>
|
||||
</h3>
|
||||
|
||||
<div id="wiki_create_form">
|
||||
<%
|
||||
baseURL = wiki_reverse("wiki_create", course=course, kwargs={"article_path" : namespace + "/" })
|
||||
%>
|
||||
<form method="GET" onsubmit="this.action='${baseURL}' + this.wiki_article_name.value.replace(/([^a-zA-Z0-9\-])/g, '');">
|
||||
<div>
|
||||
<label for="id_wiki_article_name">Title of article</label>
|
||||
<input type="text" name="wiki_article_name" id="id_wiki_article_name" />
|
||||
</div>
|
||||
<ul>
|
||||
<li>
|
||||
<input type="submit" class="button" value="Create" />
|
||||
</li>
|
||||
</ul>
|
||||
</form>
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li class="search">
|
||||
<form method="GET" action='${wiki_reverse("wiki_search_articles", course=course, namespace=namespace)}'>
|
||||
<label class="wiki_box_title">Search</label>
|
||||
<input type="text" placeholder="Search" name="value" id="wiki_search_input" value="${wiki_search_query if wiki_search_query is not UNDEFINED else '' |h}"/>
|
||||
<input type="submit" id="wiki_search_input_submit" value="Go!" />
|
||||
</form>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
</%block>
|
||||
|
||||
<section class="wiki-body">
|
||||
%if wiki_article is not UNDEFINED:
|
||||
<header>
|
||||
%if wiki_article.locked:
|
||||
<p><strong>This article has been locked</strong></p>
|
||||
%endif
|
||||
<p>Last modified: ${wiki_article.modified_on.strftime("%b %d, %Y, %I:%M %p")}</p>
|
||||
%endif
|
||||
|
||||
%if wiki_article is not UNDEFINED:
|
||||
<ul>
|
||||
|
||||
<li>
|
||||
<a href="${ wiki_reverse('wiki_view', wiki_article, course)}" class="view">View</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="${ wiki_reverse('wiki_edit', wiki_article, course)}" class="edit">Edit</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="${ wiki_reverse('wiki_history', wiki_article, course)}" class="history">History</a>
|
||||
</li>
|
||||
</ul>
|
||||
</header>
|
||||
%endif
|
||||
|
||||
<%block name="wiki_page_title"/>
|
||||
<%block name="wiki_body"/>
|
||||
</section>
|
||||
</div>
|
||||
</section>
|
||||
</%block>
|
||||
@@ -1,76 +0,0 @@
|
||||
##This file is based on the template from the SimpleWiki source which carries the GPL license
|
||||
|
||||
<%inherit file="simplewiki_base.html"/>
|
||||
|
||||
<%block name="title">
|
||||
<title>
|
||||
%if create_article:
|
||||
Wiki – Create Article – MITx 6.002x
|
||||
%else:
|
||||
${"Edit " + wiki_title + " - " if wiki_title is not UNDEFINED else ""}MITx 6.002x Wiki
|
||||
%endif
|
||||
</title></%block>
|
||||
|
||||
<%block name="wiki_page_title">
|
||||
%if create_article:
|
||||
<h1>Create article</h1>
|
||||
%else:
|
||||
<h1>${ wiki_article.title }</h1>
|
||||
%endif
|
||||
</%block>
|
||||
|
||||
<%block name="wiki_head">
|
||||
<script type="text/javascript" src="${ settings.LIB_URL }vendor/CodeMirror/codemirror.js"></script>
|
||||
<link rel="stylesheet" href="${ settings.LIB_URL }vendor/CodeMirror/codemirror.css" />
|
||||
|
||||
<script type="text/javascript" src="${ settings.LIB_URL }vendor/CodeMirror/xml.js"></script>
|
||||
<script type="text/javascript" src="${ settings.LIB_URL }vendor/CodeMirror/mitx_markdown.js"></script>
|
||||
|
||||
<script>
|
||||
$(function(){
|
||||
$(document).ready(function() {
|
||||
//TODO: Re-enable this once the styling supports it
|
||||
// var editor = CodeMirror.fromTextArea(document.getElementById("id_contents"), {
|
||||
// mode: 'mitx_markdown',
|
||||
// matchBrackets: true,
|
||||
// theme: "default",
|
||||
// lineWrapping: true,
|
||||
// });
|
||||
//
|
||||
// //Store the inital contents so we can compare for unsaved changes
|
||||
// var initial_contents = editor.getValue();
|
||||
//
|
||||
// window.onbeforeunload = function askConfirm() { //Warn the user before they navigate away
|
||||
// if ( editor.getValue() != initial_contents ) {
|
||||
// return "You have made changes to the article that have not been saved yet.";
|
||||
// }
|
||||
// };
|
||||
//
|
||||
// $("#submit_edit").click(function() {
|
||||
// initial_contents = editor.getValue();
|
||||
// });
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
</script>
|
||||
</%block>
|
||||
|
||||
|
||||
<%block name="wiki_body">
|
||||
<form method="POST" id="wiki_revision">
|
||||
<div style="display:none">
|
||||
<input type="hidden" name="csrfmiddlewaretoken" value="${csrf_token}"/>
|
||||
</div>
|
||||
${wiki_form}
|
||||
%if create_article:
|
||||
<input type="submit" id="submit_edit" value="Create article" />
|
||||
%else:
|
||||
<input type="submit" id="submit_edit" name="edit" value="Save Changes" />
|
||||
<input type="submit" id="submit_delete" name="delete" value="Delete article" />
|
||||
%endif
|
||||
|
||||
<%include file="simplewiki_instructions.html"/>
|
||||
|
||||
</%block>
|
||||
@@ -1,79 +0,0 @@
|
||||
##This file is based on the template from the SimpleWiki source which carries the GPL license
|
||||
|
||||
<%inherit file="simplewiki_base.html"/>
|
||||
|
||||
<%!
|
||||
from simplewiki.views import wiki_reverse
|
||||
%>
|
||||
|
||||
<%block name="title"><title>Wiki Error – MITx 6.002x</title></%block>
|
||||
|
||||
|
||||
<%block name="wiki_page_title">
|
||||
<h1>Oops...</h1>
|
||||
</%block>
|
||||
|
||||
|
||||
<%block name="wiki_body">
|
||||
<div class="wiki_error">
|
||||
%if wiki_error is not UNDEFINED:
|
||||
${wiki_error}
|
||||
%endif
|
||||
|
||||
%if wiki_err_notfound is not UNDEFINED:
|
||||
<p>
|
||||
The page you requested could not be found.
|
||||
Click <a href="${wiki_reverse("wiki_create", course=course, kwargs={'article_path' : article_path})}">here</a> to create it.
|
||||
</p>
|
||||
%elif wiki_err_no_namespace is not UNDEFINED and wiki_err_no_namespace:
|
||||
<p>
|
||||
You must specify a namespace to create an article in.
|
||||
</p>
|
||||
%elif wiki_err_bad_namespace is not UNDEFINED and wiki_err_bad_namespace:
|
||||
<p>
|
||||
The namespace for this article does not exist. This article cannot be created.
|
||||
</p>
|
||||
%elif wiki_err_locked is not UNDEFINED and wiki_err_locked:
|
||||
<p>
|
||||
The article you are trying to modify is locked.
|
||||
</p>
|
||||
%elif wiki_err_noread is not UNDEFINED and wiki_err_noread:
|
||||
<p>
|
||||
You do not have access to read this article.
|
||||
</p>
|
||||
%elif wiki_err_nowrite is not UNDEFINED and wiki_err_nowrite:
|
||||
<p>
|
||||
You do not have access to edit this article.
|
||||
</p>
|
||||
%elif wiki_err_noanon is not UNDEFINED and wiki_err_noanon:
|
||||
<p>
|
||||
Anonymous attachments are not allowed. Try logging in.
|
||||
</p>
|
||||
%elif wiki_err_create is not UNDEFINED and wiki_err_create:
|
||||
<p>
|
||||
You do not have access to create this article.
|
||||
</p>
|
||||
%elif wiki_err_encode is not UNDEFINED and wiki_err_encode:
|
||||
<p>
|
||||
The url you requested could not be handled by the wiki.
|
||||
Probably you used a bad character in the URL.
|
||||
Only use digits, English letters, underscore and dash. For instance
|
||||
/wiki/An_Article-1
|
||||
</p>
|
||||
%elif wiki_err_deleted is not UNDEFINED and wiki_err_deleted:
|
||||
<p>
|
||||
The article you tried to access has been deleted. You may be able to restore it to an earlier version in its <a href="${wiki_reverse("wiki_history", wiki_article, course)}">history</a>, or <a href="${wiki_reverse("wiki_edit", wiki_article, course)}">create a new version</a>.
|
||||
</p>
|
||||
%elif wiki_err_norevision is not UNDEFINED:
|
||||
<p>
|
||||
This article does not contain revision ${wiki_err_norevision | h}.
|
||||
</p>
|
||||
%else:
|
||||
<p>
|
||||
An error has occured.
|
||||
</p>
|
||||
%endif
|
||||
|
||||
</div>
|
||||
</%block>
|
||||
|
||||
@@ -1,92 +0,0 @@
|
||||
##This file is based on the template from the SimpleWiki source which carries the GPL license
|
||||
|
||||
<%inherit file="simplewiki_base.html"/>
|
||||
|
||||
<%block name="title"><title>${"Revision history of " + wiki_title + " - " if wiki_title is not UNDEFINED else ""}Wiki – MITx 6.002x</title></%block>
|
||||
|
||||
<%!
|
||||
from django.core.urlresolvers import reverse
|
||||
from simplewiki.views import wiki_reverse
|
||||
%>
|
||||
|
||||
<%block name="wiki_page_title">
|
||||
<h1>
|
||||
${ wiki_article.title }
|
||||
</h1>
|
||||
</%block>
|
||||
|
||||
<%block name="wiki_body">
|
||||
<form method="POST">
|
||||
<div style="display:none">
|
||||
<input type="hidden" name="csrfmiddlewaretoken" value="${csrf_token}"/>
|
||||
</div>
|
||||
<table id="wiki_history_table" class="wiki-history">
|
||||
<thead>
|
||||
<tr>
|
||||
<th id="revision">Revision</th>
|
||||
<th id="comment">Comment</th>
|
||||
<th id="diff">Diff</th>
|
||||
<th id="modified">Modified</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<% loopCount = 0 %>
|
||||
%for revision in wiki_history:
|
||||
%if revision.deleted < 2 or show_delete_revision:
|
||||
<% loopCount += 1 %>
|
||||
<tr style="border-top: 1px" class="${'dark ' if (loopCount % 2) == 0 else ''}${'deleted ' if (revision.deleted==2) else ''}" >
|
||||
<td width="15px">
|
||||
<input type="radio" name="revision" id="${revision.id}" value="${revision.id}"${"checked" if wiki_article.current_revision.id == revision.id else ""}/>
|
||||
<label for="${revision.id}">
|
||||
${ revision }
|
||||
%if revision.previous_revision:
|
||||
%if not revision.counter == revision.previous_revision.counter + 1:
|
||||
<br/>(based on ${revision.previous_revision})
|
||||
%endif
|
||||
%endif
|
||||
</label>
|
||||
</td>
|
||||
<td>
|
||||
${ revision.revision_text if revision.revision_text else "<i>None</i>" }</td>
|
||||
<td class="diff">
|
||||
%for x in revision.get_diff():
|
||||
${x|h}<br/>
|
||||
%endfor </td>
|
||||
<td>${revision.get_user()}
|
||||
<br/>
|
||||
${revision.revision_date.strftime("%b %d, %Y, %I:%M %p")}
|
||||
</td>
|
||||
</tr>
|
||||
%endif
|
||||
%endfor
|
||||
</tbody>
|
||||
%if wiki_prev_page or wiki_next_page:
|
||||
<tfoot>
|
||||
<tr>
|
||||
<td colspan="4">
|
||||
%if wiki_prev_page:
|
||||
<a href="${wiki_reverse('wiki_history', wiki_article, course, kwargs={'page' : wiki_prev_page})}">Previous page</a>
|
||||
%endif
|
||||
%if wiki_next_page:
|
||||
<a href="${wiki_reverse('wiki_history', wiki_article, course, kwargs={'page' : wiki_next_page})}">Next page</a>
|
||||
%endif
|
||||
</td>
|
||||
</tr>
|
||||
</tfoot>
|
||||
%endif
|
||||
</table>
|
||||
<div class="history-controls"><input type="submit" name="view" value="View revision"/>
|
||||
<input type="submit" name="change" value="Change to revision"
|
||||
%if not wiki_write:
|
||||
disabled="true"
|
||||
%endif
|
||||
/>
|
||||
%if show_delete_revision:
|
||||
<input type="submit" name="delete" value="Delete revision"/>
|
||||
<input type="submit" name="restore" value="Restore revision"/>
|
||||
<input type="submit" name="delete_all" value="Delete all revisions">
|
||||
<input type="submit" name="lock_article" value="${'Lock Article' if not wiki_article.locked else 'Unlock Article'}">
|
||||
%endif
|
||||
</div>
|
||||
</form>
|
||||
</%block>
|
||||
@@ -1,24 +0,0 @@
|
||||
<div id="wiki_edit_instructions">
|
||||
This wiki uses <strong>Markdown</strong> for styling.
|
||||
<h2> MITx Additions: </h2>
|
||||
<p class="markdown-example">circuit-schematic:</p>
|
||||
<p class="markdown-example"><span>$</span>LaTeX Math Expression<span>$</span></p>
|
||||
To create a new wiki article, create a link to it. Clicking the link gives you the creation page.
|
||||
<p class="markdown-example">[Article Name](wiki:ArticleName)</p>
|
||||
|
||||
<h2>Useful examples: </h2>
|
||||
<p class="markdown-example">[Link](http://google.com)</p>
|
||||
<p class="markdown-example">Huge Header
|
||||
<br>====</p>
|
||||
<p class="markdown-example">Smaller Header
|
||||
<br>-------</p>
|
||||
<p class="markdown-example">*emphasis* or _emphasis_</p>
|
||||
<p class="markdown-example">**strong** or __strong__</p>
|
||||
<p class="markdown-example">- Unordered List
|
||||
<br>  - Sub Item 1
|
||||
<br>  - Sub Item 2</p>
|
||||
<p class="markdown-example">1. Ordered
|
||||
<br>2. List</p>
|
||||
|
||||
<p>Need more help? There are several <a href="http://daringfireball.net/projects/markdown/basics">useful</a> <a href="http://greg.vario.us/doc/markdown.txt">guides</a> <a href="http://www.lowendtalk.com/discussion/6/miniature-markdown-guide">online</a>.</p>
|
||||
</div>
|
||||
@@ -1,63 +0,0 @@
|
||||
##This file is based on the template from the SimpleWiki source which carries the GPL license
|
||||
|
||||
<%inherit file="simplewiki_base.html"/>
|
||||
|
||||
<%block name="title"><title>Wiki - Revision feed - MITx 6.002x</title></%block>
|
||||
|
||||
<%!
|
||||
from simplewiki.views import wiki_reverse
|
||||
%>
|
||||
|
||||
<%block name="wiki_page_title">
|
||||
<h1>Revision Feed - Page ${wiki_page}</h1>
|
||||
</%block>
|
||||
|
||||
<%block name="wiki_body">
|
||||
<table id="wiki_history_table" class="wiki-history">
|
||||
<thead>
|
||||
<tr>
|
||||
<th id="revision">Revision</th>
|
||||
<th id="comment">Comment</th>
|
||||
<th id="diff">Diff</th>
|
||||
<th id="modified">Modified</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<% loopCount = 0 %>
|
||||
%for revision in wiki_history:
|
||||
%if revision.deleted < 2 or show_delete_revision:
|
||||
<% loopCount += 1 %>
|
||||
<tr style="border-top: 1px" class="${'dark ' if (loopCount % 2) == 0 else ''}${'deleted ' if (revision.deleted==2) else ''}" >
|
||||
<td width="15px">
|
||||
<a href="${wiki_reverse('wiki_view_revision', revision.article, course, kwargs={'revision_number' : revision.counter})}"> ${revision.article.title} - ${revision}</a>
|
||||
</td>
|
||||
<td>
|
||||
${ revision.revision_text if revision.revision_text else "<i>None</i>" }</td>
|
||||
<td class="diff">
|
||||
%for x in revision.get_diff():
|
||||
${x|h}<br/>
|
||||
%endfor </td>
|
||||
<td>${revision.get_user()}
|
||||
<br/>
|
||||
${revision.revision_date.strftime("%b %d, %Y, %I:%M %p")}
|
||||
</td>
|
||||
</tr>
|
||||
%endif
|
||||
%endfor
|
||||
</tbody>
|
||||
%if wiki_prev_page or wiki_next_page:
|
||||
<tfoot>
|
||||
<tr>
|
||||
<td colspan="4">
|
||||
%if wiki_prev_page:
|
||||
<a href="${wiki_reverse("wiki_revision_feed", course=course, namespace=namespace, kwargs={'page': wiki_prev_page})}">Previous page</a>
|
||||
%endif
|
||||
%if wiki_next_page:
|
||||
<a href="${wiki_reverse("wiki_revision_feed", course=course, namespace=namespace, kwargs={'page': wiki_next_page})}">Next page</a>
|
||||
%endif
|
||||
</td>
|
||||
</tr>
|
||||
</tfoot>
|
||||
%endif
|
||||
</table>
|
||||
</%block>
|
||||
@@ -1,34 +0,0 @@
|
||||
##This file is based on the template from the SimpleWiki source which carries the GPL license
|
||||
|
||||
<%inherit file="simplewiki_base.html"/>
|
||||
|
||||
<%block name="title"><title>Wiki - Search Results - MITx 6.002x</title></%block>
|
||||
|
||||
<%!
|
||||
from simplewiki.views import wiki_reverse
|
||||
%>
|
||||
|
||||
<%block name="wiki_page_title">
|
||||
<h2 class="wiki-title">
|
||||
%if wiki_search_query:
|
||||
Search results for ${wiki_search_query | h}
|
||||
%else:
|
||||
Displaying all articles
|
||||
%endif
|
||||
</h2>
|
||||
</%block>
|
||||
|
||||
<%block name="wiki_body">
|
||||
<section class="results">
|
||||
<ul class="article-list">
|
||||
%for article in wiki_search_results:
|
||||
<% article_deleted = not article.current_revision.deleted == 0 %>
|
||||
<li><h3><a href="${wiki_reverse("wiki_view", article, course)}">${article.title} ${'(Deleted)' if article_deleted else ''}</a></h3></li>
|
||||
%endfor
|
||||
|
||||
%if not wiki_search_results:
|
||||
No articles matching <b>${wiki_search_query if wiki_search_query is not UNDEFINED else ""} </b>!
|
||||
%endif
|
||||
</ul>
|
||||
</section>
|
||||
</%block>
|
||||
@@ -1,37 +0,0 @@
|
||||
##This file is based on the template from the SimpleWiki source which carries the GPL license
|
||||
##This file has been converted to Mako, but not tested. It is because uploads are disabled for the wiki. If they are reenabled, this may contain bugs.
|
||||
<%!
|
||||
from django.template.defaultfilters import filesizeformat
|
||||
%>
|
||||
|
||||
|
||||
%if started:
|
||||
<script type="text/javascript">
|
||||
parent.document.getElementById("wiki_attach_progress_container").style.display='block';
|
||||
</script>
|
||||
%else:
|
||||
%if finished:
|
||||
<script type="text/javascript">
|
||||
parent.document.getElementById("wiki_attach_progress_container").style.display='none';
|
||||
parent.location.reload();
|
||||
</script>
|
||||
%else:
|
||||
%if overwrite_warning:
|
||||
<script type="text/javascript">
|
||||
if (confirm('Warning: The filename already exists? Really overwrite ${ filename }?'))
|
||||
parent.document.getElementById("wiki_attach_overwrite").checked=true;
|
||||
parent.document.getElementById("wiki_attach_overwrite").form.submit();
|
||||
</script>
|
||||
%else:
|
||||
%if too_big:
|
||||
<script type="text/javascript">
|
||||
alert('File is too big. Maximum: ${filesizeformat(max_size)}\nYour file was: ${filesizeformat(file.size)}');
|
||||
</script>
|
||||
%else:
|
||||
<script type="text/javascript">
|
||||
parent.document.getElementById("wiki_attach_progress").style.width='${progress_width}%';
|
||||
</script>
|
||||
%endif
|
||||
%endif
|
||||
%endif
|
||||
%endif
|
||||
@@ -1,15 +0,0 @@
|
||||
##This file is based on the template from the SimpleWiki source which carries the GPL license
|
||||
|
||||
<%inherit file="simplewiki_base.html"/>
|
||||
|
||||
<%block name="title"><title>${wiki_title + " - " if wiki_title is not UNDEFINED else ""}Wiki – MITx 6.002x</title></%block>
|
||||
|
||||
<%block name="wiki_page_title">
|
||||
<h1>${ wiki_article.title } ${'<span style="color: red;">- Deleted Revision!</span>' if wiki_current_revision_deleted else ''}</h1>
|
||||
</%block>
|
||||
|
||||
<%block name="wiki_body">
|
||||
<div id="wiki_article">
|
||||
${ wiki_article_revision.contents_parsed| n}
|
||||
</div>
|
||||
</%block>
|
||||
Reference in New Issue
Block a user