diff --git a/boards/mdx_neboard.py b/boards/mdx_neboard.py deleted file mode 100644 --- a/boards/mdx_neboard.py +++ /dev/null @@ -1,296 +0,0 @@ -# coding=utf-8 -from xml import etree - -import re -import random -import bbcode - -from urllib.parse import unquote - -from django.core.exceptions import ObjectDoesNotExist -from django.urls import reverse -from django.utils.translation import ugettext_lazy as _ - -import boards -from boards import settings -from swineboard.settings import ALLOWED_HOSTS - - -__author__ = 'neko259' - - -REFLINK_PATTERN = re.compile(r'^\d+$') -GLOBAL_REFLINK_PATTERN = re.compile(r'(\w+)::([^:]+)::(\d+)') -MULTI_NEWLINES_PATTERN = re.compile(r'(\r?\n){2,}') -ONE_NEWLINE = '\n' -REGEX_URL = re.compile(r'https?\://[a-zA-Z0-9\-\.]+\.[a-zA-Z]{2,3}(/\S*)?') -LINE_BREAK_HTML = '
' -SPOILER_SPACE = ' ' -REGEX_ANY_LINE_BREAK = re.compile(r'(' + LINE_BREAK_HTML + '|\r|\n)') -QUOTE_REPLACEMENT = '\g<1>>' - -MAX_SPOILER_MULTIPLIER = 2 -MAX_SPOILER_SPACE_COUNT = 20 - - -class TextFormatter: - """ - An interface for formatter that can be used in the text format panel - """ - - def __init__(self): - pass - - name = '' - - # Left and right tags for the button preview - preview_left = '' - preview_right = '' - - # Tag name to enclose the text in the form - tag_name = '' - - has_input = 'false' - input_prompt = '' - - -class AutolinkPattern: - def handleMatch(self, m): - link_element = etree.Element('a') - href = m.group(2) - link_element.set('href', href) - link_element.text = href - - return link_element - - -class QuotePattern(TextFormatter): - name = '>q' - preview_left = '' - preview_right = '' - - tag_name = 'quote' - - -class SpoilerPattern(TextFormatter): - name = 'spoiler' - preview_left = '' - preview_right = '' - - tag_name = 'spoiler' - - -class CommentPattern(TextFormatter): - name = '' - preview_left = '// ' - preview_right = '' - - tag_name = 'comment' - - -# TODO Use tag here -class StrikeThroughPattern(TextFormatter): - name = 's' - preview_left = '' - preview_right = '' - - tag_name = 's' - - -class ItalicPattern(TextFormatter): - name = 'i' - preview_left = '' - preview_right = '' - - tag_name = 'i' - - -class BoldPattern(TextFormatter): - name = 'b' - preview_left = '' - preview_right = '' - - tag_name = 'b' - - -class CodePattern(TextFormatter): - name = 'code' - preview_left = '' - preview_right = '' - - tag_name = 'code' - - -class HintPattern(TextFormatter): - name = 'hint' - preview_left = '' - preview_right = '' - - tag_name = 'hint' - - -class ColorPattern(TextFormatter): - name = 'color' - preview_left = '' - preview_right = '' - - tag_name = 'color' - - has_input = 'true' - input_prompt = _('Enter color (name or #ccc code)') - - -def render_reflink(tag_name, value, options, parent, context): - result = '>>%s' % value - - post = None - if REFLINK_PATTERN.match(value): - post_id = int(value) - - try: - post = boards.models.Post.objects.get(id=post_id) - - except ObjectDoesNotExist: - pass - elif GLOBAL_REFLINK_PATTERN.match(value): - match = GLOBAL_REFLINK_PATTERN.search(value) - try: - global_id = boards.models.GlobalId.objects.get( - key_type=match.group(1), key=match.group(2), - local_id=match.group(3)) - post = global_id.post - except ObjectDoesNotExist: - pass - - if post is not None: - result = post.get_link_view() - - return result - - -def render_quote(tag_name, value, options, parent, context): - source = options.get('quote') or options.get('source') - - if source: - result = '
%s
%s
' % (source, value) - else: - # Insert a ">" at the start of every line - result = '>{}'.format( - REGEX_ANY_LINE_BREAK.sub(QUOTE_REPLACEMENT, value)) - - return result - - -def render_hint(tag_name, value, options, parent, context): - if 'hint' in options: - hint = options['hint'] - result = '{}'.format(hint, value) - else: - result = value - return result - - -def render_notification(tag_name, value, options, parent, content): - username = value.lower() - - return '@{}'.format( - reverse('notifications', kwargs={'username': username}), username) - - -def render_tag(tag_name, value, options, parent, context): - tag_name = value.lower() - - tag = boards.models.Tag.objects.get_by_alias(tag_name) - if tag: - url = tag.get_view() - else: - url = tag_name - - return url - - -def render_spoiler(tag_name, value, options, parent, context): - if settings.get_bool('Forms', 'AdditionalSpoilerSpaces'): - text_len = len(value) - space_count = min(random.randint(0, text_len * MAX_SPOILER_MULTIPLIER), - MAX_SPOILER_SPACE_COUNT) - side_spaces = SPOILER_SPACE * (space_count // 2) - else: - side_spaces = '' - return '{}{}{}'.format(side_spaces, - value, side_spaces) - - -formatters = [ - QuotePattern, - SpoilerPattern, - ItalicPattern, - BoldPattern, - CommentPattern, - StrikeThroughPattern, - CodePattern, - HintPattern, - ColorPattern, -] - - -PREPARSE_PATTERNS = { - r'(?)>>(\d+)': r'[post]\1[/post]', # Reflink ">>123" - r'^>([^>].+)': r'[quote]\1[/quote]', # Quote ">text" - r'^//\s?(.+)': r'[comment]\1[/comment]', # Comment "//text" - r'\B@(\w+)': r'[user]\1[/user]', # User notification "@user" -} - -for hostname in ALLOWED_HOSTS: - if hostname != '*': - PREPARSE_PATTERNS[r'https?://{}/thread/\d+/#(\d+)/?'.format(hostname)] = r'[post]\1[/post]' - PREPARSE_PATTERNS[r'https?://{}/thread/(\d+)/?'.format(hostname)] = r'[post]\1[/post]' - - -class Parser: - def __init__(self): - # The newline hack is added because br's margin does not work in all - # browsers except firefox, when the div's does. - self.parser = bbcode.Parser(newline=LINE_BREAK_HTML) - - self.parser.add_formatter('post', render_reflink, strip=True) - self.parser.add_formatter('quote', render_quote, strip=True) - self.parser.add_formatter('hint', render_hint, strip=True) - self.parser.add_formatter('user', render_notification, strip=True) - self.parser.add_formatter('tag', render_tag, strip=True) - self.parser.add_formatter('spoiler', render_spoiler, strip=True) - self.parser.add_simple_formatter( - 'comment', '// %(value)s', strip=True) - self.parser.add_simple_formatter( - 's', '%(value)s') - self.parser.add_simple_formatter('code', - '
%(value)s
', - render_embedded=False, - escape_html=True, - replace_links=False, - replace_cosmetic=False) - - def preparse(self, text): - """ - Performs manual parsing before the bbcode parser is used. - Preparsed text is saved as raw and the text before preparsing is lost. - """ - new_text = MULTI_NEWLINES_PATTERN.sub(ONE_NEWLINE, text) - - for key, value in PREPARSE_PATTERNS.items(): - new_text = re.sub(key, value, new_text, flags=re.MULTILINE) - - for link in REGEX_URL.findall(text): - new_text = new_text.replace(link, unquote(link)) - - return new_text - - def parse(self, text): - return self.parser.format(text) - - -parser = Parser() - - -def get_parser(): - return parser diff --git a/boards/mdx_swineboard.py b/boards/mdx_swineboard.py new file mode 100644 --- /dev/null +++ b/boards/mdx_swineboard.py @@ -0,0 +1,296 @@ +# coding=utf-8 +from xml import etree + +import re +import random +import bbcode + +from urllib.parse import unquote + +from django.core.exceptions import ObjectDoesNotExist +from django.urls import reverse +from django.utils.translation import ugettext_lazy as _ + +import boards +from boards import settings +from swineboard.settings import ALLOWED_HOSTS + + +__author__ = 'neko259' + + +REFLINK_PATTERN = re.compile(r'^\d+$') +GLOBAL_REFLINK_PATTERN = re.compile(r'(\w+)::([^:]+)::(\d+)') +MULTI_NEWLINES_PATTERN = re.compile(r'(\r?\n){2,}') +ONE_NEWLINE = '\n' +REGEX_URL = re.compile(r'https?\://[a-zA-Z0-9\-\.]+\.[a-zA-Z]{2,3}(/\S*)?') +LINE_BREAK_HTML = '
' +SPOILER_SPACE = ' ' +REGEX_ANY_LINE_BREAK = re.compile(r'(' + LINE_BREAK_HTML + '|\r|\n)') +QUOTE_REPLACEMENT = '\g<1>>' + +MAX_SPOILER_MULTIPLIER = 2 +MAX_SPOILER_SPACE_COUNT = 20 + + +class TextFormatter: + """ + An interface for formatter that can be used in the text format panel + """ + + def __init__(self): + pass + + name = '' + + # Left and right tags for the button preview + preview_left = '' + preview_right = '' + + # Tag name to enclose the text in the form + tag_name = '' + + has_input = 'false' + input_prompt = '' + + +class AutolinkPattern: + def handleMatch(self, m): + link_element = etree.Element('a') + href = m.group(2) + link_element.set('href', href) + link_element.text = href + + return link_element + + +class QuotePattern(TextFormatter): + name = '>q' + preview_left = '' + preview_right = '' + + tag_name = 'quote' + + +class SpoilerPattern(TextFormatter): + name = 'spoiler' + preview_left = '' + preview_right = '' + + tag_name = 'spoiler' + + +class CommentPattern(TextFormatter): + name = '' + preview_left = '// ' + preview_right = '' + + tag_name = 'comment' + + +# TODO Use tag here +class StrikeThroughPattern(TextFormatter): + name = 's' + preview_left = '' + preview_right = '' + + tag_name = 's' + + +class ItalicPattern(TextFormatter): + name = 'i' + preview_left = '' + preview_right = '' + + tag_name = 'i' + + +class BoldPattern(TextFormatter): + name = 'b' + preview_left = '' + preview_right = '' + + tag_name = 'b' + + +class CodePattern(TextFormatter): + name = 'code' + preview_left = '' + preview_right = '' + + tag_name = 'code' + + +class HintPattern(TextFormatter): + name = 'hint' + preview_left = '' + preview_right = '' + + tag_name = 'hint' + + +class ColorPattern(TextFormatter): + name = 'color' + preview_left = '' + preview_right = '' + + tag_name = 'color' + + has_input = 'true' + input_prompt = _('Enter color (name or #ccc code)') + + +def render_reflink(tag_name, value, options, parent, context): + result = '>>%s' % value + + post = None + if REFLINK_PATTERN.match(value): + post_id = int(value) + + try: + post = boards.models.Post.objects.get(id=post_id) + + except ObjectDoesNotExist: + pass + elif GLOBAL_REFLINK_PATTERN.match(value): + match = GLOBAL_REFLINK_PATTERN.search(value) + try: + global_id = boards.models.GlobalId.objects.get( + key_type=match.group(1), key=match.group(2), + local_id=match.group(3)) + post = global_id.post + except ObjectDoesNotExist: + pass + + if post is not None: + result = post.get_link_view() + + return result + + +def render_quote(tag_name, value, options, parent, context): + source = options.get('quote') or options.get('source') + + if source: + result = '
%s
%s
' % (source, value) + else: + # Insert a ">" at the start of every line + result = '>{}'.format( + REGEX_ANY_LINE_BREAK.sub(QUOTE_REPLACEMENT, value)) + + return result + + +def render_hint(tag_name, value, options, parent, context): + if 'hint' in options: + hint = options['hint'] + result = '{}'.format(hint, value) + else: + result = value + return result + + +def render_notification(tag_name, value, options, parent, content): + username = value.lower() + + return '@{}'.format( + reverse('notifications', kwargs={'username': username}), username) + + +def render_tag(tag_name, value, options, parent, context): + tag_name = value.lower() + + tag = boards.models.Tag.objects.get_by_alias(tag_name) + if tag: + url = tag.get_view() + else: + url = tag_name + + return url + + +def render_spoiler(tag_name, value, options, parent, context): + if settings.get_bool('Forms', 'AdditionalSpoilerSpaces'): + text_len = len(value) + space_count = min(random.randint(0, text_len * MAX_SPOILER_MULTIPLIER), + MAX_SPOILER_SPACE_COUNT) + side_spaces = SPOILER_SPACE * (space_count // 2) + else: + side_spaces = '' + return '{}{}{}'.format(side_spaces, + value, side_spaces) + + +formatters = [ + QuotePattern, + SpoilerPattern, + ItalicPattern, + BoldPattern, + CommentPattern, + StrikeThroughPattern, + CodePattern, + HintPattern, + ColorPattern, +] + + +PREPARSE_PATTERNS = { + r'(?)>>(\d+)': r'[post]\1[/post]', # Reflink ">>123" + r'^>([^>].+)': r'[quote]\1[/quote]', # Quote ">text" + r'^//\s?(.+)': r'[comment]\1[/comment]', # Comment "//text" + r'\B@(\w+)': r'[user]\1[/user]', # User notification "@user" +} + +for hostname in ALLOWED_HOSTS: + if hostname != '*': + PREPARSE_PATTERNS[r'https?://{}/thread/\d+/#(\d+)/?'.format(hostname)] = r'[post]\1[/post]' + PREPARSE_PATTERNS[r'https?://{}/thread/(\d+)/?'.format(hostname)] = r'[post]\1[/post]' + + +class Parser: + def __init__(self): + # The newline hack is added because br's margin does not work in all + # browsers except firefox, when the div's does. + self.parser = bbcode.Parser(newline=LINE_BREAK_HTML) + + self.parser.add_formatter('post', render_reflink, strip=True) + self.parser.add_formatter('quote', render_quote, strip=True) + self.parser.add_formatter('hint', render_hint, strip=True) + self.parser.add_formatter('user', render_notification, strip=True) + self.parser.add_formatter('tag', render_tag, strip=True) + self.parser.add_formatter('spoiler', render_spoiler, strip=True) + self.parser.add_simple_formatter( + 'comment', '// %(value)s', strip=True) + self.parser.add_simple_formatter( + 's', '%(value)s') + self.parser.add_simple_formatter('code', + '
%(value)s
', + render_embedded=False, + escape_html=True, + replace_links=False, + replace_cosmetic=False) + + def preparse(self, text): + """ + Performs manual parsing before the bbcode parser is used. + Preparsed text is saved as raw and the text before preparsing is lost. + """ + new_text = MULTI_NEWLINES_PATTERN.sub(ONE_NEWLINE, text) + + for key, value in PREPARSE_PATTERNS.items(): + new_text = re.sub(key, value, new_text, flags=re.MULTILINE) + + for link in REGEX_URL.findall(text): + new_text = new_text.replace(link, unquote(link)) + + return new_text + + def parse(self, text): + return self.parser.format(text) + + +parser = Parser() + + +def get_parser(): + return parser diff --git a/tools/neboard.service b/tools/neboard.service deleted file mode 100644 --- a/tools/neboard.service +++ /dev/null @@ -1,10 +0,0 @@ -[Unit] -Description=Swineboard imageboard -After=network.target - -[Service] -ExecStart=/usr/bin/uwsgi_python33 --ini uwsgi.ini -WorkingDirectory= - -[Install] -WantedBy=multi-user.target diff --git a/tools/swineboard.service b/tools/swineboard.service new file mode 100644 --- /dev/null +++ b/tools/swineboard.service @@ -0,0 +1,10 @@ +[Unit] +Description=Swineboard imageboard +After=network.target + +[Service] +ExecStart=/usr/bin/uwsgi_python33 --ini uwsgi.ini +WorkingDirectory= + +[Install] +WantedBy=multi-user.target