Commit e32bcf4c332e08954da68fbfd0e5817b2f646215

Authored by Zambom
1 parent f10f68cc

Adding general chat message sent (Adjusts to be made)

amadeus/static/js/chat.js
1   -function getModalInfo(btn, space) {
  1 +function getModalInfo(btn, space, space_type) {
2 2 var url = btn.data('url');
3 3  
4 4 $.ajax({
5 5 method: 'get',
6 6 url: url,
7   - data: {'space': space},
  7 + data: {'space': space, 'space_type': space_type},
8 8 success: function (response) {
9 9 $("#chat-modal-info").html(response);
10 10  
... ... @@ -13,4 +13,51 @@ function getModalInfo(btn, space) {
13 13 $.material.init();
14 14 }
15 15 });
  16 +}
  17 +
  18 +function getForm(field) {
  19 + var url = field.find('h4').data('url');
  20 +
  21 + $.ajax({
  22 + url: url,
  23 + success: function (data) {
  24 + $('#chat-modal-form').html(data);
  25 +
  26 + setChatFormSubmit();
  27 +
  28 + $('#chat-modal-form').modal('show');
  29 + }
  30 + });
  31 +}
  32 +
  33 +function setChatFormSubmit() {
  34 + var frm = $('#chat-form');
  35 +
  36 + frm.submit(function () {
  37 + var formData = new FormData($(this)[0]);
  38 +
  39 + $.ajax({
  40 + type: frm.attr('method'),
  41 + url: frm.attr('action'),
  42 + data: formData,
  43 + dataType: "json",
  44 + async: false,
  45 + success: function (data) {
  46 + $('.messages-container').append(data.view);
  47 +
  48 + $('#chat-modal-form').modal('hide');
  49 +
  50 + alertify.success(data.message);
  51 + },
  52 + error: function(data) {
  53 + $("#chat-modal-form").html(data.responseText);
  54 + setChatFormSubmit();
  55 + },
  56 + cache: false,
  57 + contentType: false,
  58 + processData: false
  59 + });
  60 +
  61 + return false;
  62 + });
16 63 }
17 64 \ No newline at end of file
... ...
chat/forms.py 0 → 100644
... ... @@ -0,0 +1,44 @@
  1 +# coding=utf-8
  2 +from django import forms
  3 +from django.utils.translation import ugettext_lazy as _
  4 +from django.utils.html import strip_tags
  5 +from django.db.models import Q
  6 +
  7 +from resubmit.widgets import ResubmitFileWidget
  8 +
  9 +from .models import TalkMessages
  10 +
  11 +class Validation(forms.ModelForm):
  12 + MAX_UPLOAD_SIZE = 5*1024*1024
  13 +
  14 + def clean_text(self):
  15 + text = self.cleaned_data.get('text', '')
  16 + cleaned_text = strip_tags(text)
  17 +
  18 + if cleaned_text == '':
  19 + self._errors['text'] = [_('This field is required.')]
  20 +
  21 + return ValueError
  22 +
  23 + return text
  24 +
  25 + def clean_image(self):
  26 + image = self.cleaned_data.get('image', False)
  27 +
  28 + if image:
  29 + if hasattr(image, '_size'):
  30 + if image._size > self.MAX_UPLOAD_SIZE:
  31 + self._errors['image'] = [_("The image is too large. It should have less than 5MB.")]
  32 +
  33 + return ValueError
  34 +
  35 + return image
  36 +
  37 +class ChatMessageForm(Validation):
  38 + class Meta:
  39 + model = TalkMessages
  40 + fields = ['text', 'image']
  41 + widgets = {
  42 + 'text': forms.Textarea,
  43 + 'image': ResubmitFileWidget(attrs={'accept':'image/*'}),
  44 + }
0 45 \ No newline at end of file
... ...
chat/models.py
... ... @@ -36,13 +36,13 @@ class CategoryTalk(Conversation):
36 36 space = models.ForeignKey(Category, verbose_name = ('Category'), related_name = 'talk_category', null = True)
37 37  
38 38 class SubjectTalk(Conversation):
39   - space = models.ForeignKey(Subject, verbose_name = _('Subject'), related_name = 'talk_subject')
  39 + space = models.ForeignKey(Subject, verbose_name = _('Subject'), related_name = 'talk_subject', null = True)
40 40  
41 41 class TalkMessages(models.Model):
42 42 text = models.TextField(_('Comment'), blank = True)
43   - image = models.ImageField(verbose_name = _('Image'), null=True, blank = True, upload_to = upload_filename, validators = [validate_img_extension])
44   - talk = models.ForeignKey(Conversation, verbose_name = _('Conversation'), related_name = 'message_talk')
45   - user = models.ForeignKey(User, verbose_name = _('User'), related_name = 'message_user')
  43 + image = models.ImageField(verbose_name = _('Image'), null = True, blank = True, upload_to = upload_filename, validators = [validate_img_extension])
  44 + talk = models.ForeignKey(Conversation, verbose_name = _('Conversation'), related_name = 'message_talk', null = True)
  45 + user = models.ForeignKey(User, verbose_name = _('User'), related_name = 'message_user', null = True)
46 46 create_date = models.DateTimeField(_('Create Date'), auto_now_add = True)
47 47  
48 48 class ChatVisualizations(models.Model):
... ...
chat/templates/chat/_form.html 0 → 100644
... ... @@ -0,0 +1,113 @@
  1 +{% load static i18n %}
  2 +{% load widget_tweaks %}
  3 +
  4 +<div class="modal-dialog" role="document">
  5 + <div class="modal-content">
  6 + <div class="modal-body">
  7 + <form id="chat-form" method="post" action="{{ form_url }}" enctype="multipart/form-data">
  8 + {% csrf_token %}
  9 +
  10 + <div class="form-group{% if form.has_error %} has-error {% endif %}">
  11 + <label for="{{ form.text.auto_id }}">{{ form.text.label }} <span>*</span></label>
  12 + {% render_field form.text class='form-control text_simple_wysiwyg' %}
  13 +
  14 + <span id="helpBlock" class="help-block">{{ form.text.help_text }}</span>
  15 +
  16 + {% if form.text.errors %}
  17 + <div class="alert alert-danger alert-dismissible" role="alert">
  18 + <button type="button" class="close" data-dismiss="alert" aria-label="Close">
  19 + <span aria-hidden="true">&times;</span>
  20 + </button>
  21 + <ul>
  22 + {% for error in form.text.errors %}
  23 + <li>{{ error }}</li>
  24 + {% endfor %}
  25 + </ul>
  26 + </div>
  27 + {% endif %}
  28 + </div>
  29 +
  30 + <div class="form-group{% if form.has_error %} has-error {% endif %} is-fileinput">
  31 + {% render_field form.image %}
  32 +
  33 + <div class="filedrag">
  34 + {% trans 'Click or drop the file here' %}<br />
  35 +
  36 + <small>{% trans 'The file could not exceed 5MB.' %}</small>
  37 + </div>
  38 +
  39 + <span id="helpBlock" class="help-block">{{ form.image.help_text }}</span>
  40 +
  41 + {% if form.image.errors %}
  42 + <div class="alert alert-danger alert-dismissible" role="alert">
  43 + <button type="button" class="close" data-dismiss="alert" aria-label="Close">
  44 + <span aria-hidden="true">&times;</span>
  45 + </button>
  46 + <ul>
  47 + {% for error in form.image.errors %}
  48 + <li>{{ error }}</li>
  49 + {% endfor %}
  50 + </ul>
  51 + </div>
  52 + {% endif %}
  53 + </div>
  54 + </form>
  55 + </div>
  56 + <div class="modal-footer">
  57 + <div class="col-md-12">
  58 + <button type="submit" id="button" form="chat-form" class="btn btn-success btn-raised post-button pull-left">{% trans "Save" %}</button>
  59 + <button type="button" class="btn btn-raised btn-default pull-right" data-dismiss="modal">{% trans "Cancel" %}</button>
  60 + </div>
  61 + </div>
  62 + </div>
  63 +</div>
  64 +
  65 +<script type="text/javascript">
  66 + $(function () {
  67 + $('.text_simple_wysiwyg').summernote({
  68 + dialogsInBody: true,
  69 + height: 150,
  70 + toolbar: [
  71 + // [groupName, [list of button]]
  72 + ['style', ['bold', 'italic']],
  73 + ['insert', ['link']]
  74 + ]
  75 + });
  76 +
  77 + $.material.init();
  78 +
  79 + if (window.File && window.FileList && window.FileReader) {
  80 + Init();
  81 + }
  82 + });
  83 +
  84 + // initialize
  85 + function Init() {
  86 + var small = $("#id_image"),
  87 + filedrag = $(".filedrag"),
  88 + common = $(".common-file-input");
  89 +
  90 + // file select
  91 + small.on("change", FileSelectHandler);
  92 +
  93 + // is XHR2 available?
  94 + var xhr = new XMLHttpRequest();
  95 + if (xhr.upload) {
  96 + // file drop
  97 + filedrag.on("drop", FileSelectHandler);
  98 + filedrag.attr('style', 'display:block');
  99 + common.attr('style', 'display:none');
  100 + }
  101 + }
  102 +
  103 + // file selection
  104 + function FileSelectHandler(e) {
  105 + var files = e.target.files || e.dataTransfer.files,
  106 + parent = $(e.target.offsetParent);
  107 +
  108 + // process all File objects
  109 + for (var i = 0, f; f = files[i]; i++) {
  110 + parent.find('.filedrag').html(f.name);
  111 + }
  112 + }
  113 +</script>
... ...
chat/templates/chat/_message.html 0 → 100644
... ... @@ -0,0 +1,6 @@
  1 +<div class="col-md-12">
  2 + <p>{{ talk_msg.user }}</p>
  3 + {% autoescape off %}
  4 + {{ talk_msg.text }}
  5 + {% endautoescape %}
  6 +</div>
0 7 \ No newline at end of file
... ...
chat/templates/chat/_profile.html
... ... @@ -17,7 +17,7 @@
17 17 <a class="status {{ status }}" title="{{ status|status_text }}"></a>
18 18 <b>{{ participant }}</b>
19 19 </h4>
20   - <a href="#" onclick="getModalInfo($(this), '{{ space }}'); return false;" data-url='{% url "chat:talk" participant.email %}' class="btn btn-raised btn-success btn-block">{% trans 'Send Message' %}</a>
  20 + <a href="#" onclick="getModalInfo($(this), '{{ space }}', '{{ space_type }}'); return false;" data-url='{% url "chat:talk" participant.email %}' class="btn btn-raised btn-success btn-block">{% trans 'Send Message' %}</a>
21 21 </div>
22 22 <div class="col-md-8">
23 23 <div class="form-group">
... ...
chat/templates/chat/_view_participant.html
... ... @@ -10,7 +10,7 @@
10 10 <h4><a class="status {{ status }}" data-toggle="tooltip" title="{{ status|status_text }}"></a> {{ participant }}</h4>
11 11 </div>
12 12 <div class="col-md-4 buttons pull-right text-center">
13   - <a href="#" onclick="getModalInfo($(this), '{{ space }}'); return false;" data-url='{% url "chat:profile" participant.email %}' class="btn btn-raised btn-default">{% trans 'See Profile' %}</a>
14   - <a href="#" onclick="getModalInfo($(this), '{{ space }}'); return false;" data-url='{% url "chat:talk" participant.email %}' class="btn btn-raised btn-success">{% trans 'Send Message' %}</a>
  13 + <a href="#" onclick="getModalInfo($(this), '{{ space }}', '{{ space_type }}'); return false;" data-url='{% url "chat:profile" participant.email %}' class="btn btn-raised btn-default">{% trans 'See Profile' %}</a>
  14 + <a href="#" onclick="getModalInfo($(this), '{{ space }}', '{{ space_type }}'); return false;" data-url='{% url "chat:talk" participant.email %}' class="btn btn-raised btn-success">{% trans 'Send Message' %}</a>
15 15 </div>
16 16 </div>
... ...
chat/templates/chat/list_participants.html
... ... @@ -53,7 +53,7 @@
53 53  
54 54 <div class="participants-group">
55 55 {% for participant in participants %}
56   - {% include 'chat/_view_participant.html' with space="0" %}
  56 + {% include 'chat/_view_participant.html' with space="0" space_type='general' %}
57 57 {% endfor %}
58 58 </div>
59 59  
... ... @@ -71,5 +71,7 @@
71 71  
72 72 <div class="modal fade" id="chat-modal-info" tabindex="-1" role="dialog" aria-labelledby="myModalLabel"></div>
73 73  
  74 + <div class="modal fade" id="chat-modal-form" tabindex="-1" role="dialog" aria-labelledby="myModalLabel"></div>
  75 +
74 76 <script type="text/javascript" src="{% static 'js/chat.js' %}"></script>
75 77 {% endblock %}
76 78 \ No newline at end of file
... ...
chat/templates/chat/talk.html
... ... @@ -39,6 +39,9 @@
39 39 </div>
40 40 <div class="row-fluid">
41 41 <div class="messages-container">
  42 + {% for talk_msg in messages %}
  43 + {% include 'chat/_message.html' %}
  44 + {% endfor %}
42 45 </div>
43 46 </div>
44 47 </div>
... ... @@ -49,9 +52,9 @@
49 52 <img src="{{ request.user.image_url }}" class="img-responsive" />
50 53 </div>
51 54 </div>
52   - <div class="col-lg-11 col-md-11 col-sm-11 col-xs-11 message-field" onclick="comment($(this))">
53   - <div>
54   - <h4 data-url="">{% trans 'Type a new message to ' %}{{ participant }} <i class="fa fa-camera pull-right"></i></h4>
  55 + <div class="col-lg-11 col-md-11 col-sm-11 col-xs-11 message-field">
  56 + <div onclick="getForm($(this));">
  57 + <h4 data-url="{% url 'chat:create' participant.email talk_id space space_type %}">{% trans 'Type a new message to ' %}{{ participant }} <i class="fa fa-camera pull-right"></i></h4>
55 58 </div>
56 59 </div>
57 60 </div>
... ...
chat/urls.py
... ... @@ -4,6 +4,8 @@ from . import views
4 4 urlpatterns = [
5 5 url(r'^$', views.GeneralIndex.as_view(), name='manage_general'),
6 6 url(r'^participants/$', views.GeneralParticipants.as_view(), name='participants_general'),
  7 + url(r'^render_message/([\w_-]+)/$', views.render_message, name='render_message'),
7 8 url(r'^talk/(?P<email>[\w.%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,4})/$', views.GetTalk.as_view(), name = 'talk'),
  9 + url(r'^send_message/(?P<email>[\w.%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,4})/(?P<talk_id>[\w_-]+)/(?P<space>[\w_-]+)/(?P<space_type>[\w_-]+)/$', views.SendMessage.as_view(), name = 'create'),
8 10 url(r'^participant/profile/(?P<email>[\w.%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,4})/$', views.ParticipantProfile.as_view(), name = 'profile'),
9 11 ]
10 12 \ No newline at end of file
... ...
chat/views.py
... ... @@ -10,9 +10,12 @@ from django.utils.translation import ugettext_lazy as _
10 10 from django.contrib.auth.mixins import LoginRequiredMixin
11 11 from django.db.models import Q
12 12  
  13 +from categories.models import Category
  14 +from subjects.models import Subject
13 15 from users.models import User
14 16  
15   -from .models import Conversation, TalkMessages, ChatVisualizations
  17 +from .models import Conversation, GeneralTalk, CategoryTalk, SubjectTalk, TalkMessages, ChatVisualizations
  18 +from .forms import ChatMessageForm
16 19  
17 20 class GeneralIndex(LoginRequiredMixin, generic.ListView):
18 21 login_url = reverse_lazy("users:login")
... ... @@ -75,6 +78,24 @@ class GeneralParticipants(LoginRequiredMixin, generic.ListView):
75 78  
76 79 return context
77 80  
  81 +class ParticipantProfile(LoginRequiredMixin, generic.DetailView):
  82 + login_url = reverse_lazy("users:login")
  83 + redirect_field_name = 'next'
  84 +
  85 + model = User
  86 + slug_field = 'email'
  87 + slug_url_kwarg = 'email'
  88 + context_object_name = 'participant'
  89 + template_name = 'chat/_profile.html'
  90 +
  91 + def get_context_data(self, **kwargs):
  92 + context = super(ParticipantProfile, self).get_context_data(**kwargs)
  93 +
  94 + context['space'] = self.request.GET.get('space', '0')
  95 + context['space_type'] = self.request.GET.get('space_type', 'general')
  96 +
  97 + return context
  98 +
78 99 class GetTalk(LoginRequiredMixin, generic.ListView):
79 100 login_url = reverse_lazy("users:login")
80 101 redirect_field_name = 'next'
... ... @@ -82,6 +103,7 @@ class GetTalk(LoginRequiredMixin, generic.ListView):
82 103 context_object_name = 'messages'
83 104 template_name = 'chat/talk.html'
84 105 paginate_by = 20
  106 + talk_id = "-1"
85 107  
86 108 def get_queryset(self):
87 109 user = self.request.user
... ... @@ -93,6 +115,7 @@ class GetTalk(LoginRequiredMixin, generic.ListView):
93 115  
94 116 if talks.count() > 0:
95 117 talk = talks[0]
  118 + self.talk_id = talk.id
96 119  
97 120 messages = TalkMessages.objects.filter(talk = talk).order_by('-create_date')
98 121  
... ... @@ -104,22 +127,93 @@ class GetTalk(LoginRequiredMixin, generic.ListView):
104 127 user_email = self.kwargs.get('email', '')
105 128  
106 129 context['participant'] = get_object_or_404(User, email = user_email)
  130 + context['talk_id'] = self.talk_id
  131 + context['space'] = self.request.GET.get('space', '0')
  132 + context['space_type'] = self.request.GET.get('space_type', 'general')
107 133  
108 134 return context
109 135  
110   -class ParticipantProfile(LoginRequiredMixin, generic.DetailView):
  136 +class SendMessage(LoginRequiredMixin, generic.edit.CreateView):
111 137 login_url = reverse_lazy("users:login")
112 138 redirect_field_name = 'next'
113 139  
114   - model = User
115   - slug_field = 'email'
116   - slug_url_kwarg = 'email'
117   - context_object_name = 'participant'
118   - template_name = 'chat/_profile.html'
  140 + form_class = ChatMessageForm
  141 + template_name = "chat/_form.html"
  142 +
  143 + def form_invalid(self, form):
  144 + context = super(SendMessage, self).form_invalid(form)
  145 + context.status_code = 400
  146 +
  147 + return context
  148 +
  149 + def form_valid(self, form):
  150 + self.object = form.save(commit = False)
  151 +
  152 + self.object.user = self.request.user
  153 +
  154 + talk_id = self.kwargs.get('talk_id', '-1')
  155 + user = get_object_or_404(User, email = self.kwargs.get('email', ''))
  156 + space_type = self.kwargs.get('space_type', 'general')
  157 + space = self.kwargs.get('space', 0)
  158 +
  159 + if talk_id == "-1":
  160 + if space_type == 'general':
  161 + talk = GeneralTalk.objects.create(user_one = self.request.user, user_two = user, space = 0)
  162 + elif space_type == 'category':
  163 + cat = get_object_or_404(Category, id = space)
  164 + talk = CategoryTalk.objects.create(user_one = self.request.user, user_two = user, space = cat)
  165 + else:
  166 + sub = get_object_or_404(Subject, id = space)
  167 + talk = SubjectTalk.objects.create(user_one = self.request.user, user_two = user, space = sub)
  168 + else:
  169 + talk = get_object_or_404(Conversation, id = talk_id)
  170 +
  171 + self.object.talk = talk
  172 +
  173 + self.object.save()
  174 +
  175 + #entries = []
  176 +
  177 + #paths = [reverse("mural:manage_general")]
  178 +
  179 + #notification = {
  180 + # "type": "mural",
  181 + # "subtype": "post",
  182 + # "paths": paths,
  183 + # "user_icon": self.object.user.image_url,
  184 + # "simple_notify": _("%s has made a post in General")%(str(self.object.user)),
  185 + # "complete": render_to_string("mural/_view.html", {"post": self.object}, self.request),
  186 + # "container": ".post",
  187 + # "accordion": False,
  188 + # "post_type": "general"
  189 + #}
  190 +
  191 + #notification = json.dumps(notification)
  192 +
  193 + #Group("user-%s" % user.id).send({'text': notification})
  194 +
  195 + ChatVisualizations.objects.create(viewed = False, message = self.object, user = user)
  196 +
  197 + return super(SendMessage, self).form_valid(form)
119 198  
120 199 def get_context_data(self, **kwargs):
121   - context = super(ParticipantProfile, self).get_context_data(**kwargs)
  200 + context = super(SendMessage, self).get_context_data(**kwargs)
122 201  
123   - context['space'] = self.request.GET.get('space', '0')
  202 + context['form_url'] = reverse_lazy('chat:create', args = (), kwargs = {'email': self.kwargs.get('email', ''), 'talk_id': self.kwargs.get('talk_id', None), 'space': self.kwargs.get('space', '0'), 'space_type': self.kwargs.get('space_type', 'general')})
124 203  
125   - return context
126 204 \ No newline at end of file
  205 + return context
  206 +
  207 + def get_success_url(self):
  208 + return reverse_lazy('chat:render_message', args = (self.object.id, ))
  209 +
  210 +def render_message(request, talk_msg):
  211 + msg = get_object_or_404(TalkMessages, id = talk_msg)
  212 +
  213 + context = {}
  214 + context['talk_msg'] = msg
  215 +
  216 + message = _('Message sent successfully!')
  217 +
  218 + html = render_to_string("chat/_message.html", context, request)
  219 +
  220 + return JsonResponse({'message': message, 'view': html, 'new_id': msg.id})
127 221 \ No newline at end of file
... ...