# HG changeset patch # User neko259 # Date 2015-01-13 09:27:52 # Node ID ce97c7545adc1f2fc622ca47434aa5b81f101f7a # Parent 011dea602b6b53994f3ed63e3abd4e29c570296d # Parent f79c88624c28e07ed9bd474d0a5c7a637212f1d4 Merged with default branch diff --git a/.hgtags b/.hgtags --- a/.hgtags +++ b/.hgtags @@ -16,3 +16,7 @@ 7f7c33ba6e3f3797ca866c5ed5d358a2393f1371 a6b9dd9547bdc17b681502efcceb17aa5c09adf4 1.8.1 8318fa1615d1946e4519f5735ae880909521990d 2.0 e23590ee7e2067a3f0fc3cbcfd66404b47127feb 2.1 +4d998aba79e4abf0a2e78e93baaa2c2800b1c49c 2.2 +07fdef4ac33a859250d03f17c594089792bca615 2.2.1 +bcc74d45f060ecd3ff06ff448165aea0d026cb3e 2.2.2 +b0e629ff24eb47a449ecfb455dc6cc600d18c9e2 2.2.3 diff --git a/boards/abstracts/settingsmanager.py b/boards/abstracts/settingsmanager.py --- a/boards/abstracts/settingsmanager.py +++ b/boards/abstracts/settingsmanager.py @@ -5,6 +5,7 @@ from boards.models import Tag SESSION_SETTING = 'setting' +# Remove this, it is not used any more cause there is a user's permission PERMISSION_MODERATE = 'moderator' SETTING_THEME = 'theme' diff --git a/boards/admin.py b/boards/admin.py --- a/boards/admin.py +++ b/boards/admin.py @@ -2,42 +2,53 @@ from django.contrib import admin from boards.models import Post, Tag, Ban, Thread, KeyPair +@admin.register(Post) class PostAdmin(admin.ModelAdmin): list_display = ('id', 'title', 'text') list_filter = ('pub_time', 'thread_new') search_fields = ('id', 'title', 'text') + exclude = ('referenced_posts', 'refmap') + readonly_fields = ('poster_ip', 'thread_new') +@admin.register(Tag) class TagAdmin(admin.ModelAdmin): - list_display = ('name',) + def thread_count(self, obj: Tag) -> int: + return obj.get_thread_count() + list_display = ('name', 'thread_count') + search_fields = ('name',) + + +@admin.register(Thread) class ThreadAdmin(admin.ModelAdmin): - def title(self, obj): - return obj.get_opening_post().title + def title(self, obj: Thread) -> str: + return obj.get_opening_post().get_title() - def reply_count(self, obj): + def reply_count(self, obj: Thread) -> int: return obj.get_reply_count() - list_display = ('id', 'title', 'reply_count', 'archived') - list_filter = ('bump_time', 'archived') + def ip(self, obj: Thread): + return obj.get_opening_post().poster_ip + + list_display = ('id', 'title', 'reply_count', 'archived', 'ip') + list_filter = ('bump_time', 'archived', 'bumpable') search_fields = ('id', 'title') + filter_horizontal = ('tags',) +@admin.register(KeyPair) class KeyPairAdmin(admin.ModelAdmin): list_display = ('public_key', 'primary') list_filter = ('primary',) search_fields = ('public_key',) + +@admin.register(Ban) class BanAdmin(admin.ModelAdmin): list_display = ('ip', 'can_read') list_filter = ('can_read',) search_fields = ('ip',) - -admin.site.register(Post, PostAdmin) -admin.site.register(Tag, TagAdmin) -admin.site.register(Ban, BanAdmin) -admin.site.register(Thread, ThreadAdmin) -admin.site.register(KeyPair, KeyPairAdmin) diff --git a/boards/context_processors.py b/boards/context_processors.py --- a/boards/context_processors.py +++ b/boards/context_processors.py @@ -1,5 +1,4 @@ -from boards.abstracts.settingsmanager import PERMISSION_MODERATE, \ - get_settings_manager +from boards.abstracts.settingsmanager import get_settings_manager __author__ = 'neko259' @@ -19,7 +18,7 @@ PERMISSION_MODERATE = 'moderation' def user_and_ui_processor(request): - context = {} + context = dict() context[CONTEXT_PPD] = float(Post.objects.get_posts_per_day()) @@ -31,7 +30,7 @@ def user_and_ui_processor(request): # This shows the moderator panel try: - moderate = request.user.has_perm('moderation') + moderate = request.user.has_perm(PERMISSION_MODERATE) except AttributeError: moderate = False context[CONTEXT_MODERATOR] = moderate diff --git a/boards/forms.py b/boards/forms.py --- a/boards/forms.py +++ b/boards/forms.py @@ -8,7 +8,7 @@ from django.utils.translation import uge from boards.mdx_neboard import formatters from boards.models.post import TITLE_MAX_LENGTH -from boards.models import PostImage +from boards.models import PostImage, Tag from neboard import settings from boards import utils import boards.settings as board_settings @@ -216,6 +216,17 @@ class ThreadForm(PostForm): raise forms.ValidationError( _('Inappropriate characters in tags.')) + tag_models = [] + required_tag_exists = False + for tag in tags.split(): + tag_model = Tag.objects.filter(name=tag.strip().lower(), + required=True) + if tag_model.exists(): + required_tag_exists = True + + if not required_tag_exists: + raise forms.ValidationError(_('Need at least 1 required tag.')) + return tags def clean(self): diff --git a/boards/locale/ru/LC_MESSAGES/django.mo b/boards/locale/ru/LC_MESSAGES/django.mo index 77d9ef1d015f8ed800b750afb4ab31bcb9ca7eea..036d4fd1b32decb9e0a867271ff8dc58f282948e GIT binary patch literal 6702 zc$|$_Yit}>6~2@fV#hd%okv5Vy=h6CG~MkweWjZ?i4!}iiC?juLP5wKdnfiZ>zVD$ ztQ|uuoVXzYTS*mBT9rOXDxvZNa5i@0S8VuIgj8wv4@jtjN+859KnMvW1mZjA+ca1H_)XoR)QiBDyA)q*Kdlu0t97`o25vUvt+;&( z7z0)SA2;)Raa#vG1l$1pGVo5I3tR;ZjGmW(TY=}y`cHsWz^ev-X5>Evk}1CeYT!q} zEx>;RHv{j3&?ey1t3>Zn;Aene16Bi1tdjj-2Ywznx=QSQ2e=0KzLA>&J_P*0==qD0 z``0S5@2(2*x3WUU>wuNOjTPeemI^s{dxf0$l$ozLXU3-Es6;A*k&)zxy|d#lBdk5`L* z_f(00_g6`LcT~yz6TtPrJyqi8Q6u+UmFVjQZUkn5*FT}u1n?e=8>=O*&sPg?GSy=D z%fS19->a5=*Q&+7539wGzXI0+?_MK%wyzOBH36Ri_NI5P0zXUpjr^b1h~7J) zozr6vcL+27Uqf#dYGJ2iyld34DNfxK8-}(K@mJKfoC9 z-WnOV0BeEi8p-cyjl}1I!OJyr&UB5$;deDsXaB5`_}p77xT9A5+f^(4I#?_IJYOq% zhRynS%=oohIsbj&5bzhZ;_troV#mq#V)t2KBk)IN{O9$uf9(d*_rM16Gj7J6z;jfu z8-#yHN%Wd8L{(%XK&N#gMo zZX>`B;0wTC-YxP^Y!*K3-z;%BYH(n)`0>rna^59_Q@}@n9{`^Q{v8Nf7B8~#A@h91 zU>v{4mH0u|PW%$)nR3*sBo`e@YKHi>-mFtCk^K*wG3A)fr?c0Toy*)(5<80LlS=A~ za@0h5$FI%EQXYt_ht%@xfI;fx#7#}{P|{cEI*i}FO8N)Kj^e7MAJ9d0RWEM-5Vc?=;U;i&TG<8_LUWCH;wVNBx92*{p;!g^T*zHYIgL z+}y9E$8?$Xc7s$`sv(uqq1CS%(rFzI__mb_R6{l#@ccj>uw2(psRLdbGWN+(9rOkV zZ5If+(AKU!Z1$)|CkTC~Hyhe1opn>Tj|E#brJRs&e1trRe3OH9pS5bw*Uq5TZ|lKq z5b9oA;|SZgQ*m|3#_@-(blUbu^q`lr)iX{iWxJ#*$

ogg&lKN)T0j-0`8?bL}mV^9QZ8 zgs#mCWxHz6*skipF^FLY*+w_Xf$H$>A;%sT^s<4Nb2RIPw(7JqX$Ns69FaRYXi|!? z7dWBkkEkvS5$m!ozi$8#hK}1GsICETn6uS&!pUUd^44vAFels|APTHFuE{c^k2D9i zt&#oWy6Vaxeo5@iWK!5ifyEv9NLe^F<2hi8>H-r_*wEr-`v)X5UD>_?L$YBjfKEDL zg!hACUBga@b&gWkh#OibRX6O!59xNXiAj%Pz_%jBQg+%Ibcpi3BRa@fedI#-GD@;F63=Vi48^%Q&G0(s&*)dzz^)I7?JjUifdudv*dℑd^S&Kq z(;+*Nq|Lr=?tr-|pIje6wtH=ms+W5i>cm4Z`$FDnrC>TWE;?9Q-1St-4xE11riURr z?SWj1QyHiitRXAt^PNnnOKT{88%;x*SO!Ws3G()42Q$nM1=80c2t)8N-9ud?=%G63 z@Vyu8zA)CDiam>*IG&r-9SsMMG#qZy&o*^-HMh4_Qc?L~tTpI&Qn3Ts{vg)vC3R&- zdv}a09-Cr~+;4U!>Yj)t>SBpqy6(y3V^8i#>`Wve80$o|f|A^GO%0u~*7jIqgMOwx z+1kA0EA4GfmDIXo-M-}pX$nSCA3E03qT3o;oAjQh)`sSm{SA$colRX`dm-xfXW?qB z+qMRix}~A*@G&xZPfN@Gv=jII{*p{m``OCY=GLZ?hjsBpB_#nR6(bfVIkAss(w5`y zW{L)OSbwbhP;6I8jto0)`>`gs&r2ckNxiGr2`f9&S%frp2&@f~+RgAVsDEs?mdE;S z?$)|QeSMvN@Ig(Fi7oYYb$Xvp=p>K#*6%DV?Wup99(hM%PhCR4^pb3WOkz9s)M3xg z?fAnY`fjusU5O^6Tr`tEouAOrLNuK}9nIy(RCF~qXjr@2tD>~-#r}C#&^d{C9=oqY>jwT^96V0mV z5~i<5QWH81TbhLy`Q!07`idet+bj!pt zCvRRW9e254vxbH9(Ts+tFc$(dkjAryx$qU9!b=@p$&ZWn9R5vXjXWHWtLXa$U&)1O z3QV-1qpPrf9(IgkYKHuuqrgJLID%fVFq%mgmngt1nvV=}EUt+g(e!Pm%j}I7%j^~R zry+m_$84CTM7_;UEF$1z6a})HZ9@+52x}4`X15=BVKFCc1{*3VJZDu!%VFoe0z`;aS@sD)LiP3s7LUGC`+eGY!ep)Wk87%x35#?=?Co_ty$e$@_LCHbOTLp%Y#nWtdG+V|x zqk-uh*QNTRGOnsY1cSIEwXXaRD|`3~v{~AJU1Oh)FRd$BkmVY*6-C=nT1K z{bri!dYv^bmUXK9nc`XO6!p9rN)`ob(%1sVQ+i|-nUAjDriR~T;U)HkLtFMaNj@73 z!CK_e1f8@?ah;ZEJfibwS%{bjf+FCQDdQD)@{%ql2-*reCCzlA^eK7^`DeMvg<6zo zj>@cbFMbo`&oY_jus+5eYcx3m2s52m;< zZ|xpp)p_c6$iN%)(NK8nz`kPto8-5`JRLYC@1QGu!nCNQqxe-xR_pvLg$~KhqWHl> zy(%sSfuH#^Qtnf{w_qQ=Ru?$hW0bF@!h5Og(Y&JQBm|LPG!*(3bx|=>=fIAs|E+CF z3Yp?Q+n_;$O_UbGn(n\n" "Language-Team: LANGUAGE \n" @@ -41,7 +41,7 @@ msgstr "" #: forms.py:23 msgid "tag1 several_words_tag" -msgstr "тег1 тег_из_нескольких_слов" +msgstr "метка1 метка_из_нескольких_слов" #: forms.py:25 msgid "Such image was already posted" @@ -57,9 +57,9 @@ msgstr "Текст" #: forms.py:29 msgid "Tag" -msgstr "Тег" +msgstr "Метка" -#: forms.py:30 templates/boards/base.html:36 templates/search/search.html:9 +#: forms.py:30 templates/boards/base.html:38 templates/search/search.html:9 #: templates/search/search.html.py:13 msgid "Search" msgstr "Поиск" @@ -91,28 +91,32 @@ msgstr "Изображение должно быть менее %s байт" msgid "Either text or image must be entered." msgstr "Текст или картинка должны быть введены." -#: forms.py:198 +#: forms.py:194 #, python-format msgid "Wait %s seconds after last posting" msgstr "Подождите %s секунд после последнего постинга" -#: forms.py:214 templates/boards/tags.html:7 templates/boards/rss/post.html:10 +#: forms.py:210 templates/boards/rss/post.html:10 templates/boards/tags.html:7 msgid "Tags" -msgstr "Теги" +msgstr "Метки" -#: forms.py:221 forms.py:247 +#: forms.py:217 forms.py:254 msgid "Inappropriate characters in tags." -msgstr "Недопустимые символы в тегах." +msgstr "Недопустимые символы в метках." -#: forms.py:234 +#: forms.py:228 +msgid "Need at least 1 required tag." +msgstr "Нужна хотя бы 1 обязательная метка." + +#: forms.py:241 msgid "Theme" msgstr "Тема" -#: forms.py:270 +#: forms.py:277 msgid "Invalid master password" msgstr "Неверный мастер-пароль" -#: forms.py:284 +#: forms.py:291 #, python-format msgid "Wait %s minutes after last login" msgstr "Подождите %s минут после последнего входа" @@ -141,32 +145,32 @@ msgstr "лицензией" msgid "Repository" msgstr "Репозиторий" -#: templates/boards/base.html:12 +#: templates/boards/base.html:13 msgid "Feed" msgstr "Лента" -#: templates/boards/base.html:29 +#: templates/boards/base.html:30 msgid "All threads" msgstr "Все темы" -#: templates/boards/base.html:34 +#: templates/boards/base.html:36 msgid "Tag management" -msgstr "Управление тегами" +msgstr "Управление метками" -#: templates/boards/base.html:37 templates/boards/settings.html:7 +#: templates/boards/base.html:39 templates/boards/settings.html:7 msgid "Settings" msgstr "Настройки" -#: templates/boards/base.html:50 +#: templates/boards/base.html:52 msgid "Admin" msgstr "" -#: templates/boards/base.html:52 +#: templates/boards/base.html:54 #, python-format msgid "Speed: %(ppd)s posts per day" msgstr "Скорость: %(ppd)s сообщений в день" -#: templates/boards/base.html:54 +#: templates/boards/base.html:56 msgid "Up" msgstr "Вверх" @@ -178,96 +182,96 @@ msgstr "Вход" msgid "Insert your user id above" msgstr "Вставьте свой ID пользователя выше" -#: templates/boards/post.html:21 templates/boards/staticpages/help.html:17 +#: templates/boards/post.html:19 templates/boards/staticpages/help.html:17 msgid "Quote" msgstr "Цитата" -#: templates/boards/post.html:31 +#: templates/boards/post.html:27 msgid "Open" msgstr "Открыть" -#: templates/boards/post.html:33 +#: templates/boards/post.html:29 msgid "Reply" msgstr "Ответ" -#: templates/boards/post.html:40 +#: templates/boards/post.html:36 msgid "Edit" msgstr "Изменить" -#: templates/boards/post.html:42 -msgid "Delete" -msgstr "Удалить" +#: templates/boards/post.html:39 +msgid "Edit thread" +msgstr "Изменить тему" -#: templates/boards/post.html:45 -msgid "Ban IP" -msgstr "Заблокировать IP" - -#: templates/boards/post.html:76 +#: templates/boards/post.html:71 msgid "Replies" msgstr "Ответы" -#: templates/boards/post.html:86 templates/boards/thread.html:88 +#: templates/boards/post.html:79 templates/boards/thread.html:89 #: templates/boards/thread_gallery.html:59 msgid "messages" msgstr "сообщений" -#: templates/boards/post.html:87 templates/boards/thread.html:89 +#: templates/boards/post.html:80 templates/boards/thread.html:90 #: templates/boards/thread_gallery.html:60 msgid "images" msgstr "изображений" #: templates/boards/post_admin.html:19 msgid "Tags:" -msgstr "Теги:" +msgstr "Метки:" #: templates/boards/post_admin.html:30 msgid "Add tag" -msgstr "Добавить тег" +msgstr "Добавить метку" #: templates/boards/posting_general.html:56 msgid "Show tag" -msgstr "Показывать тег" +msgstr "Показывать метку" #: templates/boards/posting_general.html:60 msgid "Hide tag" -msgstr "Скрывать тег" +msgstr "Скрывать метку" -#: templates/boards/posting_general.html:79 templates/search/search.html:22 +#: templates/boards/posting_general.html:66 +msgid "Edit tag" +msgstr "Изменить метку" + +#: templates/boards/posting_general.html:82 templates/search/search.html:22 msgid "Previous page" msgstr "Предыдущая страница" -#: templates/boards/posting_general.html:94 +#: templates/boards/posting_general.html:97 #, python-format msgid "Skipped %(count)s replies. Open thread to see all replies." msgstr "Пропущено %(count)s ответов. Откройте тред, чтобы увидеть все ответы." -#: templates/boards/posting_general.html:121 templates/search/search.html:33 +#: templates/boards/posting_general.html:124 templates/search/search.html:33 msgid "Next page" msgstr "Следующая страница" -#: templates/boards/posting_general.html:126 +#: templates/boards/posting_general.html:129 msgid "No threads exist. Create the first one!" msgstr "Нет тем. Создайте первую!" -#: templates/boards/posting_general.html:132 +#: templates/boards/posting_general.html:135 msgid "Create new thread" msgstr "Создать новую тему" -#: templates/boards/posting_general.html:137 templates/boards/preview.html:16 -#: templates/boards/thread.html:58 +#: templates/boards/posting_general.html:140 templates/boards/preview.html:16 +#: templates/boards/thread.html:54 msgid "Post" msgstr "Отправить" -#: templates/boards/posting_general.html:142 +#: templates/boards/posting_general.html:145 msgid "Tags must be delimited by spaces. Text or image is required." msgstr "" -"Теги должны быть разделены пробелами. Текст или изображение обязательны." +"Метки должны быть разделены пробелами. Текст или изображение обязательны." -#: templates/boards/posting_general.html:145 templates/boards/thread.html:66 +#: templates/boards/posting_general.html:148 templates/boards/thread.html:62 msgid "Text syntax" msgstr "Синтаксис текста" -#: templates/boards/posting_general.html:157 +#: templates/boards/posting_general.html:160 msgid "Pages:" msgstr "Страницы: " @@ -275,54 +279,26 @@ msgstr "Страницы: " msgid "Preview" msgstr "Предпросмотр" +#: templates/boards/rss/post.html:5 +msgid "Post image" +msgstr "Изображение сообщения" + #: templates/boards/settings.html:15 msgid "You are moderator." msgstr "Вы модератор." #: templates/boards/settings.html:19 msgid "Hidden tags:" -msgstr "Скрытые теги:" +msgstr "Скрытые метки:" #: templates/boards/settings.html:26 msgid "No hidden tags." -msgstr "Нет скрытых тегов." +msgstr "Нет скрытых меток." #: templates/boards/settings.html:35 msgid "Save" msgstr "Сохранить" -#: templates/boards/tags.html:22 -msgid "No tags found." -msgstr "Теги не найдены." - -#: templates/boards/thread.html:20 templates/boards/thread_gallery.html:19 -msgid "Normal mode" -msgstr "Нормальный режим" - -#: templates/boards/thread.html:21 templates/boards/thread_gallery.html:20 -msgid "Gallery mode" -msgstr "Режим галереи" - -#: templates/boards/thread.html:29 -msgid "posts to bumplimit" -msgstr "сообщений до бамплимита" - -#: templates/boards/thread.html:50 -msgid "Reply to thread" -msgstr "Ответить в тему" - -#: templates/boards/thread.html:63 -msgid "Switch mode" -msgstr "Переключить режим" - -#: templates/boards/thread.html:90 templates/boards/thread_gallery.html:61 -msgid "Last update: " -msgstr "Последнее обновление: " - -#: templates/boards/rss/post.html:5 -msgid "Post image" -msgstr "Изображение сообщения" - #: templates/boards/staticpages/banned.html:6 msgid "Banned" msgstr "Заблокирован" @@ -363,3 +339,32 @@ msgstr "Комментарий" #: templates/boards/staticpages/help.html:19 msgid "You can try pasting the text and previewing the result here:" msgstr "Вы можете попробовать вставить текст и проверить результат здесь:" + +#: templates/boards/tags.html:23 +msgid "No tags found." +msgstr "Метки не найдены." + +#: templates/boards/thread.html:19 templates/boards/thread_gallery.html:19 +msgid "Normal mode" +msgstr "Нормальный режим" + +#: templates/boards/thread.html:20 templates/boards/thread_gallery.html:20 +msgid "Gallery mode" +msgstr "Режим галереи" + +#: templates/boards/thread.html:28 +msgid "posts to bumplimit" +msgstr "сообщений до бамплимита" + +#: templates/boards/thread.html:46 +msgid "Reply to thread" +msgstr "Ответить в тему" + +#: templates/boards/thread.html:59 +msgid "Switch mode" +msgstr "Переключить режим" + +#: templates/boards/thread.html:91 templates/boards/thread_gallery.html:61 +msgid "Last update: " +msgstr "Последнее обновление: " + diff --git a/boards/mdx_neboard.py b/boards/mdx_neboard.py --- a/boards/mdx_neboard.py +++ b/boards/mdx_neboard.py @@ -177,15 +177,16 @@ def bbcode_extended(markup): parser.add_formatter('post', render_reflink, strip=True) parser.add_formatter('quote', render_quote, strip=True) parser.add_simple_formatter('comment', - u'//%(value)s') + '//%(value)s') parser.add_simple_formatter('spoiler', - u'%(value)s') + '%(value)s') # TODO Use here parser.add_simple_formatter('s', - u'%(value)s') + '%(value)s') # TODO Why not use built-in tag? parser.add_simple_formatter('code', - u'

%(value)s
', render_embedded=False) + '
%(value)s
', + render_embedded=False) text = preparse_text(markup) return parser.format(text) diff --git a/boards/middlewares.py b/boards/middlewares.py --- a/boards/middlewares.py +++ b/boards/middlewares.py @@ -1,9 +1,6 @@ from django.shortcuts import redirect from boards import utils from boards.models import Ban -from django.utils.html import strip_spaces_between_tags -from django.conf import settings -from boards.views.banned import BannedView RESPONSE_CONTENT_TYPE = 'Content-Type' @@ -21,7 +18,7 @@ class BanMiddleware: def process_view(self, request, view_func, view_args, view_kwargs): - if view_func != BannedView.as_view: + if request.path != '/banned/': ip = utils.get_client_ip(request) bans = Ban.objects.filter(ip=ip) @@ -29,18 +26,3 @@ class BanMiddleware: ban = bans[0] if not ban.can_read: return redirect('banned') - - -class MinifyHTMLMiddleware(object): - def process_response(self, request, response): - try: - compress_html = settings.COMPRESS_HTML - except AttributeError: - compress_html = False - - if RESPONSE_CONTENT_TYPE in response\ - and TYPE_HTML in response[RESPONSE_CONTENT_TYPE]\ - and compress_html: - response.content = strip_spaces_between_tags( - response.content.strip()) - return response \ No newline at end of file diff --git a/boards/migrations/0001_initial.py b/boards/migrations/0001_initial.py --- a/boards/migrations/0001_initial.py +++ b/boards/migrations/0001_initial.py @@ -1,95 +1,113 @@ # -*- coding: utf-8 -*- -import datetime -from south.db import db -from south.v2 import SchemaMigration -from django.db import models +from __future__ import unicode_literals + +from django.db import models, migrations +import boards.models.image +import boards.models.base +import boards.thumbs -class Migration(SchemaMigration): - - def forwards(self, orm): - # Adding model 'Tag' - db.create_table(u'boards_tag', ( - (u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), - ('name', self.gf('django.db.models.fields.CharField')(max_length=100)), - )) - db.send_create_signal(u'boards', ['Tag']) +class Migration(migrations.Migration): - # Adding model 'Post' - db.create_table(u'boards_post', ( - (u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), - ('title', self.gf('django.db.models.fields.CharField')(max_length=50)), - ('pub_time', self.gf('django.db.models.fields.DateTimeField')()), - ('text', self.gf('markupfield.fields.MarkupField')(rendered_field=True)), - ('text_markup_type', self.gf('django.db.models.fields.CharField')(default='markdown', max_length=30)), - ('image', self.gf('boards.thumbs.ImageWithThumbsField')(max_length=100, blank=True)), - ('poster_ip', self.gf('django.db.models.fields.IPAddressField')(max_length=15)), - ('_text_rendered', self.gf('django.db.models.fields.TextField')()), - ('poster_user_agent', self.gf('django.db.models.fields.TextField')()), - ('parent', self.gf('django.db.models.fields.BigIntegerField')()), - ('last_edit_time', self.gf('django.db.models.fields.DateTimeField')()), - )) - db.send_create_signal(u'boards', ['Post']) - - # Adding M2M table for field tags on 'Post' - m2m_table_name = db.shorten_name(u'boards_post_tags') - db.create_table(m2m_table_name, ( - ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)), - ('post', models.ForeignKey(orm[u'boards.post'], null=False)), - ('tag', models.ForeignKey(orm[u'boards.tag'], null=False)) - )) - db.create_unique(m2m_table_name, ['post_id', 'tag_id']) - - # Adding model 'Admin' - db.create_table(u'boards_admin', ( - (u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), - ('name', self.gf('django.db.models.fields.CharField')(max_length=100)), - ('password', self.gf('django.db.models.fields.CharField')(max_length=100)), - )) - db.send_create_signal(u'boards', ['Admin']) - + dependencies = [ + ] - def backwards(self, orm): - # Deleting model 'Tag' - db.delete_table(u'boards_tag') - - # Deleting model 'Post' - db.delete_table(u'boards_post') - - # Removing M2M table for field tags on 'Post' - db.delete_table(db.shorten_name(u'boards_post_tags')) - - # Deleting model 'Admin' - db.delete_table(u'boards_admin') - - - models = { - u'boards.admin': { - 'Meta': {'object_name': 'Admin'}, - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'password': ('django.db.models.fields.CharField', [], {'max_length': '100'}) - }, - u'boards.post': { - 'Meta': {'object_name': 'Post'}, - '_text_rendered': ('django.db.models.fields.TextField', [], {}), - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'image': ('boards.thumbs.ImageWithThumbsField', [], {'max_length': '100', 'blank': 'True'}), - 'last_edit_time': ('django.db.models.fields.DateTimeField', [], {}), - 'parent': ('django.db.models.fields.BigIntegerField', [], {}), - 'poster_ip': ('django.db.models.fields.IPAddressField', [], {'max_length': '15'}), - 'poster_user_agent': ('django.db.models.fields.TextField', [], {}), - 'pub_time': ('django.db.models.fields.DateTimeField', [], {}), - 'tags': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['boards.Tag']", 'symmetrical': 'False'}), - 'text': ('markupfield.fields.MarkupField', [], {'rendered_field': 'True'}), - 'text_markup_type': ('django.db.models.fields.CharField', [], {'default': "'markdown'", 'max_length': '30'}), - 'title': ('django.db.models.fields.CharField', [], {'max_length': '50'}) - }, - u'boards.tag': { - 'Meta': {'object_name': 'Tag'}, - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) - } - } - - complete_apps = ['boards'] \ No newline at end of file + operations = [ + migrations.CreateModel( + name='Ban', + fields=[ + ('id', models.AutoField(serialize=False, auto_created=True, primary_key=True, verbose_name='ID')), + ('ip', models.GenericIPAddressField()), + ('reason', models.CharField(max_length=200, default='Auto')), + ('can_read', models.BooleanField(default=True)), + ], + options={ + }, + bases=(models.Model,), + ), + migrations.CreateModel( + name='Post', + fields=[ + ('id', models.AutoField(serialize=False, auto_created=True, primary_key=True, verbose_name='ID')), + ('title', models.CharField(max_length=200)), + ('pub_time', models.DateTimeField()), + ('text', models.TextField(null=True, blank=True)), + ('text_markup_type', models.CharField(choices=[('', '--'), ('bbcode', 'bbcode')], max_length=30, default='bbcode')), + ('poster_ip', models.GenericIPAddressField()), + ('_text_rendered', models.TextField(editable=False)), + ('poster_user_agent', models.TextField()), + ('last_edit_time', models.DateTimeField()), + ('refmap', models.TextField(null=True, blank=True)), + ], + options={ + 'ordering': ('id',), + }, + bases=(models.Model, boards.models.base.Viewable), + ), + migrations.CreateModel( + name='PostImage', + fields=[ + ('id', models.AutoField(serialize=False, auto_created=True, primary_key=True, verbose_name='ID')), + ('width', models.IntegerField(default=0)), + ('height', models.IntegerField(default=0)), + ('pre_width', models.IntegerField(default=0)), + ('pre_height', models.IntegerField(default=0)), + ('image', boards.thumbs.ImageWithThumbsField(height_field='height', width_field='width', upload_to=boards.models.image.PostImage._update_image_filename, blank=True)), + ('hash', models.CharField(max_length=36)), + ], + options={ + 'ordering': ('id',), + }, + bases=(models.Model,), + ), + migrations.CreateModel( + name='Tag', + fields=[ + ('id', models.AutoField(serialize=False, auto_created=True, primary_key=True, verbose_name='ID')), + ('name', models.CharField(db_index=True, max_length=100)), + ], + options={ + 'ordering': ('name',), + }, + bases=(models.Model, boards.models.base.Viewable), + ), + migrations.CreateModel( + name='Thread', + fields=[ + ('id', models.AutoField(serialize=False, auto_created=True, primary_key=True, verbose_name='ID')), + ('bump_time', models.DateTimeField()), + ('last_edit_time', models.DateTimeField()), + ('archived', models.BooleanField(default=False)), + ('bumpable', models.BooleanField(default=True)), + ('replies', models.ManyToManyField(null=True, related_name='tre+', to='boards.Post', blank=True)), + ('tags', models.ManyToManyField(to='boards.Tag')), + ], + options={ + }, + bases=(models.Model,), + ), + migrations.AddField( + model_name='tag', + name='threads', + field=models.ManyToManyField(null=True, related_name='tag+', to='boards.Thread', blank=True), + preserve_default=True, + ), + migrations.AddField( + model_name='post', + name='images', + field=models.ManyToManyField(null=True, db_index=True, related_name='ip+', to='boards.PostImage', blank=True), + preserve_default=True, + ), + migrations.AddField( + model_name='post', + name='referenced_posts', + field=models.ManyToManyField(null=True, db_index=True, related_name='rfp+', to='boards.Post', blank=True), + preserve_default=True, + ), + migrations.AddField( + model_name='post', + name='thread_new', + field=models.ForeignKey(null=True, default=None, to='boards.Thread'), + preserve_default=True, + ), + ] diff --git a/boards/migrations/0002_auto_20141118_2234.py b/boards/migrations/0002_auto_20141118_2234.py new file mode 100644 --- /dev/null +++ b/boards/migrations/0002_auto_20141118_2234.py @@ -0,0 +1,23 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import models, migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('boards', '0001_initial'), + ] + + operations = [ + migrations.RemoveField( + model_name='post', + name='text_markup_type', + ), + migrations.AlterField( + model_name='post', + name='_text_rendered', + field=models.TextField(null=True, blank=True, editable=False), + ), + ] diff --git a/boards/migrations/0002_auto__add_ban__chg_field_post_poster_ip.py b/boards/migrations/0002_auto__add_ban__chg_field_post_poster_ip.py deleted file mode 100644 --- a/boards/migrations/0002_auto__add_ban__chg_field_post_poster_ip.py +++ /dev/null @@ -1,64 +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 'Ban' - db.create_table(u'boards_ban', ( - (u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), - ('ip', self.gf('django.db.models.fields.GenericIPAddressField')(max_length=39)), - )) - db.send_create_signal(u'boards', ['Ban']) - - - # Changing field 'Post.poster_ip' - db.alter_column(u'boards_post', 'poster_ip', self.gf('django.db.models.fields.GenericIPAddressField')(max_length=39)) - - def backwards(self, orm): - # Deleting model 'Ban' - db.delete_table(u'boards_ban') - - - # Changing field 'Post.poster_ip' - db.alter_column(u'boards_post', 'poster_ip', self.gf('django.db.models.fields.IPAddressField')(max_length=15)) - - models = { - u'boards.admin': { - 'Meta': {'object_name': 'Admin'}, - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'password': ('django.db.models.fields.CharField', [], {'max_length': '100'}) - }, - u'boards.ban': { - 'Meta': {'object_name': 'Ban'}, - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'ip': ('django.db.models.fields.GenericIPAddressField', [], {'max_length': '39'}) - }, - u'boards.post': { - 'Meta': {'object_name': 'Post'}, - '_text_rendered': ('django.db.models.fields.TextField', [], {}), - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'image': ('boards.thumbs.ImageWithThumbsField', [], {'max_length': '100', 'blank': 'True'}), - 'last_edit_time': ('django.db.models.fields.DateTimeField', [], {}), - 'parent': ('django.db.models.fields.BigIntegerField', [], {}), - 'poster_ip': ('django.db.models.fields.GenericIPAddressField', [], {'max_length': '39'}), - 'poster_user_agent': ('django.db.models.fields.TextField', [], {}), - 'pub_time': ('django.db.models.fields.DateTimeField', [], {}), - 'tags': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['boards.Tag']", 'symmetrical': 'False'}), - 'text': ('markupfield.fields.MarkupField', [], {'rendered_field': 'True'}), - 'text_markup_type': ('django.db.models.fields.CharField', [], {'default': "'markdown'", 'max_length': '30'}), - 'title': ('django.db.models.fields.CharField', [], {'max_length': '50'}) - }, - u'boards.tag': { - 'Meta': {'object_name': 'Tag'}, - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) - } - } - - complete_apps = ['boards'] \ No newline at end of file diff --git a/boards/migrations/0003_auto__add_field_post_image_width__add_field_post_image_height.py b/boards/migrations/0003_auto__add_field_post_image_width__add_field_post_image_height.py deleted file mode 100644 --- a/boards/migrations/0003_auto__add_field_post_image_width__add_field_post_image_height.py +++ /dev/null @@ -1,66 +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 field 'Post.image_width' - db.add_column(u'boards_post', 'image_width', - self.gf('django.db.models.fields.IntegerField')(default=0), - keep_default=False) - - # Adding field 'Post.image_height' - db.add_column(u'boards_post', 'image_height', - self.gf('django.db.models.fields.IntegerField')(default=0), - keep_default=False) - - - def backwards(self, orm): - # Deleting field 'Post.image_width' - db.delete_column(u'boards_post', 'image_width') - - # Deleting field 'Post.image_height' - db.delete_column(u'boards_post', 'image_height') - - - models = { - u'boards.admin': { - 'Meta': {'object_name': 'Admin'}, - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'password': ('django.db.models.fields.CharField', [], {'max_length': '100'}) - }, - u'boards.ban': { - 'Meta': {'object_name': 'Ban'}, - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'ip': ('django.db.models.fields.GenericIPAddressField', [], {'max_length': '39'}) - }, - u'boards.post': { - 'Meta': {'object_name': 'Post'}, - '_text_rendered': ('django.db.models.fields.TextField', [], {}), - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'image': ('boards.thumbs.ImageWithThumbsField', [], {'max_length': '100', 'blank': 'True'}), - 'image_height': ('django.db.models.fields.IntegerField', [], {}), - 'image_width': ('django.db.models.fields.IntegerField', [], {}), - 'last_edit_time': ('django.db.models.fields.DateTimeField', [], {}), - 'parent': ('django.db.models.fields.BigIntegerField', [], {}), - 'poster_ip': ('django.db.models.fields.GenericIPAddressField', [], {'max_length': '39'}), - 'poster_user_agent': ('django.db.models.fields.TextField', [], {}), - 'pub_time': ('django.db.models.fields.DateTimeField', [], {}), - 'tags': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['boards.Tag']", 'symmetrical': 'False'}), - 'text': ('markupfield.fields.MarkupField', [], {'rendered_field': 'True'}), - 'text_markup_type': ('django.db.models.fields.CharField', [], {'default': "'markdown'", 'max_length': '30'}), - 'title': ('django.db.models.fields.CharField', [], {'max_length': '50'}) - }, - u'boards.tag': { - 'Meta': {'object_name': 'Tag'}, - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) - } - } - - complete_apps = ['boards'] \ No newline at end of file diff --git a/boards/migrations/0003_remove_tag_threads.py b/boards/migrations/0003_remove_tag_threads.py new file mode 100644 --- /dev/null +++ b/boards/migrations/0003_remove_tag_threads.py @@ -0,0 +1,18 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import models, migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('boards', '0002_auto_20141118_2234'), + ] + + operations = [ + migrations.RemoveField( + model_name='tag', + name='threads', + ), + ] diff --git a/boards/migrations/0004_auto__del_admin__add_user__add_setting__add_field_post_user.py b/boards/migrations/0004_auto__del_admin__add_user__add_setting__add_field_post_user.py deleted file mode 100644 --- a/boards/migrations/0004_auto__del_admin__add_user__add_setting__add_field_post_user.py +++ /dev/null @@ -1,130 +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): - # Deleting model 'Admin' - db.delete_table(u'boards_admin') - - # Adding model 'User' - db.create_table(u'boards_user', ( - (u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), - ('user_id', self.gf('django.db.models.fields.CharField')(max_length=50)), - ('rank', self.gf('django.db.models.fields.IntegerField')()), - ('registration_time', self.gf('django.db.models.fields.DateTimeField')()), - ('last_access_time', self.gf('django.db.models.fields.DateTimeField')()), - )) - db.send_create_signal(u'boards', ['User']) - - # Adding M2M table for field fav_tags on 'User' - m2m_table_name = db.shorten_name(u'boards_user_fav_tags') - db.create_table(m2m_table_name, ( - ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)), - ('user', models.ForeignKey(orm[u'boards.user'], null=False)), - ('tag', models.ForeignKey(orm[u'boards.tag'], null=False)) - )) - db.create_unique(m2m_table_name, ['user_id', 'tag_id']) - - # Adding M2M table for field fav_threads on 'User' - m2m_table_name = db.shorten_name(u'boards_user_fav_threads') - db.create_table(m2m_table_name, ( - ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)), - ('user', models.ForeignKey(orm[u'boards.user'], null=False)), - ('post', models.ForeignKey(orm[u'boards.post'], null=False)) - )) - db.create_unique(m2m_table_name, ['user_id', 'post_id']) - - # Adding model 'Setting' - db.create_table(u'boards_setting', ( - (u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), - ('name', self.gf('django.db.models.fields.CharField')(max_length=50)), - ('value', self.gf('django.db.models.fields.CharField')(max_length=50)), - ('user', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['boards.User'])), - )) - db.send_create_signal(u'boards', ['Setting']) - - # Adding field 'Post.user' - db.add_column(u'boards_post', 'user', - self.gf('django.db.models.fields.related.ForeignKey')(default=None, to=orm['boards.User'], null=True), - keep_default=False) - - - def backwards(self, orm): - # Adding model 'Admin' - db.create_table(u'boards_admin', ( - ('password', self.gf('django.db.models.fields.CharField')(max_length=100)), - (u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), - ('name', self.gf('django.db.models.fields.CharField')(max_length=100)), - )) - db.send_create_signal(u'boards', ['Admin']) - - # Deleting model 'User' - db.delete_table(u'boards_user') - - # Removing M2M table for field fav_tags on 'User' - db.delete_table(db.shorten_name(u'boards_user_fav_tags')) - - # Removing M2M table for field fav_threads on 'User' - db.delete_table(db.shorten_name(u'boards_user_fav_threads')) - - # Deleting model 'Setting' - db.delete_table(u'boards_setting') - - # Deleting field 'Post.user' - db.delete_column(u'boards_post', 'user_id') - - - models = { - u'boards.ban': { - 'Meta': {'object_name': 'Ban'}, - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'ip': ('django.db.models.fields.GenericIPAddressField', [], {'max_length': '39'}) - }, - u'boards.post': { - 'Meta': {'object_name': 'Post'}, - '_text_rendered': ('django.db.models.fields.TextField', [], {}), - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'image': ('boards.thumbs.ImageWithThumbsField', [], {'max_length': '100', 'blank': 'True'}), - 'image_height': ('django.db.models.fields.IntegerField', [], {'default': '0'}), - 'image_width': ('django.db.models.fields.IntegerField', [], {'default': '0'}), - 'last_edit_time': ('django.db.models.fields.DateTimeField', [], {}), - 'parent': ('django.db.models.fields.BigIntegerField', [], {}), - 'poster_ip': ('django.db.models.fields.GenericIPAddressField', [], {'max_length': '39'}), - 'poster_user_agent': ('django.db.models.fields.TextField', [], {}), - 'pub_time': ('django.db.models.fields.DateTimeField', [], {}), - 'tags': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['boards.Tag']", 'symmetrical': 'False'}), - 'text': ('markupfield.fields.MarkupField', [], {'rendered_field': 'True'}), - 'text_markup_type': ('django.db.models.fields.CharField', [], {'default': "'markdown'", 'max_length': '30'}), - 'title': ('django.db.models.fields.CharField', [], {'max_length': '50'}), - 'user': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': u"orm['boards.User']", 'null': 'True'}) - }, - u'boards.setting': { - 'Meta': {'object_name': 'Setting'}, - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}), - 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['boards.User']"}), - 'value': ('django.db.models.fields.CharField', [], {'max_length': '50'}) - }, - u'boards.tag': { - 'Meta': {'object_name': 'Tag'}, - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) - }, - u'boards.user': { - 'Meta': {'object_name': 'User'}, - 'fav_tags': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['boards.Tag']", 'symmetrical': 'False'}), - 'fav_threads': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'+'", 'symmetrical': 'False', 'to': u"orm['boards.Post']"}), - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'last_access_time': ('django.db.models.fields.DateTimeField', [], {}), - 'rank': ('django.db.models.fields.IntegerField', [], {}), - 'registration_time': ('django.db.models.fields.DateTimeField', [], {}), - 'user_id': ('django.db.models.fields.CharField', [], {'max_length': '50'}) - } - } - - complete_apps = ['boards'] \ No newline at end of file diff --git a/boards/migrations/0004_tag_required.py b/boards/migrations/0004_tag_required.py new file mode 100644 --- /dev/null +++ b/boards/migrations/0004_tag_required.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import models, migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('boards', '0003_remove_tag_threads'), + ] + + operations = [ + migrations.AddField( + model_name='tag', + name='required', + field=models.BooleanField(default=False), + preserve_default=True, + ), + ] diff --git a/boards/migrations/0005_auto.py b/boards/migrations/0005_auto.py deleted file mode 100644 --- a/boards/migrations/0005_auto.py +++ /dev/null @@ -1,73 +0,0 @@ -# -*- coding: utf-8 -*- -from south.db import db -from south.v2 import SchemaMigration -from django.db import models - - -class Migration(SchemaMigration): - - def forwards(self, orm): - # Adding M2M table for field replies on 'Post' - m2m_table_name = db.shorten_name(u'boards_post_replies') - db.create_table(m2m_table_name, ( - ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)), - ('from_post', models.ForeignKey(orm[u'boards.post'], null=False)), - ('to_post', models.ForeignKey(orm[u'boards.post'], null=False)) - )) - db.create_unique(m2m_table_name, ['from_post_id', 'to_post_id']) - - def backwards(self, orm): - # Removing M2M table for field replies on 'Post' - db.delete_table(db.shorten_name(u'boards_post_replies')) - - - models = { - u'boards.ban': { - 'Meta': {'object_name': 'Ban'}, - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'ip': ('django.db.models.fields.GenericIPAddressField', [], {'max_length': '39'}) - }, - u'boards.post': { - 'Meta': {'object_name': 'Post'}, - '_text_rendered': ('django.db.models.fields.TextField', [], {}), - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'image': ('boards.thumbs.ImageWithThumbsField', [], {'max_length': '100', 'blank': 'True'}), - 'image_height': ('django.db.models.fields.IntegerField', [], {'default': '0'}), - 'image_width': ('django.db.models.fields.IntegerField', [], {'default': '0'}), - 'last_edit_time': ('django.db.models.fields.DateTimeField', [], {}), - 'parent': ('django.db.models.fields.BigIntegerField', [], {}), - 'poster_ip': ('django.db.models.fields.GenericIPAddressField', [], {'max_length': '39'}), - 'poster_user_agent': ('django.db.models.fields.TextField', [], {}), - 'pub_time': ('django.db.models.fields.DateTimeField', [], {}), - 'replies': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'re+'", 'null': 'True', 'symmetrical': 'False', 'to': u"orm['boards.Post']"}), - 'tags': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['boards.Tag']", 'symmetrical': 'False'}), - 'text': ('markupfield.fields.MarkupField', [], {'rendered_field': 'True'}), - 'text_markup_type': ('django.db.models.fields.CharField', [], {'default': "'markdown'", 'max_length': '30'}), - 'title': ('django.db.models.fields.CharField', [], {'max_length': '50'}), - 'user': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': u"orm['boards.User']", 'null': 'True'}) - }, - u'boards.setting': { - 'Meta': {'object_name': 'Setting'}, - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}), - 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['boards.User']"}), - 'value': ('django.db.models.fields.CharField', [], {'max_length': '50'}) - }, - u'boards.tag': { - 'Meta': {'object_name': 'Tag'}, - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) - }, - u'boards.user': { - 'Meta': {'object_name': 'User'}, - 'fav_tags': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': u"orm['boards.Tag']", 'null': 'True', 'blank': 'True'}), - 'fav_threads': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'symmetrical': 'False', 'to': u"orm['boards.Post']"}), - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'last_access_time': ('django.db.models.fields.DateTimeField', [], {}), - 'rank': ('django.db.models.fields.IntegerField', [], {}), - 'registration_time': ('django.db.models.fields.DateTimeField', [], {}), - 'user_id': ('django.db.models.fields.CharField', [], {'max_length': '50'}) - } - } - - complete_apps = ['boards'] \ No newline at end of file diff --git a/boards/migrations/0006_auto__add_field_post_thread.py b/boards/migrations/0006_auto__add_field_post_thread.py deleted file mode 100644 --- a/boards/migrations/0006_auto__add_field_post_thread.py +++ /dev/null @@ -1,72 +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 field 'Post.thread' - db.add_column(u'boards_post', 'thread', - self.gf('django.db.models.fields.related.ForeignKey')(default=None, to=orm['boards.Post'], null=True), - keep_default=False) - - - def backwards(self, orm): - # Deleting field 'Post.thread' - db.delete_column(u'boards_post', 'thread_id') - - - models = { - u'boards.ban': { - 'Meta': {'object_name': 'Ban'}, - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'ip': ('django.db.models.fields.GenericIPAddressField', [], {'max_length': '39'}) - }, - u'boards.post': { - 'Meta': {'object_name': 'Post'}, - '_text_rendered': ('django.db.models.fields.TextField', [], {}), - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'image': ('boards.thumbs.ImageWithThumbsField', [], {'max_length': '100', 'blank': 'True'}), - 'image_height': ('django.db.models.fields.IntegerField', [], {'default': '0'}), - 'image_width': ('django.db.models.fields.IntegerField', [], {'default': '0'}), - 'last_edit_time': ('django.db.models.fields.DateTimeField', [], {}), - 'parent': ('django.db.models.fields.BigIntegerField', [], {}), - 'poster_ip': ('django.db.models.fields.GenericIPAddressField', [], {'max_length': '39'}), - 'poster_user_agent': ('django.db.models.fields.TextField', [], {}), - 'pub_time': ('django.db.models.fields.DateTimeField', [], {}), - 'replies': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'re+'", 'null': 'True', 'symmetrical': 'False', 'to': u"orm['boards.Post']"}), - 'tags': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['boards.Tag']", 'symmetrical': 'False'}), - 'text': ('markupfield.fields.MarkupField', [], {'rendered_field': 'True'}), - 'text_markup_type': ('django.db.models.fields.CharField', [], {'default': "'markdown'", 'max_length': '30'}), - 'thread': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': u"orm['boards.Post']", 'null': 'True'}), - 'title': ('django.db.models.fields.CharField', [], {'max_length': '50'}), - 'user': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': u"orm['boards.User']", 'null': 'True'}) - }, - u'boards.setting': { - 'Meta': {'object_name': 'Setting'}, - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}), - 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['boards.User']"}), - 'value': ('django.db.models.fields.CharField', [], {'max_length': '50'}) - }, - u'boards.tag': { - 'Meta': {'object_name': 'Tag'}, - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) - }, - u'boards.user': { - 'Meta': {'object_name': 'User'}, - 'fav_tags': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': u"orm['boards.Tag']", 'null': 'True', 'blank': 'True'}), - 'fav_threads': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'symmetrical': 'False', 'to': u"orm['boards.Post']"}), - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'last_access_time': ('django.db.models.fields.DateTimeField', [], {}), - 'rank': ('django.db.models.fields.IntegerField', [], {}), - 'registration_time': ('django.db.models.fields.DateTimeField', [], {}), - 'user_id': ('django.db.models.fields.CharField', [], {'max_length': '50'}) - } - } - - complete_apps = ['boards'] \ No newline at end of file diff --git a/boards/migrations/0007_auto.py b/boards/migrations/0007_auto.py deleted file mode 100644 --- a/boards/migrations/0007_auto.py +++ /dev/null @@ -1,77 +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 M2M table for field threads on 'Tag' - m2m_table_name = db.shorten_name(u'boards_tag_threads') - db.create_table(m2m_table_name, ( - ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)), - ('tag', models.ForeignKey(orm[u'boards.tag'], null=False)), - ('post', models.ForeignKey(orm[u'boards.post'], null=False)) - )) - db.create_unique(m2m_table_name, ['tag_id', 'post_id']) - - - def backwards(self, orm): - # Removing M2M table for field threads on 'Tag' - db.delete_table(db.shorten_name(u'boards_tag_threads')) - - - models = { - u'boards.ban': { - 'Meta': {'object_name': 'Ban'}, - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'ip': ('django.db.models.fields.GenericIPAddressField', [], {'max_length': '39'}) - }, - u'boards.post': { - 'Meta': {'object_name': 'Post'}, - '_text_rendered': ('django.db.models.fields.TextField', [], {}), - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'image': ('boards.thumbs.ImageWithThumbsField', [], {'max_length': '100', 'blank': 'True'}), - 'image_height': ('django.db.models.fields.IntegerField', [], {'default': '0'}), - 'image_width': ('django.db.models.fields.IntegerField', [], {'default': '0'}), - 'last_edit_time': ('django.db.models.fields.DateTimeField', [], {}), - 'parent': ('django.db.models.fields.BigIntegerField', [], {'default': '-1'}), - 'poster_ip': ('django.db.models.fields.GenericIPAddressField', [], {'max_length': '39'}), - 'poster_user_agent': ('django.db.models.fields.TextField', [], {}), - 'pub_time': ('django.db.models.fields.DateTimeField', [], {}), - 'replies': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'re+'", 'null': 'True', 'symmetrical': 'False', 'to': u"orm['boards.Post']"}), - 'tags': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['boards.Tag']", 'symmetrical': 'False'}), - 'text': ('markupfield.fields.MarkupField', [], {'rendered_field': 'True'}), - 'text_markup_type': ('django.db.models.fields.CharField', [], {'default': "'markdown'", 'max_length': '30'}), - 'thread': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': u"orm['boards.Post']", 'null': 'True'}), - 'title': ('django.db.models.fields.CharField', [], {'max_length': '50'}), - 'user': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': u"orm['boards.User']", 'null': 'True'}) - }, - u'boards.setting': { - 'Meta': {'object_name': 'Setting'}, - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}), - 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['boards.User']"}), - 'value': ('django.db.models.fields.CharField', [], {'max_length': '50'}) - }, - u'boards.tag': { - 'Meta': {'object_name': 'Tag'}, - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'threads': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'tag+'", 'null': 'True', 'symmetrical': 'False', 'to': u"orm['boards.Post']"}) - }, - u'boards.user': { - 'Meta': {'object_name': 'User'}, - 'fav_tags': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': u"orm['boards.Tag']", 'null': 'True', 'blank': 'True'}), - 'fav_threads': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'symmetrical': 'False', 'to': u"orm['boards.Post']"}), - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'last_access_time': ('django.db.models.fields.DateTimeField', [], {}), - 'rank': ('django.db.models.fields.IntegerField', [], {}), - 'registration_time': ('django.db.models.fields.DateTimeField', [], {}), - 'user_id': ('django.db.models.fields.CharField', [], {'max_length': '50'}) - } - } - - complete_apps = ['boards'] \ No newline at end of file diff --git a/boards/migrations/0008_auto__add_field_post_bump_time.py b/boards/migrations/0008_auto__add_field_post_bump_time.py deleted file mode 100644 --- a/boards/migrations/0008_auto__add_field_post_bump_time.py +++ /dev/null @@ -1,74 +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 field 'Post.bump_time' - db.add_column(u'boards_post', 'bump_time', - self.gf('django.db.models.fields.DateTimeField')(default=datetime.datetime(2013, 9, 14, 0, 0)), - keep_default=False) - - - def backwards(self, orm): - # Deleting field 'Post.bump_time' - db.delete_column(u'boards_post', 'bump_time') - - - models = { - u'boards.ban': { - 'Meta': {'object_name': 'Ban'}, - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'ip': ('django.db.models.fields.GenericIPAddressField', [], {'max_length': '39'}) - }, - u'boards.post': { - 'Meta': {'object_name': 'Post'}, - '_text_rendered': ('django.db.models.fields.TextField', [], {}), - 'bump_time': ('django.db.models.fields.DateTimeField', [], {}), - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'image': ('boards.thumbs.ImageWithThumbsField', [], {'max_length': '100', 'blank': 'True'}), - 'image_height': ('django.db.models.fields.IntegerField', [], {'default': '0'}), - 'image_width': ('django.db.models.fields.IntegerField', [], {'default': '0'}), - 'last_edit_time': ('django.db.models.fields.DateTimeField', [], {}), - 'parent': ('django.db.models.fields.BigIntegerField', [], {'default': '-1'}), - 'poster_ip': ('django.db.models.fields.GenericIPAddressField', [], {'max_length': '39'}), - 'poster_user_agent': ('django.db.models.fields.TextField', [], {}), - 'pub_time': ('django.db.models.fields.DateTimeField', [], {}), - 'replies': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'re+'", 'null': 'True', 'symmetrical': 'False', 'to': u"orm['boards.Post']"}), - 'tags': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['boards.Tag']", 'symmetrical': 'False'}), - 'text': ('markupfield.fields.MarkupField', [], {'rendered_field': 'True'}), - 'text_markup_type': ('django.db.models.fields.CharField', [], {'default': "'markdown'", 'max_length': '30'}), - 'thread': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': u"orm['boards.Post']", 'null': 'True'}), - 'title': ('django.db.models.fields.CharField', [], {'max_length': '50'}), - 'user': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': u"orm['boards.User']", 'null': 'True'}) - }, - u'boards.setting': { - 'Meta': {'object_name': 'Setting'}, - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}), - 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['boards.User']"}), - 'value': ('django.db.models.fields.CharField', [], {'max_length': '50'}) - }, - u'boards.tag': { - 'Meta': {'object_name': 'Tag'}, - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'threads': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'tag+'", 'null': 'True', 'symmetrical': 'False', 'to': u"orm['boards.Post']"}) - }, - u'boards.user': { - 'Meta': {'object_name': 'User'}, - 'fav_tags': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': u"orm['boards.Tag']", 'null': 'True', 'blank': 'True'}), - 'fav_threads': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'symmetrical': 'False', 'to': u"orm['boards.Post']"}), - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'last_access_time': ('django.db.models.fields.DateTimeField', [], {}), - 'rank': ('django.db.models.fields.IntegerField', [], {}), - 'registration_time': ('django.db.models.fields.DateTimeField', [], {}), - 'user_id': ('django.db.models.fields.CharField', [], {'max_length': '50'}) - } - } - - complete_apps = ['boards'] \ No newline at end of file diff --git a/boards/migrations/0009_auto__del_field_user_last_access_time.py b/boards/migrations/0009_auto__del_field_user_last_access_time.py deleted file mode 100644 --- a/boards/migrations/0009_auto__del_field_user_last_access_time.py +++ /dev/null @@ -1,73 +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): - # Deleting field 'User.last_access_time' - db.delete_column(u'boards_user', 'last_access_time') - - - def backwards(self, orm): - # Adding field 'User.last_access_time' - db.add_column(u'boards_user', 'last_access_time', - self.gf('django.db.models.fields.DateTimeField')(default=datetime.datetime(2013, 9, 16, 0, 0)), - keep_default=False) - - - models = { - u'boards.ban': { - 'Meta': {'object_name': 'Ban'}, - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'ip': ('django.db.models.fields.GenericIPAddressField', [], {'max_length': '39'}) - }, - u'boards.post': { - 'Meta': {'object_name': 'Post'}, - '_text_rendered': ('django.db.models.fields.TextField', [], {}), - 'bump_time': ('django.db.models.fields.DateTimeField', [], {}), - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'image': ('boards.thumbs.ImageWithThumbsField', [], {'max_length': '100', 'blank': 'True'}), - 'image_height': ('django.db.models.fields.IntegerField', [], {'default': '0'}), - 'image_width': ('django.db.models.fields.IntegerField', [], {'default': '0'}), - 'last_edit_time': ('django.db.models.fields.DateTimeField', [], {}), - 'parent': ('django.db.models.fields.BigIntegerField', [], {'default': '-1'}), - 'poster_ip': ('django.db.models.fields.GenericIPAddressField', [], {'max_length': '39'}), - 'poster_user_agent': ('django.db.models.fields.TextField', [], {}), - 'pub_time': ('django.db.models.fields.DateTimeField', [], {}), - 'replies': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'re+'", 'null': 'True', 'symmetrical': 'False', 'to': u"orm['boards.Post']"}), - 'tags': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['boards.Tag']", 'symmetrical': 'False'}), - 'text': ('markupfield.fields.MarkupField', [], {'rendered_field': 'True'}), - 'text_markup_type': ('django.db.models.fields.CharField', [], {'default': "'markdown'", 'max_length': '30'}), - 'thread': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': u"orm['boards.Post']", 'null': 'True'}), - 'title': ('django.db.models.fields.CharField', [], {'max_length': '50'}), - 'user': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': u"orm['boards.User']", 'null': 'True'}) - }, - u'boards.setting': { - 'Meta': {'object_name': 'Setting'}, - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}), - 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['boards.User']"}), - 'value': ('django.db.models.fields.CharField', [], {'max_length': '50'}) - }, - u'boards.tag': { - 'Meta': {'object_name': 'Tag'}, - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'threads': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'tag+'", 'null': 'True', 'symmetrical': 'False', 'to': u"orm['boards.Post']"}) - }, - u'boards.user': { - 'Meta': {'object_name': 'User'}, - 'fav_tags': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': u"orm['boards.Tag']", 'null': 'True', 'blank': 'True'}), - 'fav_threads': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'symmetrical': 'False', 'to': u"orm['boards.Post']"}), - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'rank': ('django.db.models.fields.IntegerField', [], {}), - 'registration_time': ('django.db.models.fields.DateTimeField', [], {}), - 'user_id': ('django.db.models.fields.CharField', [], {'max_length': '50'}) - } - } - - complete_apps = ['boards'] \ No newline at end of file diff --git a/boards/migrations/0010_auto__del_field_post_parent.py b/boards/migrations/0010_auto__del_field_post_parent.py deleted file mode 100644 --- a/boards/migrations/0010_auto__del_field_post_parent.py +++ /dev/null @@ -1,72 +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): - # Deleting field 'Post.parent' - db.delete_column(u'boards_post', 'parent') - - - def backwards(self, orm): - # Adding field 'Post.parent' - db.add_column(u'boards_post', 'parent', - self.gf('django.db.models.fields.BigIntegerField')(default=-1), - keep_default=False) - - - models = { - u'boards.ban': { - 'Meta': {'object_name': 'Ban'}, - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'ip': ('django.db.models.fields.GenericIPAddressField', [], {'max_length': '39'}) - }, - u'boards.post': { - 'Meta': {'object_name': 'Post'}, - '_text_rendered': ('django.db.models.fields.TextField', [], {}), - 'bump_time': ('django.db.models.fields.DateTimeField', [], {}), - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'image': ('boards.thumbs.ImageWithThumbsField', [], {'max_length': '100', 'blank': 'True'}), - 'image_height': ('django.db.models.fields.IntegerField', [], {'default': '0'}), - 'image_width': ('django.db.models.fields.IntegerField', [], {'default': '0'}), - 'last_edit_time': ('django.db.models.fields.DateTimeField', [], {}), - 'poster_ip': ('django.db.models.fields.GenericIPAddressField', [], {'max_length': '39'}), - 'poster_user_agent': ('django.db.models.fields.TextField', [], {}), - 'pub_time': ('django.db.models.fields.DateTimeField', [], {}), - 'replies': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'re+'", 'null': 'True', 'symmetrical': 'False', 'to': u"orm['boards.Post']"}), - 'tags': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['boards.Tag']", 'symmetrical': 'False'}), - 'text': ('markupfield.fields.MarkupField', [], {'rendered_field': 'True'}), - 'text_markup_type': ('django.db.models.fields.CharField', [], {'default': "'markdown'", 'max_length': '30'}), - 'thread': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': u"orm['boards.Post']", 'null': 'True'}), - 'title': ('django.db.models.fields.CharField', [], {'max_length': '50'}), - 'user': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': u"orm['boards.User']", 'null': 'True'}) - }, - u'boards.setting': { - 'Meta': {'object_name': 'Setting'}, - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}), - 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['boards.User']"}), - 'value': ('django.db.models.fields.CharField', [], {'max_length': '50'}) - }, - u'boards.tag': { - 'Meta': {'object_name': 'Tag'}, - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'threads': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'tag+'", 'null': 'True', 'symmetrical': 'False', 'to': u"orm['boards.Post']"}) - }, - u'boards.user': { - 'Meta': {'object_name': 'User'}, - 'fav_tags': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': u"orm['boards.Tag']", 'null': 'True', 'blank': 'True'}), - 'fav_threads': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'symmetrical': 'False', 'to': u"orm['boards.Post']"}), - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'rank': ('django.db.models.fields.IntegerField', [], {}), - 'registration_time': ('django.db.models.fields.DateTimeField', [], {}), - 'user_id': ('django.db.models.fields.CharField', [], {'max_length': '50'}) - } - } - - complete_apps = ['boards'] \ No newline at end of file diff --git a/boards/migrations/0011_auto__add_field_tag_linked.py b/boards/migrations/0011_auto__add_field_tag_linked.py deleted file mode 100644 --- a/boards/migrations/0011_auto__add_field_tag_linked.py +++ /dev/null @@ -1,73 +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 field 'Tag.linked' - db.add_column(u'boards_tag', 'linked', - self.gf('django.db.models.fields.related.ForeignKey')(to=orm['boards.Tag'], null=True, blank=True), - keep_default=False) - - - def backwards(self, orm): - # Deleting field 'Tag.linked' - db.delete_column(u'boards_tag', 'linked_id') - - - models = { - u'boards.ban': { - 'Meta': {'object_name': 'Ban'}, - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'ip': ('django.db.models.fields.GenericIPAddressField', [], {'max_length': '39'}) - }, - u'boards.post': { - 'Meta': {'object_name': 'Post'}, - '_text_rendered': ('django.db.models.fields.TextField', [], {}), - 'bump_time': ('django.db.models.fields.DateTimeField', [], {}), - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'image': ('boards.thumbs.ImageWithThumbsField', [], {'max_length': '100', 'blank': 'True'}), - 'image_height': ('django.db.models.fields.IntegerField', [], {'default': '0'}), - 'image_width': ('django.db.models.fields.IntegerField', [], {'default': '0'}), - 'last_edit_time': ('django.db.models.fields.DateTimeField', [], {}), - 'poster_ip': ('django.db.models.fields.GenericIPAddressField', [], {'max_length': '39'}), - 'poster_user_agent': ('django.db.models.fields.TextField', [], {}), - 'pub_time': ('django.db.models.fields.DateTimeField', [], {}), - 'replies': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'re+'", 'null': 'True', 'symmetrical': 'False', 'to': u"orm['boards.Post']"}), - 'tags': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['boards.Tag']", 'symmetrical': 'False'}), - 'text': ('markupfield.fields.MarkupField', [], {'rendered_field': 'True'}), - 'text_markup_type': ('django.db.models.fields.CharField', [], {'default': "'markdown'", 'max_length': '30'}), - 'thread': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': u"orm['boards.Post']", 'null': 'True'}), - 'title': ('django.db.models.fields.CharField', [], {'max_length': '50'}), - 'user': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': u"orm['boards.User']", 'null': 'True'}) - }, - u'boards.setting': { - 'Meta': {'object_name': 'Setting'}, - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}), - 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['boards.User']"}), - 'value': ('django.db.models.fields.CharField', [], {'max_length': '50'}) - }, - u'boards.tag': { - 'Meta': {'object_name': 'Tag'}, - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'linked': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['boards.Tag']", 'null': 'True', 'blank': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'threads': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'tag+'", 'null': 'True', 'symmetrical': 'False', 'to': u"orm['boards.Post']"}) - }, - u'boards.user': { - 'Meta': {'object_name': 'User'}, - 'fav_tags': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': u"orm['boards.Tag']", 'null': 'True', 'blank': 'True'}), - 'fav_threads': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'symmetrical': 'False', 'to': u"orm['boards.Post']"}), - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'rank': ('django.db.models.fields.IntegerField', [], {}), - 'registration_time': ('django.db.models.fields.DateTimeField', [], {}), - 'user_id': ('django.db.models.fields.CharField', [], {'max_length': '50'}) - } - } - - complete_apps = ['boards'] \ No newline at end of file diff --git a/boards/migrations/0012_auto.py b/boards/migrations/0012_auto.py deleted file mode 100644 --- a/boards/migrations/0012_auto.py +++ /dev/null @@ -1,78 +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 M2M table for field referenced_posts on 'Post' - m2m_table_name = db.shorten_name(u'boards_post_referenced_posts') - db.create_table(m2m_table_name, ( - ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)), - ('from_post', models.ForeignKey(orm[u'boards.post'], null=False)), - ('to_post', models.ForeignKey(orm[u'boards.post'], null=False)) - )) - db.create_unique(m2m_table_name, ['from_post_id', 'to_post_id']) - - - def backwards(self, orm): - # Removing M2M table for field referenced_posts on 'Post' - db.delete_table(db.shorten_name(u'boards_post_referenced_posts')) - - - models = { - u'boards.ban': { - 'Meta': {'object_name': 'Ban'}, - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'ip': ('django.db.models.fields.GenericIPAddressField', [], {'max_length': '39'}) - }, - u'boards.post': { - 'Meta': {'object_name': 'Post'}, - '_text_rendered': ('django.db.models.fields.TextField', [], {}), - 'bump_time': ('django.db.models.fields.DateTimeField', [], {}), - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'image': ('boards.thumbs.ImageWithThumbsField', [], {'max_length': '100', 'blank': 'True'}), - 'image_height': ('django.db.models.fields.IntegerField', [], {'default': '0'}), - 'image_width': ('django.db.models.fields.IntegerField', [], {'default': '0'}), - 'last_edit_time': ('django.db.models.fields.DateTimeField', [], {}), - 'poster_ip': ('django.db.models.fields.GenericIPAddressField', [], {'max_length': '39'}), - 'poster_user_agent': ('django.db.models.fields.TextField', [], {}), - 'pub_time': ('django.db.models.fields.DateTimeField', [], {}), - 'referenced_posts': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'rfp+'", 'null': 'True', 'symmetrical': 'False', 'to': u"orm['boards.Post']"}), - 'replies': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'re+'", 'null': 'True', 'symmetrical': 'False', 'to': u"orm['boards.Post']"}), - 'tags': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['boards.Tag']", 'symmetrical': 'False'}), - 'text': ('markupfield.fields.MarkupField', [], {'rendered_field': 'True'}), - 'text_markup_type': ('django.db.models.fields.CharField', [], {'default': "'markdown'", 'max_length': '30'}), - 'thread': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': u"orm['boards.Post']", 'null': 'True'}), - 'title': ('django.db.models.fields.CharField', [], {'max_length': '50'}), - 'user': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': u"orm['boards.User']", 'null': 'True'}) - }, - u'boards.setting': { - 'Meta': {'object_name': 'Setting'}, - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}), - 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['boards.User']"}), - 'value': ('django.db.models.fields.CharField', [], {'max_length': '50'}) - }, - u'boards.tag': { - 'Meta': {'object_name': 'Tag'}, - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'linked': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['boards.Tag']", 'null': 'True', 'blank': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'threads': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'tag+'", 'null': 'True', 'symmetrical': 'False', 'to': u"orm['boards.Post']"}) - }, - u'boards.user': { - 'Meta': {'object_name': 'User'}, - 'fav_tags': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': u"orm['boards.Tag']", 'null': 'True', 'blank': 'True'}), - 'fav_threads': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'symmetrical': 'False', 'to': u"orm['boards.Post']"}), - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'rank': ('django.db.models.fields.IntegerField', [], {}), - 'registration_time': ('django.db.models.fields.DateTimeField', [], {}), - 'user_id': ('django.db.models.fields.CharField', [], {'max_length': '50'}) - } - } - - complete_apps = ['boards'] \ No newline at end of file diff --git a/boards/migrations/0013_auto__add_field_ban_reason__add_field_ban_can_read.py b/boards/migrations/0013_auto__add_field_ban_reason__add_field_ban_can_read.py deleted file mode 100644 --- a/boards/migrations/0013_auto__add_field_ban_reason__add_field_ban_can_read.py +++ /dev/null @@ -1,84 +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 field 'Ban.reason' - db.add_column(u'boards_ban', 'reason', - self.gf('django.db.models.fields.CharField')(default='Auto', max_length=200), - keep_default=False) - - # Adding field 'Ban.can_read' - db.add_column(u'boards_ban', 'can_read', - self.gf('django.db.models.fields.BooleanField')(default=True), - keep_default=False) - - - def backwards(self, orm): - # Deleting field 'Ban.reason' - db.delete_column(u'boards_ban', 'reason') - - # Deleting field 'Ban.can_read' - db.delete_column(u'boards_ban', 'can_read') - - - models = { - u'boards.ban': { - 'Meta': {'object_name': 'Ban'}, - 'can_read': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'ip': ('django.db.models.fields.GenericIPAddressField', [], {'max_length': '39'}), - 'reason': ('django.db.models.fields.CharField', [], {'default': "'Auto'", 'max_length': '200'}) - }, - u'boards.post': { - 'Meta': {'object_name': 'Post'}, - '_text_rendered': ('django.db.models.fields.TextField', [], {}), - 'bump_time': ('django.db.models.fields.DateTimeField', [], {}), - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'image': ('boards.thumbs.ImageWithThumbsField', [], {'max_length': '100', 'blank': 'True'}), - 'image_height': ('django.db.models.fields.IntegerField', [], {'default': '0'}), - 'image_width': ('django.db.models.fields.IntegerField', [], {'default': '0'}), - 'last_edit_time': ('django.db.models.fields.DateTimeField', [], {}), - 'poster_ip': ('django.db.models.fields.GenericIPAddressField', [], {'max_length': '39'}), - 'poster_user_agent': ('django.db.models.fields.TextField', [], {}), - 'pub_time': ('django.db.models.fields.DateTimeField', [], {}), - 'referenced_posts': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'rfp+'", 'null': 'True', 'symmetrical': 'False', 'to': u"orm['boards.Post']"}), - 'replies': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'re+'", 'null': 'True', 'symmetrical': 'False', 'to': u"orm['boards.Post']"}), - 'tags': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['boards.Tag']", 'symmetrical': 'False'}), - 'text': ('markupfield.fields.MarkupField', [], {'rendered_field': 'True'}), - 'text_markup_type': ('django.db.models.fields.CharField', [], {'default': "'markdown'", 'max_length': '30'}), - 'thread': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': u"orm['boards.Post']", 'null': 'True'}), - 'title': ('django.db.models.fields.CharField', [], {'max_length': '50'}), - 'user': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': u"orm['boards.User']", 'null': 'True'}) - }, - u'boards.setting': { - 'Meta': {'object_name': 'Setting'}, - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}), - 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['boards.User']"}), - 'value': ('django.db.models.fields.CharField', [], {'max_length': '50'}) - }, - u'boards.tag': { - 'Meta': {'object_name': 'Tag'}, - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'linked': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['boards.Tag']", 'null': 'True', 'blank': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'threads': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'tag+'", 'null': 'True', 'symmetrical': 'False', 'to': u"orm['boards.Post']"}) - }, - u'boards.user': { - 'Meta': {'object_name': 'User'}, - 'fav_tags': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': u"orm['boards.Tag']", 'null': 'True', 'blank': 'True'}), - 'fav_threads': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'symmetrical': 'False', 'to': u"orm['boards.Post']"}), - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'rank': ('django.db.models.fields.IntegerField', [], {}), - 'registration_time': ('django.db.models.fields.DateTimeField', [], {}), - 'user_id': ('django.db.models.fields.CharField', [], {'max_length': '50'}) - } - } - - complete_apps = ['boards'] \ No newline at end of file diff --git a/boards/migrations/0014_auto__add_thread__chg_field_post_thread.py b/boards/migrations/0014_auto__add_thread__chg_field_post_thread.py deleted file mode 100644 --- a/boards/migrations/0014_auto__add_thread__chg_field_post_thread.py +++ /dev/null @@ -1,115 +0,0 @@ -# -*- coding: utf-8 -*- -from south.db import db -from south.v2 import SchemaMigration -from django.db import models - - -class Migration(SchemaMigration): - - def forwards(self, orm): - # Adding model 'Thread' - db.create_table(u'boards_thread', ( - (u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), - ('bump_time', self.gf('django.db.models.fields.DateTimeField')()), - ('last_edit_time', self.gf('django.db.models.fields.DateTimeField')()), - )) - db.send_create_signal('boards', ['Thread']) - - # Adding M2M table for field tags on 'Thread' - m2m_table_name = db.shorten_name(u'boards_thread_tags') - db.create_table(m2m_table_name, ( - ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)), - ('thread', models.ForeignKey(orm['boards.thread'], null=False)), - ('tag', models.ForeignKey(orm['boards.tag'], null=False)) - )) - db.create_unique(m2m_table_name, ['thread_id', 'tag_id']) - - db.delete_table(db.shorten_name(u'boards_tag_threads')) - # Adding M2M table for field threads on 'Tag' - m2m_table_name = db.shorten_name(u'boards_tag_threads') - db.create_table(m2m_table_name, ( - ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)), - ('thread', models.ForeignKey(orm['boards.thread'], null=False)), - ('tag', models.ForeignKey(orm['boards.tag'], null=False)) - )) - db.create_unique(m2m_table_name, ['thread_id', 'tag_id']) - - # Adding M2M table for field replies on 'Thread' - m2m_table_name = db.shorten_name(u'boards_thread_replies') - db.create_table(m2m_table_name, ( - ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)), - ('thread', models.ForeignKey(orm['boards.thread'], null=False)), - ('post', models.ForeignKey(orm['boards.post'], null=False)) - )) - db.create_unique(m2m_table_name, ['thread_id', 'post_id']) - - db.add_column(u'boards_post', 'thread_new', - self.gf('django.db.models.fields.related.ForeignKey')(default=None, to=orm['boards.Thread'], null=True), - keep_default=False) - - def backwards(self, orm): - pass - - models = { - 'boards.ban': { - 'Meta': {'object_name': 'Ban'}, - 'can_read': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'ip': ('django.db.models.fields.GenericIPAddressField', [], {'max_length': '39'}), - 'reason': ('django.db.models.fields.CharField', [], {'default': "'Auto'", 'max_length': '200'}) - }, - 'boards.post': { - 'Meta': {'object_name': 'Post'}, - '_text_rendered': ('django.db.models.fields.TextField', [], {}), - 'bump_time': ('django.db.models.fields.DateTimeField', [], {}), - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'image': ('boards.thumbs.ImageWithThumbsField', [], {'max_length': '100', 'blank': 'True'}), - 'image_height': ('django.db.models.fields.IntegerField', [], {'default': '0'}), - 'image_width': ('django.db.models.fields.IntegerField', [], {'default': '0'}), - 'last_edit_time': ('django.db.models.fields.DateTimeField', [], {}), - 'poster_ip': ('django.db.models.fields.GenericIPAddressField', [], {'max_length': '39'}), - 'poster_user_agent': ('django.db.models.fields.TextField', [], {}), - 'pub_time': ('django.db.models.fields.DateTimeField', [], {}), - 'referenced_posts': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'rfp+'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['boards.Post']"}), - 'replies': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'re+'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['boards.Post']"}), - 'tags': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['boards.Tag']", 'symmetrical': 'False'}), - 'text': ('markupfield.fields.MarkupField', [], {'rendered_field': 'True'}), - 'text_markup_type': ('django.db.models.fields.CharField', [], {'default': "'markdown'", 'max_length': '30'}), - 'thread': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': "orm['boards.Thread']", 'null': 'True'}), - 'title': ('django.db.models.fields.CharField', [], {'max_length': '50'}), - 'user': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': "orm['boards.User']", 'null': 'True'}) - }, - 'boards.setting': { - 'Meta': {'object_name': 'Setting'}, - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}), - 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['boards.User']"}), - 'value': ('django.db.models.fields.CharField', [], {'max_length': '50'}) - }, - 'boards.tag': { - 'Meta': {'object_name': 'Tag'}, - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'linked': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['boards.Tag']", 'null': 'True', 'blank': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'threads': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'tag+'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['boards.Thread']"}) - }, - 'boards.thread': { - 'Meta': {'object_name': 'Thread'}, - 'bump_time': ('django.db.models.fields.DateTimeField', [], {}), - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'last_edit_time': ('django.db.models.fields.DateTimeField', [], {}), - 'replies': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'tre+'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['boards.Post']"}), - 'tags': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['boards.Tag']", 'symmetrical': 'False'}) - }, - 'boards.user': { - 'Meta': {'object_name': 'User'}, - 'fav_tags': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': "orm['boards.Tag']", 'null': 'True', 'blank': 'True'}), - 'fav_threads': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['boards.Post']"}), - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'rank': ('django.db.models.fields.IntegerField', [], {}), - 'registration_time': ('django.db.models.fields.DateTimeField', [], {}), - 'user_id': ('django.db.models.fields.CharField', [], {'max_length': '50'}) - } - } - - complete_apps = ['boards'] \ No newline at end of file diff --git a/boards/migrations/0015_post_to_thread.py b/boards/migrations/0015_post_to_thread.py deleted file mode 100644 --- a/boards/migrations/0015_post_to_thread.py +++ /dev/null @@ -1,98 +0,0 @@ -# -*- coding: utf-8 -*- -from south.utils import datetime_utils as datetime -from south.db import db -from south.v2 import DataMigration -from django.db import models -from boards import views - - -class Migration(DataMigration): - - def forwards(self, orm): - for post in orm.Post.objects.filter(thread=None): - thread = orm.Thread.objects.create( - bump_time=post.bump_time, - last_edit_time=post.last_edit_time) - - thread.replies.add(post) - post.thread_new = thread - post.save() - print(str(post.thread_new.id)) - - for reply in post.replies.all(): - thread.replies.add(reply) - reply.thread_new = thread - reply.save() - - for tag in post.tags.all(): - thread.tags.add(tag) - tag.threads.add(thread) - - def backwards(self, orm): - pass - - models = { - 'boards.ban': { - 'Meta': {'object_name': 'Ban'}, - 'can_read': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'ip': ('django.db.models.fields.GenericIPAddressField', [], {'max_length': '39'}), - 'reason': ('django.db.models.fields.CharField', [], {'default': "'Auto'", 'max_length': '200'}) - }, - 'boards.post': { - 'Meta': {'object_name': 'Post'}, - '_text_rendered': ('django.db.models.fields.TextField', [], {}), - 'bump_time': ('django.db.models.fields.DateTimeField', [], {}), - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'image': ('boards.thumbs.ImageWithThumbsField', [], {'max_length': '100', 'blank': 'True'}), - 'image_height': ('django.db.models.fields.IntegerField', [], {'default': '0'}), - 'image_width': ('django.db.models.fields.IntegerField', [], {'default': '0'}), - 'last_edit_time': ('django.db.models.fields.DateTimeField', [], {}), - 'poster_ip': ('django.db.models.fields.GenericIPAddressField', [], {'max_length': '39'}), - 'poster_user_agent': ('django.db.models.fields.TextField', [], {}), - 'pub_time': ('django.db.models.fields.DateTimeField', [], {}), - 'referenced_posts': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'rfp+'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['boards.Post']"}), - 'replies': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'re+'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['boards.Post']"}), - 'tags': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['boards.Tag']", 'symmetrical': 'False'}), - 'text': ('markupfield.fields.MarkupField', [], {'rendered_field': 'True'}), - 'text_markup_type': ('django.db.models.fields.CharField', [], {'default': "'markdown'", 'max_length': '30'}), - 'thread': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': "orm['boards.Post']", 'null': 'True'}), - 'thread_new': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': "orm['boards.Thread']", 'null': 'True'}), - 'title': ('django.db.models.fields.CharField', [], {'max_length': '50'}), - 'user': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': "orm['boards.User']", 'null': 'True'}) - }, - 'boards.setting': { - 'Meta': {'object_name': 'Setting'}, - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}), - 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['boards.User']"}), - 'value': ('django.db.models.fields.CharField', [], {'max_length': '50'}) - }, - 'boards.tag': { - 'Meta': {'object_name': 'Tag'}, - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'linked': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['boards.Tag']", 'null': 'True', 'blank': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'threads': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'tag+'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['boards.Thread']"}) - }, - 'boards.thread': { - 'Meta': {'object_name': 'Thread'}, - 'bump_time': ('django.db.models.fields.DateTimeField', [], {}), - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'last_edit_time': ('django.db.models.fields.DateTimeField', [], {}), - 'replies': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'tre+'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['boards.Post']"}), - 'tags': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['boards.Tag']", 'symmetrical': 'False'}) - }, - 'boards.user': { - 'Meta': {'object_name': 'User'}, - 'fav_tags': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': "orm['boards.Tag']", 'null': 'True', 'blank': 'True'}), - 'fav_threads': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['boards.Post']"}), - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'rank': ('django.db.models.fields.IntegerField', [], {}), - 'registration_time': ('django.db.models.fields.DateTimeField', [], {}), - 'user_id': ('django.db.models.fields.CharField', [], {'max_length': '50'}) - } - } - - complete_apps = ['boards'] - symmetrical = True diff --git a/boards/migrations/0016_auto__del_field_post_bump_time.py b/boards/migrations/0016_auto__del_field_post_bump_time.py deleted file mode 100644 --- a/boards/migrations/0016_auto__del_field_post_bump_time.py +++ /dev/null @@ -1,110 +0,0 @@ -# -*- coding: utf-8 -*- -from south.utils import datetime_utils as datetime -from south.db import db -from south.v2 import SchemaMigration -from django.db import models - - -class Migration(SchemaMigration): - - def forwards(self, orm): - # Deleting field 'Post.bump_time' - db.delete_column(u'boards_post', 'bump_time') - - # Removing M2M table for field tags on 'Post' - db.delete_table(db.shorten_name(u'boards_post_tags')) - - # Removing M2M table for field replies on 'Post' - db.delete_table(db.shorten_name(u'boards_post_replies')) - - - def backwards(self, orm): - - # User chose to not deal with backwards NULL issues for 'Post.bump_time' - raise RuntimeError("Cannot reverse this migration. 'Post.bump_time' and its values cannot be restored.") - - # The following code is provided here to aid in writing a correct migration # Adding field 'Post.bump_time' - db.add_column(u'boards_post', 'bump_time', - self.gf('django.db.models.fields.DateTimeField')(), - keep_default=False) - - # Adding M2M table for field tags on 'Post' - m2m_table_name = db.shorten_name(u'boards_post_tags') - db.create_table(m2m_table_name, ( - ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)), - ('post', models.ForeignKey(orm['boards.post'], null=False)), - ('tag', models.ForeignKey(orm['boards.tag'], null=False)) - )) - db.create_unique(m2m_table_name, ['post_id', 'tag_id']) - - # Adding M2M table for field replies on 'Post' - m2m_table_name = db.shorten_name(u'boards_post_replies') - db.create_table(m2m_table_name, ( - ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)), - ('from_post', models.ForeignKey(orm['boards.post'], null=False)), - ('to_post', models.ForeignKey(orm['boards.post'], null=False)) - )) - db.create_unique(m2m_table_name, ['from_post_id', 'to_post_id']) - - - models = { - 'boards.ban': { - 'Meta': {'object_name': 'Ban'}, - 'can_read': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'ip': ('django.db.models.fields.GenericIPAddressField', [], {'max_length': '39'}), - 'reason': ('django.db.models.fields.CharField', [], {'default': "'Auto'", 'max_length': '200'}) - }, - 'boards.post': { - 'Meta': {'object_name': 'Post'}, - '_text_rendered': ('django.db.models.fields.TextField', [], {}), - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'image': ('boards.thumbs.ImageWithThumbsField', [], {'max_length': '100', 'blank': 'True'}), - 'image_height': ('django.db.models.fields.IntegerField', [], {'default': '0'}), - 'image_width': ('django.db.models.fields.IntegerField', [], {'default': '0'}), - 'last_edit_time': ('django.db.models.fields.DateTimeField', [], {}), - 'poster_ip': ('django.db.models.fields.GenericIPAddressField', [], {'max_length': '39'}), - 'poster_user_agent': ('django.db.models.fields.TextField', [], {}), - 'pub_time': ('django.db.models.fields.DateTimeField', [], {}), - 'referenced_posts': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'rfp+'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['boards.Post']"}), - 'text': ('markupfield.fields.MarkupField', [], {'rendered_field': 'True'}), - 'text_markup_type': ('django.db.models.fields.CharField', [], {'default': "'markdown'", 'max_length': '30'}), - 'thread': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': "orm['boards.Post']", 'null': 'True'}), - 'thread_new': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': "orm['boards.Thread']", 'null': 'True'}), - 'title': ('django.db.models.fields.CharField', [], {'max_length': '50'}), - 'user': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': "orm['boards.User']", 'null': 'True'}) - }, - 'boards.setting': { - 'Meta': {'object_name': 'Setting'}, - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}), - 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['boards.User']"}), - 'value': ('django.db.models.fields.CharField', [], {'max_length': '50'}) - }, - 'boards.tag': { - 'Meta': {'object_name': 'Tag'}, - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'linked': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['boards.Tag']", 'null': 'True', 'blank': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'threads': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'tag+'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['boards.Thread']"}) - }, - 'boards.thread': { - 'Meta': {'object_name': 'Thread'}, - 'bump_time': ('django.db.models.fields.DateTimeField', [], {}), - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'last_edit_time': ('django.db.models.fields.DateTimeField', [], {}), - 'replies': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'tre+'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['boards.Post']"}), - 'tags': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['boards.Tag']", 'symmetrical': 'False'}) - }, - 'boards.user': { - 'Meta': {'object_name': 'User'}, - 'fav_tags': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': "orm['boards.Tag']", 'null': 'True', 'blank': 'True'}), - 'fav_threads': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['boards.Post']"}), - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'rank': ('django.db.models.fields.IntegerField', [], {}), - 'registration_time': ('django.db.models.fields.DateTimeField', [], {}), - 'user_id': ('django.db.models.fields.CharField', [], {'max_length': '50'}) - } - } - - complete_apps = ['boards'] \ No newline at end of file diff --git a/boards/migrations/0017_auto__add_field_post_image_pre_width__add_field_post_image_pre_height.py b/boards/migrations/0017_auto__add_field_post_image_pre_width__add_field_post_image_pre_height.py deleted file mode 100644 --- a/boards/migrations/0017_auto__add_field_post_image_pre_width__add_field_post_image_pre_height.py +++ /dev/null @@ -1,92 +0,0 @@ -# -*- coding: utf-8 -*- -from south.utils import datetime_utils as datetime -from south.db import db -from south.v2 import SchemaMigration -from django.db import models - - -class Migration(SchemaMigration): - - def forwards(self, orm): - # Adding field 'Post.image_pre_width' - db.add_column(u'boards_post', 'image_pre_width', - self.gf('django.db.models.fields.IntegerField')(default=0), - keep_default=False) - - # Adding field 'Post.image_pre_height' - db.add_column(u'boards_post', 'image_pre_height', - self.gf('django.db.models.fields.IntegerField')(default=0), - keep_default=False) - - - def backwards(self, orm): - # Deleting field 'Post.image_pre_width' - db.delete_column(u'boards_post', 'image_pre_width') - - # Deleting field 'Post.image_pre_height' - db.delete_column(u'boards_post', 'image_pre_height') - - - models = { - 'boards.ban': { - 'Meta': {'object_name': 'Ban'}, - 'can_read': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'ip': ('django.db.models.fields.GenericIPAddressField', [], {'max_length': '39'}), - 'reason': ('django.db.models.fields.CharField', [], {'default': "'Auto'", 'max_length': '200'}) - }, - 'boards.post': { - 'Meta': {'object_name': 'Post'}, - '_text_rendered': ('django.db.models.fields.TextField', [], {}), - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'image': ('boards.thumbs.ImageWithThumbsField', [], {'max_length': '100', 'blank': 'True'}), - 'image_height': ('django.db.models.fields.IntegerField', [], {'default': '0'}), - 'image_pre_height': ('django.db.models.fields.IntegerField', [], {'default': '0'}), - 'image_pre_width': ('django.db.models.fields.IntegerField', [], {'default': '0'}), - 'image_width': ('django.db.models.fields.IntegerField', [], {'default': '0'}), - 'last_edit_time': ('django.db.models.fields.DateTimeField', [], {}), - 'poster_ip': ('django.db.models.fields.GenericIPAddressField', [], {'max_length': '39'}), - 'poster_user_agent': ('django.db.models.fields.TextField', [], {}), - 'pub_time': ('django.db.models.fields.DateTimeField', [], {}), - 'referenced_posts': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'rfp+'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['boards.Post']"}), - 'text': ('markupfield.fields.MarkupField', [], {'rendered_field': 'True'}), - 'text_markup_type': ('django.db.models.fields.CharField', [], {'default': "'markdown'", 'max_length': '30'}), - 'thread': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': "orm['boards.Post']", 'null': 'True'}), - 'thread_new': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': "orm['boards.Thread']", 'null': 'True'}), - 'title': ('django.db.models.fields.CharField', [], {'max_length': '50'}), - 'user': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': "orm['boards.User']", 'null': 'True'}) - }, - 'boards.setting': { - 'Meta': {'object_name': 'Setting'}, - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}), - 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['boards.User']"}), - 'value': ('django.db.models.fields.CharField', [], {'max_length': '50'}) - }, - 'boards.tag': { - 'Meta': {'object_name': 'Tag'}, - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'linked': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['boards.Tag']", 'null': 'True', 'blank': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'threads': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'tag+'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['boards.Thread']"}) - }, - 'boards.thread': { - 'Meta': {'object_name': 'Thread'}, - 'bump_time': ('django.db.models.fields.DateTimeField', [], {}), - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'last_edit_time': ('django.db.models.fields.DateTimeField', [], {}), - 'replies': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'tre+'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['boards.Post']"}), - 'tags': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['boards.Tag']", 'symmetrical': 'False'}) - }, - 'boards.user': { - 'Meta': {'object_name': 'User'}, - 'fav_tags': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': "orm['boards.Tag']", 'null': 'True', 'blank': 'True'}), - 'fav_threads': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['boards.Post']"}), - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'rank': ('django.db.models.fields.IntegerField', [], {}), - 'registration_time': ('django.db.models.fields.DateTimeField', [], {}), - 'user_id': ('django.db.models.fields.CharField', [], {'max_length': '50'}) - } - } - - complete_apps = ['boards'] \ No newline at end of file diff --git a/boards/migrations/0018_auto__add_field_thread_archived.py b/boards/migrations/0018_auto__add_field_thread_archived.py deleted file mode 100644 --- a/boards/migrations/0018_auto__add_field_thread_archived.py +++ /dev/null @@ -1,85 +0,0 @@ -# -*- coding: utf-8 -*- -from south.utils import datetime_utils as datetime -from south.db import db -from south.v2 import SchemaMigration -from django.db import models - - -class Migration(SchemaMigration): - - def forwards(self, orm): - # Adding field 'Thread.archived' - db.add_column(u'boards_thread', 'archived', - self.gf('django.db.models.fields.BooleanField')(default=0), - keep_default=False) - - - def backwards(self, orm): - # Deleting field 'Thread.archived' - db.delete_column(u'boards_thread', 'archived') - - - models = { - 'boards.ban': { - 'Meta': {'object_name': 'Ban'}, - 'can_read': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'ip': ('django.db.models.fields.GenericIPAddressField', [], {'max_length': '39'}), - 'reason': ('django.db.models.fields.CharField', [], {'default': "'Auto'", 'max_length': '200'}) - }, - 'boards.post': { - 'Meta': {'object_name': 'Post'}, - '_text_rendered': ('django.db.models.fields.TextField', [], {}), - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'image': ('boards.thumbs.ImageWithThumbsField', [], {'max_length': '100', 'blank': 'True'}), - 'image_height': ('django.db.models.fields.IntegerField', [], {'default': '0'}), - 'image_pre_height': ('django.db.models.fields.IntegerField', [], {'default': '0'}), - 'image_pre_width': ('django.db.models.fields.IntegerField', [], {'default': '0'}), - 'image_width': ('django.db.models.fields.IntegerField', [], {'default': '0'}), - 'last_edit_time': ('django.db.models.fields.DateTimeField', [], {}), - 'poster_ip': ('django.db.models.fields.GenericIPAddressField', [], {'max_length': '39'}), - 'poster_user_agent': ('django.db.models.fields.TextField', [], {}), - 'pub_time': ('django.db.models.fields.DateTimeField', [], {}), - 'referenced_posts': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'rfp+'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['boards.Post']"}), - 'text': ('markupfield.fields.MarkupField', [], {'rendered_field': 'True'}), - 'text_markup_type': ('django.db.models.fields.CharField', [], {'default': "'markdown'", 'max_length': '30'}), - 'thread': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': "orm['boards.Post']", 'null': 'True'}), - 'thread_new': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': "orm['boards.Thread']", 'null': 'True'}), - 'title': ('django.db.models.fields.CharField', [], {'max_length': '50'}), - 'user': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': "orm['boards.User']", 'null': 'True'}) - }, - 'boards.setting': { - 'Meta': {'object_name': 'Setting'}, - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}), - 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['boards.User']"}), - 'value': ('django.db.models.fields.CharField', [], {'max_length': '50'}) - }, - 'boards.tag': { - 'Meta': {'object_name': 'Tag'}, - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'linked': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['boards.Tag']", 'null': 'True', 'blank': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'threads': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'tag+'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['boards.Thread']"}) - }, - 'boards.thread': { - 'Meta': {'object_name': 'Thread'}, - 'archived': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), - 'bump_time': ('django.db.models.fields.DateTimeField', [], {}), - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'last_edit_time': ('django.db.models.fields.DateTimeField', [], {}), - 'replies': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'tre+'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['boards.Post']"}), - 'tags': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['boards.Tag']", 'symmetrical': 'False'}) - }, - 'boards.user': { - 'Meta': {'object_name': 'User'}, - 'fav_tags': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': "orm['boards.Tag']", 'null': 'True', 'blank': 'True'}), - 'fav_threads': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['boards.Post']"}), - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'rank': ('django.db.models.fields.IntegerField', [], {}), - 'registration_time': ('django.db.models.fields.DateTimeField', [], {}), - 'user_id': ('django.db.models.fields.CharField', [], {'max_length': '50'}) - } - } - - complete_apps = ['boards'] \ No newline at end of file diff --git a/boards/migrations/0019_auto__add_field_post_image_hash.py b/boards/migrations/0019_auto__add_field_post_image_hash.py deleted file mode 100644 --- a/boards/migrations/0019_auto__add_field_post_image_hash.py +++ /dev/null @@ -1,86 +0,0 @@ -# -*- coding: utf-8 -*- -from south.utils import datetime_utils as datetime -from south.db import db -from south.v2 import SchemaMigration -from django.db import models - - -class Migration(SchemaMigration): - - def forwards(self, orm): - # Adding field 'Post.image_hash' - db.add_column(u'boards_post', 'image_hash', - self.gf('django.db.models.fields.CharField')(default='', max_length=36), - keep_default=False) - - - def backwards(self, orm): - # Deleting field 'Post.image_hash' - db.delete_column(u'boards_post', 'image_hash') - - - models = { - 'boards.ban': { - 'Meta': {'object_name': 'Ban'}, - 'can_read': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'ip': ('django.db.models.fields.GenericIPAddressField', [], {'max_length': '39'}), - 'reason': ('django.db.models.fields.CharField', [], {'default': "'Auto'", 'max_length': '200'}) - }, - 'boards.post': { - 'Meta': {'object_name': 'Post'}, - '_text_rendered': ('django.db.models.fields.TextField', [], {}), - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'image': ('boards.thumbs.ImageWithThumbsField', [], {'max_length': '100', 'blank': 'True'}), - 'image_hash': ('django.db.models.fields.CharField', [], {'max_length': '36'}), - 'image_height': ('django.db.models.fields.IntegerField', [], {'default': '0'}), - 'image_pre_height': ('django.db.models.fields.IntegerField', [], {'default': '0'}), - 'image_pre_width': ('django.db.models.fields.IntegerField', [], {'default': '0'}), - 'image_width': ('django.db.models.fields.IntegerField', [], {'default': '0'}), - 'last_edit_time': ('django.db.models.fields.DateTimeField', [], {}), - 'poster_ip': ('django.db.models.fields.GenericIPAddressField', [], {'max_length': '39'}), - 'poster_user_agent': ('django.db.models.fields.TextField', [], {}), - 'pub_time': ('django.db.models.fields.DateTimeField', [], {}), - 'referenced_posts': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'rfp+'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['boards.Post']"}), - 'text': ('markupfield.fields.MarkupField', [], {'rendered_field': 'True'}), - 'text_markup_type': ('django.db.models.fields.CharField', [], {'default': "'markdown'", 'max_length': '30'}), - 'thread': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': "orm['boards.Post']", 'null': 'True'}), - 'thread_new': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': "orm['boards.Thread']", 'null': 'True'}), - 'title': ('django.db.models.fields.CharField', [], {'max_length': '50'}), - 'user': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': "orm['boards.User']", 'null': 'True'}) - }, - 'boards.setting': { - 'Meta': {'object_name': 'Setting'}, - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}), - 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['boards.User']"}), - 'value': ('django.db.models.fields.CharField', [], {'max_length': '50'}) - }, - 'boards.tag': { - 'Meta': {'object_name': 'Tag'}, - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'linked': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['boards.Tag']", 'null': 'True', 'blank': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'threads': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'tag+'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['boards.Thread']"}) - }, - 'boards.thread': { - 'Meta': {'object_name': 'Thread'}, - 'archived': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), - 'bump_time': ('django.db.models.fields.DateTimeField', [], {}), - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'last_edit_time': ('django.db.models.fields.DateTimeField', [], {}), - 'replies': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'tre+'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['boards.Post']"}), - 'tags': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['boards.Tag']", 'symmetrical': 'False'}) - }, - 'boards.user': { - 'Meta': {'object_name': 'User'}, - 'fav_tags': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': "orm['boards.Tag']", 'null': 'True', 'blank': 'True'}), - 'fav_threads': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['boards.Post']"}), - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'rank': ('django.db.models.fields.IntegerField', [], {}), - 'registration_time': ('django.db.models.fields.DateTimeField', [], {}), - 'user_id': ('django.db.models.fields.CharField', [], {'max_length': '50'}) - } - } - - complete_apps = ['boards'] \ No newline at end of file diff --git a/boards/migrations/0020_image_hashes.py b/boards/migrations/0020_image_hashes.py deleted file mode 100644 --- a/boards/migrations/0020_image_hashes.py +++ /dev/null @@ -1,91 +0,0 @@ -# -*- coding: utf-8 -*- -import hashlib - -from south.utils import datetime_utils as datetime -from south.db import db -from south.v2 import DataMigration -from django.db import models - -class Migration(DataMigration): - - def forwards(self, orm): - # Note: Don't use "from appname.models import ModelName". - # Use orm.ModelName to refer to models in this application, - # and orm['appname.ModelName'] for models in other applications. - for post in orm.Post.objects.filter(image_width__gt=0): - md5 = hashlib.md5() - for chunk in post.image.chunks(): - md5.update(chunk) - image_hash = md5.hexdigest() - post.image_hash = image_hash - post.save() - - def backwards(self, orm): - "Write your backwards methods here." - - models = { - 'boards.ban': { - 'Meta': {'object_name': 'Ban'}, - 'can_read': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'ip': ('django.db.models.fields.GenericIPAddressField', [], {'max_length': '39'}), - 'reason': ('django.db.models.fields.CharField', [], {'default': "'Auto'", 'max_length': '200'}) - }, - 'boards.post': { - 'Meta': {'object_name': 'Post'}, - '_text_rendered': ('django.db.models.fields.TextField', [], {}), - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'image': ('boards.thumbs.ImageWithThumbsField', [], {'max_length': '100', 'blank': 'True'}), - 'image_hash': ('django.db.models.fields.CharField', [], {'max_length': '36'}), - 'image_height': ('django.db.models.fields.IntegerField', [], {'default': '0'}), - 'image_pre_height': ('django.db.models.fields.IntegerField', [], {'default': '0'}), - 'image_pre_width': ('django.db.models.fields.IntegerField', [], {'default': '0'}), - 'image_width': ('django.db.models.fields.IntegerField', [], {'default': '0'}), - 'last_edit_time': ('django.db.models.fields.DateTimeField', [], {}), - 'poster_ip': ('django.db.models.fields.GenericIPAddressField', [], {'max_length': '39'}), - 'poster_user_agent': ('django.db.models.fields.TextField', [], {}), - 'pub_time': ('django.db.models.fields.DateTimeField', [], {}), - 'referenced_posts': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'rfp+'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['boards.Post']"}), - 'text': ('markupfield.fields.MarkupField', [], {'rendered_field': 'True'}), - 'text_markup_type': ('django.db.models.fields.CharField', [], {'default': "'markdown'", 'max_length': '30'}), - 'thread': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': "orm['boards.Post']", 'null': 'True'}), - 'thread_new': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': "orm['boards.Thread']", 'null': 'True'}), - 'title': ('django.db.models.fields.CharField', [], {'max_length': '50'}), - 'user': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': "orm['boards.User']", 'null': 'True'}) - }, - 'boards.setting': { - 'Meta': {'object_name': 'Setting'}, - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}), - 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['boards.User']"}), - 'value': ('django.db.models.fields.CharField', [], {'max_length': '50'}) - }, - 'boards.tag': { - 'Meta': {'object_name': 'Tag'}, - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'linked': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['boards.Tag']", 'null': 'True', 'blank': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'threads': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'tag+'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['boards.Thread']"}) - }, - 'boards.thread': { - 'Meta': {'object_name': 'Thread'}, - 'archived': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), - 'bump_time': ('django.db.models.fields.DateTimeField', [], {}), - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'last_edit_time': ('django.db.models.fields.DateTimeField', [], {}), - 'replies': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'tre+'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['boards.Post']"}), - 'tags': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['boards.Tag']", 'symmetrical': 'False'}) - }, - 'boards.user': { - 'Meta': {'object_name': 'User'}, - 'fav_tags': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': "orm['boards.Tag']", 'null': 'True', 'blank': 'True'}), - 'fav_threads': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['boards.Post']"}), - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'rank': ('django.db.models.fields.IntegerField', [], {}), - 'registration_time': ('django.db.models.fields.DateTimeField', [], {}), - 'user_id': ('django.db.models.fields.CharField', [], {'max_length': '50'}) - } - } - - complete_apps = ['boards'] - symmetrical = True diff --git a/boards/migrations/0021_auto__chg_field_post_title__add_index_tag_name.py b/boards/migrations/0021_auto__chg_field_post_title__add_index_tag_name.py deleted file mode 100644 --- a/boards/migrations/0021_auto__chg_field_post_title__add_index_tag_name.py +++ /dev/null @@ -1,90 +0,0 @@ -# -*- coding: utf-8 -*- -from south.utils import datetime_utils as datetime -from south.db import db -from south.v2 import SchemaMigration -from django.db import models - - -class Migration(SchemaMigration): - - def forwards(self, orm): - - # Changing field 'Post.title' - db.alter_column(u'boards_post', 'title', self.gf('django.db.models.fields.CharField')(max_length=200)) - # Adding index on 'Tag', fields ['name'] - db.create_index(u'boards_tag', ['name']) - - - def backwards(self, orm): - # Removing index on 'Tag', fields ['name'] - db.delete_index(u'boards_tag', ['name']) - - - # Changing field 'Post.title' - db.alter_column(u'boards_post', 'title', self.gf('django.db.models.fields.CharField')(max_length=50)) - - models = { - 'boards.ban': { - 'Meta': {'object_name': 'Ban'}, - 'can_read': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'ip': ('django.db.models.fields.GenericIPAddressField', [], {'max_length': '39'}), - 'reason': ('django.db.models.fields.CharField', [], {'default': "'Auto'", 'max_length': '200'}) - }, - 'boards.post': { - 'Meta': {'object_name': 'Post'}, - '_text_rendered': ('django.db.models.fields.TextField', [], {}), - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'image': ('boards.thumbs.ImageWithThumbsField', [], {'max_length': '100', 'blank': 'True'}), - 'image_hash': ('django.db.models.fields.CharField', [], {'max_length': '36'}), - 'image_height': ('django.db.models.fields.IntegerField', [], {'default': '0'}), - 'image_pre_height': ('django.db.models.fields.IntegerField', [], {'default': '0'}), - 'image_pre_width': ('django.db.models.fields.IntegerField', [], {'default': '0'}), - 'image_width': ('django.db.models.fields.IntegerField', [], {'default': '0'}), - 'last_edit_time': ('django.db.models.fields.DateTimeField', [], {}), - 'poster_ip': ('django.db.models.fields.GenericIPAddressField', [], {'max_length': '39'}), - 'poster_user_agent': ('django.db.models.fields.TextField', [], {}), - 'pub_time': ('django.db.models.fields.DateTimeField', [], {}), - 'referenced_posts': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'rfp+'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['boards.Post']"}), - 'text': ('markupfield.fields.MarkupField', [], {'rendered_field': 'True'}), - 'text_markup_type': ('django.db.models.fields.CharField', [], {'default': "'markdown'", 'max_length': '30'}), - 'thread': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': "orm['boards.Post']", 'null': 'True'}), - 'thread_new': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': "orm['boards.Thread']", 'null': 'True'}), - 'title': ('django.db.models.fields.CharField', [], {'max_length': '200'}), - 'user': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': "orm['boards.User']", 'null': 'True'}) - }, - 'boards.setting': { - 'Meta': {'object_name': 'Setting'}, - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}), - 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['boards.User']"}), - 'value': ('django.db.models.fields.CharField', [], {'max_length': '50'}) - }, - 'boards.tag': { - 'Meta': {'object_name': 'Tag'}, - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'linked': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['boards.Tag']", 'null': 'True', 'blank': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '100', 'db_index': 'True'}), - 'threads': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'tag+'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['boards.Thread']"}) - }, - 'boards.thread': { - 'Meta': {'object_name': 'Thread'}, - 'archived': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), - 'bump_time': ('django.db.models.fields.DateTimeField', [], {}), - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'last_edit_time': ('django.db.models.fields.DateTimeField', [], {}), - 'replies': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'tre+'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['boards.Post']"}), - 'tags': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['boards.Tag']", 'symmetrical': 'False'}) - }, - 'boards.user': { - 'Meta': {'object_name': 'User'}, - 'fav_tags': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': "orm['boards.Tag']", 'null': 'True', 'blank': 'True'}), - 'fav_threads': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['boards.Post']"}), - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'rank': ('django.db.models.fields.IntegerField', [], {}), - 'registration_time': ('django.db.models.fields.DateTimeField', [], {}), - 'user_id': ('django.db.models.fields.CharField', [], {'max_length': '50'}) - } - } - - complete_apps = ['boards'] \ No newline at end of file diff --git a/boards/migrations/0022_auto.py b/boards/migrations/0022_auto.py deleted file mode 100644 --- a/boards/migrations/0022_auto.py +++ /dev/null @@ -1,104 +0,0 @@ -# -*- coding: utf-8 -*- -from south.utils import datetime_utils as datetime -from south.db import db -from south.v2 import SchemaMigration -from django.db import models - - -class Migration(SchemaMigration): - - def forwards(self, orm): - # Adding M2M table for field hidden_tags on 'User' - m2m_table_name = db.shorten_name(u'boards_user_hidden_tags') - db.create_table(m2m_table_name, ( - ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)), - ('user', models.ForeignKey(orm['boards.user'], null=False)), - ('tag', models.ForeignKey(orm['boards.tag'], null=False)) - )) - db.create_unique(m2m_table_name, ['user_id', 'tag_id']) - - # Adding M2M table for field hidden_threads on 'User' - m2m_table_name = db.shorten_name(u'boards_user_hidden_threads') - db.create_table(m2m_table_name, ( - ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)), - ('user', models.ForeignKey(orm['boards.user'], null=False)), - ('post', models.ForeignKey(orm['boards.post'], null=False)) - )) - db.create_unique(m2m_table_name, ['user_id', 'post_id']) - - - def backwards(self, orm): - # Removing M2M table for field hidden_tags on 'User' - db.delete_table(db.shorten_name(u'boards_user_hidden_tags')) - - # Removing M2M table for field hidden_threads on 'User' - db.delete_table(db.shorten_name(u'boards_user_hidden_threads')) - - - models = { - 'boards.ban': { - 'Meta': {'object_name': 'Ban'}, - 'can_read': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'ip': ('django.db.models.fields.GenericIPAddressField', [], {'max_length': '39'}), - 'reason': ('django.db.models.fields.CharField', [], {'default': "'Auto'", 'max_length': '200'}) - }, - 'boards.post': { - 'Meta': {'object_name': 'Post'}, - '_text_rendered': ('django.db.models.fields.TextField', [], {}), - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'image': ('boards.thumbs.ImageWithThumbsField', [], {'max_length': '100', 'blank': 'True'}), - 'image_hash': ('django.db.models.fields.CharField', [], {'max_length': '36'}), - 'image_height': ('django.db.models.fields.IntegerField', [], {'default': '0'}), - 'image_pre_height': ('django.db.models.fields.IntegerField', [], {'default': '0'}), - 'image_pre_width': ('django.db.models.fields.IntegerField', [], {'default': '0'}), - 'image_width': ('django.db.models.fields.IntegerField', [], {'default': '0'}), - 'last_edit_time': ('django.db.models.fields.DateTimeField', [], {}), - 'poster_ip': ('django.db.models.fields.GenericIPAddressField', [], {'max_length': '39'}), - 'poster_user_agent': ('django.db.models.fields.TextField', [], {}), - 'pub_time': ('django.db.models.fields.DateTimeField', [], {}), - 'referenced_posts': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'rfp+'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['boards.Post']"}), - 'text': ('markupfield.fields.MarkupField', [], {'rendered_field': 'True'}), - 'text_markup_type': ('django.db.models.fields.CharField', [], {'default': "'markdown'", 'max_length': '30'}), - 'thread': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': "orm['boards.Post']", 'null': 'True'}), - 'thread_new': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': "orm['boards.Thread']", 'null': 'True'}), - 'title': ('django.db.models.fields.CharField', [], {'max_length': '200'}), - 'user': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': "orm['boards.User']", 'null': 'True'}) - }, - 'boards.setting': { - 'Meta': {'object_name': 'Setting'}, - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}), - 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['boards.User']"}), - 'value': ('django.db.models.fields.CharField', [], {'max_length': '50'}) - }, - 'boards.tag': { - 'Meta': {'object_name': 'Tag'}, - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'linked': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['boards.Tag']", 'null': 'True', 'blank': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '100', 'db_index': 'True'}), - 'threads': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'tag+'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['boards.Thread']"}) - }, - 'boards.thread': { - 'Meta': {'object_name': 'Thread'}, - 'archived': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), - 'bump_time': ('django.db.models.fields.DateTimeField', [], {}), - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'last_edit_time': ('django.db.models.fields.DateTimeField', [], {}), - 'replies': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'tre+'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['boards.Post']"}), - 'tags': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['boards.Tag']", 'symmetrical': 'False'}) - }, - 'boards.user': { - 'Meta': {'object_name': 'User'}, - 'fav_tags': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': "orm['boards.Tag']", 'null': 'True', 'blank': 'True'}), - 'fav_threads': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['boards.Post']"}), - 'hidden_tags': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'ht+'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['boards.Tag']"}), - 'hidden_threads': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'hth+'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['boards.Post']"}), - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'rank': ('django.db.models.fields.IntegerField', [], {}), - 'registration_time': ('django.db.models.fields.DateTimeField', [], {}), - 'user_id': ('django.db.models.fields.CharField', [], {'max_length': '50'}) - } - } - - complete_apps = ['boards'] \ No newline at end of file diff --git a/boards/migrations/0023_auto__del_field_post_thread.py b/boards/migrations/0023_auto__del_field_post_thread.py deleted file mode 100644 --- a/boards/migrations/0023_auto__del_field_post_thread.py +++ /dev/null @@ -1,87 +0,0 @@ -# -*- coding: utf-8 -*- -from south.utils import datetime_utils as datetime -from south.db import db -from south.v2 import SchemaMigration -from django.db import models - - -class Migration(SchemaMigration): - - def forwards(self, orm): - # Deleting field 'Post.thread' - db.delete_column(u'boards_post', 'thread_id') - - - def backwards(self, orm): - # Adding field 'Post.thread' - db.add_column(u'boards_post', 'thread', - self.gf('django.db.models.fields.related.ForeignKey')(default=None, to=orm['boards.Post'], null=True), - keep_default=False) - - - models = { - 'boards.ban': { - 'Meta': {'object_name': 'Ban'}, - 'can_read': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'ip': ('django.db.models.fields.GenericIPAddressField', [], {'max_length': '39'}), - 'reason': ('django.db.models.fields.CharField', [], {'default': "'Auto'", 'max_length': '200'}) - }, - 'boards.post': { - 'Meta': {'ordering': "('id',)", 'object_name': 'Post'}, - '_text_rendered': ('django.db.models.fields.TextField', [], {}), - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'image': ('boards.thumbs.ImageWithThumbsField', [], {'max_length': '100', 'blank': 'True'}), - 'image_hash': ('django.db.models.fields.CharField', [], {'max_length': '36'}), - 'image_height': ('django.db.models.fields.IntegerField', [], {'default': '0'}), - 'image_pre_height': ('django.db.models.fields.IntegerField', [], {'default': '0'}), - 'image_pre_width': ('django.db.models.fields.IntegerField', [], {'default': '0'}), - 'image_width': ('django.db.models.fields.IntegerField', [], {'default': '0'}), - 'last_edit_time': ('django.db.models.fields.DateTimeField', [], {}), - 'poster_ip': ('django.db.models.fields.GenericIPAddressField', [], {'max_length': '39'}), - 'poster_user_agent': ('django.db.models.fields.TextField', [], {}), - 'pub_time': ('django.db.models.fields.DateTimeField', [], {}), - 'referenced_posts': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'rfp+'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['boards.Post']"}), - 'text': ('markupfield.fields.MarkupField', [], {'rendered_field': 'True'}), - 'text_markup_type': ('django.db.models.fields.CharField', [], {'default': "'markdown'", 'max_length': '30'}), - 'thread_new': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': "orm['boards.Thread']", 'null': 'True'}), - 'title': ('django.db.models.fields.CharField', [], {'max_length': '200'}), - 'user': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': "orm['boards.User']", 'null': 'True'}) - }, - 'boards.setting': { - 'Meta': {'object_name': 'Setting'}, - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}), - 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['boards.User']"}), - 'value': ('django.db.models.fields.CharField', [], {'max_length': '50'}) - }, - 'boards.tag': { - 'Meta': {'ordering': "('name',)", 'object_name': 'Tag'}, - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'linked': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['boards.Tag']", 'null': 'True', 'blank': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '100', 'db_index': 'True'}), - 'threads': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'tag+'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['boards.Thread']"}) - }, - 'boards.thread': { - 'Meta': {'object_name': 'Thread'}, - 'archived': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), - 'bump_time': ('django.db.models.fields.DateTimeField', [], {}), - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'last_edit_time': ('django.db.models.fields.DateTimeField', [], {}), - 'replies': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'tre+'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['boards.Post']"}), - 'tags': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['boards.Tag']", 'symmetrical': 'False'}) - }, - 'boards.user': { - 'Meta': {'object_name': 'User'}, - 'fav_tags': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': "orm['boards.Tag']", 'null': 'True', 'blank': 'True'}), - 'fav_threads': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['boards.Post']"}), - 'hidden_tags': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'ht+'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['boards.Tag']"}), - 'hidden_threads': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'hth+'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['boards.Post']"}), - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'rank': ('django.db.models.fields.IntegerField', [], {}), - 'registration_time': ('django.db.models.fields.DateTimeField', [], {}), - 'user_id': ('django.db.models.fields.CharField', [], {'max_length': '50'}) - } - } - - complete_apps = ['boards'] \ No newline at end of file diff --git a/boards/migrations/0024_auto__add_field_post_refmap.py b/boards/migrations/0024_auto__add_field_post_refmap.py deleted file mode 100644 --- a/boards/migrations/0024_auto__add_field_post_refmap.py +++ /dev/null @@ -1,88 +0,0 @@ -# -*- coding: utf-8 -*- -from south.utils import datetime_utils as datetime -from south.db import db -from south.v2 import SchemaMigration -from django.db import models - - -class Migration(SchemaMigration): - - def forwards(self, orm): - # Adding field 'Post.refmap' - db.add_column(u'boards_post', 'refmap', - self.gf('django.db.models.fields.TextField')(null=True, blank=True), - keep_default=False) - - - def backwards(self, orm): - # Deleting field 'Post.refmap' - db.delete_column(u'boards_post', 'refmap') - - - models = { - 'boards.ban': { - 'Meta': {'object_name': 'Ban'}, - 'can_read': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'ip': ('django.db.models.fields.GenericIPAddressField', [], {'max_length': '39'}), - 'reason': ('django.db.models.fields.CharField', [], {'default': "'Auto'", 'max_length': '200'}) - }, - 'boards.post': { - 'Meta': {'ordering': "('id',)", 'object_name': 'Post'}, - '_text_rendered': ('django.db.models.fields.TextField', [], {}), - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'image': ('boards.thumbs.ImageWithThumbsField', [], {'max_length': '100', 'blank': 'True'}), - 'image_hash': ('django.db.models.fields.CharField', [], {'max_length': '36'}), - 'image_height': ('django.db.models.fields.IntegerField', [], {'default': '0'}), - 'image_pre_height': ('django.db.models.fields.IntegerField', [], {'default': '0'}), - 'image_pre_width': ('django.db.models.fields.IntegerField', [], {'default': '0'}), - 'image_width': ('django.db.models.fields.IntegerField', [], {'default': '0'}), - 'last_edit_time': ('django.db.models.fields.DateTimeField', [], {}), - 'poster_ip': ('django.db.models.fields.GenericIPAddressField', [], {'max_length': '39'}), - 'poster_user_agent': ('django.db.models.fields.TextField', [], {}), - 'pub_time': ('django.db.models.fields.DateTimeField', [], {}), - 'referenced_posts': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'rfp+'", 'to': "orm['boards.Post']", 'blank': 'True', 'symmetrical': 'False', 'null': 'True', 'db_index': 'True'}), - 'refmap': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), - 'text': ('markupfield.fields.MarkupField', [], {'rendered_field': 'True'}), - 'text_markup_type': ('django.db.models.fields.CharField', [], {'default': "'markdown'", 'max_length': '30'}), - 'thread_new': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': "orm['boards.Thread']", 'null': 'True'}), - 'title': ('django.db.models.fields.CharField', [], {'max_length': '200'}), - 'user': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': "orm['boards.User']", 'null': 'True'}) - }, - 'boards.setting': { - 'Meta': {'object_name': 'Setting'}, - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}), - 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['boards.User']"}), - 'value': ('django.db.models.fields.CharField', [], {'max_length': '50'}) - }, - 'boards.tag': { - 'Meta': {'ordering': "('name',)", 'object_name': 'Tag'}, - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'linked': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['boards.Tag']", 'null': 'True', 'blank': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '100', 'db_index': 'True'}), - 'threads': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'tag+'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['boards.Thread']"}) - }, - 'boards.thread': { - 'Meta': {'object_name': 'Thread'}, - 'archived': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), - 'bump_time': ('django.db.models.fields.DateTimeField', [], {}), - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'last_edit_time': ('django.db.models.fields.DateTimeField', [], {}), - 'replies': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'tre+'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['boards.Post']"}), - 'tags': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['boards.Tag']", 'symmetrical': 'False'}) - }, - 'boards.user': { - 'Meta': {'object_name': 'User'}, - 'fav_tags': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': "orm['boards.Tag']", 'null': 'True', 'blank': 'True'}), - 'fav_threads': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['boards.Post']"}), - 'hidden_tags': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'ht+'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['boards.Tag']"}), - 'hidden_threads': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'hth+'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['boards.Post']"}), - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'rank': ('django.db.models.fields.IntegerField', [], {}), - 'registration_time': ('django.db.models.fields.DateTimeField', [], {}), - 'user_id': ('django.db.models.fields.CharField', [], {'max_length': '50'}) - } - } - - complete_apps = ['boards'] \ No newline at end of file diff --git a/boards/migrations/0025_add_refmap_cache.py b/boards/migrations/0025_add_refmap_cache.py deleted file mode 100644 --- a/boards/migrations/0025_add_refmap_cache.py +++ /dev/null @@ -1,91 +0,0 @@ -# -*- coding: utf-8 -*- -from south.utils import datetime_utils as datetime -from south.db import db -from south.v2 import DataMigration -from django.db import models - -from boards.models import Post - -class Migration(DataMigration): - - - def forwards(self, orm): - "Write your forwards methods here." - # Note: Don't use "from appname.models import ModelName". - # Use orm.ModelName to refer to models in this application, - # and orm['appname.ModelName'] for models in other applications. - for post in orm['boards.Post'].objects.all(): - post.build_refmap() - post.save() - - def backwards(self, orm): - "Write your backwards methods here." - - models = { - 'boards.ban': { - 'Meta': {'object_name': 'Ban'}, - 'can_read': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'ip': ('django.db.models.fields.GenericIPAddressField', [], {'max_length': '39'}), - 'reason': ('django.db.models.fields.CharField', [], {'default': "'Auto'", 'max_length': '200'}) - }, - 'boards.post': { - 'Meta': {'ordering': "('id',)", 'object_name': 'Post'}, - '_text_rendered': ('django.db.models.fields.TextField', [], {}), - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'image': ('boards.thumbs.ImageWithThumbsField', [], {'max_length': '100', 'blank': 'True'}), - 'image_hash': ('django.db.models.fields.CharField', [], {'max_length': '36'}), - 'image_height': ('django.db.models.fields.IntegerField', [], {'default': '0'}), - 'image_pre_height': ('django.db.models.fields.IntegerField', [], {'default': '0'}), - 'image_pre_width': ('django.db.models.fields.IntegerField', [], {'default': '0'}), - 'image_width': ('django.db.models.fields.IntegerField', [], {'default': '0'}), - 'last_edit_time': ('django.db.models.fields.DateTimeField', [], {}), - 'poster_ip': ('django.db.models.fields.GenericIPAddressField', [], {'max_length': '39'}), - 'poster_user_agent': ('django.db.models.fields.TextField', [], {}), - 'pub_time': ('django.db.models.fields.DateTimeField', [], {}), - 'referenced_posts': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'rfp+'", 'to': "orm['boards.Post']", 'blank': 'True', 'symmetrical': 'False', 'null': 'True', 'db_index': 'True'}), - 'refmap': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), - 'text': ('markupfield.fields.MarkupField', [], {'rendered_field': 'True'}), - 'text_markup_type': ('django.db.models.fields.CharField', [], {'default': "'markdown'", 'max_length': '30'}), - 'thread_new': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': "orm['boards.Thread']", 'null': 'True'}), - 'title': ('django.db.models.fields.CharField', [], {'max_length': '200'}), - 'user': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': "orm['boards.User']", 'null': 'True'}) - }, - 'boards.setting': { - 'Meta': {'object_name': 'Setting'}, - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}), - 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['boards.User']"}), - 'value': ('django.db.models.fields.CharField', [], {'max_length': '50'}) - }, - 'boards.tag': { - 'Meta': {'ordering': "('name',)", 'object_name': 'Tag'}, - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'linked': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['boards.Tag']", 'null': 'True', 'blank': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '100', 'db_index': 'True'}), - 'threads': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'tag+'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['boards.Thread']"}) - }, - 'boards.thread': { - 'Meta': {'object_name': 'Thread'}, - 'archived': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), - 'bump_time': ('django.db.models.fields.DateTimeField', [], {}), - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'last_edit_time': ('django.db.models.fields.DateTimeField', [], {}), - 'replies': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'tre+'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['boards.Post']"}), - 'tags': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['boards.Tag']", 'symmetrical': 'False'}) - }, - 'boards.user': { - 'Meta': {'object_name': 'User'}, - 'fav_tags': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': "orm['boards.Tag']", 'null': 'True', 'blank': 'True'}), - 'fav_threads': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['boards.Post']"}), - 'hidden_tags': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'ht+'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['boards.Tag']"}), - 'hidden_threads': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'hth+'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['boards.Post']"}), - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'rank': ('django.db.models.fields.IntegerField', [], {}), - 'registration_time': ('django.db.models.fields.DateTimeField', [], {}), - 'user_id': ('django.db.models.fields.CharField', [], {'max_length': '50'}) - } - } - - complete_apps = ['boards'] - symmetrical = True diff --git a/boards/migrations/0026_auto__add_postimage.py b/boards/migrations/0026_auto__add_postimage.py deleted file mode 100644 --- a/boards/migrations/0026_auto__add_postimage.py +++ /dev/null @@ -1,118 +0,0 @@ -# -*- coding: utf-8 -*- -from south.utils import datetime_utils as 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 'PostImage' - db.create_table(u'boards_postimage', ( - (u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), - ('width', self.gf('django.db.models.fields.IntegerField')(default=0)), - ('height', self.gf('django.db.models.fields.IntegerField')(default=0)), - ('pre_width', self.gf('django.db.models.fields.IntegerField')(default=0)), - ('pre_height', self.gf('django.db.models.fields.IntegerField')(default=0)), - ('image', self.gf('boards.thumbs.ImageWithThumbsField')(max_length=100, blank=True)), - ('hash', self.gf('django.db.models.fields.CharField')(max_length=36)), - )) - db.send_create_signal('boards', ['PostImage']) - - # Adding M2M table for field images on 'Post' - m2m_table_name = db.shorten_name(u'boards_post_images') - db.create_table(m2m_table_name, ( - ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)), - ('post', models.ForeignKey(orm['boards.post'], null=False)), - ('postimage', models.ForeignKey(orm['boards.postimage'], null=False)) - )) - db.create_unique(m2m_table_name, ['post_id', 'postimage_id']) - - - def backwards(self, orm): - # Deleting model 'PostImage' - db.delete_table(u'boards_postimage') - - # Removing M2M table for field images on 'Post' - db.delete_table(db.shorten_name(u'boards_post_images')) - - - models = { - 'boards.ban': { - 'Meta': {'object_name': 'Ban'}, - 'can_read': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'ip': ('django.db.models.fields.GenericIPAddressField', [], {'max_length': '39'}), - 'reason': ('django.db.models.fields.CharField', [], {'default': "'Auto'", 'max_length': '200'}) - }, - 'boards.post': { - 'Meta': {'ordering': "('id',)", 'object_name': 'Post'}, - '_text_rendered': ('django.db.models.fields.TextField', [], {}), - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'image': ('boards.thumbs.ImageWithThumbsField', [], {'max_length': '100', 'blank': 'True'}), - 'image_hash': ('django.db.models.fields.CharField', [], {'max_length': '36'}), - 'image_height': ('django.db.models.fields.IntegerField', [], {'default': '0'}), - 'image_pre_height': ('django.db.models.fields.IntegerField', [], {'default': '0'}), - 'image_pre_width': ('django.db.models.fields.IntegerField', [], {'default': '0'}), - 'image_width': ('django.db.models.fields.IntegerField', [], {'default': '0'}), - 'images': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'ip+'", 'to': "orm['boards.PostImage']", 'blank': 'True', 'symmetrical': 'False', 'null': 'True', 'db_index': 'True'}), - 'last_edit_time': ('django.db.models.fields.DateTimeField', [], {}), - 'poster_ip': ('django.db.models.fields.GenericIPAddressField', [], {'max_length': '39'}), - 'poster_user_agent': ('django.db.models.fields.TextField', [], {}), - 'pub_time': ('django.db.models.fields.DateTimeField', [], {}), - 'referenced_posts': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'rfp+'", 'to': "orm['boards.Post']", 'blank': 'True', 'symmetrical': 'False', 'null': 'True', 'db_index': 'True'}), - 'refmap': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), - 'text': ('markupfield.fields.MarkupField', [], {'rendered_field': 'True'}), - 'text_markup_type': ('django.db.models.fields.CharField', [], {'default': "'markdown'", 'max_length': '30'}), - 'thread_new': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': "orm['boards.Thread']", 'null': 'True'}), - 'title': ('django.db.models.fields.CharField', [], {'max_length': '200'}), - 'user': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': "orm['boards.User']", 'null': 'True'}) - }, - 'boards.postimage': { - 'Meta': {'ordering': "('id',)", 'object_name': 'PostImage'}, - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'image': ('boards.thumbs.ImageWithThumbsField', [], {'max_length': '100', 'blank': 'True'}), - 'hash': ('django.db.models.fields.CharField', [], {'max_length': '36'}), - 'height': ('django.db.models.fields.IntegerField', [], {'default': '0'}), - 'pre_height': ('django.db.models.fields.IntegerField', [], {'default': '0'}), - 'pre_width': ('django.db.models.fields.IntegerField', [], {'default': '0'}), - 'width': ('django.db.models.fields.IntegerField', [], {'default': '0'}) - }, - 'boards.setting': { - 'Meta': {'object_name': 'Setting'}, - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}), - 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['boards.User']"}), - 'value': ('django.db.models.fields.CharField', [], {'max_length': '50'}) - }, - 'boards.tag': { - 'Meta': {'ordering': "('name',)", 'object_name': 'Tag'}, - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'linked': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['boards.Tag']", 'null': 'True', 'blank': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '100', 'db_index': 'True'}), - 'threads': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'tag+'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['boards.Thread']"}) - }, - 'boards.thread': { - 'Meta': {'object_name': 'Thread'}, - 'archived': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), - 'bump_time': ('django.db.models.fields.DateTimeField', [], {}), - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'last_edit_time': ('django.db.models.fields.DateTimeField', [], {}), - 'replies': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'tre+'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['boards.Post']"}), - 'tags': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['boards.Tag']", 'symmetrical': 'False'}) - }, - 'boards.user': { - 'Meta': {'object_name': 'User'}, - 'fav_tags': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': "orm['boards.Tag']", 'null': 'True', 'blank': 'True'}), - 'fav_threads': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['boards.Post']"}), - 'hidden_tags': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'ht+'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['boards.Tag']"}), - 'hidden_threads': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'hth+'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['boards.Post']"}), - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'rank': ('django.db.models.fields.IntegerField', [], {}), - 'registration_time': ('django.db.models.fields.DateTimeField', [], {}), - 'user_id': ('django.db.models.fields.CharField', [], {'max_length': '50'}) - } - } - - complete_apps = ['boards'] \ No newline at end of file diff --git a/boards/migrations/0027_image_field_to_model.py b/boards/migrations/0027_image_field_to_model.py deleted file mode 100644 --- a/boards/migrations/0027_image_field_to_model.py +++ /dev/null @@ -1,110 +0,0 @@ -# -*- coding: utf-8 -*- -from south.utils import datetime_utils as datetime -from south.db import db -from south.v2 import DataMigration -from django.db import models - - -class Migration(DataMigration): - - def forwards(self, orm): - for post in orm['boards.Post'].objects.all(): - if post.image: - image = orm['boards.PostImage']() - - image.width = post.image_width - image.height = post.image_height - - image.pre_width = post.image_pre_width - image.pre_height = post.image_pre_height - - image.image = post.image - image.hash = post.image_hash - - image.save() - - post.images.clear() - post.images.add(image) - - def backwards(self, orm): - "Write your backwards methods here." - - models = { - 'boards.ban': { - 'Meta': {'object_name': 'Ban'}, - 'can_read': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'ip': ('django.db.models.fields.GenericIPAddressField', [], {'max_length': '39'}), - 'reason': ('django.db.models.fields.CharField', [], {'default': "'Auto'", 'max_length': '200'}) - }, - 'boards.post': { - 'Meta': {'ordering': "('id',)", 'object_name': 'Post'}, - '_text_rendered': ('django.db.models.fields.TextField', [], {}), - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'image': ('boards.thumbs.ImageWithThumbsField', [], {'max_length': '100', 'blank': 'True'}), - 'image_hash': ('django.db.models.fields.CharField', [], {'max_length': '36'}), - 'image_height': ('django.db.models.fields.IntegerField', [], {'default': '0'}), - 'image_pre_height': ('django.db.models.fields.IntegerField', [], {'default': '0'}), - 'image_pre_width': ('django.db.models.fields.IntegerField', [], {'default': '0'}), - 'image_width': ('django.db.models.fields.IntegerField', [], {'default': '0'}), - 'images': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'ip+'", 'to': "orm['boards.PostImage']", 'blank': 'True', 'symmetrical': 'False', 'null': 'True', 'db_index': 'True'}), - 'last_edit_time': ('django.db.models.fields.DateTimeField', [], {}), - 'poster_ip': ('django.db.models.fields.GenericIPAddressField', [], {'max_length': '39'}), - 'poster_user_agent': ('django.db.models.fields.TextField', [], {}), - 'pub_time': ('django.db.models.fields.DateTimeField', [], {}), - 'referenced_posts': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'rfp+'", 'to': "orm['boards.Post']", 'blank': 'True', 'symmetrical': 'False', 'null': 'True', 'db_index': 'True'}), - 'refmap': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), - 'text': ('markupfield.fields.MarkupField', [], {'rendered_field': 'True'}), - 'text_markup_type': ('django.db.models.fields.CharField', [], {'default': "'markdown'", 'max_length': '30'}), - 'thread_new': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': "orm['boards.Thread']", 'null': 'True'}), - 'title': ('django.db.models.fields.CharField', [], {'max_length': '200'}), - 'user': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': "orm['boards.User']", 'null': 'True'}) - }, - 'boards.postimage': { - 'Meta': {'ordering': "('id',)", 'object_name': 'PostImage'}, - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'image': ('boards.thumbs.ImageWithThumbsField', [], {'max_length': '100', 'blank': 'True'}), - 'hash': ('django.db.models.fields.CharField', [], {'max_length': '36'}), - 'height': ('django.db.models.fields.IntegerField', [], {'default': '0'}), - 'pre_height': ('django.db.models.fields.IntegerField', [], {'default': '0'}), - 'pre_width': ('django.db.models.fields.IntegerField', [], {'default': '0'}), - 'width': ('django.db.models.fields.IntegerField', [], {'default': '0'}) - }, - 'boards.setting': { - 'Meta': {'object_name': 'Setting'}, - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}), - 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['boards.User']"}), - 'value': ('django.db.models.fields.CharField', [], {'max_length': '50'}) - }, - 'boards.tag': { - 'Meta': {'ordering': "('name',)", 'object_name': 'Tag'}, - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'linked': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['boards.Tag']", 'null': 'True', 'blank': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '100', 'db_index': 'True'}), - 'threads': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'tag+'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['boards.Thread']"}) - }, - 'boards.thread': { - 'Meta': {'object_name': 'Thread'}, - 'archived': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), - 'bump_time': ('django.db.models.fields.DateTimeField', [], {}), - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'last_edit_time': ('django.db.models.fields.DateTimeField', [], {}), - 'replies': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'tre+'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['boards.Post']"}), - 'tags': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['boards.Tag']", 'symmetrical': 'False'}) - }, - 'boards.user': { - 'Meta': {'object_name': 'User'}, - 'fav_tags': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': "orm['boards.Tag']", 'null': 'True', 'blank': 'True'}), - 'fav_threads': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['boards.Post']"}), - 'hidden_tags': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'ht+'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['boards.Tag']"}), - 'hidden_threads': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'hth+'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['boards.Post']"}), - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'rank': ('django.db.models.fields.IntegerField', [], {}), - 'registration_time': ('django.db.models.fields.DateTimeField', [], {}), - 'user_id': ('django.db.models.fields.CharField', [], {'max_length': '50'}) - } - } - - complete_apps = ['boards'] - symmetrical = True diff --git a/boards/migrations/0028_auto__del_field_post_image_pre_height__del_field_post_image__del_field.py b/boards/migrations/0028_auto__del_field_post_image_pre_height__del_field_post_image__del_field.py deleted file mode 100644 --- a/boards/migrations/0028_auto__del_field_post_image_pre_height__del_field_post_image__del_field.py +++ /dev/null @@ -1,141 +0,0 @@ -# -*- coding: utf-8 -*- -from south.utils import datetime_utils as datetime -from south.db import db -from south.v2 import SchemaMigration -from django.db import models - - -class Migration(SchemaMigration): - - def forwards(self, orm): - # Deleting field 'Post.image_pre_height' - db.delete_column(u'boards_post', 'image_pre_height') - - # Deleting field 'Post.image' - db.delete_column(u'boards_post', 'image') - - # Deleting field 'Post.image_pre_width' - db.delete_column(u'boards_post', 'image_pre_width') - - # Deleting field 'Post.image_width' - db.delete_column(u'boards_post', 'image_width') - - # Deleting field 'Post.image_height' - db.delete_column(u'boards_post', 'image_height') - - # Deleting field 'Post.image_hash' - db.delete_column(u'boards_post', 'image_hash') - - - def backwards(self, orm): - # Adding field 'Post.image_pre_height' - db.add_column(u'boards_post', 'image_pre_height', - self.gf('django.db.models.fields.IntegerField')(default=0), - keep_default=False) - - - # User chose to not deal with backwards NULL issues for 'Post.image' - raise RuntimeError("Cannot reverse this migration. 'Post.image' and its values cannot be restored.") - - # The following code is provided here to aid in writing a correct migration # Adding field 'Post.image' - db.add_column(u'boards_post', 'image', - self.gf('boards.thumbs.ImageWithThumbsField')(max_length=100, blank=True), - keep_default=False) - - # Adding field 'Post.image_pre_width' - db.add_column(u'boards_post', 'image_pre_width', - self.gf('django.db.models.fields.IntegerField')(default=0), - keep_default=False) - - # Adding field 'Post.image_width' - db.add_column(u'boards_post', 'image_width', - self.gf('django.db.models.fields.IntegerField')(default=0), - keep_default=False) - - # Adding field 'Post.image_height' - db.add_column(u'boards_post', 'image_height', - self.gf('django.db.models.fields.IntegerField')(default=0), - keep_default=False) - - - # User chose to not deal with backwards NULL issues for 'Post.image_hash' - raise RuntimeError("Cannot reverse this migration. 'Post.image_hash' and its values cannot be restored.") - - # The following code is provided here to aid in writing a correct migration # Adding field 'Post.image_hash' - db.add_column(u'boards_post', 'image_hash', - self.gf('django.db.models.fields.CharField')(max_length=36), - keep_default=False) - - - models = { - 'boards.ban': { - 'Meta': {'object_name': 'Ban'}, - 'can_read': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'ip': ('django.db.models.fields.GenericIPAddressField', [], {'max_length': '39'}), - 'reason': ('django.db.models.fields.CharField', [], {'default': "'Auto'", 'max_length': '200'}) - }, - 'boards.post': { - 'Meta': {'ordering': "('id',)", 'object_name': 'Post'}, - '_text_rendered': ('django.db.models.fields.TextField', [], {}), - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'images': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'ip+'", 'to': "orm['boards.PostImage']", 'blank': 'True', 'symmetrical': 'False', 'null': 'True', 'db_index': 'True'}), - 'last_edit_time': ('django.db.models.fields.DateTimeField', [], {}), - 'poster_ip': ('django.db.models.fields.GenericIPAddressField', [], {'max_length': '39'}), - 'poster_user_agent': ('django.db.models.fields.TextField', [], {}), - 'pub_time': ('django.db.models.fields.DateTimeField', [], {}), - 'referenced_posts': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'rfp+'", 'to': "orm['boards.Post']", 'blank': 'True', 'symmetrical': 'False', 'null': 'True', 'db_index': 'True'}), - 'refmap': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), - 'text': ('markupfield.fields.MarkupField', [], {'rendered_field': 'True'}), - 'text_markup_type': ('django.db.models.fields.CharField', [], {'default': "'markdown'", 'max_length': '30'}), - 'thread_new': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': "orm['boards.Thread']", 'null': 'True'}), - 'title': ('django.db.models.fields.CharField', [], {'max_length': '200'}), - 'user': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': "orm['boards.User']", 'null': 'True'}) - }, - 'boards.postimage': { - 'Meta': {'ordering': "('id',)", 'object_name': 'PostImage'}, - 'hash': ('django.db.models.fields.CharField', [], {'max_length': '36'}), - 'height': ('django.db.models.fields.IntegerField', [], {'default': '0'}), - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'image': ('boards.thumbs.ImageWithThumbsField', [], {'max_length': '100', 'blank': 'True'}), - 'pre_height': ('django.db.models.fields.IntegerField', [], {'default': '0'}), - 'pre_width': ('django.db.models.fields.IntegerField', [], {'default': '0'}), - 'width': ('django.db.models.fields.IntegerField', [], {'default': '0'}) - }, - 'boards.setting': { - 'Meta': {'object_name': 'Setting'}, - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}), - 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['boards.User']"}), - 'value': ('django.db.models.fields.CharField', [], {'max_length': '50'}) - }, - 'boards.tag': { - 'Meta': {'ordering': "('name',)", 'object_name': 'Tag'}, - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'linked': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['boards.Tag']", 'null': 'True', 'blank': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '100', 'db_index': 'True'}), - 'threads': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'tag+'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['boards.Thread']"}) - }, - 'boards.thread': { - 'Meta': {'object_name': 'Thread'}, - 'archived': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), - 'bump_time': ('django.db.models.fields.DateTimeField', [], {}), - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'last_edit_time': ('django.db.models.fields.DateTimeField', [], {}), - 'replies': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'tre+'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['boards.Post']"}), - 'tags': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['boards.Tag']", 'symmetrical': 'False'}) - }, - 'boards.user': { - 'Meta': {'object_name': 'User'}, - 'fav_tags': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': "orm['boards.Tag']", 'null': 'True', 'blank': 'True'}), - 'fav_threads': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['boards.Post']"}), - 'hidden_tags': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'ht+'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['boards.Tag']"}), - 'hidden_threads': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'hth+'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['boards.Post']"}), - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'rank': ('django.db.models.fields.IntegerField', [], {}), - 'registration_time': ('django.db.models.fields.DateTimeField', [], {}), - 'user_id': ('django.db.models.fields.CharField', [], {'max_length': '50'}) - } - } - - complete_apps = ['boards'] \ No newline at end of file diff --git a/boards/migrations/0029_auto__del_setting__del_user__del_field_post_user.py b/boards/migrations/0029_auto__del_setting__del_user__del_field_post_user.py deleted file mode 100644 --- a/boards/migrations/0029_auto__del_setting__del_user__del_field_post_user.py +++ /dev/null @@ -1,146 +0,0 @@ -# -*- coding: utf-8 -*- -from south.utils import datetime_utils as datetime -from south.db import db -from south.v2 import SchemaMigration -from django.db import models - - -class Migration(SchemaMigration): - - def forwards(self, orm): - # Deleting model 'Setting' - db.delete_table(u'boards_setting') - - # Deleting model 'User' - db.delete_table(u'boards_user') - - # Removing M2M table for field hidden_threads on 'User' - db.delete_table(db.shorten_name(u'boards_user_hidden_threads')) - - # Removing M2M table for field fav_threads on 'User' - db.delete_table(db.shorten_name(u'boards_user_fav_threads')) - - # Removing M2M table for field fav_tags on 'User' - db.delete_table(db.shorten_name(u'boards_user_fav_tags')) - - # Removing M2M table for field hidden_tags on 'User' - db.delete_table(db.shorten_name(u'boards_user_hidden_tags')) - - # Deleting field 'Post.user' - db.delete_column(u'boards_post', 'user_id') - - - def backwards(self, orm): - # Adding model 'Setting' - db.create_table(u'boards_setting', ( - ('user', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['boards.User'])), - (u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), - ('value', self.gf('django.db.models.fields.CharField')(max_length=50)), - ('name', self.gf('django.db.models.fields.CharField')(max_length=50)), - )) - db.send_create_signal('boards', ['Setting']) - - # Adding model 'User' - db.create_table(u'boards_user', ( - ('registration_time', self.gf('django.db.models.fields.DateTimeField')()), - (u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), - ('user_id', self.gf('django.db.models.fields.CharField')(max_length=50)), - ('rank', self.gf('django.db.models.fields.IntegerField')()), - )) - db.send_create_signal('boards', ['User']) - - # Adding M2M table for field hidden_threads on 'User' - m2m_table_name = db.shorten_name(u'boards_user_hidden_threads') - db.create_table(m2m_table_name, ( - ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)), - ('user', models.ForeignKey(orm['boards.user'], null=False)), - ('post', models.ForeignKey(orm['boards.post'], null=False)) - )) - db.create_unique(m2m_table_name, ['user_id', 'post_id']) - - # Adding M2M table for field fav_threads on 'User' - m2m_table_name = db.shorten_name(u'boards_user_fav_threads') - db.create_table(m2m_table_name, ( - ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)), - ('user', models.ForeignKey(orm['boards.user'], null=False)), - ('post', models.ForeignKey(orm['boards.post'], null=False)) - )) - db.create_unique(m2m_table_name, ['user_id', 'post_id']) - - # Adding M2M table for field fav_tags on 'User' - m2m_table_name = db.shorten_name(u'boards_user_fav_tags') - db.create_table(m2m_table_name, ( - ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)), - ('user', models.ForeignKey(orm['boards.user'], null=False)), - ('tag', models.ForeignKey(orm['boards.tag'], null=False)) - )) - db.create_unique(m2m_table_name, ['user_id', 'tag_id']) - - # Adding M2M table for field hidden_tags on 'User' - m2m_table_name = db.shorten_name(u'boards_user_hidden_tags') - db.create_table(m2m_table_name, ( - ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)), - ('user', models.ForeignKey(orm['boards.user'], null=False)), - ('tag', models.ForeignKey(orm['boards.tag'], null=False)) - )) - db.create_unique(m2m_table_name, ['user_id', 'tag_id']) - - # Adding field 'Post.user' - db.add_column(u'boards_post', 'user', - self.gf('django.db.models.fields.related.ForeignKey')(default=None, to=orm['boards.User'], null=True), - keep_default=False) - - - models = { - 'boards.ban': { - 'Meta': {'object_name': 'Ban'}, - 'can_read': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'ip': ('django.db.models.fields.GenericIPAddressField', [], {'max_length': '39'}), - 'reason': ('django.db.models.fields.CharField', [], {'default': "'Auto'", 'max_length': '200'}) - }, - 'boards.post': { - 'Meta': {'ordering': "('id',)", 'object_name': 'Post'}, - '_text_rendered': ('django.db.models.fields.TextField', [], {}), - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'images': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'ip+'", 'to': "orm['boards.PostImage']", 'blank': 'True', 'symmetrical': 'False', 'null': 'True', 'db_index': 'True'}), - 'last_edit_time': ('django.db.models.fields.DateTimeField', [], {}), - 'poster_ip': ('django.db.models.fields.GenericIPAddressField', [], {'max_length': '39'}), - 'poster_user_agent': ('django.db.models.fields.TextField', [], {}), - 'pub_time': ('django.db.models.fields.DateTimeField', [], {}), - 'referenced_posts': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'rfp+'", 'to': "orm['boards.Post']", 'blank': 'True', 'symmetrical': 'False', 'null': 'True', 'db_index': 'True'}), - 'refmap': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), - 'text': ('markupfield.fields.MarkupField', [], {'rendered_field': 'True'}), - 'text_markup_type': ('django.db.models.fields.CharField', [], {'default': "'markdown'", 'max_length': '30'}), - 'thread_new': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': "orm['boards.Thread']", 'null': 'True'}), - 'title': ('django.db.models.fields.CharField', [], {'max_length': '200'}) - }, - 'boards.postimage': { - 'Meta': {'ordering': "('id',)", 'object_name': 'PostImage'}, - 'hash': ('django.db.models.fields.CharField', [], {'max_length': '36'}), - 'height': ('django.db.models.fields.IntegerField', [], {'default': '0'}), - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'image': ('boards.thumbs.ImageWithThumbsField', [], {'max_length': '100', 'blank': 'True'}), - 'pre_height': ('django.db.models.fields.IntegerField', [], {'default': '0'}), - 'pre_width': ('django.db.models.fields.IntegerField', [], {'default': '0'}), - 'width': ('django.db.models.fields.IntegerField', [], {'default': '0'}) - }, - 'boards.tag': { - 'Meta': {'ordering': "('name',)", 'object_name': 'Tag'}, - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'linked': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['boards.Tag']", 'null': 'True', 'blank': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '100', 'db_index': 'True'}), - 'threads': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'tag+'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['boards.Thread']"}) - }, - 'boards.thread': { - 'Meta': {'object_name': 'Thread'}, - 'archived': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), - 'bump_time': ('django.db.models.fields.DateTimeField', [], {}), - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'last_edit_time': ('django.db.models.fields.DateTimeField', [], {}), - 'replies': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'tre+'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['boards.Post']"}), - 'tags': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['boards.Tag']", 'symmetrical': 'False'}) - } - } - - complete_apps = ['boards'] \ No newline at end of file diff --git a/boards/migrations/0030_auto__del_field_tag_linked.py b/boards/migrations/0030_auto__del_field_tag_linked.py deleted file mode 100644 --- a/boards/migrations/0030_auto__del_field_tag_linked.py +++ /dev/null @@ -1,73 +0,0 @@ -# -*- coding: utf-8 -*- -from south.utils import datetime_utils as datetime -from south.db import db -from south.v2 import SchemaMigration -from django.db import models - - -class Migration(SchemaMigration): - - def forwards(self, orm): - # Deleting field 'Tag.linked' - db.delete_column(u'boards_tag', 'linked_id') - - - def backwards(self, orm): - # Adding field 'Tag.linked' - db.add_column(u'boards_tag', 'linked', - self.gf('django.db.models.fields.related.ForeignKey')(to=orm['boards.Tag'], null=True, blank=True), - keep_default=False) - - - models = { - 'boards.ban': { - 'Meta': {'object_name': 'Ban'}, - 'can_read': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'ip': ('django.db.models.fields.GenericIPAddressField', [], {'max_length': '39'}), - 'reason': ('django.db.models.fields.CharField', [], {'default': "'Auto'", 'max_length': '200'}) - }, - 'boards.post': { - 'Meta': {'ordering': "('id',)", 'object_name': 'Post'}, - '_text_rendered': ('django.db.models.fields.TextField', [], {}), - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'images': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'ip+'", 'to': "orm['boards.PostImage']", 'blank': 'True', 'symmetrical': 'False', 'null': 'True', 'db_index': 'True'}), - 'last_edit_time': ('django.db.models.fields.DateTimeField', [], {}), - 'poster_ip': ('django.db.models.fields.GenericIPAddressField', [], {'max_length': '39'}), - 'poster_user_agent': ('django.db.models.fields.TextField', [], {}), - 'pub_time': ('django.db.models.fields.DateTimeField', [], {}), - 'referenced_posts': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'rfp+'", 'to': "orm['boards.Post']", 'blank': 'True', 'symmetrical': 'False', 'null': 'True', 'db_index': 'True'}), - 'refmap': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), - 'text': ('markupfield.fields.MarkupField', [], {'rendered_field': 'True'}), - 'text_markup_type': ('django.db.models.fields.CharField', [], {'default': "'bbcode'", 'max_length': '30'}), - 'thread_new': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': "orm['boards.Thread']", 'null': 'True'}), - 'title': ('django.db.models.fields.CharField', [], {'max_length': '200'}) - }, - 'boards.postimage': { - 'Meta': {'ordering': "('id',)", 'object_name': 'PostImage'}, - 'hash': ('django.db.models.fields.CharField', [], {'max_length': '36'}), - 'height': ('django.db.models.fields.IntegerField', [], {'default': '0'}), - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'image': ('boards.thumbs.ImageWithThumbsField', [], {'max_length': '100', 'blank': 'True'}), - 'pre_height': ('django.db.models.fields.IntegerField', [], {'default': '0'}), - 'pre_width': ('django.db.models.fields.IntegerField', [], {'default': '0'}), - 'width': ('django.db.models.fields.IntegerField', [], {'default': '0'}) - }, - 'boards.tag': { - 'Meta': {'ordering': "('name',)", 'object_name': 'Tag'}, - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '100', 'db_index': 'True'}), - 'threads': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'tag+'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['boards.Thread']"}) - }, - 'boards.thread': { - 'Meta': {'object_name': 'Thread'}, - 'archived': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), - 'bump_time': ('django.db.models.fields.DateTimeField', [], {}), - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'last_edit_time': ('django.db.models.fields.DateTimeField', [], {}), - 'replies': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'tre+'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['boards.Post']"}), - 'tags': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['boards.Tag']", 'symmetrical': 'False'}) - } - } - - complete_apps = ['boards'] \ No newline at end of file diff --git a/boards/models/base.py b/boards/models/base.py --- a/boards/models/base.py +++ b/boards/models/base.py @@ -6,5 +6,13 @@ class Viewable(): pass def get_view(self, *args, **kwargs): - """Get an HTML view for a model""" - pass \ No newline at end of file + """ + Gets an HTML view for a model + """ + pass + + def get_search_view(self, *args, **kwargs): + """ + Gets an HTML view for search. + """ + pass diff --git a/boards/models/image.py b/boards/models/image.py --- a/boards/models/image.py +++ b/boards/models/image.py @@ -4,6 +4,7 @@ from random import random import time from django.db import models from boards import thumbs +from boards.models.base import Viewable __author__ = 'neko259' @@ -11,9 +12,13 @@ from boards import thumbs IMAGE_THUMB_SIZE = (200, 150) IMAGES_DIRECTORY = 'images/' FILE_EXTENSION_DELIMITER = '.' +HASH_LENGTH = 36 + +CSS_CLASS_IMAGE = 'image' +CSS_CLASS_THUMB = 'thumb' -class PostImage(models.Model): +class PostImage(models.Model, Viewable): class Meta: app_label = 'boards' ordering = ('id',) @@ -43,7 +48,7 @@ class PostImage(models.Model): height_field='height', preview_width_field='pre_width', preview_height_field='pre_height') - hash = models.CharField(max_length=36) + hash = models.CharField(max_length=HASH_LENGTH) def save(self, *args, **kwargs): """ @@ -60,3 +65,19 @@ class PostImage(models.Model): def __str__(self): return self.image.url + def get_view(self): + return '
' \ + '' \ + '' \ + '' \ + '
'\ + .format(CSS_CLASS_IMAGE, CSS_CLASS_THUMB, self.image.url, + self.image.url_200x150, + str(self.hash), str(self.pre_width), + str(self.pre_height), str(self.width), str(self.height)) diff --git a/boards/models/post.py b/boards/models/post.py --- a/boards/models/post.py +++ b/boards/models/post.py @@ -4,21 +4,30 @@ import logging import re import xml.etree.ElementTree as et +from adjacent import Client from django.core.cache import cache from django.core.urlresolvers import reverse from django.db import models, transaction +from django.db.models import TextField from django.template.loader import render_to_string from django.utils import timezone -from markupfield.fields import MarkupField - from boards.models import PostImage, KeyPair, GlobalId, Signature +from boards import settings +from boards.mdx_neboard import bbcode_extended +from boards.models import PostImage from boards.models.base import Viewable from boards.models.thread import Thread from boards import utils +from boards.utils import datetime_to_epoch ENCODING_UNICODE = 'unicode' +WS_NOTIFICATION_TYPE_NEW_POST = 'new_post' +WS_NOTIFICATION_TYPE = 'notification_type' + +WS_CHANNEL_THREAD = "thread:" + APP_LABEL_BOARDS = 'boards' CACHE_KEY_PPD = 'ppd' @@ -32,8 +41,6 @@ IMAGE_THUMB_SIZE = (200, 150) TITLE_MAX_LENGTH = 200 -DEFAULT_MARKUP_TYPE = 'bbcode' - # TODO This should be removed NO_IP = '0.0.0.0' @@ -69,12 +76,32 @@ ATTR_MIMETYPE = 'mimetype' STATUS_SUCCESS = 'success' -logger = logging.getLogger(__name__) +PARAMETER_TRUNCATED = 'truncated' +PARAMETER_TAG = 'tag' +PARAMETER_OFFSET = 'offset' +PARAMETER_DIFF_TYPE = 'type' +PARAMETER_BUMPABLE = 'bumpable' +PARAMETER_THREAD = 'thread' +PARAMETER_IS_OPENING = 'is_opening' +PARAMETER_MODERATOR = 'moderator' +PARAMETER_POST = 'post' +PARAMETER_OP_ID = 'opening_post_id' +PARAMETER_NEED_OPEN_LINK = 'need_open_link' + +DIFF_TYPE_HTML = 'html' +DIFF_TYPE_JSON = 'json' + +PREPARSE_PATTERNS = { + r'>>(\d+)': r'[post]\1[/post]', # Reflink ">>123" + r'^>([^>].+)': r'[quote]\1[/quote]', # Quote ">text" + r'^//(.+)': r'[comment]\1[/comment]', # Comment "//text" +} class PostManager(models.Manager): - def create_post(self, title, text, image=None, thread=None, ip=NO_IP, - tags=None): + @transaction.atomic + def create_post(self, title: str, text: str, image=None, thread=None, + ip=NO_IP, tags: list=None): """ Creates new post """ @@ -88,13 +115,12 @@ class PostManager(models.Manager): last_edit_time=posting_time) new_thread = True else: - thread.bump() - thread.last_edit_time = posting_time - thread.save() new_thread = False + pre_text = self._preparse_text(text) + post = self.create(title=title, - text=text, + text=pre_text, pub_time=posting_time, thread_new=thread, poster_ip=ip, @@ -104,43 +130,31 @@ class PostManager(models.Manager): post.set_global_id() + logger = logging.getLogger('boards.post.create') + + logger.info('Created post {} by {}'.format( + post, post.poster_ip)) + if image: post_image = PostImage.objects.create(image=image) post.images.add(post_image) - logger.info('Created image #%d for post #%d' % (post_image.id, - post.id)) + logger.info('Created image #{} for post #{}'.format( + post_image.id, post.id)) thread.replies.add(post) list(map(thread.add_tag, tags)) if new_thread: Thread.objects.process_oldest_threads() - self.connect_replies(post) + else: + thread.bump() + thread.last_edit_time = posting_time + thread.save() - logger.info('Created post #%d with title %s' - % (post.id, post.get_title())) + self.connect_replies(post) return post - def delete_post(self, post): - """ - Deletes post and update or delete its thread - """ - - post_id = post.id - - thread = post.get_thread() - - if post.is_opening(): - thread.delete() - else: - thread.last_edit_time = timezone.now() - thread.save() - - post.delete() - - logger.info('Deleted post #%d (%s)' % (post_id, post.get_title())) - def delete_posts_by_ip(self, ip): """ Deletes all posts of the author with same IP @@ -148,7 +162,7 @@ class PostManager(models.Manager): posts = self.filter(poster_ip=ip) for post in posts: - self.delete_post(post) + post.delete() # TODO This can be moved into a post def connect_replies(self, post): @@ -156,8 +170,9 @@ class PostManager(models.Manager): Connects replies to a post to show them as a reflink map """ - for reply_number in post.get_replied_ids(): - ref_post = self.filter(id=reply_number) + for reply_number in re.finditer(REGEX_REPLY, post.get_raw_text()): + post_id = reply_number.group(1) + ref_post = self.filter(id=post_id) if ref_post.count() > 0: referenced_post = ref_post[0] referenced_post.referenced_posts.add(post) @@ -280,6 +295,17 @@ class PostManager(models.Manager): # TODO Throw an exception? pass + def _preparse_text(self, text): + """ + Preparses text to change patterns like '>>' to a proper bbcode + tags. + """ + + for key, value in PREPARSE_PATTERNS.items(): + text = re.sub(key, value, text, flags=re.MULTILINE) + + return text + class Post(models.Model, Viewable): """A post is a message.""" @@ -292,8 +318,8 @@ class Post(models.Model, Viewable): title = models.CharField(max_length=TITLE_MAX_LENGTH) pub_time = models.DateTimeField() - text = MarkupField(default_markup_type=DEFAULT_MARKUP_TYPE, - escape_html=False) + text = TextField(blank=True, null=True) + _text_rendered = TextField(blank=True, null=True, editable=False) images = models.ManyToManyField(PostImage, null=True, blank=True, related_name='ip+', db_index=True) @@ -322,14 +348,21 @@ class Post(models.Model, Viewable): # One post can be signed by many nodes that give their trust to it signature = models.ManyToManyField('Signature', null=True, blank=True) - def __unicode__(self): - return '#' + str(self.id) + ' ' + self.title + ' (' + \ - self.text.raw[:50] + ')' + def __str__(self): + return 'P#{}/{}'.format(self.id, self.title) + + def get_title(self) -> str: + """ + Gets original post title or part of its text. + """ - def get_title(self): - return self.title + title = self.title + if not title: + title = self.get_text() - def build_refmap(self): + return title + + def build_refmap(self) -> None: """ Builds a replies map string from replies list. This is a cache to stop the server from recalculating the map on every post show. @@ -349,10 +382,13 @@ class Post(models.Model, Viewable): def get_sorted_referenced_posts(self): return self.refmap - def is_referenced(self): - return len(self.refmap) > 0 + def is_referenced(self) -> bool: + if not self.refmap: + return False + else: + return len(self.refmap) > 0 - def is_opening(self): + def is_opening(self) -> bool: """ Checks if this is an opening post or just a reply. """ @@ -371,18 +407,6 @@ class Post(models.Model, Viewable): thread.last_edit_time = edit_time thread.save(update_fields=['last_edit_time']) - @transaction.atomic - def remove_tag(self, tag): - edit_time = timezone.now() - - thread = self.get_thread() - thread.remove_tag(tag) - self.last_edit_time = edit_time - self.save(update_fields=['last_edit_time']) - - thread.last_edit_time = edit_time - thread.save(update_fields=['last_edit_time']) - def get_url(self, thread=None): """ Gets full url to the post. @@ -407,7 +431,7 @@ class Post(models.Model, Viewable): return link - def get_thread(self): + def get_thread(self) -> Thread: """ Gets post's thread. """ @@ -417,25 +441,17 @@ class Post(models.Model, Viewable): def get_referenced_posts(self): return self.referenced_posts.only('id', 'thread_new') - def get_text(self): - return self.text - def get_view(self, moderator=False, need_open_link=False, truncated=False, *args, **kwargs): - if 'is_opening' in kwargs: - is_opening = kwargs['is_opening'] - else: - is_opening = self.is_opening() + """ + Renders post's HTML view. Some of the post params can be passed over + kwargs for the means of caching (if we view the thread, some params + are same for every post and don't need to be computed over and over. + """ - if 'thread' in kwargs: - thread = kwargs['thread'] - else: - thread = self.get_thread() - - if 'can_bump' in kwargs: - can_bump = kwargs['can_bump'] - else: - can_bump = thread.can_bump() + is_opening = kwargs.get(PARAMETER_IS_OPENING, self.is_opening()) + thread = kwargs.get(PARAMETER_THREAD, self.get_thread()) + can_bump = kwargs.get(PARAMETER_BUMPABLE, thread.can_bump()) if is_opening: opening_post_id = self.id @@ -443,22 +459,26 @@ class Post(models.Model, Viewable): opening_post_id = thread.get_opening_post_id() return render_to_string('boards/post.html', { - 'post': self, - 'moderator': moderator, - 'is_opening': is_opening, - 'thread': thread, - 'bumpable': can_bump, - 'need_open_link': need_open_link, - 'truncated': truncated, - 'opening_post_id': opening_post_id, + PARAMETER_POST: self, + PARAMETER_MODERATOR: moderator, + PARAMETER_IS_OPENING: is_opening, + PARAMETER_THREAD: thread, + PARAMETER_BUMPABLE: can_bump, + PARAMETER_NEED_OPEN_LINK: need_open_link, + PARAMETER_TRUNCATED: truncated, + PARAMETER_OP_ID: opening_post_id, }) - def get_first_image(self): + def get_search_view(self, *args, **kwargs): + return self.get_view(args, kwargs) + + def get_first_image(self) -> PostImage: return self.images.earliest('id') def delete(self, using=None): """ - Deletes all post images and the post itself. + Deletes all post images and the post itself. If the post is opening, + thread with all posts is deleted. """ self.images.all().delete() @@ -466,7 +486,16 @@ class Post(models.Model, Viewable): if self.global_id: self.global_id.delete() + if self.is_opening(): + self.get_thread().delete() + else: + thread = self.get_thread() + thread.last_edit_time = timezone.now() + thread.save() + super(Post, self).delete(using) + logging.getLogger('boards.post.delete').info( + 'Deleted post {}'.format(self)) def set_global_id(self, key_pair=None): """ @@ -494,6 +523,7 @@ class Post(models.Model, Viewable): def get_pub_time_epoch(self): return utils.datetime_to_epoch(self.pub_time) + # TODO Use this to connect replies def get_replied_ids(self): """ Gets ID list of the posts that this post replies. @@ -516,3 +546,78 @@ class Post(models.Model, Viewable): except GlobalId.DoesNotExist: pass return local_replied + global_replied + + + def get_post_data(self, format_type=DIFF_TYPE_JSON, request=None, + include_last_update=False): + """ + Gets post HTML or JSON data that can be rendered on a page or used by + API. + """ + + if format_type == DIFF_TYPE_HTML: + params = dict() + params['post'] = self + if PARAMETER_TRUNCATED in request.GET: + params[PARAMETER_TRUNCATED] = True + + return render_to_string('boards/api_post.html', params) + elif format_type == DIFF_TYPE_JSON: + post_json = { + 'id': self.id, + 'title': self.title, + 'text': self._text_rendered, + } + if self.images.exists(): + post_image = self.get_first_image() + post_json['image'] = post_image.image.url + post_json['image_preview'] = post_image.image.url_200x150 + if include_last_update: + post_json['bump_time'] = datetime_to_epoch( + self.thread_new.bump_time) + return post_json + + def send_to_websocket(self, request, recursive=True): + """ + Sends post HTML data to the thread web socket. + """ + + if not settings.WEBSOCKETS_ENABLED: + return + + client = Client() + + thread = self.get_thread() + thread_id = thread.id + channel_name = WS_CHANNEL_THREAD + str(thread.get_opening_post_id()) + client.publish(channel_name, { + WS_NOTIFICATION_TYPE: WS_NOTIFICATION_TYPE_NEW_POST, + }) + client.send() + + logger = logging.getLogger('boards.post.websocket') + + logger.info('Sent notification from post #{} to channel {}'.format( + self.id, channel_name)) + + if recursive: + for reply_number in re.finditer(REGEX_REPLY, self.get_raw_text()): + post_id = reply_number.group(1) + ref_post = Post.objects.filter(id=post_id)[0] + + # If post is in this thread, its thread was already notified. + # Otherwise, notify its thread separately. + if ref_post.thread_new_id != thread_id: + ref_post.send_to_websocket(request, recursive=False) + + def save(self, force_insert=False, force_update=False, using=None, + update_fields=None): + self._text_rendered = bbcode_extended(self.get_raw_text()) + + super().save(force_insert, force_update, using, update_fields) + + def get_text(self) -> str: + return self._text_rendered + + def get_raw_text(self) -> str: + return self.text diff --git a/boards/models/tag.py b/boards/models/tag.py --- a/boards/models/tag.py +++ b/boards/models/tag.py @@ -1,9 +1,8 @@ from django.template.loader import render_to_string from django.db import models -from django.db.models import Count, Sum +from django.db.models import Count from django.core.urlresolvers import reverse -from boards.models import Thread from boards.models.base import Viewable @@ -17,10 +16,9 @@ class TagManager(models.Manager): Gets tags that have non-archived threads. """ - tags = self.annotate(Count('threads')) \ - .filter(threads__count__gt=0).order_by('name') - - return tags + return self.filter(thread__archived=False)\ + .annotate(num_threads=Count('thread')).filter(num_threads__gt=0)\ + .order_by('-required', 'name') class Tag(models.Model, Viewable): @@ -36,43 +34,38 @@ class Tag(models.Model, Viewable): ordering = ('name',) name = models.CharField(max_length=100, db_index=True) - threads = models.ManyToManyField(Thread, null=True, - blank=True, related_name='tag+') + required = models.BooleanField(default=False) - def __unicode__(self): + def __str__(self): return self.name - def is_empty(self): + def is_empty(self) -> bool: """ Checks if the tag has some threads. """ return self.get_thread_count() == 0 - def get_thread_count(self): - return self.threads.count() - - def get_post_count(self, archived=False): - """ - Gets posts count for the tag's threads. - """ - - posts_count = 0 - - threads = self.threads.filter(archived=archived) - if threads.exists(): - posts_count = threads.annotate(posts_count=Count('replies')) \ - .aggregate(posts_sum=Sum('posts_count'))['posts_sum'] - - if not posts_count: - posts_count = 0 - - return posts_count + def get_thread_count(self) -> int: + return self.get_threads().count() def get_url(self): return reverse('tag', kwargs={'tag_name': self.name}) - def get_view(self, *args, **kwargs): + def get_threads(self): + return self.thread_set.order_by('-bump_time') + + def is_required(self): + return self.required + + def get_view(self): + link = '{}'.format( + self.get_url(), self.name) + if self.is_required(): + link = '{}'.format(link) + return link + + def get_search_view(self, *args, **kwargs): return render_to_string('boards/tag.html', { 'tag': self, }) diff --git a/boards/models/thread.py b/boards/models/thread.py --- a/boards/models/thread.py +++ b/boards/models/thread.py @@ -1,5 +1,5 @@ import logging -from django.db.models import Count +from django.db.models import Count, Sum from django.utils import timezone from django.core.cache import cache from django.db import models @@ -38,8 +38,9 @@ class ThreadManager(models.Manager): def _archive_thread(self, thread): thread.archived = True + thread.bumpable = False thread.last_edit_time = timezone.now() - thread.save(update_fields=['archived', 'last_edit_time']) + thread.save(update_fields=['archived', 'last_edit_time', 'bumpable']) class Thread(models.Model): @@ -54,6 +55,7 @@ class Thread(models.Model): replies = models.ManyToManyField('Post', symmetrical=False, null=True, blank=True, related_name='tre+') archived = models.BooleanField(default=False) + bumpable = models.BooleanField(default=True) def get_tags(self): """ @@ -70,30 +72,24 @@ class Thread(models.Model): if self.can_bump(): self.bump_time = timezone.now() + if self.get_reply_count() >= settings.MAX_POSTS_PER_THREAD: + self.bumpable = False + logger.info('Bumped thread %d' % self.id) def get_reply_count(self): return self.replies.count() def get_images_count(self): - # TODO Use sum - total_count = 0 - for post_with_image in self.replies.annotate(images_count=Count( - 'images')): - total_count += post_with_image.images_count - return total_count + return self.replies.annotate(images_count=Count( + 'images')).aggregate(Sum('images_count'))['images_count__sum'] def can_bump(self): """ Checks if the thread can be bumped by replying to it. """ - if self.archived: - return False - - post_count = self.get_reply_count() - - return post_count < settings.MAX_POSTS_PER_THREAD + return self.bumpable def get_last_replies(self): """ @@ -127,7 +123,7 @@ class Thread(models.Model): query = self.replies.order_by('pub_time').prefetch_related('images') if view_fields_only: - query = query.defer('poster_user_agent', 'text_markup_type') + query = query.defer('poster_user_agent') return query.all() def get_replies_with_images(self, view_fields_only=False): @@ -140,11 +136,6 @@ class Thread(models.Model): """ self.tags.add(tag) - tag.threads.add(self) - - def remove_tag(self, tag): - self.tags.remove(tag) - tag.threads.remove(self) def get_opening_post(self, only_id=False): """ @@ -185,4 +176,7 @@ class Thread(models.Model): if self.replies.exists(): self.replies.all().delete() - super(Thread, self).delete(using) \ No newline at end of file + super(Thread, self).delete(using) + + def __str__(self): + return 'T#{}/{}'.format(self.id, self.get_opening_post_id()) \ No newline at end of file diff --git a/boards/search_indexes.py b/boards/search_indexes.py --- a/boards/search_indexes.py +++ b/boards/search_indexes.py @@ -21,4 +21,4 @@ class TagIndex(indexes.SearchIndex, inde return Tag def index_queryset(self, using=None): - return self.get_model().objects.get_not_empty_tags() + return self.get_model().objects.all() diff --git a/boards/settings.py b/boards/settings.py --- a/boards/settings.py +++ b/boards/settings.py @@ -1,5 +1,5 @@ -VERSION = '2.1 Aya' -SITE_NAME = 'n3b0a2d' +VERSION = '2.2.3 Miyu' +SITE_NAME = 'Neboard' CACHE_TIMEOUT = 600 # Timeout for caching, if cache is used LOGIN_TIMEOUT = 3600 # Timeout between login tries @@ -18,3 +18,5 @@ LAST_REPLIES_COUNT = 3 ARCHIVE_THREADS = True # Limit posting speed LIMIT_POSTING_SPEED = False +# Thread update +WEBSOCKETS_ENABLED = True diff --git a/boards/static/css/md/base_page.css b/boards/static/css/md/base_page.css --- a/boards/static/css/md/base_page.css +++ b/boards/static/css/md/base_page.css @@ -1,3 +1,12 @@ +* { + text-decoration: none; + font-weight: inherit; +} + +b { + font-weight: bold; +} + html { background: #555; color: #ffffff; @@ -157,6 +166,10 @@ p, .br { width: 100%; } +.post-form textarea { + resize: vertical; +} + .form-submit { display: table; margin-bottom: 1ex; diff --git a/boards/static/js/3party/centrifuge.js b/boards/static/js/3party/centrifuge.js new file mode 100644 --- /dev/null +++ b/boards/static/js/3party/centrifuge.js @@ -0,0 +1,1256 @@ +/** + * Centrifuge javascript client + * v0.5.2 + */ +;(function () { + 'use strict'; + + /** + * Oliver Caldwell + * http://oli.me.uk/2013/06/01/prototypical-inheritance-done-right/ + */ + + if (!Object.create) { + Object.create = (function(){ + function F(){} + + return function(o){ + if (arguments.length != 1) { + throw new Error('Object.create implementation only accepts one parameter.'); + } + F.prototype = o; + return new F() + } + })() + } + + if (!Array.prototype.indexOf) { + Array.prototype.indexOf = function (searchElement /*, fromIndex */) { + 'use strict'; + if (this == null) { + throw new TypeError(); + } + var n, k, t = Object(this), + len = t.length >>> 0; + + if (len === 0) { + return -1; + } + n = 0; + if (arguments.length > 1) { + n = Number(arguments[1]); + if (n != n) { // shortcut for verifying if it's NaN + n = 0; + } else if (n != 0 && n != Infinity && n != -Infinity) { + n = (n > 0 || -1) * Math.floor(Math.abs(n)); + } + } + if (n >= len) { + return -1; + } + for (k = n >= 0 ? n : Math.max(len - Math.abs(n), 0); k < len; k++) { + if (k in t && t[k] === searchElement) { + return k; + } + } + return -1; + }; + } + + function extend(destination, source) { + destination.prototype = Object.create(source.prototype); + destination.prototype.constructor = destination; + return source.prototype; + } + + /** + * EventEmitter v4.2.3 - git.io/ee + * Oliver Caldwell + * MIT license + * @preserve + */ + + /** + * Class for managing events. + * Can be extended to provide event functionality in other classes. + * + * @class EventEmitter Manages event registering and emitting. + */ + function EventEmitter() {} + + // Shortcuts to improve speed and size + + // Easy access to the prototype + var proto = EventEmitter.prototype; + + /** + * Finds the index of the listener for the event in it's storage array. + * + * @param {Function[]} listeners Array of listeners to search through. + * @param {Function} listener Method to look for. + * @return {Number} Index of the specified listener, -1 if not found + * @api private + */ + function indexOfListener(listeners, listener) { + var i = listeners.length; + while (i--) { + if (listeners[i].listener === listener) { + return i; + } + } + + return -1; + } + + /** + * Alias a method while keeping the context correct, to allow for overwriting of target method. + * + * @param {String} name The name of the target method. + * @return {Function} The aliased method + * @api private + */ + function alias(name) { + return function aliasClosure() { + return this[name].apply(this, arguments); + }; + } + + /** + * Returns the listener array for the specified event. + * Will initialise the event object and listener arrays if required. + * Will return an object if you use a regex search. The object contains keys for each matched event. So /ba[rz]/ might return an object containing bar and baz. But only if you have either defined them with defineEvent or added some listeners to them. + * Each property in the object response is an array of listener functions. + * + * @param {String|RegExp} evt Name of the event to return the listeners from. + * @return {Function[]|Object} All listener functions for the event. + */ + proto.getListeners = function getListeners(evt) { + var events = this._getEvents(); + var response; + var key; + + // Return a concatenated array of all matching events if + // the selector is a regular expression. + if (typeof evt === 'object') { + response = {}; + for (key in events) { + if (events.hasOwnProperty(key) && evt.test(key)) { + response[key] = events[key]; + } + } + } + else { + response = events[evt] || (events[evt] = []); + } + + return response; + }; + + /** + * Takes a list of listener objects and flattens it into a list of listener functions. + * + * @param {Object[]} listeners Raw listener objects. + * @return {Function[]} Just the listener functions. + */ + proto.flattenListeners = function flattenListeners(listeners) { + var flatListeners = []; + var i; + + for (i = 0; i < listeners.length; i += 1) { + flatListeners.push(listeners[i].listener); + } + + return flatListeners; + }; + + /** + * Fetches the requested listeners via getListeners but will always return the results inside an object. This is mainly for internal use but others may find it useful. + * + * @param {String|RegExp} evt Name of the event to return the listeners from. + * @return {Object} All listener functions for an event in an object. + */ + proto.getListenersAsObject = function getListenersAsObject(evt) { + var listeners = this.getListeners(evt); + var response; + + if (listeners instanceof Array) { + response = {}; + response[evt] = listeners; + } + + return response || listeners; + }; + + /** + * Adds a listener function to the specified event. + * The listener will not be added if it is a duplicate. + * If the listener returns true then it will be removed after it is called. + * If you pass a regular expression as the event name then the listener will be added to all events that match it. + * + * @param {String|RegExp} evt Name of the event to attach the listener to. + * @param {Function} listener Method to be called when the event is emitted. If the function returns true then it will be removed after calling. + * @return {Object} Current instance of EventEmitter for chaining. + */ + proto.addListener = function addListener(evt, listener) { + var listeners = this.getListenersAsObject(evt); + var listenerIsWrapped = typeof listener === 'object'; + var key; + + for (key in listeners) { + if (listeners.hasOwnProperty(key) && indexOfListener(listeners[key], listener) === -1) { + listeners[key].push(listenerIsWrapped ? listener : { + listener: listener, + once: false + }); + } + } + + return this; + }; + + /** + * Alias of addListener + */ + proto.on = alias('addListener'); + + /** + * Semi-alias of addListener. It will add a listener that will be + * automatically removed after it's first execution. + * + * @param {String|RegExp} evt Name of the event to attach the listener to. + * @param {Function} listener Method to be called when the event is emitted. If the function returns true then it will be removed after calling. + * @return {Object} Current instance of EventEmitter for chaining. + */ + proto.addOnceListener = function addOnceListener(evt, listener) { + //noinspection JSValidateTypes + return this.addListener(evt, { + listener: listener, + once: true + }); + }; + + /** + * Alias of addOnceListener. + */ + proto.once = alias('addOnceListener'); + + /** + * Defines an event name. This is required if you want to use a regex to add a listener to multiple events at once. If you don't do this then how do you expect it to know what event to add to? Should it just add to every possible match for a regex? No. That is scary and bad. + * You need to tell it what event names should be matched by a regex. + * + * @param {String} evt Name of the event to create. + * @return {Object} Current instance of EventEmitter for chaining. + */ + proto.defineEvent = function defineEvent(evt) { + this.getListeners(evt); + return this; + }; + + /** + * Uses defineEvent to define multiple events. + * + * @param {String[]} evts An array of event names to define. + * @return {Object} Current instance of EventEmitter for chaining. + */ + proto.defineEvents = function defineEvents(evts) { + for (var i = 0; i < evts.length; i += 1) { + this.defineEvent(evts[i]); + } + return this; + }; + + /** + * Removes a listener function from the specified event. + * When passed a regular expression as the event name, it will remove the listener from all events that match it. + * + * @param {String|RegExp} evt Name of the event to remove the listener from. + * @param {Function} listener Method to remove from the event. + * @return {Object} Current instance of EventEmitter for chaining. + */ + proto.removeListener = function removeListener(evt, listener) { + var listeners = this.getListenersAsObject(evt); + var index; + var key; + + for (key in listeners) { + if (listeners.hasOwnProperty(key)) { + index = indexOfListener(listeners[key], listener); + + if (index !== -1) { + listeners[key].splice(index, 1); + } + } + } + + return this; + }; + + /** + * Alias of removeListener + */ + proto.off = alias('removeListener'); + + /** + * Adds listeners in bulk using the manipulateListeners method. + * If you pass an object as the second argument you can add to multiple events at once. The object should contain key value pairs of events and listeners or listener arrays. You can also pass it an event name and an array of listeners to be added. + * You can also pass it a regular expression to add the array of listeners to all events that match it. + * Yeah, this function does quite a bit. That's probably a bad thing. + * + * @param {String|Object|RegExp} evt An event name if you will pass an array of listeners next. An object if you wish to add to multiple events at once. + * @param {Function[]} [listeners] An optional array of listener functions to add. + * @return {Object} Current instance of EventEmitter for chaining. + */ + proto.addListeners = function addListeners(evt, listeners) { + // Pass through to manipulateListeners + return this.manipulateListeners(false, evt, listeners); + }; + + /** + * Removes listeners in bulk using the manipulateListeners method. + * If you pass an object as the second argument you can remove from multiple events at once. The object should contain key value pairs of events and listeners or listener arrays. + * You can also pass it an event name and an array of listeners to be removed. + * You can also pass it a regular expression to remove the listeners from all events that match it. + * + * @param {String|Object|RegExp} evt An event name if you will pass an array of listeners next. An object if you wish to remove from multiple events at once. + * @param {Function[]} [listeners] An optional array of listener functions to remove. + * @return {Object} Current instance of EventEmitter for chaining. + */ + proto.removeListeners = function removeListeners(evt, listeners) { + // Pass through to manipulateListeners + return this.manipulateListeners(true, evt, listeners); + }; + + /** + * Edits listeners in bulk. The addListeners and removeListeners methods both use this to do their job. You should really use those instead, this is a little lower level. + * The first argument will determine if the listeners are removed (true) or added (false). + * If you pass an object as the second argument you can add/remove from multiple events at once. The object should contain key value pairs of events and listeners or listener arrays. + * You can also pass it an event name and an array of listeners to be added/removed. + * You can also pass it a regular expression to manipulate the listeners of all events that match it. + * + * @param {Boolean} remove True if you want to remove listeners, false if you want to add. + * @param {String|Object|RegExp} evt An event name if you will pass an array of listeners next. An object if you wish to add/remove from multiple events at once. + * @param {Function[]} [listeners] An optional array of listener functions to add/remove. + * @return {Object} Current instance of EventEmitter for chaining. + */ + proto.manipulateListeners = function manipulateListeners(remove, evt, listeners) { + var i; + var value; + var single = remove ? this.removeListener : this.addListener; + var multiple = remove ? this.removeListeners : this.addListeners; + + // If evt is an object then pass each of it's properties to this method + if (typeof evt === 'object' && !(evt instanceof RegExp)) { + for (i in evt) { + if (evt.hasOwnProperty(i) && (value = evt[i])) { + // Pass the single listener straight through to the singular method + if (typeof value === 'function') { + single.call(this, i, value); + } + else { + // Otherwise pass back to the multiple function + multiple.call(this, i, value); + } + } + } + } + else { + // So evt must be a string + // And listeners must be an array of listeners + // Loop over it and pass each one to the multiple method + i = listeners.length; + while (i--) { + single.call(this, evt, listeners[i]); + } + } + + return this; + }; + + /** + * Removes all listeners from a specified event. + * If you do not specify an event then all listeners will be removed. + * That means every event will be emptied. + * You can also pass a regex to remove all events that match it. + * + * @param {String|RegExp} [evt] Optional name of the event to remove all listeners for. Will remove from every event if not passed. + * @return {Object} Current instance of EventEmitter for chaining. + */ + proto.removeEvent = function removeEvent(evt) { + var type = typeof evt; + var events = this._getEvents(); + var key; + + // Remove different things depending on the state of evt + if (type === 'string') { + // Remove all listeners for the specified event + delete events[evt]; + } + else if (type === 'object') { + // Remove all events matching the regex. + for (key in events) { + //noinspection JSUnresolvedFunction + if (events.hasOwnProperty(key) && evt.test(key)) { + delete events[key]; + } + } + } + else { + // Remove all listeners in all events + delete this._events; + } + + return this; + }; + + /** + * Emits an event of your choice. + * When emitted, every listener attached to that event will be executed. + * If you pass the optional argument array then those arguments will be passed to every listener upon execution. + * Because it uses `apply`, your array of arguments will be passed as if you wrote them out separately. + * So they will not arrive within the array on the other side, they will be separate. + * You can also pass a regular expression to emit to all events that match it. + * + * @param {String|RegExp} evt Name of the event to emit and execute listeners for. + * @param {Array} [args] Optional array of arguments to be passed to each listener. + * @return {Object} Current instance of EventEmitter for chaining. + */ + proto.emitEvent = function emitEvent(evt, args) { + var listeners = this.getListenersAsObject(evt); + var listener; + var i; + var key; + var response; + + for (key in listeners) { + if (listeners.hasOwnProperty(key)) { + i = listeners[key].length; + + while (i--) { + // If the listener returns true then it shall be removed from the event + // The function is executed either with a basic call or an apply if there is an args array + listener = listeners[key][i]; + + if (listener.once === true) { + this.removeListener(evt, listener.listener); + } + + response = listener.listener.apply(this, args || []); + + if (response === this._getOnceReturnValue()) { + this.removeListener(evt, listener.listener); + } + } + } + } + + return this; + }; + + /** + * Alias of emitEvent + */ + proto.trigger = alias('emitEvent'); + + //noinspection JSValidateJSDoc,JSCommentMatchesSignature + /** + * Subtly different from emitEvent in that it will pass its arguments on to the listeners, as opposed to taking a single array of arguments to pass on. + * As with emitEvent, you can pass a regex in place of the event name to emit to all events that match it. + * + * @param {String|RegExp} evt Name of the event to emit and execute listeners for. + * @param {...*} Optional additional arguments to be passed to each listener. + * @return {Object} Current instance of EventEmitter for chaining. + */ + proto.emit = function emit(evt) { + var args = Array.prototype.slice.call(arguments, 1); + return this.emitEvent(evt, args); + }; + + /** + * Sets the current value to check against when executing listeners. If a + * listeners return value matches the one set here then it will be removed + * after execution. This value defaults to true. + * + * @param {*} value The new value to check for when executing listeners. + * @return {Object} Current instance of EventEmitter for chaining. + */ + proto.setOnceReturnValue = function setOnceReturnValue(value) { + this._onceReturnValue = value; + return this; + }; + + /** + * Fetches the current value to check against when executing listeners. If + * the listeners return value matches this one then it should be removed + * automatically. It will return true by default. + * + * @return {*|Boolean} The current value to check for or the default, true. + * @api private + */ + proto._getOnceReturnValue = function _getOnceReturnValue() { + if (this.hasOwnProperty('_onceReturnValue')) { + return this._onceReturnValue; + } + else { + return true; + } + }; + + /** + * Fetches the events object and creates one if required. + * + * @return {Object} The events storage object. + * @api private + */ + proto._getEvents = function _getEvents() { + return this._events || (this._events = {}); + }; + + /** + * Mixes in the given objects into the target object by copying the properties. + * @param deep if the copy must be deep + * @param target the target object + * @param objects the objects whose properties are copied into the target + */ + function mixin(deep, target, objects) { + var result = target || {}; + + // Skip first 2 parameters (deep and target), and loop over the others + for (var i = 2; i < arguments.length; ++i) { + var object = arguments[i]; + + if (object === undefined || object === null) { + continue; + } + + for (var propName in object) { + //noinspection JSUnfilteredForInLoop + var prop = fieldValue(object, propName); + //noinspection JSUnfilteredForInLoop + var targ = fieldValue(result, propName); + + // Avoid infinite loops + if (prop === target) { + continue; + } + // Do not mixin undefined values + if (prop === undefined) { + continue; + } + + if (deep && typeof prop === 'object' && prop !== null) { + if (prop instanceof Array) { + //noinspection JSUnfilteredForInLoop + result[propName] = mixin(deep, targ instanceof Array ? targ : [], prop); + } else { + var source = typeof targ === 'object' && !(targ instanceof Array) ? targ : {}; + //noinspection JSUnfilteredForInLoop + result[propName] = mixin(deep, source, prop); + } + } else { + //noinspection JSUnfilteredForInLoop + result[propName] = prop; + } + } + } + + return result; + } + + function fieldValue(object, name) { + try { + return object[name]; + } catch (x) { + return undefined; + } + } + + function endsWith(value, suffix) { + return value.indexOf(suffix, value.length - suffix.length) !== -1; + } + + function stripSlash(value) { + if (value.substring(value.length - 1) == "/") { + value = value.substring(0, value.length - 1); + } + return value; + } + + function isString(value) { + if (value === undefined || value === null) { + return false; + } + return typeof value === 'string' || value instanceof String; + } + + function isFunction(value) { + if (value === undefined || value === null) { + return false; + } + return typeof value === 'function'; + } + + function log(level, args) { + if (window.console) { + var logger = window.console[level]; + if (isFunction(logger)) { + logger.apply(window.console, args); + } + } + } + + function Centrifuge(options) { + this._sockjs = false; + this._status = 'disconnected'; + this._reconnect = true; + this._transport = null; + this._messageId = 0; + this._clientId = null; + this._subscriptions = {}; + this._messages = []; + this._isBatching = false; + this._config = { + retry: 3000, + info: null, + debug: false, + server: null, + protocols_whitelist: [ + 'websocket', + 'xdr-streaming', + 'xhr-streaming', + 'iframe-eventsource', + 'iframe-htmlfile', + 'xdr-polling', + 'xhr-polling', + 'iframe-xhr-polling', + 'jsonp-polling' + ] + }; + if (options) { + this.configure(options); + } + } + + extend(Centrifuge, EventEmitter); + + var centrifuge_proto = Centrifuge.prototype; + + centrifuge_proto._debug = function () { + if (this._config.debug === true) { + log('debug', arguments); + } + }; + + centrifuge_proto._configure = function (configuration) { + this._debug('Configuring centrifuge object with', configuration); + + if (!configuration) { + configuration = {}; + } + + this._config = mixin(false, this._config, configuration); + + if (!this._config.url) { + throw 'Missing required configuration parameter \'url\' specifying the Centrifuge server URL'; + } + + if (!this._config.token) { + throw 'Missing required configuration parameter \'token\' specifying the sign of authorization request'; + } + + if (!this._config.project) { + throw 'Missing required configuration parameter \'project\' specifying project ID in Centrifuge'; + } + + if (!this._config.user && this._config.user !== '') { + throw 'Missing required configuration parameter \'user\' specifying user\'s unique ID in your application'; + } + + if (!this._config.timestamp) { + throw 'Missing required configuration parameter \'timestamp\''; + } + + this._config.url = stripSlash(this._config.url); + + if (endsWith(this._config.url, 'connection')) { + //noinspection JSUnresolvedVariable + if (typeof window.SockJS === 'undefined') { + throw 'You need to include SockJS client library before Centrifuge javascript client library or use pure Websocket connection endpoint'; + } + this._sockjs = true; + } + }; + + centrifuge_proto._setStatus = function (newStatus) { + if (this._status !== newStatus) { + this._debug('Status', this._status, '->', newStatus); + this._status = newStatus; + } + }; + + centrifuge_proto._isDisconnected = function () { + return this._isConnected() === false; + }; + + centrifuge_proto._isConnected = function () { + return this._status === 'connected'; + }; + + centrifuge_proto._nextMessageId = function () { + return ++this._messageId; + }; + + centrifuge_proto._clearSubscriptions = function () { + this._subscriptions = {}; + }; + + centrifuge_proto._send = function (messages) { + // We must be sure that the messages have a clientId. + // This is not guaranteed since the handshake may take time to return + // (and hence the clientId is not known yet) and the application + // may create other messages. + for (var i = 0; i < messages.length; ++i) { + var message = messages[i]; + message.uid = '' + this._nextMessageId(); + + if (this._clientId) { + message.clientId = this._clientId; + } + + this._debug('Send', message); + this._transport.send(JSON.stringify(message)); + } + }; + + centrifuge_proto._connect = function (callback) { + + this._clientId = null; + + this._reconnect = true; + + this._clearSubscriptions(); + + this._setStatus('connecting'); + + var self = this; + + if (callback) { + this.on('connect', callback); + } + + if (this._sockjs === true) { + //noinspection JSUnresolvedFunction + var sockjs_options = { + protocols_whitelist: this._config.protocols_whitelist + }; + if (this._config.server !== null) { + sockjs_options['server'] = this._config.server; + } + + this._transport = new SockJS(this._config.url, null, sockjs_options); + + } else { + this._transport = new WebSocket(this._config.url); + } + + this._setStatus('connecting'); + + this._transport.onopen = function () { + + var centrifugeMessage = { + 'method': 'connect', + 'params': { + 'token': self._config.token, + 'user': self._config.user, + 'project': self._config.project, + 'timestamp': self._config.timestamp + } + }; + + if (self._config.info !== null) { + self._debug("connect using additional info"); + centrifugeMessage['params']['info'] = self._config.info; + } else { + self._debug("connect without additional info"); + } + self.send(centrifugeMessage); + }; + + this._transport.onerror = function (error) { + self._debug(error); + }; + + this._transport.onclose = function () { + self._setStatus('disconnected'); + self.trigger('disconnect'); + if (self._reconnect === true) { + window.setTimeout(function () { + if (self._reconnect === true) { + self._connect.call(self); + } + }, self._config.retry); + } + }; + + this._transport.onmessage = function (event) { + var data; + data = JSON.parse(event.data); + self._debug('Received', data); + self._receive(data); + }; + }; + + centrifuge_proto._disconnect = function () { + this._clientId = null; + this._setStatus('disconnected'); + this._subscriptions = {}; + this._reconnect = false; + this._transport.close(); + }; + + centrifuge_proto._getSubscription = function (channel) { + var subscription; + subscription = this._subscriptions[channel]; + if (!subscription) { + return null; + } + return subscription; + }; + + centrifuge_proto._removeSubscription = function (channel) { + try { + delete this._subscriptions[channel]; + } catch (e) { + this._debug('nothing to delete for channel ', channel); + } + }; + + centrifuge_proto._connectResponse = function (message) { + if (message.error === null) { + this._clientId = message.body; + this._setStatus('connected'); + this.trigger('connect', [message]); + } else { + this.trigger('error', [message]); + this.trigger('connect:error', [message]); + } + }; + + centrifuge_proto._disconnectResponse = function (message) { + if (message.error === null) { + this.disconnect(); + //this.trigger('disconnect', [message]); + //this.trigger('disconnect:success', [message]); + } else { + this.trigger('error', [message]); + this.trigger('disconnect:error', [message.error]); + } + }; + + centrifuge_proto._subscribeResponse = function (message) { + if (message.error !== null) { + this.trigger('error', [message]); + } + var body = message.body; + if (body === null) { + return; + } + var channel = body.channel; + var subscription = this.getSubscription(channel); + if (!subscription) { + return; + } + if (message.error === null) { + subscription.trigger('subscribe:success', [body]); + subscription.trigger('ready', [body]); + } else { + subscription.trigger('subscribe:error', [message.error]); + subscription.trigger('error', [message]); + } + }; + + centrifuge_proto._unsubscribeResponse = function (message) { + var body = message.body; + var channel = body.channel; + var subscription = this.getSubscription(channel); + if (!subscription) { + return; + } + if (message.error === null) { + subscription.trigger('unsubscribe', [body]); + this._centrifuge._removeSubscription(channel); + } + }; + + centrifuge_proto._publishResponse = function (message) { + var body = message.body; + var channel = body.channel; + var subscription = this.getSubscription(channel); + if (!subscription) { + return; + } + if (message.error === null) { + subscription.trigger('publish:success', [body]); + } else { + subscription.trigger('publish:error', [message.error]); + this.trigger('error', [message]); + } + }; + + centrifuge_proto._presenceResponse = function (message) { + var body = message.body; + var channel = body.channel; + var subscription = this.getSubscription(channel); + if (!subscription) { + return; + } + if (message.error === null) { + subscription.trigger('presence', [body]); + subscription.trigger('presence:success', [body]); + } else { + subscription.trigger('presence:error', [message.error]); + this.trigger('error', [message]); + } + }; + + centrifuge_proto._historyResponse = function (message) { + var body = message.body; + var channel = body.channel; + var subscription = this.getSubscription(channel); + if (!subscription) { + return; + } + if (message.error === null) { + subscription.trigger('history', [body]); + subscription.trigger('history:success', [body]); + } else { + subscription.trigger('history:error', [message.error]); + this.trigger('error', [message]); + } + }; + + centrifuge_proto._joinResponse = function(message) { + var body = message.body; + var channel = body.channel; + var subscription = this.getSubscription(channel); + if (!subscription) { + return; + } + subscription.trigger('join', [body]); + }; + + centrifuge_proto._leaveResponse = function(message) { + var body = message.body; + var channel = body.channel; + var subscription = this.getSubscription(channel); + if (!subscription) { + return; + } + subscription.trigger('leave', [body]); + }; + + centrifuge_proto._messageResponse = function (message) { + var body = message.body; + var channel = body.channel; + var subscription = this.getSubscription(channel); + if (subscription === null) { + return; + } + subscription.trigger('message', [body]); + }; + + centrifuge_proto._dispatchMessage = function(message) { + if (message === undefined || message === null) { + return; + } + + var method = message.method; + + if (!method) { + return; + } + + switch (method) { + case 'connect': + this._connectResponse(message); + break; + case 'disconnect': + this._disconnectResponse(message); + break; + case 'subscribe': + this._subscribeResponse(message); + break; + case 'unsubscribe': + this._unsubscribeResponse(message); + break; + case 'publish': + this._publishResponse(message); + break; + case 'presence': + this._presenceResponse(message); + break; + case 'history': + this._historyResponse(message); + break; + case 'join': + this._joinResponse(message); + break; + case 'leave': + this._leaveResponse(message); + break; + case 'ping': + break; + case 'message': + this._messageResponse(message); + break; + default: + break; + } + }; + + centrifuge_proto._receive = function (data) { + if (Object.prototype.toString.call(data) === Object.prototype.toString.call([])) { + for (var i in data) { + if (data.hasOwnProperty(i)) { + var msg = data[i]; + this._dispatchMessage(msg); + } + } + } else if (Object.prototype.toString.call(data) === Object.prototype.toString.call({})) { + this._dispatchMessage(data); + } + }; + + centrifuge_proto._flush = function() { + var messages = this._messages.slice(0); + this._messages = []; + this._send(messages); + }; + + centrifuge_proto._ping = function () { + var centrifugeMessage = { + "method": "ping", + "params": {} + }; + this.send(centrifugeMessage); + }; + + /* PUBLIC API */ + + centrifuge_proto.getClientId = function () { + return this._clientId; + }; + + centrifuge_proto.isConnected = centrifuge_proto._isConnected; + + centrifuge_proto.isDisconnected = centrifuge_proto._isDisconnected; + + centrifuge_proto.configure = function (configuration) { + this._configure.call(this, configuration); + }; + + centrifuge_proto.connect = centrifuge_proto._connect; + + centrifuge_proto.disconnect = centrifuge_proto._disconnect; + + centrifuge_proto.getSubscription = centrifuge_proto._getSubscription; + + centrifuge_proto.ping = centrifuge_proto._ping; + + centrifuge_proto.send = function (message) { + if (this._isBatching === true) { + this._messages.push(message); + } else { + this._send([message]); + } + }; + + centrifuge_proto.startBatching = function () { + // start collecting messages without sending them to Centrifuge until flush + // method called + this._isBatching = true; + }; + + centrifuge_proto.stopBatching = function(flush) { + // stop collecting messages + flush = flush || false; + this._isBatching = false; + if (flush === true) { + this.flush(); + } + }; + + centrifuge_proto.flush = function() { + this._flush(); + }; + + centrifuge_proto.subscribe = function (channel, callback) { + + if (arguments.length < 1) { + throw 'Illegal arguments number: required 1, got ' + arguments.length; + } + if (!isString(channel)) { + throw 'Illegal argument type: channel must be a string'; + } + if (this.isDisconnected()) { + throw 'Illegal state: already disconnected'; + } + + var current_subscription = this.getSubscription(channel); + + if (current_subscription !== null) { + return current_subscription; + } else { + var subscription = new Subscription(this, channel); + this._subscriptions[channel] = subscription; + subscription.subscribe(callback); + return subscription; + } + }; + + centrifuge_proto.unsubscribe = function (channel) { + if (arguments.length < 1) { + throw 'Illegal arguments number: required 1, got ' + arguments.length; + } + if (!isString(channel)) { + throw 'Illegal argument type: channel must be a string'; + } + if (this.isDisconnected()) { + return; + } + + var subscription = this.getSubscription(channel); + if (subscription !== null) { + subscription.unsubscribe(); + } + }; + + centrifuge_proto.publish = function (channel, data, callback) { + var subscription = this.getSubscription(channel); + if (subscription === null) { + this._debug("subscription not found for channel " + channel); + return null; + } + subscription.publish(data, callback); + return subscription; + }; + + centrifuge_proto.presence = function (channel, callback) { + var subscription = this.getSubscription(channel); + if (subscription === null) { + this._debug("subscription not found for channel " + channel); + return null; + } + subscription.presence(callback); + return subscription; + }; + + centrifuge_proto.history = function (channel, callback) { + var subscription = this.getSubscription(channel); + if (subscription === null) { + this._debug("subscription not found for channel " + channel); + return null; + } + subscription.history(callback); + return subscription; + }; + + function Subscription(centrifuge, channel) { + /** + * The constructor for a centrifuge object, identified by an optional name. + * The default name is the string 'default'. + * @param name the optional name of this centrifuge object + */ + this._centrifuge = centrifuge; + this.channel = channel; + } + + extend(Subscription, EventEmitter); + + var sub_proto = Subscription.prototype; + + sub_proto.getChannel = function () { + return this.channel; + }; + + sub_proto.getCentrifuge = function () { + return this._centrifuge; + }; + + sub_proto.subscribe = function (callback) { + var centrifugeMessage = { + "method": "subscribe", + "params": { + "channel": this.channel + } + }; + this._centrifuge.send(centrifugeMessage); + if (callback) { + this.on('message', callback); + } + }; + + sub_proto.unsubscribe = function () { + this._centrifuge._removeSubscription(this.channel); + var centrifugeMessage = { + "method": "unsubscribe", + "params": { + "channel": this.channel + } + }; + this._centrifuge.send(centrifugeMessage); + }; + + sub_proto.publish = function (data, callback) { + var centrifugeMessage = { + "method": "publish", + "params": { + "channel": this.channel, + "data": data + } + }; + if (callback) { + this.on('publish:success', callback); + } + this._centrifuge.send(centrifugeMessage); + }; + + sub_proto.presence = function (callback) { + var centrifugeMessage = { + "method": "presence", + "params": { + "channel": this.channel + } + }; + if (callback) { + this.on('presence', callback); + } + this._centrifuge.send(centrifugeMessage); + }; + + sub_proto.history = function (callback) { + var centrifugeMessage = { + "method": "history", + "params": { + "channel": this.channel + } + }; + if (callback) { + this.on('history', callback); + } + this._centrifuge.send(centrifugeMessage); + }; + + // Expose the class either via AMD, CommonJS or the global object + if (typeof define === 'function' && define.amd) { + define(function () { + return Centrifuge; + }); + } else if (typeof module === 'object' && module.exports) { + //noinspection JSUnresolvedVariable + module.exports = Centrifuge; + } else { + //noinspection JSUnusedGlobalSymbols + this.Centrifuge = Centrifuge; + } + +}.call(this)); diff --git a/boards/static/js/thread_update.js b/boards/static/js/thread_update.js --- a/boards/static/js/thread_update.js +++ b/boards/static/js/thread_update.js @@ -3,7 +3,7 @@ JavaScript code in this page. - Copyright (C) 2013 neko259 + Copyright (C) 2013-2014 neko259 The JavaScript code in this page is free software: you can redistribute it and/or modify it under the terms of the GNU @@ -23,12 +23,140 @@ for the JavaScript code in this page. */ -var THREAD_UPDATE_DELAY = 10000; +var wsUser = ''; var loading = false; -var lastUpdateTime = null; var unreadPosts = 0; +var documentOriginalTitle = ''; +// Thread ID does not change, can be stored one time +var threadId = $('div.thread').children('.post').first().attr('id'); + +/** + * Connect to websocket server and subscribe to thread updates. On any update we + * request a thread diff. + * + * @returns {boolean} true if connected, false otherwise + */ +function connectWebsocket() { + var metapanel = $('.metapanel')[0]; + + var wsHost = metapanel.getAttribute('data-ws-host'); + var wsPort = metapanel.getAttribute('data-ws-port'); + + if (wsHost.length > 0 && wsPort.length > 0) + var centrifuge = new Centrifuge({ + "url": 'ws://' + wsHost + ':' + wsPort + "/connection/websocket", + "project": metapanel.getAttribute('data-ws-project'), + "user": wsUser, + "timestamp": metapanel.getAttribute('data-last-update'), + "token": metapanel.getAttribute('data-ws-token'), + "debug": false + }); + + centrifuge.on('error', function(error_message) { + console.log("Error connecting to websocket server."); + return false; + }); + + centrifuge.on('connect', function() { + var channelName = 'thread:' + threadId; + centrifuge.subscribe(channelName, function(message) { + getThreadDiff(); + }); + + // For the case we closed the browser and missed some updates + getThreadDiff(); + $('#autoupdate').text('[+]'); + }); + + centrifuge.connect(); + + return true; +} + +/** + * Get diff of the posts from the current thread timestamp. + * This is required if the browser was closed and some post updates were + * missed. + */ +function getThreadDiff() { + var lastUpdateTime = $('.metapanel').attr('data-last-update'); + + var diffUrl = '/api/diff_thread/' + threadId + '/' + lastUpdateTime + '/'; + + $.getJSON(diffUrl) + .success(function(data) { + var addedPosts = data.added; + + for (var i = 0; i < addedPosts.length; i++) { + var postText = addedPosts[i]; + var post = $(postText); + + updatePost(post) + + lastPost = post; + } + + var updatedPosts = data.updated; + + for (var i = 0; i < updatedPosts.length; i++) { + var postText = updatedPosts[i]; + var post = $(postText); + + updatePost(post) + } + + // TODO Process removed posts if any + $('.metapanel').attr('data-last-update', data.last_update); + }) +} + +/** + * Add or update the post on html page. + */ +function updatePost(postHtml) { + // This needs to be set on start because the page is scrolled after posts + // are added or updated + var bottom = isPageBottom(); + + var post = $(postHtml); + + var threadBlock = $('div.thread'); + + var lastUpdate = ''; + + var postId = post.attr('id'); + + // If the post already exists, replace it. Otherwise add as a new one. + var existingPosts = threadBlock.children('.post[id=' + postId + ']'); + + if (existingPosts.size() > 0) { + existingPosts.replaceWith(post); + } else { + var threadPosts = threadBlock.children('.post'); + var lastPost = threadPosts.last(); + + post.appendTo(lastPost.parent()); + + updateBumplimitProgress(1); + showNewPostsTitle(1); + + lastUpdate = post.children('.post-info').first() + .children('.pub_time').first().text(); + + if (bottom) { + scrollToBottom(); + } + } + + processNewPost(post); + updateMetadataPanel(lastUpdate) +} + +/** + * Initiate a blinking animation on a node to show it was updated. + */ function blink(node) { var blinkCount = 2; @@ -38,103 +166,15 @@ function blink(node) { } } -function updateThread() { - if (loading) { - return; - } - - loading = true; - - var threadPosts = $('div.thread').children('.post'); - - var lastPost = threadPosts.last(); - var threadId = threadPosts.first().attr('id'); - - var diffUrl = '/api/diff_thread/' + threadId + '/' + lastUpdateTime + '/'; - $.getJSON(diffUrl) - .success(function(data) { - var bottom = isPageBottom(); - - var lastUpdate = ''; - - var addedPosts = data.added; - for (var i = 0; i < addedPosts.length; i++) { - var postText = addedPosts[i]; - - var post = $(postText); - - if (lastUpdate === '') { - lastUpdate = post.find('.pub_time').text(); - } - - post.appendTo(lastPost.parent()); - processNewPost(post); - - lastPost = post; - blink(post); - } - - var updatedPosts = data.updated; - for (var i = 0; i < updatedPosts.length; i++) { - var postText = updatedPosts[i]; - - var post = $(postText); - - if (lastUpdate === '') { - lastUpdate = post.find('.pub_time').text(); - } - - var postId = post.attr('id'); - - var oldPost = $('div.thread').children('.post[id=' + postId + ']'); - - oldPost.replaceWith(post); - processNewPost(post); - - blink(post); - } - - // TODO Process deleted posts - - lastUpdateTime = data.last_update; - loading = false; - - if (bottom) { - scrollToBottom(); - } - - var hasPostChanges = (updatedPosts.length > 0) - || (addedPosts.length > 0); - if (hasPostChanges) { - updateMetadataPanel(lastUpdate); - } - - updateBumplimitProgress(data.added.length); - - if (data.added.length + data.updated.length > 0) { - showNewPostsTitle(data.added.length); - } - }) - .error(function(data) { - // TODO Show error message that server is unavailable? - - loading = false; - }); -} - function isPageBottom() { var scroll = $(window).scrollTop() / ($(document).height() - - $(window).height()) + - $(window).height()); return scroll == 1 } function initAutoupdate() { - loading = false; - - lastUpdateTime = $('.metapanel').attr('data-last-update'); - - setInterval(updateThread, THREAD_UPDATE_DELAY); + return connectWebsocket(); } function getReplyCount() { @@ -145,6 +185,10 @@ function getImageCount() { return $('.thread').find('img').length } +/** + * Update post count, images count and last update time in the metadata + * panel. + */ function updateMetadataPanel(lastUpdate) { var replyCountField = $('#reply-count'); var imageCountField = $('#image-count'); @@ -185,7 +229,6 @@ function updateBumplimitProgress(postDel } } -var documentOriginalTitle = ''; /** * Show 'new posts' text in the title if the document is not visible to a user */ @@ -230,7 +273,7 @@ function updateOnPost(response, statusTe if (status === 'ok') { resetForm(form); - updateThread(); + getThreadDiff(); } else { var errors = json.errors; for (var i = 0; i < errors.length; i++) { @@ -241,6 +284,8 @@ function updateOnPost(response, statusTe showAsErrors(form, error); } } + + scrollToBottom(); } /** @@ -264,25 +309,26 @@ function showAsErrors(form, text) { function processNewPost(post) { addRefLinkPreview(post[0]); highlightCode(post); + blink(post); } $(document).ready(function(){ - initAutoupdate(); + if (initAutoupdate()) { + // Post form data over AJAX + var threadId = $('div.thread').children('.post').first().attr('id'); - // Post form data over AJAX - var threadId = $('div.thread').children('.post').first().attr('id'); - - var form = $('#form'); + var form = $('#form'); - var options = { - beforeSubmit: function(arr, $form, options) { - showAsErrors($('form'), gettext('Sending message...')); - }, - success: updateOnPost, - url: '/api/add_post/' + threadId + '/' - }; + var options = { + beforeSubmit: function(arr, $form, options) { + showAsErrors($('form'), gettext('Sending message...')); + }, + success: updateOnPost, + url: '/api/add_post/' + threadId + '/' + }; - form.ajaxForm(options); + form.ajaxForm(options); - resetForm(form); + resetForm(form); + } }); diff --git a/boards/templates/boards/base.html b/boards/templates/boards/base.html --- a/boards/templates/boards/base.html +++ b/boards/templates/boards/base.html @@ -9,6 +9,7 @@ + {% trans "All threads" %} {% for tag in tags %} - #{{ tag.name }}, + {% autoescape off %} + {{ tag.get_view }}{% if not forloop.last %},{% endif %} + {% endautoescape %} {% endfor %} [...], @@ -39,9 +41,9 @@ {% block content %}{% endblock %} + - diff --git a/boards/templates/boards/post.html b/boards/templates/boards/post.html --- a/boards/templates/boards/post.html +++ b/boards/templates/boards/post.html @@ -4,101 +4,99 @@ {% get_current_language as LANGUAGE_CODE %} -{% spaceless %} - {% cache 600 post post.id post.last_edit_time thread.archived bumpable truncated moderator LANGUAGE_CODE need_open_link %} - {% if thread.archived %} -
- {% elif bumpable %} -
- {% else %} -
- {% endif %} +{% if thread.archived %} +
+{% elif bumpable %} +
+{% else %} +
+{% endif %} - +{% endif %} +
diff --git a/boards/templates/boards/post_admin.html b/boards/templates/boards/post_admin.html deleted file mode 100644 --- a/boards/templates/boards/post_admin.html +++ /dev/null @@ -1,38 +0,0 @@ -{% extends "boards/base.html" %} - -{% load i18n %} -{% load cache %} -{% load static from staticfiles %} -{% load board %} - -{% block head %} -#{{ post.id }} - {{ site_name }} -{% endblock %} - -{% block content %} - {% spaceless %} - - {% post_view post moderator=moderator %} - - {% if post.is_opening %} -
- {% trans 'Tags:' %} - {% for tag in post.thread_new.get_tags %} - #{{ tag.name }} - [X] - {% if not forloop.last %},{% endif %} - {% endfor %} -
-
{% csrf_token %} - {{ tag_form.as_div }} -
- -
-
-
-
- {% endif %} - - {% endspaceless %} -{% endblock %} diff --git a/boards/templates/boards/posting_general.html b/boards/templates/boards/posting_general.html --- a/boards/templates/boards/posting_general.html +++ b/boards/templates/boards/posting_general.html @@ -15,7 +15,7 @@ {% if current_page.has_previous %} {% if tag in fav_tags %} + class="fav" rel="nofollow">★ {% else %} + class="not_fav" rel="nofollow">★ {% endif %} {% if tag in hidden_tags %} H + class="fav" rel="nofollow">H {% else %} H + class="not_fav" rel="nofollow">H {% endif %} - #{{ tag.name }} + {% autoescape off %} + {{ tag.get_view }} + {% endautoescape %} + {% if moderator %} + [{% trans 'Edit tag' %}] + {% endif %}
{% endif %} @@ -70,7 +75,7 @@ diff --git a/boards/templates/boards/tags.html b/boards/templates/boards/tags.html --- a/boards/templates/boards/tags.html +++ b/boards/templates/boards/tags.html @@ -14,8 +14,9 @@ {% if all_tags %} {% for tag in all_tags %}
- - #{{ tag.name }} + {% autoescape off %} + {{ tag.get_view }} + {% endautoescape %}
{% endfor %} {% else %} diff --git a/boards/templates/boards/thread.html b/boards/templates/boards/thread.html --- a/boards/templates/boards/thread.html +++ b/boards/templates/boards/thread.html @@ -11,7 +11,6 @@ {% endblock %} {% block content %} - {% spaceless %} {% get_current_language as LANGUAGE_CODE %} {% cache 600 thread_view thread.id thread.last_edit_time moderator LANGUAGE_CODE %} @@ -34,57 +33,59 @@
{% with can_bump=thread.can_bump %} {% for post in thread.get_replies %} - {% if forloop.first %} - {% post_view post moderator=moderator is_opening=True thread=thread can_bump=can_bump opening_post_id=opening_post.id %} - {% else %} - {% post_view post moderator=moderator is_opening=False thread=thread can_bump=can_bump opening_post_id=opening_post.id %} - {% endif %} + {% with is_opening=forloop.first %} + {% post_view post moderator=moderator is_opening=is_opening thread=thread bumpable=can_bump opening_post_id=opening_post.id %} + {% endwith %} {% endfor %} {% endwith %}
{% if not thread.archived %} - -
- -
{% trans "Reply to thread" %} #{{ opening_post.id }}
-
-
-
{% csrf_token %} +
+ +
{% trans "Reply to thread" %} #{{ opening_post.id }}
+
+
+ {% csrf_token %}
- {{ form.as_div }} -
- -
- + {{ form.as_div }} +
+ +
+ +
+ + {% trans 'Switch mode' %} + +
- - {% trans 'Switch mode' %} - -
-
- - + + + {% endif %} {% endcache %} - - {% endspaceless %} {% endblock %} {% block metapanel %} {% get_current_language as LANGUAGE_CODE %} - + {% cache 600 thread_meta thread.last_edit_time moderator LANGUAGE_CODE %} + [-] {{ thread.get_reply_count }}/{{ max_replies }} {% trans 'messages' %}, {{ thread.get_images_count }} {% trans 'images' %}. {% trans 'Last update: ' %}{{ thread.last_edit_time }} diff --git a/boards/templates/search/search.html b/boards/templates/search/search.html --- a/boards/templates/search/search.html +++ b/boards/templates/search/search.html @@ -25,7 +25,7 @@ {% endif %} {% for result in page.object_list %} - {{ result.object.get_view }} + {{ result.object.get_search_view }} {% endfor %} {% if page.has_next %} @@ -35,4 +35,4 @@
{% endif %} {% endif %} -{% endblock %} \ No newline at end of file +{% endblock %} diff --git a/boards/tests/test_forms.py b/boards/tests/test_forms.py --- a/boards/tests/test_forms.py +++ b/boards/tests/test_forms.py @@ -1,7 +1,7 @@ from django.test import TestCase, Client import time from boards import settings -from boards.models import Post +from boards.models import Post, Tag import neboard @@ -22,6 +22,7 @@ class FormTest(TestCase): valid_tags = 'tag1 tag_2 тег_3' invalid_tags = '$%_356 ---' + Tag.objects.create(name='tag1', required=True) response = client.post(NEW_THREAD_PAGE, {'title': 'test title', 'text': TEST_TEXT, diff --git a/boards/tests/test_pages.py b/boards/tests/test_pages.py --- a/boards/tests/test_pages.py +++ b/boards/tests/test_pages.py @@ -7,12 +7,10 @@ NEW_THREAD_PAGE = '/' THREAD_PAGE_ONE = '/thread/1/' THREAD_PAGE = '/thread/' TAG_PAGE = '/tag/' -HTTP_CODE_REDIRECT = 302 +HTTP_CODE_REDIRECT = 301 HTTP_CODE_OK = 200 HTTP_CODE_NOT_FOUND = 404 -PAGE_404 = 'boards/404.html' - class PagesTest(TestCase): @@ -33,7 +31,7 @@ class PagesTest(TestCase): response_not_existing = client.get(THREAD_PAGE + str( existing_post_id + 1) + '/') - self.assertEqual(PAGE_404, response_not_existing.templates[0].name, + self.assertEqual(HTTP_CODE_NOT_FOUND, response_not_existing.status_code, 'Not existing thread is opened') response_existing = client.get(TAG_PAGE + tag_name + '/') @@ -42,8 +40,7 @@ class PagesTest(TestCase): 'Cannot open existing tag') response_not_existing = client.get(TAG_PAGE + 'not_tag' + '/') - self.assertEqual(PAGE_404, - response_not_existing.templates[0].name, + self.assertEqual(HTTP_CODE_NOT_FOUND, response_not_existing.status_code, 'Not existing tag is opened') reply_id = Post.objects.create_post('', TEST_TEXT, @@ -51,6 +48,5 @@ class PagesTest(TestCase): .get_thread()) response_not_existing = client.get(THREAD_PAGE + str( reply_id) + '/') - self.assertEqual(PAGE_404, - response_not_existing.templates[0].name, + self.assertEqual(HTTP_CODE_REDIRECT, response_not_existing.status_code, 'Reply is opened as a thread') diff --git a/boards/tests/test_parser.py b/boards/tests/test_parser.py new file mode 100644 --- /dev/null +++ b/boards/tests/test_parser.py @@ -0,0 +1,27 @@ +from django.test import TestCase +from boards.models import Post + + +class ParserTest(TestCase): + def test_preparse_quote(self): + raw_text = '>quote\nQuote in >line\nLine\n>Quote' + preparsed_text = Post.objects._preparse_text(raw_text) + + self.assertEqual( + '[quote]quote[/quote]\nQuote in >line\nLine\n[quote]Quote[/quote]', + preparsed_text, 'Quote not preparsed.') + + def test_preparse_comment(self): + raw_text = '//comment' + preparsed_text = Post.objects._preparse_text(raw_text) + + self.assertEqual('[comment]comment[/comment]', preparsed_text, + 'Comment not preparsed.') + + def test_preparse_reflink(self): + raw_text = '>>12\nText' + preparsed_text = Post.objects._preparse_text(raw_text) + + self.assertEqual('[post]12[/post]\nText', + preparsed_text, 'Reflink not preparsed.') + diff --git a/boards/tests/test_post.py b/boards/tests/test_post.py --- a/boards/tests/test_post.py +++ b/boards/tests/test_post.py @@ -26,7 +26,7 @@ class PostTests(TestCase): post = self._create_post() post_id = post.id - Post.objects.delete_post(post) + post.delete() self.assertFalse(Post.objects.filter(id=post_id).exists()) @@ -37,9 +37,12 @@ class PostTests(TestCase): thread = opening_post.get_thread() reply = Post.objects.create_post("", "", thread=thread) - thread.delete() + opening_post.delete() - self.assertFalse(Post.objects.filter(id=reply.id).exists()) + self.assertFalse(Post.objects.filter(id=reply.id).exists(), + 'Reply was not deleted with the thread.') + self.assertFalse(Post.objects.filter(id=opening_post.id).exists(), + 'Opening post was not deleted with the thread.') def test_post_to_thread(self): """Test adding post to a thread""" @@ -84,7 +87,6 @@ class PostTests(TestCase): thread = post.get_thread() self.assertIsNotNone(post, 'Post not created') self.assertTrue(tag in thread.tags.all(), 'Tag not added to thread') - self.assertTrue(thread in tag.threads.all(), 'Thread not added to tag') def test_thread_max_count(self): """Test deletion of old posts when the max thread count is reached""" @@ -139,4 +141,23 @@ class PostTests(TestCase): self.assertTrue(post_global_reflink in post.referenced_posts.all(), 'Global reflink not connecting posts.') - # TODO Check that links are parsed into the rendered text + def test_thread_replies(self): + """ + Tests that the replies can be queried from a thread in all possible + ways. + """ + + tag = Tag.objects.create(name='test_tag') + opening_post = Post.objects.create_post(title='title', text='text', + tags=[tag]) + thread = opening_post.get_thread() + + reply1 = Post.objects.create_post(title='title', text='text', thread=thread) + reply2 = Post.objects.create_post(title='title', text='text', thread=thread) + + replies = thread.get_replies() + self.assertTrue(len(replies) > 0, 'No replies found for thread.') + + replies = thread.get_replies(view_fields_only=True) + self.assertTrue(len(replies) > 0, + 'No replies found for thread with view fields only.') diff --git a/boards/tests/test_views.py b/boards/tests/test_views.py --- a/boards/tests/test_views.py +++ b/boards/tests/test_views.py @@ -8,6 +8,10 @@ logger = logging.getLogger(__name__) HTTP_CODE_OK = 200 +EXCLUDED_VIEWS = { + 'banned', +} + class ViewTest(TestCase): @@ -21,13 +25,17 @@ class ViewTest(TestCase): for url in urls.urlpatterns: try: view_name = url.name + if view_name in EXCLUDED_VIEWS: + logger.debug('View {} is excluded.'.format(view_name)) + continue + logger.debug('Testing view %s' % view_name) try: response = client.get(reverse(view_name)) self.assertEqual(HTTP_CODE_OK, response.status_code, - '%s view not opened' % view_name) + 'View not opened: {}'.format(view_name)) except NoReverseMatch: # This view just needs additional arguments pass diff --git a/boards/thumbs.py b/boards/thumbs.py --- a/boards/thumbs.py +++ b/boards/thumbs.py @@ -212,8 +212,4 @@ class ImageWithThumbsField(ImageField): thumb_height_ratio = int(original_height * scale_ratio) setattr(instance, thumb_width_field, thumb_width_ratio) - setattr(instance, thumb_height_field, thumb_height_ratio) - - -from south.modelsinspector import add_introspection_rules -add_introspection_rules([], ["^boards\.thumbs\.ImageWithThumbsField"]) + setattr(instance, thumb_height_field, thumb_height_ratio) \ No newline at end of file diff --git a/boards/urls.py b/boards/urls.py --- a/boards/urls.py +++ b/boards/urls.py @@ -5,11 +5,9 @@ from boards.rss import AllThreadsFeed, T from boards.views import api, tag_threads, all_threads, \ settings, all_tags from boards.views.authors import AuthorsView -from boards.views.delete_post import DeletePostView from boards.views.ban import BanUserView from boards.views.search import BoardSearchView from boards.views.static import StaticPageView -from boards.views.post_admin import PostAdminView from boards.views.preview import PostPreviewView from boards.views.sync import get_post_sync_data @@ -37,15 +35,9 @@ urlpatterns = patterns('', url(r'^thread/(?P\w+)/mode/(?P\w+)/$', views.thread.ThreadView .as_view(), name='thread_mode'), - # /boards/post_admin/ - url(r'^post_admin/(?P\w+)/$', PostAdminView.as_view(), - name='post_admin'), - url(r'^settings/$', settings.SettingsView.as_view(), name='settings'), url(r'^tags/$', all_tags.AllTagsView.as_view(), name='tags'), url(r'^authors/$', AuthorsView.as_view(), name='authors'), - url(r'^delete/(?P\w+)/$', DeletePostView.as_view(), - name='delete'), url(r'^ban/(?P\w+)/$', BanUserView.as_view(), name='ban'), url(r'^banned/$', views.banned.BannedView.as_view(), name='banned'), diff --git a/boards/utils.py b/boards/utils.py --- a/boards/utils.py +++ b/boards/utils.py @@ -1,8 +1,8 @@ """ This module contains helper functions and helper classes. """ -import hashlib import time +import hmac from django.utils import timezone @@ -14,55 +14,6 @@ KEY_CAPTCHA_DELAY_TIME = 'key_captcha_de KEY_CAPTCHA_LAST_ACTIVITY = 'key_captcha_last_activity' -def need_include_captcha(request): - """ - Check if request is made by a user. - It contains rules which check for bots. - """ - - if not settings.ENABLE_CAPTCHA: - return False - - enable_captcha = False - - #newcomer - if KEY_CAPTCHA_LAST_ACTIVITY not in request.session: - return settings.ENABLE_CAPTCHA - - last_activity = request.session[KEY_CAPTCHA_LAST_ACTIVITY] - current_delay = int(time.time()) - last_activity - - delay_time = (request.session[KEY_CAPTCHA_DELAY_TIME] - if KEY_CAPTCHA_DELAY_TIME in request.session - else settings.CAPTCHA_DEFAULT_SAFE_TIME) - - if current_delay < delay_time: - enable_captcha = True - - return enable_captcha - - -def update_captcha_access(request, passed): - """ - Update captcha fields. - It will reduce delay time if user passed captcha verification and - it will increase it otherwise. - """ - session = request.session - - delay_time = (request.session[KEY_CAPTCHA_DELAY_TIME] - if KEY_CAPTCHA_DELAY_TIME in request.session - else settings.CAPTCHA_DEFAULT_SAFE_TIME) - - if passed: - delay_time -= 2 if delay_time >= 7 else 5 - else: - delay_time += 10 - - session[KEY_CAPTCHA_LAST_ACTIVITY] = int(time.time()) - session[KEY_CAPTCHA_DELAY_TIME] = delay_time - - def get_client_ip(request): x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR') if x_forwarded_for: @@ -76,3 +27,17 @@ def datetime_to_epoch(datetime): return int(time.mktime(timezone.localtime( datetime,timezone.get_current_timezone()).timetuple()) * 1000000 + datetime.microsecond) + + +def get_websocket_token(user_id='', timestamp=''): + """ + Create token to validate information provided by new connection. + """ + + sign = hmac.new(settings.CENTRIFUGE_PROJECT_SECRET.encode()) + sign.update(settings.CENTRIFUGE_PROJECT_ID.encode()) + sign.update(user_id.encode()) + sign.update(timestamp.encode()) + token = sign.hexdigest() + + return token \ No newline at end of file diff --git a/boards/views/all_tags.py b/boards/views/all_tags.py --- a/boards/views/all_tags.py +++ b/boards/views/all_tags.py @@ -7,7 +7,8 @@ from boards.models.tag import Tag class AllTagsView(BaseBoardView): def get(self, request): - context = self.get_context_data(request=request) - context['all_tags'] = Tag.objects.get_not_empty_tags() + params = dict() - return render(request, 'boards/tags.html', context) + params['all_tags'] = Tag.objects.get_not_empty_tags() + + return render(request, 'boards/tags.html', params) diff --git a/boards/views/all_threads.py b/boards/views/all_threads.py --- a/boards/views/all_threads.py +++ b/boards/views/all_threads.py @@ -1,5 +1,3 @@ -import string - from django.db import transaction from django.shortcuts import render, redirect @@ -12,6 +10,7 @@ from boards.views.banned import BannedVi from boards.views.base import BaseBoardView, CONTEXT_FORM from boards.views.posting_mixin import PostMixin + FORM_TAGS = 'tags' FORM_TEXT = 'text' FORM_TITLE = 'title' @@ -34,7 +33,7 @@ class AllThreadsView(PostMixin, BaseBoar super(AllThreadsView, self).__init__() def get(self, request, page=DEFAULT_PAGE, form=None): - context = self.get_context_data(request=request) + params = self.get_context_data(request=request) if not form: form = ThreadForm(error_class=PlainErrorList) @@ -46,12 +45,12 @@ class AllThreadsView(PostMixin, BaseBoar threads = paginator.page(page).object_list - context[PARAMETER_THREADS] = threads - context[CONTEXT_FORM] = form + params[PARAMETER_THREADS] = threads + params[CONTEXT_FORM] = form - self._get_page_context(paginator, context, page) + self._get_page_context(paginator, params, page) - return render(request, TEMPLATE, context) + return render(request, TEMPLATE, params) def post(self, request, page=DEFAULT_PAGE): form = ThreadForm(request.POST, request.FILES, @@ -66,14 +65,13 @@ class AllThreadsView(PostMixin, BaseBoar return self.get(request, page, form) - @staticmethod - def _get_page_context(paginator, context, page): + def _get_page_context(self, paginator, params, page): """ Get pagination context variables """ - context[PARAMETER_PAGINATOR] = paginator - context[PARAMETER_CURRENT_PAGE] = paginator.page(int(page)) + params[PARAMETER_PAGINATOR] = paginator + params[PARAMETER_CURRENT_PAGE] = paginator.page(int(page)) @staticmethod def parse_tags_string(tag_strings): @@ -112,14 +110,10 @@ class AllThreadsView(PostMixin, BaseBoar title = data[FORM_TITLE] text = data[FORM_TEXT] + image = data.get(FORM_IMAGE) text = self._remove_invalid_links(text) - if FORM_IMAGE in list(data.keys()): - image = data[FORM_IMAGE] - else: - image = None - tag_strings = data[FORM_TAGS] tags = self.parse_tags_string(tag_strings) @@ -127,6 +121,10 @@ class AllThreadsView(PostMixin, BaseBoar post = Post.objects.create_post(title=title, text=text, image=image, ip=ip, tags=tags) + # This is required to update the threads to which posts we have replied + # when creating this one + post.send_to_websocket(request) + if html_response: return redirect(post.get_url()) diff --git a/boards/views/api.py b/boards/views/api.py --- a/boards/views/api.py +++ b/boards/views/api.py @@ -7,7 +7,6 @@ from django.shortcuts import get_object_ from django.template import RequestContext from django.utils import timezone from django.core import serializers -from django.template.loader import render_to_string from boards.forms import PostForm, PlainErrorList from boards.models import Post, Thread, Tag @@ -56,14 +55,12 @@ def api_get_threaddiff(request, thread_i pub_time__lte=filter_time, last_edit_time__gt=filter_time) - diff_type = DIFF_TYPE_HTML - if PARAMETER_DIFF_TYPE in request.GET: - diff_type = request.GET[PARAMETER_DIFF_TYPE] + diff_type = request.GET.get(PARAMETER_DIFF_TYPE, DIFF_TYPE_HTML) for post in added_posts: - json_data['added'].append(_get_post_data(post.id, diff_type, request)) + json_data['added'].append(get_post_data(post.id, diff_type, request)) for post in updated_posts: - json_data['updated'].append(_get_post_data(post.id, diff_type, request)) + json_data['updated'].append(get_post_data(post.id, diff_type, request)) json_data['last_update'] = datetime_to_epoch(thread.last_edit_time) return HttpResponse(content=json.dumps(json_data)) @@ -114,8 +111,6 @@ def get_post(request, post_id): in threads list with 'truncated' get parameter. """ - logger.info('Getting post #%s' % post_id) - post = get_object_or_404(Post, id=post_id) context = RequestContext(request) @@ -123,7 +118,8 @@ def get_post(request, post_id): if PARAMETER_TRUNCATED in request.GET: context[PARAMETER_TRUNCATED] = True - return render(request, 'boards/api_post.html', context) + # TODO Use dict here + return render(request, 'boards/api_post.html', context_instance=context) # TODO Test this @@ -138,7 +134,7 @@ def api_get_threads(request, count): tag_name = request.GET[PARAMETER_TAG] if tag_name is not None: tag = get_object_or_404(Tag, name=tag_name) - threads = tag.threads.filter(archived=False) + threads = tag.get_threads().filter(archived=False) else: threads = Thread.objects.filter(archived=False) @@ -156,7 +152,7 @@ def api_get_threads(request, count): opening_post = thread.get_opening_post() # TODO Add tags, replies and images count - opening_posts.append(_get_post_data(opening_post.id, + opening_posts.append(get_post_data(opening_post.id, include_last_update=True)) return HttpResponse(content=json.dumps(opening_posts)) @@ -196,7 +192,7 @@ def api_get_thread_posts(request, openin json_post_list = [] for post in posts: - json_post_list.append(_get_post_data(post.id)) + json_post_list.append(get_post_data(post.id)) json_data['last_update'] = datetime_to_epoch(thread.last_edit_time) json_data['posts'] = json_post_list @@ -219,30 +215,9 @@ def api_get_post(request, post_id): return HttpResponse(content=json) -# TODO Add pub time and replies -def _get_post_data(post_id, format_type=DIFF_TYPE_JSON, request=None, - include_last_update=False): - if format_type == DIFF_TYPE_HTML: - post = get_object_or_404(Post, id=post_id) - - context = RequestContext(request) - context['post'] = post - if PARAMETER_TRUNCATED in request.GET: - context[PARAMETER_TRUNCATED] = True - - return render_to_string('boards/api_post.html', context) - elif format_type == DIFF_TYPE_JSON: - post = get_object_or_404(Post, id=post_id) - post_json = { - 'id': post.id, - 'title': post.title, - 'text': post.text.rendered, - } - if post.images.exists(): - post_image = post.get_first_image() - post_json['image'] = post_image.image.url - post_json['image_preview'] = post_image.image.url_200x150 - if include_last_update: - post_json['bump_time'] = datetime_to_epoch( - post.thread_new.bump_time) - return post_json +# TODO Remove this method and use post method directly +def get_post_data(post_id, format_type=DIFF_TYPE_JSON, request=None, + include_last_update=False): + post = get_object_or_404(Post, id=post_id) + return post.get_post_data(format_type=format_type, request=request, + include_last_update=include_last_update) diff --git a/boards/views/authors.py b/boards/views/authors.py --- a/boards/views/authors.py +++ b/boards/views/authors.py @@ -7,7 +7,7 @@ from boards.views.base import BaseBoardV class AuthorsView(BaseBoardView): def get(self, request): - context = self.get_context_data(request=request) - context['authors'] = authors + params = dict() + params['authors'] = authors - return render(request, 'boards/authors.html', context) + return render(request, 'boards/authors.html', params) diff --git a/boards/views/banned.py b/boards/views/banned.py --- a/boards/views/banned.py +++ b/boards/views/banned.py @@ -9,8 +9,9 @@ class BannedView(BaseBoardView): def get(self, request): """Show the page that notifies that user is banned""" - context = self.get_context_data(request=request) + params = dict() ban = get_object_or_404(Ban, ip=utils.get_client_ip(request)) - context['ban_reason'] = ban.reason - return render(request, 'boards/staticpages/banned.html', context) + params['ban_reason'] = ban.reason + + return render(request, 'boards/staticpages/banned.html', params) diff --git a/boards/views/base.py b/boards/views/base.py --- a/boards/views/base.py +++ b/boards/views/base.py @@ -14,11 +14,7 @@ CONTEXT_FORM = 'form' class BaseBoardView(View): def get_context_data(self, **kwargs): - request = kwargs['request'] - # context = self._default_context(request) - context = RequestContext(request) - - return context + return dict() @transaction.atomic def _ban_current_user(self, request): diff --git a/boards/views/delete_post.py b/boards/views/delete_post.py deleted file mode 100644 --- a/boards/views/delete_post.py +++ /dev/null @@ -1,28 +0,0 @@ -from django.shortcuts import redirect, get_object_or_404 -from django.db import transaction - -from boards.abstracts.settingsmanager import PERMISSION_MODERATE,\ - get_settings_manager -from boards.views.base import BaseBoardView -from boards.views.mixins import RedirectNextMixin -from boards.models import Post - - -class DeletePostView(BaseBoardView, RedirectNextMixin): - - @transaction.atomic - def get(self, request, post_id): - post = get_object_or_404(Post, id=post_id) - - opening_post = post.is_opening() - - settings_manager = get_settings_manager(request) - if settings_manager.has_permission(PERMISSION_MODERATE): - # TODO Show confirmation page before deletion - Post.objects.delete_post(post) - - if not opening_post: - thread = post.thread_new - return redirect('thread', post_id=thread.get_opening_post().id) - else: - return self.redirect_to_next(request) diff --git a/boards/views/mixins.py b/boards/views/mixins.py --- a/boards/views/mixins.py +++ b/boards/views/mixins.py @@ -1,3 +1,4 @@ +PARAM_NEXT = 'next' PARAMETER_METHOD = 'method' from django.shortcuts import redirect @@ -13,8 +14,8 @@ class RedirectNextMixin: current view has finished its work. """ - if 'next' in request.GET: - next_page = request.GET['next'] + if PARAM_NEXT in request.GET: + next_page = request.GET[PARAM_NEXT] return HttpResponseRedirect(next_page) else: return redirect('index') diff --git a/boards/views/not_found.py b/boards/views/not_found.py --- a/boards/views/not_found.py +++ b/boards/views/not_found.py @@ -9,5 +9,9 @@ class NotFoundView(BaseBoardView): """ def get(self, request): - context = self.get_context_data(request=request) - return render(request, 'boards/404.html', context) + params = self.get_context_data() + + response = render(request, 'boards/404.html', params) + response.status_code = 404 + + return response diff --git a/boards/views/post_admin.py b/boards/views/post_admin.py deleted file mode 100644 --- a/boards/views/post_admin.py +++ /dev/null @@ -1,60 +0,0 @@ -from django.shortcuts import render, get_object_or_404, redirect - -from boards.abstracts.settingsmanager import PERMISSION_MODERATE,\ - get_settings_manager -from boards.views.base import BaseBoardView -from boards.views.mixins import DispatcherMixin -from boards.models.post import Post -from boards.models.tag import Tag -from boards.forms import AddTagForm, PlainErrorList - - -class PostAdminView(BaseBoardView, DispatcherMixin): - - def get(self, request, post_id, form=None): - settings_manager = get_settings_manager(request) - if not settings_manager.has_permission(PERMISSION_MODERATE): - redirect('index') - - post = get_object_or_404(Post, id=post_id) - - if not form: - dispatch_result = self.dispatch_method(request, post) - if dispatch_result: - return dispatch_result - form = AddTagForm() - - context = self.get_context_data(request=request) - - context['post'] = post - - context['tag_form'] = form - - return render(request, 'boards/post_admin.html', context) - - def post(self, request, post_id): - settings_manager = get_settings_manager(request) - if not settings_manager.has_permission(PERMISSION_MODERATE): - redirect('index') - - post = get_object_or_404(Post, id=post_id) - return self.dispatch_method(request, post) - - def delete_tag(self, request, post): - tag_name = request.GET['tag'] - tag = get_object_or_404(Tag, name=tag_name) - - post.remove_tag(tag) - - return redirect('post_admin', post.id) - - def add_tag(self, request, post): - form = AddTagForm(request.POST, error_class=PlainErrorList) - if form.is_valid(): - tag_name = form.cleaned_data['tag'] - tag, created = Tag.objects.get_or_create(name=tag_name) - - post.add_tag(tag) - return redirect('post_admin', post.id) - else: - return self.get(request, post.id, form) diff --git a/boards/views/preview.py b/boards/views/preview.py --- a/boards/views/preview.py +++ b/boards/views/preview.py @@ -18,7 +18,8 @@ class PostPreviewView(View): def get(self, request): context = RequestContext(request) - return render(request, TEMPLATE, context) + # TODO Use dict here + return render(request, TEMPLATE, context_instance=context) def post(self, request): context = RequestContext(request) @@ -32,4 +33,5 @@ class PostPreviewView(View): context[CONTEXT_RESULT] = rendered_text context[CONTEXT_QUERY] = raw_text - return render(request, TEMPLATE, context) + # TODO Use dict here + return render(request, TEMPLATE, context_instance=context) diff --git a/boards/views/search.py b/boards/views/search.py --- a/boards/views/search.py +++ b/boards/views/search.py @@ -1,10 +1,14 @@ from django.shortcuts import render -from django.template import RequestContext from django.views.generic import View from haystack.query import SearchQuerySet + from boards.abstracts.paginator import get_paginator from boards.forms import SearchForm, PlainErrorList + +MIN_QUERY_LENGTH = 3 +RESULTS_PER_PAGE = 10 + FORM_QUERY = 'query' CONTEXT_QUERY = 'query' @@ -20,21 +24,20 @@ TEMPLATE = 'search/search.html' class BoardSearchView(View): def get(self, request): - context = RequestContext(request) + params = dict() + form = SearchForm(request.GET, error_class=PlainErrorList) - context[CONTEXT_FORM] = form + params[CONTEXT_FORM] = form if form.is_valid(): query = form.cleaned_data[FORM_QUERY] - if len(query) >= 3: - results = SearchQuerySet().auto_query(query).order_by('-id').load_all() - paginator = get_paginator(results, 10) + if len(query) >= MIN_QUERY_LENGTH: + results = SearchQuerySet().auto_query(query).order_by('-id') + paginator = get_paginator(results, RESULTS_PER_PAGE) - if REQUEST_PAGE in request.GET: - page = int(request.GET[REQUEST_PAGE]) - else: - page = 1 - context[CONTEXT_PAGE] = paginator.page(page) - context[CONTEXT_QUERY] = query + page = int(request.GET.get(REQUEST_PAGE, '1')) - return render(request, TEMPLATE, context) + params[CONTEXT_PAGE] = paginator.page(page) + params[CONTEXT_QUERY] = query + + return render(request, TEMPLATE, params) diff --git a/boards/views/settings.py b/boards/views/settings.py --- a/boards/views/settings.py +++ b/boards/views/settings.py @@ -5,24 +5,27 @@ from boards.abstracts.settingsmanager im from boards.views.base import BaseBoardView, CONTEXT_FORM from boards.forms import SettingsForm, PlainErrorList +FORM_THEME = 'theme' + CONTEXT_HIDDEN_TAGS = 'hidden_tags' class SettingsView(BaseBoardView): def get(self, request): - context = self.get_context_data(request=request) + params = self.get_context_data() settings_manager = get_settings_manager(request) selected_theme = settings_manager.get_theme() - form = SettingsForm(initial={'theme': selected_theme}, + form = SettingsForm(initial={FORM_THEME: selected_theme}, error_class=PlainErrorList) - context[CONTEXT_FORM] = form - context[CONTEXT_HIDDEN_TAGS] = settings_manager.get_hidden_tags() + params[CONTEXT_FORM] = form + params[CONTEXT_HIDDEN_TAGS] = settings_manager.get_hidden_tags() - return render(request, 'boards/settings.html', context) + # TODO Use dict here + return render(request, 'boards/settings.html', params) def post(self, request): settings_manager = get_settings_manager(request) @@ -31,7 +34,7 @@ class SettingsView(BaseBoardView): form = SettingsForm(request.POST, error_class=PlainErrorList) if form.is_valid(): - selected_theme = form.cleaned_data['theme'] + selected_theme = form.cleaned_data[FORM_THEME] settings_manager.set_theme(selected_theme) diff --git a/boards/views/static.py b/boards/views/static.py --- a/boards/views/static.py +++ b/boards/views/static.py @@ -10,5 +10,4 @@ class StaticPageView(BaseBoardView): Show a static page that needs only tags list and a CSS """ - context = self.get_context_data(request=request) - return render(request, 'boards/staticpages/' + name + '.html', context) + return render(request, 'boards/staticpages/' + name + '.html') diff --git a/boards/views/tag_threads.py b/boards/views/tag_threads.py --- a/boards/views/tag_threads.py +++ b/boards/views/tag_threads.py @@ -1,11 +1,14 @@ from django.shortcuts import get_object_or_404 from boards.abstracts.settingsmanager import get_settings_manager -from boards.models import Tag +from boards.models import Tag, Thread from boards.views.all_threads import AllThreadsView, DEFAULT_PAGE from boards.views.mixins import DispatcherMixin, RedirectNextMixin from boards.forms import ThreadForm, PlainErrorList +PARAM_HIDDEN_TAGS = 'hidden_tags' +PARAM_FAV_TAGS = 'fav_tags' +PARAM_TAG = 'tag' __author__ = 'neko259' @@ -17,20 +20,20 @@ class TagView(AllThreadsView, Dispatcher def get_threads(self): tag = get_object_or_404(Tag, name=self.tag_name) - return tag.threads.all().order_by('-bump_time') + return tag.get_threads() def get_context_data(self, **kwargs): - context = super(TagView, self).get_context_data(**kwargs) + params = super(TagView, self).get_context_data(**kwargs) settings_manager = get_settings_manager(kwargs['request']) tag = get_object_or_404(Tag, name=self.tag_name) - context['tag'] = tag + params[PARAM_TAG] = tag - context['fav_tags'] = settings_manager.get_fav_tags() - context['hidden_tags'] = settings_manager.get_hidden_tags() + params[PARAM_FAV_TAGS] = settings_manager.get_fav_tags() + params[PARAM_HIDDEN_TAGS] = settings_manager.get_hidden_tags() - return context + return params def get(self, request, tag_name, page=DEFAULT_PAGE, form=None): self.tag_name = tag_name diff --git a/boards/views/thread.py b/boards/views/thread.py --- a/boards/views/thread.py +++ b/boards/views/thread.py @@ -10,6 +10,7 @@ from boards.models import Post, Ban from boards.views.banned import BannedView from boards.views.base import BaseBoardView, CONTEXT_FORM from boards.views.posting_mixin import PostMixin +import neboard TEMPLATE_GALLERY = 'boards/thread_gallery.html' TEMPLATE_NORMAL = 'boards/thread.html' @@ -22,6 +23,10 @@ CONTEXT_LASTUPDATE = "last_update" CONTEXT_MAX_REPLIES = 'max_replies' CONTEXT_THREAD = 'thread' CONTEXT_BUMPABLE = 'bumpable' +CONTEXT_WS_TOKEN = 'ws_token' +CONTEXT_WS_PROJECT = 'ws_project' +CONTEXT_WS_HOST = 'ws_host' +CONTEXT_WS_PORT = 'ws_port' FORM_TITLE = 'title' FORM_TEXT = 'text' @@ -48,36 +53,44 @@ class ThreadView(BaseBoardView, PostMixi thread_to_show = opening_post.get_thread() - context = self.get_context_data(request=request) + params = dict() + + params[CONTEXT_FORM] = form + params[CONTEXT_LASTUPDATE] = str(utils.datetime_to_epoch( + thread_to_show.last_edit_time)) + params[CONTEXT_THREAD] = thread_to_show + params[CONTEXT_MAX_REPLIES] = settings.MAX_POSTS_PER_THREAD - context[CONTEXT_FORM] = form - context[CONTEXT_LASTUPDATE] = utils.datetime_to_epoch( - thread_to_show.last_edit_time) - context[CONTEXT_THREAD] = thread_to_show - context[CONTEXT_MAX_REPLIES] = settings.MAX_POSTS_PER_THREAD + if settings.WEBSOCKETS_ENABLED: + params[CONTEXT_WS_TOKEN] = utils.get_websocket_token( + timestamp=params[CONTEXT_LASTUPDATE]) + params[CONTEXT_WS_PROJECT] = neboard.settings.CENTRIFUGE_PROJECT_ID + params[CONTEXT_WS_HOST] = request.get_host().split(':')[0] + params[CONTEXT_WS_PORT] = neboard.settings.CENTRIFUGE_PORT + # TODO Move this to subclasses: NormalThreadView, GalleryThreadView etc if MODE_NORMAL == mode: bumpable = thread_to_show.can_bump() - context[CONTEXT_BUMPABLE] = bumpable + params[CONTEXT_BUMPABLE] = bumpable if bumpable: left_posts = settings.MAX_POSTS_PER_THREAD \ - thread_to_show.get_reply_count() - context[CONTEXT_POSTS_LEFT] = left_posts - context[CONTEXT_BUMPLIMIT_PRG] = str( + params[CONTEXT_POSTS_LEFT] = left_posts + params[CONTEXT_BUMPLIMIT_PRG] = str( float(left_posts) / settings.MAX_POSTS_PER_THREAD * 100) - context[CONTEXT_OP] = opening_post + params[CONTEXT_OP] = opening_post document = TEMPLATE_NORMAL elif MODE_GALLERY == mode: - context[CONTEXT_POSTS] = thread_to_show.get_replies_with_images( + params[CONTEXT_POSTS] = thread_to_show.get_replies_with_images( view_fields_only=True) document = TEMPLATE_GALLERY else: raise Http404 - return render(request, document, context) + return render(request, document, params) def post(self, request, post_id, mode=MODE_NORMAL): opening_post = get_object_or_404(Post, id=post_id) @@ -99,37 +112,24 @@ class ThreadView(BaseBoardView, PostMixi return self.get(request, post_id, mode, form) - @transaction.atomic def new_post(self, request, form, opening_post=None, html_response=True): """Add a new post (in thread or as a reply).""" ip = utils.get_client_ip(request) - is_banned = Ban.objects.filter(ip=ip).exists() - - if is_banned: - if html_response: - return redirect(BannedView().as_view()) - else: - return None data = form.cleaned_data title = data[FORM_TITLE] text = data[FORM_TEXT] + image = data.get(FORM_IMAGE) text = self._remove_invalid_links(text) - if FORM_IMAGE in list(data.keys()): - image = data[FORM_IMAGE] - else: - image = None - - tags = [] - post_thread = opening_post.get_thread() post = Post.objects.create_post(title=title, text=text, image=image, - thread=post_thread, ip=ip, tags=tags) + thread=post_thread, ip=ip) + post.send_to_websocket(request) thread_to_show = (opening_post.id if opening_post else post.id) diff --git a/manage.py b/manage.py --- a/manage.py +++ b/manage.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 import os import sys diff --git a/neboard/settings.py b/neboard/settings.py --- a/neboard/settings.py +++ b/neboard/settings.py @@ -82,6 +82,7 @@ STATICFILES_DIRS = ( STATICFILES_FINDERS = ( 'django.contrib.staticfiles.finders.FileSystemFinder', 'django.contrib.staticfiles.finders.AppDirectoriesFinder', + 'compressor.finders.CompressorFinder', ) if DEBUG: @@ -115,7 +116,6 @@ MIDDLEWARE_CLASSES = ( 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'boards.middlewares.BanMiddleware', - 'boards.middlewares.MinifyHTMLMiddleware', ) ROOT_URLCONF = 'neboard.urls' @@ -144,8 +144,6 @@ INSTALLED_APPS = ( 'django.contrib.humanize', 'django_cleanup', - # Migrations - 'south', 'debug_toolbar', # Search @@ -164,10 +162,10 @@ LOGGING = { 'disable_existing_loggers': False, 'formatters': { 'verbose': { - 'format': '%(levelname)s %(asctime)s %(module)s %(process)d %(thread)d %(message)s' + 'format': '%(levelname)s %(asctime)s %(name)s %(process)d %(thread)d %(message)s' }, 'simple': { - 'format': '%(levelname)s %(asctime)s [%(module)s] %(message)s' + 'format': '%(levelname)s %(asctime)s [%(name)s] %(message)s' }, }, 'filters': { @@ -197,10 +195,6 @@ HAYSTACK_CONNECTIONS = { }, } -MARKUP_FIELD_TYPES = ( - ('bbcode', bbcode_extended), -) - THEMES = [ ('md', 'Mystic Dark'), ('md_centered', 'Mystic Dark (centered)'), @@ -208,11 +202,16 @@ THEMES = [ ('pg', 'Photon Gray'), ] -POPULAR_TAGS = 10 - POSTING_DELAY = 20 # seconds -COMPRESS_HTML = True +# Websocket settins +CENTRIFUGE_HOST = 'localhost' +CENTRIFUGE_PORT = '9090' + +CENTRIFUGE_ADDRESS = 'http://{}:{}'.format(CENTRIFUGE_HOST, CENTRIFUGE_PORT) +CENTRIFUGE_PROJECT_ID = '' +CENTRIFUGE_PROJECT_SECRET = '' +CENTRIFUGE_TIMEOUT = 5 # Debug mode middlewares if DEBUG: @@ -221,7 +220,7 @@ if DEBUG: ) def custom_show_toolbar(request): - return False + return True DEBUG_TOOLBAR_CONFIG = { 'ENABLE_STACKTRACES': True, @@ -232,4 +231,3 @@ if DEBUG: #DEBUG_TOOLBAR_PANELS += ( # 'debug_toolbar.panels.profiling.ProfilingDebugPanel', #) - diff --git a/readme.markdown b/readme.markdown --- a/readme.markdown +++ b/readme.markdown @@ -7,23 +7,6 @@ Main repository: https://bitbucket.org/n Site: http://neboard.me/ -# DEPENDENCIES # - -## REQUIRED ## - -* pillow -* django >= 1.6 -* django_cleanup -* django-markupfield -* markdown -* python-markdown -* django-simple-captcha -* line-profiler - -## OPTIONAL ## - -* django-debug-toolbar - # INSTALLATION # 1. Install all dependencies over pip or system-wide diff --git a/requirements.txt b/requirements.txt --- a/requirements.txt +++ b/requirements.txt @@ -1,10 +1,9 @@ httplib2 simplejson -south>=0.8.4 +adjacent haystack pillow -django>=1.6 +django>=1.7 django_cleanup -django-markupfield bbcode ecdsa diff --git a/tools/neboard.service b/tools/neboard.service new file mode 100644 --- /dev/null +++ b/tools/neboard.service @@ -0,0 +1,10 @@ +[Unit] +Description=Neboard imageboard +After=network.target + +[Service] +ExecStart=/usr/bin/uwsgi_python33 --ini uwsgi.ini +WorkingDirectory= + +[Install] +WantedBy=multi-user.target diff --git a/tools/uwsgi.ini b/tools/uwsgi.ini new file mode 100755 --- /dev/null +++ b/tools/uwsgi.ini @@ -0,0 +1,11 @@ +[uwsgi] +module = neboard.wsgi:application +master = true +pidfile = /tmp/neboard.pid +socket = 127.0.0.1:8080 +processes = 5 +harakiri = 20 +max-requests = 5000 +disable-logging = true +vacuum = true +# socket=/var/run/neboard.sock