remotes/origin/PR-39
ArturBaybulatov 9 years ago
commit bada04ca94
  1. 2
      api/views.py
  2. 10
      assets/css/main.css
  3. 166
      assets/js/chat.js
  4. 15
      assets/js/chat_contractor.js
  5. 320
      assets/js/chat_customer.js
  6. 18
      chat/chat.py
  7. 1
      chat/filters.py
  8. 2
      chat/templates/chat_contractor.html
  9. 1
      chat/templates/chat_customer.html
  10. 16
      chat/templates/dialog_delete.html
  11. 9
      chat/views.py
  12. 3
      projects/apps.py
  13. 23
      projects/migrations/0028_stage_approve_time.py
  14. 20
      projects/migrations/0029_auto_20160908_1159.py
  15. 1
      projects/models.py
  16. 14
      projects/signals.py
  17. 26
      templates/home.html
  18. 3
      templates/partials/base.html
  19. 9
      templates/partials/header.html
  20. 2
      users/templates/contractor_office_chat_projects.html
  21. 7
      users/templates/contractor_profile.html

@ -117,7 +117,7 @@ class MessageViewSet(ModelViewSet):
filter_class = MessageFilterSet
def get_queryset(self):
queryset = Message.objects.all()
queryset = Message.objects.filter(is_delete=False)
search_param = self.request.query_params.get('operand', None)
recipent_id = self.request.query_params.get('recipent_id', None)
sender_id = self.request.query_params.get('sender_id', None)

@ -213,14 +213,14 @@ ul li {
}
.changeBlock1 {
float: right;
margin-right: -15px;
float: left;
margin-left: -15px;
background-color: rgba(0,0,0,0.7);
}
.changeBlock2 {
float: left;
margin-left: -15px;
float: right;
margin-right: -15px;
background-color: rgba(255,0,6,0.7);
}
@ -5966,4 +5966,4 @@ a.linkS2[data-target="#withdraw-money"]{
input[type="radio"]{
opacity: 0;
}
/*end_new*/
/*end_new*/

@ -15,6 +15,8 @@ var SocketHandler = function () {
var message = JSON.parse(event.data);
var inbox;
if (message.answer_type == 'contact' || message.answer_type == 'add_message_contact') {
var docSpace = document.getElementById('documentSpace');
docSpace.innerHTML += message.docs_attach;
var sumSenderRecipent = parseInt(message.recipent_id) + parseInt(message.sender_id);
var inboxClass = document.getElementsByClassName('contact-space' + sumSenderRecipent);
if (inboxClass.length > 0) {
@ -24,8 +26,12 @@ var SocketHandler = function () {
}
} else if (message.answer_type == 'order' || message.answer_type == 'add_message_order') {
inbox = document.getElementById('message-chat-order-space');
var docOrderSpace = document.getElementById('documentOrderSpace');
docOrderSpace.innerHTML += message.docs_attach;
} else if (message.answer_type == 'add_message_team') {
inbox = document.getElementById('message-chat-team-space');
var docSpace = document.getElementById('documentTeamSpace');
docSpace.innerHTML += message.docs_attach;
} else if (message.answer_type == 'approve_stages') {
var resOrderId = message.order_id;
$.jGrowl(message.msg, {
@ -56,53 +62,13 @@ var SocketHandler = function () {
};
this.send_order_message = function (orderId) {
var data = {
"format_type": "order_message",
"order_id": orderId
}
sock.send(JSON.stringify(data));
console.log(data);
};
this.send_stages_approve = function (data) {
sock.send(JSON.stringify(data));
console.log(data);
};
this.send_contact_message = function (userId) {
var data = {
"format_type": "add_message",
"user_id": userId
}
sock.send(JSON.stringify(data));
console.log(data);
};
this.add_team_message = function (messageData) {
console.log(messageData);
this.send_message = function (messageData) {
sock.send(JSON.stringify(messageData));
}
this.add_contact_message = function (messageData) {
console.log(messageData);
sock.send(JSON.stringify(messageData));
};
this.send_message = function (form) {
var elements = form.elements;
var data = {};
var i = 0;
for (var i; i < elements.length; i++) {
if (elements[i].name == 'message') {
data[elements[i].name] = elements[i].value;
}
}
sock.send(JSON.stringify(data));
var textareaMessage = document.getElementById("message");
textareaMessage.value = "";
}
}
function csrfSafeMethod(method) {
@ -113,6 +79,21 @@ var socket = new SocketHandler();
var csrftoken = getCookie('csrftoken');
$(function () {
function dialog(message, yesCallback, notCallback) {
$("#dialog_delete .modal-title").html(message);
var dialog = $("#dialog_delete").modal('show');
$("#btnYes").click(function () {
yesCallback();
$("#dialog_delete").modal('hide');
});
$("#btnNot").click(function () {
notCallback();
$("#dialog_delete").modal('hide');
});
}
var currentHash = URI(location.href).hash();
if (currentHash.indexOf("#order") == 0) {
var ordHashId = currentHash.replace("#order", "");
@ -130,7 +111,7 @@ $(function () {
$(".order-block").first().trigger('click');
}, 500);
}
// Информация о заказе
$(".full-order-info").click('on', function (e) {
e.preventDefault();
e.stopPropagation();
@ -171,23 +152,23 @@ $(function () {
dataType: 'json',
success: function (data) {
var outTable = '';
if(data.username) {
if (data.username) {
outTable += '<tr><td>Ник</td><td>' + data.username + '</td>';
}
if(data.fio) {
if (data.fio) {
outTable += '<tr><td>Ф.И.О</td><td>' + data.fio + '</td>';
}
if(data.skype) {
outTable += '<tr><td>Skype</td><td>'+ data.skype +'</td>';
if (data.skype) {
outTable += '<tr><td>Skype</td><td>' + data.skype + '</td>';
}
if(data.website) {
outTable += '<tr><td>Сайт</td><td>'+ data.website +'</td>';
if (data.website) {
outTable += '<tr><td>Сайт</td><td>' + data.website + '</td>';
}
if(data.phone) {
outTable += '<tr><td>Телефон</td><td>'+ data.phone +'</td>';
if (data.phone) {
outTable += '<tr><td>Телефон</td><td>' + data.phone + '</td>';
}
$("#contact-info table").html(outTable);
@ -343,33 +324,42 @@ $(function () {
});
$('.deleteMess').on('click', function (e) {
e.preventDefault();
e.stopPropagation();
var senderId = userId;
var recipentId = $(this).attr('data-recipent-id');
var _this = $(this);
$.ajax({
url: '/chat/messages_delete/',
type: 'POST',
beforeSend: function (xhr) {
xhr.setRequestHeader("X-CSRFToken", getCookie('csrftoken'))
},
data: {'sender_id': senderId, 'recipent_id': recipentId},
dataType: 'json',
success: function (json) {
if (json.status == 'ok') {
_this.parent().remove();
$("#message-chat-space").html("");
}
},
error: function (e) {
console.log('error');
console.log(e);
}
});
dialog("Вы действительно хотите удалить сообщения этого пользователя?",
function(){
$.ajax({
url: '/chat/messages_delete/',
type: 'POST',
beforeSend: function (xhr) {
xhr.setRequestHeader("X-CSRFToken", getCookie('csrftoken'))
},
data: {'sender_id': senderId, 'recipent_id': recipentId},
dataType: 'json',
success: function (json) {
if (json.status == 'ok') {
_this.parent().remove();
$("#message-chat-space").html("");
}
},
error: function (e) {
console.log('error');
console.log(e);
}
});
}.bind(null, senderId, recipentId, _this),
function () {
});
});
$('#add-note-contractor').on('click', function (e) {
@ -406,7 +396,7 @@ $(function () {
data: $("#add-form-order-note").serialize(),
dataType: 'json',
success: function (json) {
$("<li>"+ json.text +"</li>").appendTo(".order-notes-block");
$("<li>" + json.text + "</li>").appendTo(".order-notes-block");
$("#add-form-order-note #chat2").val("");
},
error: function (e) {
@ -428,7 +418,7 @@ $(function () {
data: $("#add-form-team-note").serialize(),
dataType: 'json',
success: function (json) {
$("<li>"+ json.text +"</li>").appendTo(".team-notes-block");
$("<li>" + json.text + "</li>").appendTo(".team-notes-block");
$("#add-form-team-note #chat2").val("");
},
error: function (e) {
@ -449,10 +439,16 @@ $(function () {
if (chatMessage) {
var sendLinks = $("#document-send-order a");
var sendLinkIds = "";
var documentLinks = "";
var documentAttachFiles = "";
$.each(sendLinks, function (i, v) {
sendLinkIds += $(this).attr('data-id') + ';';
documentLinks += 'Входящий файл: <br> <a href="'+ $(this).attr('href') + '">'+ $(this).text() +'</a><br>';
documentAttachFiles += '<li style="word-break: break-all;">' +
'<a class="file-link" href="' + $(this).attr('href') + '">' + $(this).text() + '</a>' +
'<div class="remove-document" data-id="' + $(this).attr('data-id') + '" style="right:-10px;"></div></li>';
});
socket.add_contact_message({
socket.send_message({
"format_type": "add_message_order",
"data": {
"sender_id": senderId,
@ -460,6 +456,10 @@ $(function () {
"chat_message": chatMessage,
"order_id": orderId,
"document_send_links": sendLinkIds,
"document_data": {
"document_links": documentLinks,
"document_attach_files": documentAttachFiles,
}
}
});
@ -481,17 +481,28 @@ $(function () {
$("#contact-chat-form .errorEmptyMessage").hide();
var sendLinks = $("#document-send-contact a");
var sendLinkIds = "";
var documentLinks = "";
var documentAttachFiles = "";
$.each(sendLinks, function (i, v) {
sendLinkIds += $(this).attr('data-id') + ';';
documentLinks += 'Входящий файл: <br> <a href="'+ $(this).attr('href') + '">'+ $(this).text() +'</a><br>';
documentAttachFiles += '<li style="word-break: break-all;">' +
'<a class="file-link" href="' + $(this).attr('href') + '">' + $(this).text() + '</a>' +
'<div class="remove-document" data-id="' + $(this).attr('data-id') + '" style="right:-10px;"></div></li>';
});
console.log(sendLinkIds);
socket.add_contact_message({
socket.send_message({
"format_type": "add_message_contact",
"data": {
"sender_id": senderId,
"recipent_id": recipentId,
"chat_message": chatMessage,
"document_send_links": sendLinkIds,
"document_data": {
"document_links": documentLinks,
"document_attach_files": documentAttachFiles,
}
}
});
$("#chat").val("");
@ -581,10 +592,7 @@ $(function () {
dataType: 'json',
done: function (e, data) {
$.each(data.result.files, function (index, file) {
// var currentValue = '';
// currentValue += file.id + ';';
//$("#documentSendIds").val(currentValue);
var htmlImg = '<a href="' + file.url + '" class="send-doc" data-id="' + file.id + '">' + file.name + '</a><br />';
var htmlImg = '<a href="/chat/download/' + file.name + '" class="send-doc" data-id="' + file.id + '">' + file.name + '</a><br />';
var document_send = $(htmlImg).appendTo("#document-send-order");
});
},
@ -627,7 +635,7 @@ $(function () {
dataType: 'json',
done: function (e, data) {
$.each(data.result.files, function (index, file) {
var htmlImg = '<a href="' + file.url + '" class="send-doc" data-id="' + file.id + '">' + file.name + '</a>';
var htmlImg = '<a href="/chat/download/' + file.name + '" class="send-doc" data-id="' + file.id + '">' + file.name + '</a>';
var document_send = $(htmlImg).appendTo("#document-send-contact");
});
},

@ -35,7 +35,7 @@ $(function () {
var currentValue = $("#documentSendIds").val();
currentValue += file.id + ';';
$("#documentSendIds").val(currentValue);
var htmlImg = '<a href="' + file.url + '" class="send-doc" data-id="' + file.id + '">' + file.name + '</a>';
var htmlImg = '<a href="/chat/download/' + file.name + '" class="send-doc" data-id="' + file.id + '">' + file.name + '</a>';
var document_send = $(htmlImg).appendTo("#document-send");
});
},
@ -544,10 +544,17 @@ $(function () {
if (chatMessage) {
var sendLinks = $("#document-send a");
var sendLinkIds = "";
var documentLinks = "";
var documentAttachFiles = "";
$.each(sendLinks, function (i, v) {
sendLinkIds += $(this).attr('data-id') + ';';
documentLinks += 'Входящий файл: <br> <a href="'+ $(this).attr('href') + '">'+ $(this).text() +'</a><br>';
documentAttachFiles += '<li style="word-break: break-all;">' +
'<a class="file-link" href="' + $(this).attr('href') + '">' + $(this).text() + '</a>' +
'<div class="remove-document" data-id="' + $(this).attr('data-id') + '" style="right:-10px;"></div></li>';
});
socket.add_team_message({
socket.send_message({
"format_type": "add_message_team",
"data": {
"sender_id": senderId,
@ -556,6 +563,10 @@ $(function () {
"team_id": teamId,
"order_id": orderId,
"document_send_links": sendLinkIds,
"document_data": {
"document_links": documentLinks,
"document_attach_files": documentAttachFiles,
}
}
});

@ -1,320 +0,0 @@
$(function () {
var currentChatUser = {
{
request.user.pk
}
}
;
var socket = new SocketHandler();
var form = document.getElementById('message_form');
var csrftoken = getCookie('csrftoken');
$("#reserve-button").on("click", function (e) {
e.preventDefault();
var orderId = $(this).attr('data-order-id');
$.ajax({
url: '/api/stages/',
type: 'GET',
data: {csrfmiddlewaretoken: csrftoken, 'order': orderId},
dataType: 'json',
success: function (json) {
console.log(json.results);
}
});
});
function getStages(orderId, senderId, recipentId) {
$.ajax({
url: '/api/stages/',
type: 'GET',
data: {csrfmiddlewaretoken: csrftoken, 'order': orderId},
dataType: 'json',
success: function (json) {
var stageCount = json.results.length;
if (stageCount == 0) {
stageCountVal = 1;
} else {
stageCountVal = stageCount;
}
var htmlInbox = "";
var htmlInboxStage = '<p class="textStepss">Какое кол-во этапов подразумевает работа? ' +
'<input type="text" id="countStage" value="' + stageCountVal + '"size="3"/></p>';
if (stageCount == 0) {
htmlInboxStage += '<div class="numberStepp box-sizing" id="stage1">' +
'<p>Этап <span class="stage-span-id">1</span></p><form class="new-stages-form" id="stage-form">' +
'<label for="">Название</label><input class="form-control" name="name" type="text" />' +
'<label for="">Цена</label><input class="form-control" name="cost" type="text" />' +
'<input class="form-control orderStagesInput" name="order" type="hidden" value="' + orderId + '"/>' +
'<label for="">Срок</label><input class="form-control" name="term" type="text" />' +
'<label for="">Результат</label><input class="form-control" name="result" type="text" />' +
'<label for="">Позиция</label><input class="form-control" name="pos" value="1" type="text" />' +
'</form></div>';
}
var statusNotAgreed = true;
$.each(json.results, function (i, v) {
if (v.status == "not_agreed") {
htmlInbox += '<div class="numberStepp box-sizing">' +
'<p>Этап</p><form class="update-stages-form" data-stage-id="' + v.id + '" id="stage-form-' + v.pos + '">' +
'<label for="">Название</label><input class="form-control" type="text" name="name" value="' + v.name + '" />' +
'<label for="">Цена</label><input class="form-control" type="text" name="cost" value="' + v.cost + '" />' +
'<input class="form-control orderStagesInput" type="hidden" name="order" value="' + v.order + '"/>' +
'<label for="">Срок</label><input class="form-control" type="text" name="term" value="' + v.term + '" />' +
'<label for="">Результат</label><input class="form-control" type="text" name="result" value="' + v.result + '" />' +
'</form></div>';
} else {
statusNotAgreed = false;
htmlInboxStage = "";
htmlInbox += '<div class="numberStepp box-sizing"><div class="insetNumStepp">' +
'<p class="titleNumStepp"><span>Этап ' + v.pos + '</span>' + v.name + '</p>' +
'<p class="textNumStepp">Результаты этапа:' + v.result + '</p><div>' +
'<p>до Дата</p><span>' + v.cost + '<i class="fa fa-rub"></i></span></div></div></div>';
}
});
if (statusNotAgreed) {
htmlInbox += '<div class="box-sizing disTab" style="text-align:center;"><div class="checkbox"><input type="checkbox" style="opacity:1">Перейти в режим безопасной сделки' +
'</div></div><div class="textAreaBlock2 box-sizing disTab">' +
'<a href="#" data-sender-id="' + senderId + '" data-recipent-id="' + recipentId + '" data-order-id="' + orderId + '" id="addStagesForm">отправить на согласование</a> </div>';
}
htmlInbox = htmlInboxStage + htmlInbox;
$("#order-stages").html(htmlInbox);
}
});
}
setTimeout(function () {
$(".user-block").first().trigger('click');
}, 10);
setTimeout(function () {
$(".order-block").first().trigger('click');
}, 100);
$("#order-stages").on('click', "#addStagesForm", function (e) {
e.preventDefault();
$(".new-stages-form").each(function (i, v) {
$.ajax({
url: '/api/stages/',
type: 'POST',
beforeSend: function (xhr) {
xhr.setRequestHeader("X-CSRFToken", getCookie('csrftoken'))
},
data: $(this).serialize(),
dataType: 'json',
success: function (json) {
console.log(json);
},
error: function (e) {
console.log(e);
}
});
});
$(".update-stages-form").each(function (i, v) {
var currentStageId = parseInt($(this).attr('data-stage-id'));
$.ajax({
url: '/api/stages/' + currentStageId + '/',
type: 'PUT',
beforeSend: function (xhr) {
xhr.setRequestHeader("X-CSRFToken", getCookie('csrftoken'))
},
data: $(this).serialize(),
dataType: 'json',
success: function (json) {
console.log(json);
},
error: function (e) {
console.log('error');
console.log(e);
}
});
});
var currentOrderId = $(this).attr('data-order-id');
var currentRecipentId = $(this).attr('data-recipent-id');
getStages(currentOrderId, userId, currentRecipentId);
socket.send_stages_approve({
"format_type": "approve_stages",
"data": {
"sender_id": userId,
"recipent_id": currentRecipentId,
"order_id": currentOrderId,
}
});
});
$('#order-stages-tab').on('change', '#countStage', function () {
var countStage = parseInt($(this).val());
var currentCountStage = $(".numberStepp").length;
if (countStage > currentCountStage) {
for (var jj = currentCountStage; jj < countStage; jj++) {
var pos = jj + 1;
var lastFormStage = $(".numberStepp").last();
var orderId = lastFormStage.find('.orderStagesInput').val();
var addFormTemplate = '<div class="numberStepp box-sizing" id="stage1">' +
'<p>Этап <span class="stage-span-id">' + pos + '</span></p><form class="new-stages-form" id="stage-form">' +
'<label for="">Название</label><input class="form-control" name="name" type="text" />' +
'<label for="">Цена</label><input class="form-control" name="cost" type="text" />' +
'<input class="form-control orderStagesInput" name="order" type="hidden" value="' + orderId + '" />' +
'<label for="">Срок</label><input class="form-control" name="term" type="text" />' +
'<label for="">Результат</label><input class="form-control" name="result" type="text" />' +
'<label for="">Позиция</label><input class="form-control" name="pos" value="' + pos + '" type="text" />'
'</form></div>';
lastFormStage.after(addFormTemplate);
}
} else if (countStage < currentCountStage) {
var ii = currentCountStage;
$($(".numberStepp").get().reverse()).each(function () {
var currenFormName = ($(this).find('form').attr('class'));
if (ii > countStage) {
$(this).remove();
}
ii--;
});
}
});
$('.order-block').on('click', function () {
$("#chat-order-add").css("display", "block");
$("#formsetStage").css("display", "block");
$('.order-block').each(function () {
$(this).removeClass('orAct');
});
$(this).addClass('orAct');
var orderId = $(this).attr('data-id');
var recipentId = $(this).attr('data-recipent-id');
$("#chat-order-add #orderId").val(orderId);
$("#projectReviewId").val(orderId);
$("#reserve-button").attr('data-order-id', orderId);
$("#targetContractorId").val(recipentId);
$("#chat-order-add #recipentId").val(recipentId);
$(".orderStagesInput").val(orderId);
var inbox = document.getElementById('message-chat-order-space');
inbox.innerHTML = '';
$.ajax({
url: '/api/message',
type: 'GET',
data: {csrfmiddlewaretoken: csrftoken, 'order': orderId},
dataType: 'json',
success: function (json) {
$.each(json.results, function (i, v) {
var senderName = 'Вы';
var className = 'youChat';
if (v.sender.id !== currentChatUser) {
senderName = v.sender.username;
className = '';
}
inbox.innerHTML += '<div class="col-lg-12 insetCommChat ' + className + '"><div class="topCommChat">' +
'<p class="nameCommChat">' + senderName + '</p><span>' + v.created + '</span></div>' +
'<p class="textCommChat">' + v.text + '</p></div>';
});
}
});
getStages(orderId, userId, recipentId);
});
// Вытащить сообщения для конактов
$('.user-block').on('click', function () {
var userId = $(this).attr('data-id');
$("#contact-chat-form #recipentId").val(userId);
$("#add-form-contractor-note #recipentNoteContractor").val(userId);
$('.user-block').each(function () {
$(this).removeClass('mesAct');
});
$(this).addClass('mesAct');
var inbox = document.getElementById('message-chat-space');
inbox.innerHTML = '';
$.ajax({
url: '/api/message',
type: 'GET',
data: {
csrfmiddlewaretoken: csrftoken,
'operand': 'in',
'sender_id': currentChatUser,
'recipent_id': userId
},
dataType: 'json',
success: function (json) {
$.each(json.results, function (i, v) {
var senderName = 'Вы';
var className = 'youChat';
if (v.sender.id == userId) {
senderName = v.sender.username;
className = '';
}
inbox.innerHTML += '<div class="col-lg-12 insetCommChat ' + className + '"><div class="topCommChat">' +
'<p class="nameCommChat">' + senderName + '</p> <span>' + v.created + '</span></div>' +
'<p class="textCommChat">' + v.text + '</p></div>';
});
}
});
});
$('#contact-chat-add-message').on('click', function (e) {
e.preventDefault();
var chatMessage = $("#chat").val();
var recipentId = $("#recipentId").val();
var senderId = $("#senderId").val();
socket.add_contact_message({
"format_type": "add_message_contact",
"data": {
"sender_id": senderId,
"recipent_id": recipentId,
"chat_message": chatMessage,
}
});
$("#chat").val("");
});
$('#order-review-add').on('click', function () {
alert('add review');
});
$('#order-chat-add-message').on('click', function (e) {
e.preventDefault();
var chatMessage = $("#chat-order-add #chat").val();
var recipentId = $("#chat-order-add #recipentId").val();
var senderId = $("#chat-order-add #senderId").val();
var orderId = $("#chat-order-add #orderId").val();
socket.add_contact_message({
"format_type": "add_message_order",
"data": {
"sender_id": senderId,
"recipent_id": recipentId,
"chat_message": chatMessage,
"order_id": orderId,
}
});
$("#chat-order-add #chat").val("");
});
});
var userId = '{{ request.user.pk }}';

@ -61,6 +61,12 @@ class ChatHandler(websocket.WebSocketHandler):
team_id = message_data['data'].get('team_id', None)
message = message_data['data'].get('chat_message', None)
docs_send_links = message_data['data'].get('document_send_links', None)
if 'document_data' in message_data['data']:
docs_links = message_data['data']['document_data'].get('document_links', "");
docs_attach = message_data['data']['document_data'].get('document_attach_files', "")
else:
docs_links = ''
docs_attach = ''
message = html.escape(message)
message = message.replace('\n', '<br />')
@ -100,10 +106,20 @@ class ChatHandler(websocket.WebSocketHandler):
msg_data = cursor_msg.fetchone()
sender_name = msg_data[5]
msg_time = msg_data[2].strftime("%Y-%m-%d %H:%M:%S")
if docs_links:
message += '<br><br>' + docs_links;
waiters = tuple(w for c, w in self.waiters if c == recipent_id or c == sender_id)
for waiter in waiters:
waiter.write_message({'msg': message, 'msg_time': msg_time, 'order_id': order_id, 'recipent_id': recipent_id,'sender_id': sender_id, 'sender_name': sender_name, 'answer_type': answer_type})
waiter.write_message({'msg': message,
'msg_time': msg_time,
'order_id': order_id,
'recipent_id': recipent_id,
'sender_id': sender_id,
'sender_name': sender_name,
'answer_type': answer_type,
'docs_attach': docs_attach,
})
def check_origin(self, origin):
return True

@ -21,6 +21,7 @@ class MessageFilterSet(FilterSet):
recipent = RelatedFilter('users.filters.UserFilterSet')
private_type = AllLookupsFilter()
team = RelatedFilter('users.filters.TeamFilterSet')
order = RelatedFilter('projects.filters.OrderFilterSet')
class Meta:
model = Message

@ -31,7 +31,7 @@
</div>
</div>
</div>
{% include 'dialog_delete.html' %}
<div class="tab-content">
<!-- Tab1 contacts block -->
<div class="chatBlock disTab tab-pane fade in active" id="tab1">

@ -23,6 +23,7 @@
</div>
</div>
</div>
{% include 'dialog_delete.html' %}
<div class="tab-content">
<!-- Tab1 (contacts block)-->
<div class="chatBlock disTab tab-pane fade in active" id="tab1">

@ -0,0 +1,16 @@
<div id="dialog_delete" class="modal fade" role="dialog">
<div class="modal-dialog" role="document" style="width:400px;">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×
</button>
<h4 class="modal-title"></h4>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-danger btn-lg" id="btnNot">Нет</button>
<button type="button" class="btn btn-success btn-lg" id="btnYes">Да</button>
</div>
</div>
</div>
</div>

@ -77,7 +77,8 @@ class ChatUserView(LoginRequiredMixin, View):
orders = Order.objects.filter(Q(contractor=request.user) | Q(team_id__in=team_ids)).all()
contractor_contacts = Message.objects.values_list('sender_id', 'recipent_id').filter(
Q(recipent_id=request.user.pk) | Q(sender_id=request.user.pk)).filter(Q(team_id=None)).distinct()
Q(recipent_id=request.user.pk) | Q(sender_id=request.user.pk)).filter(Q(team_id=None)).\
filter(is_delete=False).distinct()
users_ids = []
for msg in contractor_contacts:
a, b = msg
@ -91,7 +92,7 @@ class ChatUserView(LoginRequiredMixin, View):
chat_messages = Message.objects.filter(Q(sender=request.user.pk) | Q(recipent=request.user.pk)).order_by(
'created')
your_teams = teams
your_teams = Team.objects.filter(Q(contractors__id=request.user.pk) | Q(owner=request.user))
self.template_name = 'chat_contractor.html'
return render(request, self.template_name, {'orders': orders,
'contacts_users': contacts_users,
@ -106,8 +107,8 @@ def messages_delete(request):
sender = request.POST.get('sender_id')
recipent = request.POST.get('recipent_id')
queryset = Message.objects.all()
# queryset = queryset.filter(Q(sender__in=[sender,recipent]),Q(recipent__in=[sender,recipent]))
# queryset.delete()
queryset = queryset.filter(Q(sender__in=[sender, recipent]), Q(recipent__in=[sender, recipent]))
queryset.update(is_delete=True)
data = {'status': 'ok'}
return HttpResponse(json.dumps(data), content_type='application/json')
else:

@ -5,5 +5,6 @@ from django.apps import AppConfig
class ProjectsConfig(AppConfig):
name = 'projects'
def ready(self):
import projects.signals

@ -0,0 +1,23 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.7 on 2016-09-08 08:17
from __future__ import unicode_literals
import datetime
from django.db import migrations, models
from django.utils.timezone import utc
class Migration(migrations.Migration):
dependencies = [
('projects', '0027_auto_20160907_1658'),
]
operations = [
migrations.AddField(
model_name='stage',
name='approve_time',
field=models.DateTimeField(default=datetime.datetime(2016, 9, 8, 8, 17, 17, 715320, tzinfo=utc)),
preserve_default=False,
),
]

@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.7 on 2016-09-08 08:59
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('projects', '0028_stage_approve_time'),
]
operations = [
migrations.AlterField(
model_name='stage',
name='approve_time',
field=models.DateTimeField(blank=True, null=True),
),
]

@ -258,6 +258,7 @@ class Stage(models.Model):
term_type = models.CharField(max_length=10, choices=TERM_TYPES, default='hour')
status = models.CharField(choices=STATUSES, max_length=30, default='not_agreed')
created = models.DateTimeField(default=timezone.now)
approve_time = models.DateTimeField(null=True, blank=True)
pos = models.IntegerField(default=0, null=True, blank=True)
is_paid = models.BooleanField(default=False)
close_contractor = models.BooleanField(default=False)

@ -1,8 +1,12 @@
from django.core.signals import request_finished
from django.db.models.signals import post_save
from django.utils import timezone
from django.dispatch import receiver
from .models import Project
from .models import Stage
@receiver(request_finished)
def add_project_test(sender, **kwargs):
pr = Project.objects.create(name='Test', price=100, user=2, spec=2)
pr.save()
@receiver(post_save, sender=Stage)
def set_approve_time(sender, instance, created, **kwargs):
if instance.status == 'in_process' and not instance.approve_time:
instance.approve_time = timezone.now()
instance.save()

@ -12,33 +12,35 @@
<div class="container-fluid">
<div class="row">
<div class="col-lg-6">
<div class="changeBlock changeBlock1">
{% if request.user.is_authenticated and request.user.is_contractor %}
<a href="{% url 'users:contractor-profile' pk=request.user.pk %}">Я исполнитель</a>
<div class="col-lg-6">
<div class="changeBlock changeBlock2">
{% if request.user.is_authenticated and request.user.is_customer %}
<a href="{% url 'users:customer-profile-open-projects' pk=request.user.pk %}">Я заказчик</a>
{% else %}
<a href="{% url 'registration_register' %}?type=contractor">Я исполнитель</a>
<a href="{% url 'registration_register' %}?type=customer">Я заказчик</a>
{% endif %}
<p>
{{ main_settings.contractor_text|safe }}
{{ main_settings.customer_text|safe }}
</p>
</div>
<div class="square">
<div class="square">
<div class="insetSquare"></div>
</div>
</div>
<div class="col-lg-6">
<div class="changeBlock changeBlock2">
{% if request.user.is_authenticated and request.user.is_customer %}
<a href="{% url 'users:customer-profile-open-projects' pk=request.user.pk %}">Я заказчик</a>
<div class="changeBlock changeBlock1">
{% if request.user.is_authenticated and request.user.is_contractor %}
<a href="{% url 'users:contractor-profile' pk=request.user.pk %}">Я исполнитель</a>
{% else %}
<a href="{% url 'registration_register' %}?type=customer">Я заказчик</a>
<a href="{% url 'registration_register' %}?type=contractor">Я исполнитель</a>
{% endif %}
<p>
{{ main_settings.customer_text|safe }}
{{ main_settings.contractor_text|safe }}
</p>
</div>
</div>
</div>
</div>

@ -96,6 +96,7 @@
sock.send('{"dummy": 1}');
}, 15000);
};
sock.onmessage = function (event) {
var notificationData = JSON.parse(event.data);
console.log(notificationData);
@ -108,7 +109,6 @@
$.jGrowl("Вам пришло новое сообщение!<br />" + outMessage, { life: 15000});
};
this.add_message = function (messageData) {
sock.send(JSON.stringify(messageData));
};
@ -116,7 +116,6 @@
};
var userId = '{{ request.user.pk }}';
if (userId) {
var socketMain = new SocketHandlerMain(userId);
}

@ -21,7 +21,7 @@
<div class="col-lg-7">
<ul class="mainMenu">
<li class="icon_tm1">
<a href="{% url 'projects:project-filter' %}">Биржа проектов</a>
<a href="{% url 'projects:project-filter' %}">Поиск заказов</a>
<span></span>
</li>
@ -48,7 +48,7 @@
<div class="col-lg-7">
<ul class="mainMenu">
<li class="icon_tm1">
<a href="{% url 'projects:project-filter' %}">Биржа проектов</a>
<a href="{% url 'projects:project-filter' %}">Поиск заказов</a>
<span></span>
</li>
<li class="icon_tm2">
@ -93,7 +93,7 @@
</a>
</li>
{% endif %}
<li class="icon_mm3">
<li class="icon_mm8">
<a href="{{ profile_url }}">
Профиль<span></span>
</a>
@ -112,14 +112,13 @@
<a href="/pages/faq">FAQ<span></span></a>
</li>
<li class="icon_mm6">
<li class="icon_mm7">
<a href="{% url 'auth_logout' %}">Выйти<span></span></a>
</li>
</ul>
</div>
</div>
<div class="imgProfile">
{% if request.user.is_contractor %}
<a href="{{ profile_url }}">

@ -136,8 +136,6 @@
{% endblock %}
{% block js_block %}
<script type="text/javascript">
var userId = {{ request.user.pk }};

@ -493,12 +493,13 @@
</div>
</div>
<div class="col-lg-12 wr-inset-pluss">
<a href="#" data-toggle="modal" data-target="#resume-text-edit" style="float: left; margin-right: 10px;">
<span class="glyphicon glyphicon-pencil" aria-hidden="true"></span>
</a>
<div class="pluss-block" id="resume-text-out">
{{ contractor.contractor_resume.text|safe }}
</div>
<a href="#" data-toggle="modal" data-target="#resume-text-edit">
<span class="glyphicon glyphicon-pencil" aria-hidden="true"></span>
</a>
<!-- Редактирование текста резюме (модальное окно)-->
<div id="resume-text-edit" class="modal fade">

Loading…
Cancel
Save