Commit 7d3bfadddc238ad69efe7b8c6c26b045d7bb0b24
Exists in
master
and in
3 other branches
Merge branch 'refactoring' of https://github.com/amadeusproject/amadeuslms into refactoring
Showing
7 changed files
with
270 additions
and
19 deletions
Show diff stats
amadeus/static/css/base/amadeus.css
... | ... | @@ -1349,9 +1349,9 @@ div.dataTables_wrapper div.dataTables_paginate { |
1349 | 1349 | border-width: 1px; |
1350 | 1350 | border-style: solid; |
1351 | 1351 | border-radius: 10px; |
1352 | - margin-right: 10px; | |
1352 | + margin-right: 5px; | |
1353 | 1353 | position: relative; |
1354 | - top: 3px; | |
1354 | + top: -1px; | |
1355 | 1355 | display: inline-block; |
1356 | 1356 | border-spacing: 0; |
1357 | 1357 | border-collapse: collapse; | ... | ... |
amadeus/static/js/chat.js
1 | +var new_msgs = {}; | |
2 | + | |
1 | 3 | function getModalInfo(btn, space, space_type) { |
2 | 4 | var url = btn.data('url'); |
3 | 5 | |
... | ... | @@ -6,13 +8,15 @@ function getModalInfo(btn, space, space_type) { |
6 | 8 | url: url, |
7 | 9 | data: {'space': space, 'space_type': space_type}, |
8 | 10 | success: function (response) { |
11 | + var modal_shown = $("#chat-modal-info").is(":visible"); | |
12 | + | |
9 | 13 | $("#chat-modal-info").html(response); |
10 | 14 | |
11 | 15 | $("#chat-modal-info").modal('show'); |
12 | 16 | |
13 | 17 | $.material.init(); |
14 | 18 | |
15 | - $('#chat-modal-info').on('shown.bs.modal', function () { | |
19 | + if (modal_shown) { | |
16 | 20 | $(".messages-container").each(function () { |
17 | 21 | var height = $(this)[0].scrollHeight; |
18 | 22 | |
... | ... | @@ -20,7 +24,19 @@ function getModalInfo(btn, space, space_type) { |
20 | 24 | }); |
21 | 25 | |
22 | 26 | setShortChatFormSubmit(); |
23 | - }); | |
27 | + setFiltersSubmitAndPagination(); | |
28 | + } else { | |
29 | + $('#chat-modal-info').on('shown.bs.modal', function () { | |
30 | + $(".messages-container").each(function () { | |
31 | + var height = $(this)[0].scrollHeight; | |
32 | + | |
33 | + $(this).animate({scrollTop: height}, 0); | |
34 | + }); | |
35 | + | |
36 | + setShortChatFormSubmit(); | |
37 | + setFiltersSubmitAndPagination(); | |
38 | + }); | |
39 | + } | |
24 | 40 | |
25 | 41 | $("#msg_editable").on('click', function () { |
26 | 42 | $(this).trigger('focusin'); |
... | ... | @@ -93,9 +109,13 @@ function setChatFormSubmit() { |
93 | 109 | $(this).animate({scrollTop: height}, 0); |
94 | 110 | }); |
95 | 111 | |
96 | - $('#chat-modal-form').modal('hide'); | |
112 | + if (typeof(new_msgs[data.talk_id]) == 'undefined') { | |
113 | + new_msgs[data.talk_id] = []; | |
114 | + } | |
115 | + | |
116 | + new_msgs[data.talk_id].push(data.new_id); | |
97 | 117 | |
98 | - alertify.success(data.message); | |
118 | + $('#chat-modal-form').modal('hide'); | |
99 | 119 | }, |
100 | 120 | error: function(data) { |
101 | 121 | $("#chat-modal-form").html(data.responseText); |
... | ... | @@ -137,13 +157,16 @@ function setShortChatFormSubmit() { |
137 | 157 | $(this).animate({scrollTop: height}, 0); |
138 | 158 | }); |
139 | 159 | |
160 | + if (typeof(new_msgs[data.talk_id]) == 'undefined') { | |
161 | + new_msgs[data.talk_id] = []; | |
162 | + } | |
163 | + | |
164 | + new_msgs[data.talk_id].push(data.new_id); | |
165 | + | |
140 | 166 | editable.html(""); |
141 | 167 | editable.trigger("focusout"); |
142 | - | |
143 | - alertify.success(data.message); | |
144 | 168 | }, |
145 | 169 | error: function(data) { |
146 | - alertify.error(data.responseText); | |
147 | 170 | setShortChatFormSubmit(); |
148 | 171 | }, |
149 | 172 | cache: false, |
... | ... | @@ -154,4 +177,133 @@ function setShortChatFormSubmit() { |
154 | 177 | |
155 | 178 | return false; |
156 | 179 | }); |
180 | +} | |
181 | + | |
182 | +function favorite(btn) { | |
183 | + var action = btn.data('action'), | |
184 | + url = btn.data('url'); | |
185 | + | |
186 | + $.ajax({ | |
187 | + url: url, | |
188 | + data: {'action': action}, | |
189 | + dataType: 'json', | |
190 | + success: function (response) { | |
191 | + if (action == 'favorite') { | |
192 | + btn.switchClass("btn_fav", "btn_unfav", 250, "easeInOutQuad"); | |
193 | + btn.data('action', 'unfavorite'); | |
194 | + } else { | |
195 | + btn.switchClass("btn_unfav", "btn_fav", 250, "easeInOutQuad"); | |
196 | + btn.data('action', 'favorite'); | |
197 | + } | |
198 | + | |
199 | + btn.attr('data-original-title', response.label); | |
200 | + } | |
201 | + }); | |
202 | +} | |
203 | + | |
204 | +function setFiltersSubmitAndPagination() { | |
205 | + var filters = $('#chat-filters'), | |
206 | + clear_filters = $('#clear_filter'), | |
207 | + messages = $('.messages-container'), | |
208 | + loading = messages.find('.loading-msgs'), | |
209 | + more = messages.find('.more-msgs'), | |
210 | + msg_section = $('.messages-list'); | |
211 | + | |
212 | + filters.submit(function () { | |
213 | + var favorite = $(this).find("input[name='favorite']").is(':checked') ? "True" : "", | |
214 | + mine = $(this).find("input[name='mine']").is(':checked') ? "True" : "", | |
215 | + url = messages.data('url'); | |
216 | + | |
217 | + msg_section.html(''); | |
218 | + | |
219 | + more.hide(); | |
220 | + loading.show(); | |
221 | + | |
222 | + $.ajax({ | |
223 | + url: url, | |
224 | + data: {'favorite': favorite, 'mine': mine}, | |
225 | + dataType: 'json', | |
226 | + success: function (data) { | |
227 | + loading.hide(); | |
228 | + | |
229 | + if (data.count > 0) { | |
230 | + msg_section.append(data.messages); | |
231 | + | |
232 | + messages.data('pages', data.num_pages); | |
233 | + messages.data('page', data.num_page); | |
234 | + | |
235 | + if (data.num_page < data.num_pages) { | |
236 | + more.show(); | |
237 | + } else { | |
238 | + more.hide(); | |
239 | + } | |
240 | + } | |
241 | + | |
242 | + messages.data('fav', favorite); | |
243 | + messages.data('mine', mine); | |
244 | + | |
245 | + messages.each(function () { | |
246 | + var height = $(this)[0].scrollHeight; | |
247 | + | |
248 | + $(this).animate({scrollTop: height}, 0); | |
249 | + }); | |
250 | + } | |
251 | + }); | |
252 | + | |
253 | + return false; | |
254 | + }); | |
255 | + | |
256 | + clear_filters.click(function () { | |
257 | + var frm = $(this).parent(); | |
258 | + | |
259 | + $("input[type='checkbox']").prop('checked', false); | |
260 | + | |
261 | + frm.submit(); | |
262 | + }); | |
263 | + | |
264 | + more.click(function () { | |
265 | + var url = messages.data('url'), | |
266 | + pageNum = messages.data('page'), | |
267 | + numberPages = messages.data('pages'), | |
268 | + favorites = messages.data('fav'), | |
269 | + mine = messages.data('mine'), | |
270 | + talk = messages.data('talk'); | |
271 | + | |
272 | + var showing; | |
273 | + | |
274 | + if (typeof(new_msgs[talk]) == 'undefined') { | |
275 | + showing = ""; | |
276 | + } else { | |
277 | + showing = new_msgs[talk].join(','); | |
278 | + } | |
279 | + | |
280 | + if (pageNum == numberPages) { | |
281 | + return false | |
282 | + } | |
283 | + | |
284 | + pageNum = pageNum + 1; | |
285 | + | |
286 | + more.hide(); | |
287 | + loading.show(); | |
288 | + | |
289 | + $.ajax({ | |
290 | + url: url, | |
291 | + data: {'page': pageNum, 'favorite': favorites, 'mine': mine, 'showing': showing}, | |
292 | + dataType: 'json', | |
293 | + success: function (data) { | |
294 | + loading.hide(); | |
295 | + | |
296 | + msg_section.prepend(data.messages); | |
297 | + | |
298 | + messages.data('pages', data.num_pages); | |
299 | + messages.data('page', data.num_page); | |
300 | + | |
301 | + if (data.num_page < data.num_pages) { | |
302 | + more.show(); | |
303 | + } else { | |
304 | + more.hide(); | |
305 | + } | |
306 | + } | |
307 | + }); | |
308 | + }); | |
157 | 309 | } |
158 | 310 | \ No newline at end of file | ... | ... |
chat/templates/chat/_message.html
1 | +{% load chat_tags %} | |
2 | + | |
1 | 3 | <div class="col-md-12 message-view"> |
2 | 4 | <h4 class="message-user"> |
3 | 5 | {{ talk_msg.user }} |
... | ... | @@ -5,7 +7,7 @@ |
5 | 7 | ({{ talk_msg.create_date }}) |
6 | 8 | </span> |
7 | 9 | <span class="btn-group pull-right"> |
8 | - <button class="btn btn-sm btn_menu btn_fav" onclick="favorite($(this))" data-url="" data-action="" data-toggle="tooltip" data-placement="top" title=""> | |
10 | + <button class="btn btn-sm btn_menu {{ talk_msg|fav_class:request.user }}" onclick="favorite($(this))" data-url="{% url 'chat:favorite' talk_msg.id %}" data-action="{{ talk_msg|fav_action:request.user }}" data-toggle="tooltip" data-placement="top" title="{{ talk_msg|fav_label:request.user }}"> | |
9 | 11 | <i class="fa fa-thumb-tack"></i> |
10 | 12 | </button> |
11 | 13 | </span> | ... | ... |
chat/templates/chat/talk.html
... | ... | @@ -22,7 +22,7 @@ |
22 | 22 | <div class="talk-filter"> |
23 | 23 | <h4>{% trans 'Filter' %}</h4> |
24 | 24 | |
25 | - <form id="post-filters" class="form-inline" action="" method="GET"> | |
25 | + <form id="chat-filters" class="form-inline" action="" method="GET"> | |
26 | 26 | <div class="checkbox"> |
27 | 27 | <label> |
28 | 28 | <input name="favorite" type="checkbox"> {% trans 'Favorite messages' %} <i class="fa fa-thumb-tack"></i> |
... | ... | @@ -39,7 +39,16 @@ |
39 | 39 | </div> |
40 | 40 | </div> |
41 | 41 | <div class="row-fluid"> |
42 | - <div class="messages-container"> | |
42 | + <div class="messages-container" data-talk="{{ talk_id }}" data-url="{% url 'chat:load_messages' talk_id %}" data-page="{{ page_obj.number }}" data-pages="{{ paginator.num_pages }}"> | |
43 | + <button type="button" class="btn btn-block btn-success btn-raised more-msgs" style="{% if paginator.num_pages == page_obj.number %}display:none;{% endif %}margin:0px"> | |
44 | + {% trans 'See old messages' %} | |
45 | + </button> | |
46 | + | |
47 | + <div class="alert alert-success loading-msgs" role="alert" style="display:none"> | |
48 | + <center> | |
49 | + <span class="fa fa-spin fa-circle-o-notch"></span> | |
50 | + </center> | |
51 | + </div> | |
43 | 52 | <div class="messages_new"> |
44 | 53 | {% trans 'You have new messages...' %} |
45 | 54 | </div> | ... | ... |
chat/templatetags/chat_tags.py
... | ... | @@ -7,7 +7,7 @@ from django.contrib.sessions.models import Session |
7 | 7 | |
8 | 8 | from log.models import Log |
9 | 9 | |
10 | -from chat.models import TalkMessages, ChatVisualizations | |
10 | +from chat.models import TalkMessages, ChatVisualizations, ChatFavorites | |
11 | 11 | |
12 | 12 | register = template.Library() |
13 | 13 | |
... | ... | @@ -55,4 +55,25 @@ def last_message(chat): |
55 | 55 | def notifies(chat, user): |
56 | 56 | total = ChatVisualizations.objects.filter(message__talk = chat, user = user).count() |
57 | 57 | |
58 | - return total | |
59 | 58 | \ No newline at end of file |
59 | + return total | |
60 | + | |
61 | +@register.filter(name = 'fav_label') | |
62 | +def fav_label(message, user): | |
63 | + if ChatFavorites.objects.filter(message = message, user = user).exists(): | |
64 | + return _('Unfavorite') | |
65 | + | |
66 | + return _('Favorite') | |
67 | + | |
68 | +@register.filter(name = 'fav_action') | |
69 | +def fav_action(message, user): | |
70 | + if ChatFavorites.objects.filter(message = message, user = user).exists(): | |
71 | + return "unfavorite" | |
72 | + | |
73 | + return "favorite" | |
74 | + | |
75 | +@register.filter(name = 'fav_class') | |
76 | +def fav_class(message, user): | |
77 | + if ChatFavorites.objects.filter(message = message, user = user).exists(): | |
78 | + return "btn_unfav" | |
79 | + | |
80 | + return "btn_fav" | |
60 | 81 | \ No newline at end of file | ... | ... |
chat/urls.py
... | ... | @@ -5,6 +5,8 @@ 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 | 7 | url(r'^render_message/([\w_-]+)/$', views.render_message, name='render_message'), |
8 | + url(r'^favorite/([\w_-]+)/$', views.favorite, name='favorite'), | |
9 | + url(r'^load_messages/([\w_-]+)/$', views.load_messages, name='load_messages'), | |
8 | 10 | url(r'^talk/(?P<email>[\w.%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,4})/$', views.GetTalk.as_view(), name = 'talk'), |
9 | 11 | 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'), |
10 | 12 | url(r'^participant/profile/(?P<email>[\w.%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,4})/$', views.ParticipantProfile.as_view(), name = 'profile'), | ... | ... |
chat/views.py
... | ... | @@ -7,10 +7,12 @@ from django.http import JsonResponse |
7 | 7 | from django.template.loader import render_to_string |
8 | 8 | from django.core.urlresolvers import reverse, reverse_lazy |
9 | 9 | import textwrap |
10 | +from datetime import datetime | |
10 | 11 | from django.utils import formats |
11 | 12 | from django.utils.html import strip_tags |
12 | 13 | from django.utils.translation import ugettext_lazy as _ |
13 | 14 | from django.contrib.auth.mixins import LoginRequiredMixin |
15 | +from django.contrib.auth.decorators import login_required | |
14 | 16 | from django.db.models import Q |
15 | 17 | |
16 | 18 | from channels import Group |
... | ... | @@ -20,7 +22,7 @@ from categories.models import Category |
20 | 22 | from subjects.models import Subject |
21 | 23 | from users.models import User |
22 | 24 | |
23 | -from .models import Conversation, GeneralTalk, CategoryTalk, SubjectTalk, TalkMessages, ChatVisualizations | |
25 | +from .models import Conversation, GeneralTalk, CategoryTalk, SubjectTalk, TalkMessages, ChatVisualizations, ChatFavorites | |
24 | 26 | from .forms import ChatMessageForm |
25 | 27 | |
26 | 28 | class GeneralIndex(LoginRequiredMixin, generic.ListView): |
... | ... | @@ -81,7 +83,7 @@ class GeneralParticipants(LoginRequiredMixin, generic.ListView): |
81 | 83 | |
82 | 84 | context['title'] = _('Messages - Participants') |
83 | 85 | context['totals'] = self.totals |
84 | - context['search'] = self.request.GET.get('search') | |
86 | + context['search'] = self.request.GET.get('search', '') | |
85 | 87 | context['chat_menu_active'] = 'subjects_menu_active' |
86 | 88 | |
87 | 89 | return context |
... | ... | @@ -222,8 +224,71 @@ def render_message(request, talk_msg): |
222 | 224 | context = {} |
223 | 225 | context['talk_msg'] = msg |
224 | 226 | |
225 | - message = _('Message sent successfully!') | |
226 | - | |
227 | 227 | html = render_to_string("chat/_message.html", context, request) |
228 | 228 | |
229 | - return JsonResponse({'message': message, 'view': html, 'new_id': msg.id}) | |
230 | 229 | \ No newline at end of file |
230 | + return JsonResponse({'view': html, 'new_id': msg.id, 'talk_id': msg.talk.id}) | |
231 | + | |
232 | +@login_required | |
233 | +def favorite(request, message): | |
234 | + action = request.GET.get('action', '') | |
235 | + message = get_object_or_404(TalkMessages, id = message) | |
236 | + | |
237 | + if action == 'favorite': | |
238 | + ChatFavorites.objects.create(message = message, user = request.user) | |
239 | + | |
240 | + return JsonResponse({'label': _('Unfavorite')}) | |
241 | + else: | |
242 | + ChatFavorites.objects.filter(message = message, user = request.user).delete() | |
243 | + | |
244 | + return JsonResponse({'label': _('Favorite')}) | |
245 | + | |
246 | +def load_messages(request, talk): | |
247 | + context = { | |
248 | + 'request': request, | |
249 | + } | |
250 | + | |
251 | + user = request.user | |
252 | + favorites = request.GET.get('favorite', False) | |
253 | + mines = request.GET.get('mine', False) | |
254 | + showing = request.GET.get('showing', '') | |
255 | + n_views = 0 | |
256 | + | |
257 | + if not favorites: | |
258 | + if mines: | |
259 | + messages = TalkMessages.objects.filter(talk__id = talk, user = user) | |
260 | + else: | |
261 | + messages = TalkMessages.objects.filter(talk__id = talk) | |
262 | + else: | |
263 | + if mines: | |
264 | + messages = TalkMessages.objects.filter(talk__id = talk, chat_favorites_message__isnull = False, chat_favorites_message__user = user, user = user) | |
265 | + else: | |
266 | + messages = TalkMessages.objects.filter(talk__id = talk, chat_favorites_message__isnull = False, chat_favorites_message__user = user) | |
267 | + | |
268 | + if showing: #Exclude ajax creation messages results | |
269 | + showing = showing.split(',') | |
270 | + messages = messages.exclude(id__in = showing) | |
271 | + | |
272 | + has_page = request.GET.get('page', None) | |
273 | + | |
274 | + if has_page is None: | |
275 | + views = ChatVisualizations.objects.filter(Q(user = user) & Q(viewed = False) & (Q(message__talk__id = talk))) | |
276 | + n_views = views.count() | |
277 | + views.update(viewed = True, date_viewed = datetime.now()) | |
278 | + | |
279 | + paginator = Paginator(messages.order_by("-create_date"), 20) | |
280 | + | |
281 | + try: | |
282 | + page_number = int(request.GET.get('page', 1)) | |
283 | + except ValueError: | |
284 | + raise Http404 | |
285 | + | |
286 | + try: | |
287 | + page_obj = paginator.page(page_number) | |
288 | + except EmptyPage: | |
289 | + raise Http404 | |
290 | + | |
291 | + context['messages'] = page_obj.object_list | |
292 | + | |
293 | + response = render_to_string("chat/_list_messages.html", context, request) | |
294 | + | |
295 | + return JsonResponse({"messages": response, "unviewed": n_views, "count": messages.count(), "num_pages": paginator.num_pages, "num_page": page_obj.number}) | |
231 | 296 | \ No newline at end of file | ... | ... |