diff --git a/accounts_app/models.py b/accounts_app/models.py index 3c7c9ad..731b432 100644 --- a/accounts_app/models.py +++ b/accounts_app/models.py @@ -90,9 +90,10 @@ class UserProfile(AbstractBaseUser, PermissionsMixin): def get_min_ava(self): if self.avatar: - path = self.avatar.min() - if os.path.exists(path): - return path + url_path = self.avatar.min() + real_path = url_path[1:] + if os.path.exists(real_path): + return url_path else: return DEFAULT_PICTURE else: diff --git a/msg_app/forms.py b/msg_app/forms.py index c489cd9..fd99831 100644 --- a/msg_app/forms.py +++ b/msg_app/forms.py @@ -17,7 +17,7 @@ class ConversationForm(forms.ModelForm): class Meta: model = Conversation - exclude = ['date_create'] + exclude = ['date_create', 'author'] def create(self, author): participants = self.cleaned_data['participants'] diff --git a/msg_app/locale/ru/LC_MESSAGES/django.po b/msg_app/locale/ru/LC_MESSAGES/django.po new file mode 100644 index 0000000..de5da31 --- /dev/null +++ b/msg_app/locale/ru/LC_MESSAGES/django.po @@ -0,0 +1,161 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# Dmitry Novikov nerosketch@gmail.com, 2017. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2017-10-04 17:52+0300\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: Dmitry Novikov nerosketch@gmail.com\n" +"Language: ru\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=4; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n" +"%10<=4 && (n%100<12 || n%100>14) ? 1 : n%10==0 || (n%10>=5 && n%10<=9) || (n" +"%100>=11 && n%100<=14)? 2 : 3);\n" + +#: forms.py:25 +msgid "you must choose at least 1 participants" +msgstr "вы должны выбрать как минимум одного участника" + +#: models.py:14 templates/msg_app/conversations.html.py:54 +msgid "New" +msgstr "Новая" + +#: models.py:15 +msgid "Seen" +msgstr "Просмотренное" + +#: models.py:16 +msgid "Deleted" +msgstr "Удалённое" + +#: models.py:28 +msgid "Message status" +msgstr "Статус сообщения" + +#: models.py:29 +msgid "Messages statuses" +msgstr "Статусы сообщений" + +#: models.py:33 +msgid "Body" +msgstr "Тело" + +#: models.py:34 +msgid "sent at" +msgstr "отправлено" + +#: models.py:36 models.py:234 +msgid "Conversation" +msgstr "Беседа" + +#: models.py:66 +msgid "Message" +msgstr "Сообщение" + +#: models.py:67 +msgid "Messages" +msgstr "Сообщения" + +#: models.py:69 +msgid "Can view messages" +msgstr "может просматривать сообщения" + +#: models.py:77 +msgid "Admin" +msgstr "Админ" + +#: models.py:78 +msgid "Guest" +msgstr "Гость" + +#: models.py:79 +msgid "Banned user" +msgstr "Запрещённый пользователь" + +#: models.py:80 +msgid "Inviter" +msgstr "Создатель" + +#: models.py:90 +msgid "Conversation membership" +msgstr "Членство в беседе" + +#: models.py:91 +msgid "Conversation memberships" +msgstr "Членства в беседах" + +#: models.py:100 +msgid "Participant profile does not found" +msgstr "Учётная запись участника не найдена" + +#: models.py:110 +msgid "No name" +msgstr "Без имени" + +#: models.py:235 templates/msg_app/conversations.html.py:14 +msgid "Conversations" +msgstr "Беседы" + +#: models.py:237 +msgid "Can view conversation" +msgstr "Может просматривать беседы" + +#: templates/msg_app/chat.html:7 templates/msg_app/conversations.html.py:7 +msgid "Private messages" +msgstr "Личные сообщения" + +#: templates/msg_app/chat.html:16 +msgid "peoples" +msgstr "участников" + +#: templates/msg_app/chat.html:26 +msgid "Delete" +msgstr "Удалить" + +#: templates/msg_app/chat.html:58 +msgid "Message history is empty" +msgstr "История сообщений пуста" + +#: templates/msg_app/chat.html:75 +msgid "Send" +msgstr "Отправить" + +#: templates/msg_app/conversations.html:32 +#, python-format +msgid "%(participants_count)s participants, %(msg_count)s messages" +msgstr "%(participants_count)s участников, %(msg_count)s сообщений" + +#: templates/msg_app/conversations.html:38 +msgid "No messages found" +msgstr "Сообщения не найдены" + +#: templates/msg_app/conversations.html:47 +msgid "Any conversations not found" +msgstr "Не найдено ни одной беседы" + +#: templates/msg_app/modal_new_conversation.html:5 +msgid "Create conversation" +msgstr "Создать беседу" + +#: templates/msg_app/modal_new_conversation.html:19 +msgid "for select multiple press ctrl and click on field" +msgstr "Для выбора нескольких ывриантов зажмите ctrl и кликните вариант" + +#: templates/msg_app/modal_new_conversation.html:28 +msgid "Add" +msgstr "Добавить" + +#: views.py:26 +msgid "Conversation has been created" +msgstr "Беседа создана" + +#: views.py:29 views.py:48 +msgid "fix form errors" +msgstr "заполните все поля в соответствии с их форматом" diff --git a/msg_app/migrations/0001_initial.py b/msg_app/migrations/0001_initial.py new file mode 100644 index 0000000..c47429f --- /dev/null +++ b/msg_app/migrations/0001_initial.py @@ -0,0 +1,103 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9 on 2017-10-04 17:44 +from __future__ import unicode_literals + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.CreateModel( + name='Conversation', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('title', models.CharField(max_length=32)), + ('date_create', models.DateTimeField(auto_now_add=True)), + ('author', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), + ], + options={ + 'verbose_name': 'Conversation', + 'verbose_name_plural': 'Conversations', + 'db_table': 'conversations', + 'permissions': (('can_view_conversation', 'Can view conversation'),), + }, + ), + migrations.CreateModel( + name='ConversationMembership', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('status', models.CharField(choices=[('adm', 'Admin'), ('gst', 'Guest'), ('ban', 'Banned user'), ('inv', 'Inviter')], default='gst', max_length=3)), + ('account', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='memberships', to=settings.AUTH_USER_MODEL)), + ('conversation', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='msg_app.Conversation')), + ('who_invite_that_user', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='self_conversations', to=settings.AUTH_USER_MODEL)), + ], + options={ + 'verbose_name': 'Conversation membership', + 'verbose_name_plural': 'Conversation memberships', + 'db_table': 'conversation_memberships', + }, + ), + migrations.CreateModel( + name='Message', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('text', models.TextField(verbose_name='Body')), + ('sent_at', models.DateTimeField(auto_now_add=True, verbose_name='sent at')), + ('attachment', models.FileField(blank=True, null=True, upload_to='messages_attachments/%Y_%m_%d')), + ], + options={ + 'verbose_name': 'Message', + 'verbose_name_plural': 'Messages', + 'db_table': 'messages', + 'ordering': ['-sent_at'], + 'permissions': (('can_view_messages', 'Can view messages'),), + }, + ), + migrations.CreateModel( + name='MessageStatus', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('state', models.CharField(choices=[('new', 'New'), ('old', 'Seen'), ('del', 'Deleted')], default='new', max_length=3)), + ('msg', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='msg_statuses', to='msg_app.Message')), + ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='usr_msg_status', to=settings.AUTH_USER_MODEL)), + ], + options={ + 'verbose_name': 'Message status', + 'verbose_name_plural': 'Messages statuses', + 'db_table': 'message_status', + }, + ), + migrations.AddField( + model_name='message', + name='account_status', + field=models.ManyToManyField(through='msg_app.MessageStatus', to=settings.AUTH_USER_MODEL), + ), + migrations.AddField( + model_name='message', + name='author', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='messages', to=settings.AUTH_USER_MODEL), + ), + migrations.AddField( + model_name='message', + name='conversation', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='msg_app.Conversation', verbose_name='Conversation'), + ), + migrations.AddField( + model_name='conversation', + name='participants', + field=models.ManyToManyField(related_name='conversations', through='msg_app.ConversationMembership', to=settings.AUTH_USER_MODEL), + ), + migrations.AlterUniqueTogether( + name='messagestatus', + unique_together=set([('msg', 'user', 'state')]), + ), + ] diff --git a/msg_app/models.py b/msg_app/models.py index f12b29f..a1d0eaa 100644 --- a/msg_app/models.py +++ b/msg_app/models.py @@ -8,7 +8,7 @@ class MessageError(Exception): class MessageStatus(models.Model): - msg = models.ForeignKey('Message') + msg = models.ForeignKey('Message', related_name='msg_statuses') user = models.ForeignKey(UserProfile, related_name='usr_msg_status') MESSAGE_STATES = ( ('new', _('New')), @@ -17,6 +17,9 @@ class MessageStatus(models.Model): ) state = models.CharField(max_length=3, choices=MESSAGE_STATES, default='new') + def __str__(self): + return "%s for %s (%s)" % (self.get_state_display(), self.user, self.msg) + class Meta: db_table = 'message_status' unique_together = ( @@ -30,12 +33,12 @@ class Message(models.Model): text = models.TextField(_("Body")) sent_at = models.DateTimeField(_("sent at"), auto_now_add=True) author = models.ForeignKey(UserProfile, related_name='messages') - conversation = models.ForeignKey('Conversation', verbose_name=_('Dialog')) + conversation = models.ForeignKey('Conversation', verbose_name=_('Conversation')) attachment = models.FileField(upload_to='messages_attachments/%Y_%m_%d', blank=True, null=True) account_status = models.ManyToManyField(UserProfile, through=MessageStatus, through_fields=('msg', 'user')) def __str__(self): - return self.text[9:] + return self.text[:9] def _set_status(self, account, code): try: @@ -107,7 +110,7 @@ class ConversationManager(models.Manager): title = _('No name') else: title = ', '.join(usernames) - conversation = self.create(title=title) + conversation = self.create(title=title, author=author) for acc in other_participants: ConversationMembership.objects.create( account=acc, conversation=conversation, status='adm', who_invite_that_user=author @@ -122,12 +125,19 @@ class ConversationManager(models.Manager): ms_count = MessageStatus.objects.filter(user=account, state='new').count() return ms_count + def fetch(self, account): + conversations = self.filter(models.Q(author=account) | models.Q(participants__in=[account])).annotate( + msg_count=models.Count('message', distinct=True) + ) + return conversations + class Conversation(models.Model): title = models.CharField(max_length=32) participants = models.ManyToManyField(UserProfile, related_name='conversations', through='ConversationMembership', through_fields=('conversation', 'account')) + author = models.ForeignKey(UserProfile) date_create = models.DateTimeField(auto_now_add=True) def __str__(self): @@ -158,13 +168,6 @@ class Conversation(models.Model): MessageStatus.objects.create(msg=msg, user=participant) return msg - def get_author(self): - try: - accs = ConversationMembership.objects.filter(status='inv', conversation=self) - return accs[0].account - except IndexError: - pass - def remove_message(self, msg): if isinstance(msg, Message): m = msg @@ -213,6 +216,18 @@ class Conversation(models.Model): def find_messages_by_text(self, text): return Message.objects.filter(text__icontains=text, conversation=self) + def _make_messages_status(self, account, status): + qs = MessageStatus.objects.filter(msg__conversation=self, user=account).exclude(state='del') + if status != 'del': + qs = qs.exclude(state=status) + return qs.update(state=status) + + def make_messages_status_new(self, account): + return self._make_messages_status(account, 'new') + + def make_messages_status_old(self, account): + return self._make_messages_status(account, 'old') + class Meta: db_table = 'conversations' verbose_name = _("Conversation") diff --git a/msg_app/templates/msg_app/chat.html b/msg_app/templates/msg_app/chat.html index 57e86b8..5ee0394 100644 --- a/msg_app/templates/msg_app/chat.html +++ b/msg_app/templates/msg_app/chat.html @@ -13,7 +13,7 @@