##// END OF EJS Templates
Added sticker pack functionality
neko259 -
r1951:1024ce38 default
parent child Browse files
Show More
@@ -0,0 +1,54 b''
1 # -*- coding: utf-8 -*-
2 # Generated by Django 1.11 on 2017-10-25 08:48
3 from __future__ import unicode_literals
4
5 from django.db import migrations, models
6 import django.db.models.deletion
7
8
9 class Migration(migrations.Migration):
10
11 dependencies = [
12 ('boards', '0065_attachmentsticker'),
13 ]
14
15 def stickers_to_pack(apps, schema_editor):
16 AttachmentSticker = apps.get_model('boards', 'AttachmentSticker')
17 StickerPack = apps.get_model('boards', 'StickerPack')
18
19 stickers = AttachmentSticker.objects.all()
20 if len(stickers) > 0:
21 stickerpack = StickerPack.objects.create(name='general')
22 for sticker in stickers:
23 sticker.stickerpack = stickerpack
24 if '/' in sticker.name:
25 sticker.name = sticker.name.split('/')[1]
26 sticker.save()
27
28 operations = [
29 migrations.CreateModel(
30 name='StickerPack',
31 fields=[
32 ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
33 ('name', models.TextField(unique=True)),
34 ('tripcode', models.TextField(blank=True)),
35 ],
36 ),
37 migrations.AddField(
38 model_name='attachmentsticker',
39 name='stickerpack',
40 field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='boards.StickerPack', null=True),
41 preserve_default=False,
42 ),
43 migrations.AddField(
44 model_name='thread',
45 name='stickerpack',
46 field=models.BooleanField(default=False),
47 ),
48 migrations.RunPython(stickers_to_pack),
49 migrations.AlterField(
50 model_name='attachmentsticker',
51 name='stickerpack',
52 field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='boards.StickerPack', null=False),
53 ),
54 ]
@@ -1,1 +1,4 b''
1 import re
2
1 3 FILE_DIRECTORY = 'files/'
4 REGEX_TAGS = re.compile(r'^[\w\s\d]+$', re.UNICODE)
@@ -18,7 +18,8 b' class SessionStickerFactory(StickerFacto'
18 18
19 19 class ModelStickerFactory(StickerFactory):
20 20 def get_image(self, alias):
21 return Attachment.objects.get_by_alias(alias)
21 if alias.count('/') == 1:
22 return Attachment.objects.get_by_alias(alias)
22 23
23 24
24 25 def get_attachment_by_alias(alias, session):
@@ -1,5 +1,6 b''
1 1 from boards.abstracts.sticker_factory import StickerFactory
2 from boards.models.attachment import FILE_TYPES_IMAGE, AttachmentSticker
2 from boards.models.attachment import FILE_TYPES_IMAGE, AttachmentSticker, \
3 StickerPack
3 4 from django.contrib import admin
4 5 from django.utils.translation import ugettext_lazy as _
5 6 from django.core.urlresolvers import reverse
@@ -166,6 +167,11 b' class AttachmentStickerAdmin(admin.Model'
166 167 search_fields = ('name',)
167 168
168 169
170 @admin.register(StickerPack)
171 class StickerPackAdmin(admin.ModelAdmin):
172 search_fields = ('name',)
173
174
169 175 @admin.register(GlobalId)
170 176 class GlobalIdAdmin(admin.ModelAdmin):
171 177 def is_linked(self, obj):
@@ -2,7 +2,6 b' import hashlib'
2 2 import logging
3 3 import re
4 4 import time
5 import traceback
6 5
7 6 import pytz
8 7
@@ -18,12 +17,14 b' from django.core.cache import cache'
18 17 import boards.settings as board_settings
19 18 import neboard
20 19 from boards import utils
20 from boards.abstracts.constants import REGEX_TAGS
21 21 from boards.abstracts.sticker_factory import get_attachment_by_alias
22 22 from boards.abstracts.settingsmanager import get_settings_manager
23 23 from boards.forms.fields import UrlFileField
24 24 from boards.mdx_neboard import formatters
25 25 from boards.models import Attachment
26 26 from boards.models import Tag
27 from boards.models.attachment import StickerPack
27 28 from boards.models.attachment.downloaders import download, REGEX_MAGNET
28 29 from boards.models.post import TITLE_MAX_LENGTH
29 30 from boards.utils import validate_file_size, get_file_mimetype, \
@@ -36,7 +37,6 b" SECTION_FORMS = 'Forms'"
36 37 POW_HASH_LENGTH = 16
37 38 POW_LIFE_MINUTES = 5
38 39
39 REGEX_TAGS = re.compile(r'^[\w\s\d]+$', re.UNICODE)
40 40 REGEX_USERNAMES = re.compile(r'^[\w\s\d,]+$', re.UNICODE)
41 41 REGEX_URL = re.compile(r'^(http|https|ftp):\/\/', re.UNICODE)
42 42
@@ -485,6 +485,7 b' class ThreadForm(PostForm):'
485 485 widget=forms.TextInput(attrs={ATTRIBUTE_PLACEHOLDER: TAGS_PLACEHOLDER}),
486 486 max_length=100, label=_('Tags'), required=True)
487 487 monochrome = forms.BooleanField(label=_('Monochrome'), required=False)
488 stickerpack = forms.BooleanField(label=_('Sticker Pack'), required=False)
488 489
489 490 def clean_tags(self):
490 491 tags = self.cleaned_data['tags'].strip()
@@ -534,6 +535,36 b' class ThreadForm(PostForm):'
534 535 def is_monochrome(self):
535 536 return self.cleaned_data['monochrome']
536 537
538 def clean_stickerpack(self):
539 stickerpack = self.cleaned_data['stickerpack']
540 if stickerpack:
541 tripcode = self.get_tripcode()
542 if not tripcode:
543 raise forms.ValidationError(_(
544 'Tripcode should be specified to own a stickerpack.'))
545 title = self.get_title()
546 if not title:
547 raise forms.ValidationError(_(
548 'Title should be specified as a stickerpack name.'))
549 if not REGEX_TAGS.match(title):
550 raise forms.ValidationError(_('Inappropriate sticker pack name.'))
551
552 existing_pack = StickerPack.objects.filter(name=title).first()
553 if existing_pack:
554 if existing_pack.tripcode != tripcode:
555 raise forms.ValidationError(_(
556 'A sticker pack with this name already exists and is'
557 ' owned by another tripcode.'))
558 if not existing_pack.tripcode:
559 raise forms.ValidationError(_(
560 'This sticker pack can only be updated by an '
561 'administrator.'))
562
563 return stickerpack
564
565 def is_stickerpack(self):
566 return self.cleaned_data['stickerpack']
567
537 568
538 569 class SettingsForm(NeboardForm):
539 570
1 NO CONTENT: modified file, binary diff hidden
@@ -619,3 +619,24 b' msgstr "\xd0\x93\xd0\xbb\xd0\xbe\xd0\xb1\xd0\xb0\xd0\xbb\xd1\x8c\xd0\xbd\xd1\x8b\xd0\xb5 \xd1\x81\xd1\x82\xd0\xb8\xd0\xba\xd0\xb5\xd1\x80\xd1\x8b"'
619 619
620 620 msgid "Remove sticker"
621 621 msgstr "Удалить стикер"
622
623 msgid "Sticker Pack"
624 msgstr "Набор Стикеров"
625
626 msgid "Tripcode should be specified to own a stickerpack."
627 msgstr "Для владения набором стикеров необходимо указать трипкод."
628
629 msgid "Title should be specified as a stickerpack name."
630 msgstr "Заголовок должен быть указан в качестве имени набора стикеров."
631
632 msgid "A sticker pack with this name already exists and is owned by another tripcode."
633 msgstr "Набор стикеров с данным именем уже существует и принадлежит другому трипкоду."
634
635 msgid "This sticker pack can only be updated by an administrator."
636 msgstr "Этот набор стикеров может быть изменён только администратором."
637
638 msgid "To add a sticker, create a stickerpack thread using the title as a pack name, and a tripcode to own the pack. Then, add posts with title as a sticker name, and the same tripcode, to the thread. Their attachments would become stickers."
639 msgstr "Чтобы добавить стикер, создайте тему-набор с заголовком в качестве названия набора стикеров, и трипкодом для подтверждения владения набором. Затем, добавляйте сообщения с заголовком в качестве имени стикера, и тем же трипкодомм. Их вложения станут стикерами."
640
641 msgid "Inappropriate sticker pack name."
642 msgstr "Недопустимое имя набора стикеров."
1 NO CONTENT: modified file, binary diff hidden
@@ -619,3 +619,24 b' msgstr "\xd0\x93\xd0\xbb\xd0\xbe\xd0\xb1\xd0\xb0\xd0\xbb\xd1\x8c\xd0\xbd\xd1\x96 \xd1\x81\xd1\x82\xd1\x96\xd0\xba\xd0\xb5\xd1\x80\xd0\xb8"'
619 619
620 620 msgid "Remove sticker"
621 621 msgstr "Видалити стікер"
622
623 msgid "Sticker Pack"
624 msgstr "Набір Стікерів"
625
626 msgid "Tripcode should be specified to own a stickerpack."
627 msgstr "Для володіння набором стікерів необхідно вказати тріпкод."
628
629 msgid "Title should be specified as a stickerpack name."
630 msgstr "Заголовок повинен бути вказаний в якості імені набору стікерів."
631
632 msgid "A sticker pack with this name already exists and is owned by another tripcode."
633 msgstr "Набір стікерів з вказаним іменем вже є в наявності та належить іншому тріпкоду."
634
635 msgid "This sticker pack can only be updated by an administrator."
636 msgstr "Цей набір стікерів може бути змінений лише адміністратором."
637
638 msgid "To add a sticker, create a stickerpack thread using the title as a pack name, and a tripcode to own the pack. Then, add posts with title as a sticker name, and the same tripcode, to the thread. Their attachments would become stickers."
639 msgstr "Щоб додати стікер, створіть тему-набір з заголовком у якості набору стікерів, та тріпкодом для підтвердження володіння наборомт. Потім, додавайте повідомлення з заголовком у якості імені стікеру та з тим самим тріпкодом. Їхні вкладення станут стікерами."
640
641 msgid "Inappropriate sticker pack name."
642 msgstr "Неприпустиме ім'я набору стікерів."
@@ -55,8 +55,9 b' class AttachmentManager(models.Manager):'
55 55 return attachment
56 56
57 57 def get_by_alias(self, name):
58 pack_name, sticker_name = name.split('/')
58 59 try:
59 return AttachmentSticker.objects.get(name=name).attachment
60 return AttachmentSticker.objects.get(name=sticker_name, stickerpack__name=pack_name).attachment
60 61 except AttachmentSticker.DoesNotExist:
61 62 return None
62 63
@@ -163,9 +164,22 b' class Attachment(models.Model):'
163 164 return self.url is None or len(self.url) == 0
164 165
165 166
167 class StickerPack(models.Model):
168 name = models.TextField(unique=True)
169 tripcode = models.TextField(blank=True)
170
171 def __str__(self):
172 return self.name
173
174
166 175 class AttachmentSticker(models.Model):
167 176 attachment = models.ForeignKey('Attachment')
168 177 name = models.TextField(unique=True)
178 stickerpack = models.ForeignKey('StickerPack')
169 179
170 180 def __str__(self):
171 return self.name
181 # Local stickers do not have a sticker pack
182 if hasattr(self, 'stickerpack'):
183 return '{}/{}'.format(str(self.stickerpack), self.name)
184 else:
185 return self.name
@@ -1,20 +1,20 b''
1 1 import logging
2
3 2 from datetime import datetime, timedelta, date
4 3 from datetime import time as dtime
5 4
6 from boards.abstracts.exceptions import BannedException, ArchiveException
5 from django.core.exceptions import PermissionDenied
7 6 from django.db import models, transaction
7 from django.dispatch import Signal
8 8 from django.utils import timezone
9 from django.dispatch import Signal
10 from django.core.exceptions import PermissionDenied
11 9
12 10 import boards
13
14 from boards.models.user import Ban
11 from boards import utils
12 from boards.abstracts.exceptions import ArchiveException
13 from boards.abstracts.constants import REGEX_TAGS
15 14 from boards.mdx_neboard import Parser
16 15 from boards.models import Attachment
17 from boards import utils
16 from boards.models.attachment import StickerPack, AttachmentSticker
17 from boards.models.user import Ban
18 18
19 19 __author__ = 'neko259'
20 20
@@ -30,7 +30,7 b' class PostManager(models.Manager):'
30 30 def create_post(self, title: str, text: str, files=[], thread=None,
31 31 ip=NO_IP, tags: list=None,
32 32 tripcode='', monochrome=False, images=[],
33 file_urls=[]):
33 file_urls=[], stickerpack=False):
34 34 """
35 35 Creates new post
36 36 """
@@ -54,7 +54,7 b' class PostManager(models.Manager):'
54 54 if not thread:
55 55 thread = boards.models.thread.Thread.objects.create(
56 56 bump_time=posting_time, last_edit_time=posting_time,
57 monochrome=monochrome)
57 monochrome=monochrome, stickerpack=stickerpack)
58 58 list(map(thread.tags.add, tags))
59 59 new_thread = True
60 60
@@ -89,6 +89,8 b' class PostManager(models.Manager):'
89 89 thread.bump()
90 90 thread.save()
91 91
92 self._create_stickers(post)
93
92 94 return post
93 95
94 96 def delete_posts_by_ip(self, ip):
@@ -190,3 +192,37 b' class PostManager(models.Manager):'
190 192
191 193 def _add_file_to_post(self, file, post):
192 194 post.attachments.add(Attachment.objects.create_with_hash(file))
195
196 def _create_stickers(self, post):
197 thread = post.get_thread()
198 stickerpack_thread = thread.is_stickerpack()
199 if stickerpack_thread:
200 logger = logging.getLogger('boards.stickers')
201 if not post.is_opening():
202 has_title = len(post.title) > 0
203 has_one_attachment = post.attachments.count() == 1
204 opening_post = thread.get_opening_post()
205 valid_name = REGEX_TAGS.match(post.title)
206 if has_title and has_one_attachment and valid_name:
207 existing_sticker = AttachmentSticker.objects.filter(
208 name=post.get_title()).first()
209 attachment = post.attachments.first()
210 if existing_sticker:
211 existing_sticker.attachment = attachment
212 existing_sticker.save()
213 logger.info('Updated sticker {} with new attachment'.format(existing_sticker))
214 else:
215 try:
216 stickerpack = StickerPack.objects.get(
217 name=opening_post.get_title(), tripcode=post.tripcode)
218 sticker = AttachmentSticker.objects.create(
219 stickerpack=stickerpack, name=post.get_title(),
220 attachment=attachment)
221 logger.info('Created sticker {}'.format(sticker))
222 except StickerPack.DoesNotExist:
223 pass
224 else:
225 stickerpack, created = StickerPack.objects.get_or_create(
226 name=post.get_title(), tripcode=post.tripcode)
227 if created:
228 logger.info('Created stickerpack {}'.format(stickerpack))
@@ -97,6 +97,7 b' class Thread(models.Model):'
97 97 status = models.CharField(max_length=50, default=STATUS_ACTIVE,
98 98 choices=STATUS_CHOICES, db_index=True)
99 99 monochrome = models.BooleanField(default=False)
100 stickerpack = models.BooleanField(default=False)
100 101
101 102 def get_tags(self) -> QuerySet:
102 103 """
@@ -262,6 +263,9 b' class Thread(models.Model):'
262 263 def is_monochrome(self):
263 264 return self.monochrome
264 265
266 def is_stickerpack(self):
267 return self.stickerpack
268
265 269 # If tags have parent, add them to the tag list
266 270 @transaction.atomic
267 271 def refresh_tags(self):
@@ -1,5 +1,6 b''
1 1 import re
2 2 import os
3 import logging
3 4
4 5 from django.db.models.signals import post_save, pre_save, pre_delete, \
5 6 post_delete
@@ -9,7 +10,8 b' from django.utils import timezone'
9 10 from boards import thumbs
10 11 from boards.mdx_neboard import get_parser
11 12
12 from boards.models import Post, GlobalId, Attachment
13 from boards.models import Post, GlobalId, Attachment, Thread
14 from boards.models.attachment import StickerPack, AttachmentSticker
13 15 from boards.models.attachment.viewers import FILE_TYPES_IMAGE
14 16 from boards.models.post import REGEX_NOTIFICATION, REGEX_REPLY,\
15 17 REGEX_GLOBAL_REPLY
@@ -15,7 +15,7 b''
15 15 {% for sticker in local_stickers %}
16 16 <div class="gallery_image">
17 17 {{ sticker.attachment.get_view|safe }}
18 <div>{{ sticker.name }}</div>
18 <div>{{ sticker }}</div>
19 19 <div><a href="?action=remove&name={{ sticker.name }}">{% trans "Remove sticker" %}</a></div>
20 20 </div>
21 21 {% endfor %}
@@ -25,7 +25,7 b''
25 25 {% for sticker in global_stickers %}
26 26 <div class="gallery_image">
27 27 {{ sticker.attachment.get_view|safe }}
28 <div>{{ sticker.name }}</div>
28 <div>{{ sticker }}</div>
29 29 </div>
30 30 {% endfor %}
31 31 {% endif %}
@@ -6,6 +6,9 b''
6 6 <div class="{{ css_class }}" id="{{ post.id }}" data-uid="{{ post.uid }}" {% if tree_depth %}style="margin-left: {{ tree_depth }}em;"{% endif %}>
7 7 <div class="post-info">
8 8 <a class="post_id" href="{{ post.get_absolute_url }}">#{{ post.id }}</a>
9 {% if is_opening and thread.is_stickerpack %}
10 &#128247;
11 {% endif %}
9 12 <span class="title">{{ post.title }}</span>
10 13 {% if perms.boards.change_post and post.has_ip %}
11 14 <span class="pub_time" style="border-bottom: solid 2px #{{ post.get_ip_color }};" title="{{ post.poster_ip }}">
@@ -9,6 +9,7 b''
9 9 {% block staticcontent %}
10 10 <h2>{% trans 'Help' %}</h2>
11 11 <p>{% trans 'View available stickers:' %} <a href="{% url 'stickers' %}">{% trans 'Stickers' %}</a></p>
12 <p>{% trans 'To add a sticker, create a stickerpack thread using the title as a pack name, and a tripcode to own the pack. Then, add posts with title as a sticker name, and the same tripcode, to the thread. Their attachments would become stickers.' %}</p>
12 13 <hr />
13 14 <p>[i]<i>{% trans 'Italic text' %}</i>[/i]</p>
14 15 <p>[b]<b>{% trans 'Bold text' %}</b>[/b]</p>
@@ -142,12 +142,13 b' class AllThreadsView(PostMixin, FileUplo'
142 142
143 143 tags = data[FORM_TAGS]
144 144 monochrome = form.is_monochrome()
145 stickerpack = form.is_stickerpack()
145 146
146 147 post = Post.objects.create_post(title=title, text=text, files=files,
147 148 ip=ip, tags=tags,
148 149 tripcode=form.get_tripcode(),
149 150 monochrome=monochrome, images=images,
150 file_urls=file_urls)
151 file_urls=file_urls, stickerpack=stickerpack)
151 152
152 153 if form.is_subscribe():
153 154 settings_manager = get_settings_manager(request)
@@ -3,6 +3,7 b' import logging'
3 3
4 4 from django.core import serializers
5 5 from django.db import transaction
6 from django.db.models import Q
6 7 from django.http import HttpResponse, HttpResponseBadRequest
7 8 from django.shortcuts import get_object_or_404
8 9 from django.views.decorators.csrf import csrf_protect
@@ -194,12 +195,12 b' def api_get_stickers(request):'
194 195 if not term:
195 196 return HttpResponseBadRequest()
196 197
197 global_stickers = AttachmentSticker.objects.filter(name__contains=term)
198 global_stickers = AttachmentSticker.objects.filter(Q(name__icontains=term) | Q(stickerpack__name__icontains=term))
198 199 local_stickers = [sticker for sticker in get_settings_manager(request).get_stickers() if term in sticker.name]
199 200 stickers = list(global_stickers) + local_stickers
200 201
201 202 image_dict = [{'thumb': sticker.attachment.get_thumb_url(),
202 'alias': sticker.name}
203 'alias': str(sticker)}
203 204 for sticker in stickers]
204 205
205 206 return HttpResponse(content=json.dumps(image_dict))
General Comments 0
You need to be logged in to leave comments. Login now