diff --git a/archilance/settings/base.py b/archilance/settings/base.py index 94b91cd..a5f81b5 100644 --- a/archilance/settings/base.py +++ b/archilance/settings/base.py @@ -224,6 +224,7 @@ AUTH_USER_MODEL = 'users.User' ACCOUNT_ACTIVATION_DAYS = 7 REGISTRATION_AUTO_LOGIN = True LOGIN_REDIRECT_URL = '/projects/' +LOGIN_URL = '/users/login/' if DEBUG: EMAIL_BACKEND = 'django.core.mail.backends.dummy.EmailBackend' diff --git a/chat/templates/chat_contractor.html b/chat/templates/chat_contractor.html index 79fbf73..15b1fdc 100644 --- a/chat/templates/chat_contractor.html +++ b/chat/templates/chat_contractor.html @@ -24,9 +24,9 @@ {% if team_orders %} -
  • - Исполнители -
  • +
  • + Исполнители +
  • {% endif %} @@ -34,7 +34,7 @@
    - +
    @@ -47,9 +47,24 @@ {% endthumbnail %}

    -

    {{ contact.username }}
    +
    {{ contact.username }}

    - Контакты + + + Контакты 0 @@ -70,7 +85,7 @@ @@ -85,16 +100,17 @@
    - + - +

    Заказы

    {% for order in orders %} -
    +

    {{ order }}

    @@ -121,7 +137,7 @@

    Прикрепить файл

    - Не более 10 файлов с общим объемом 500мб + Не более 10 файлов с общим объемом 500мб
    отправить
    @@ -154,87 +170,89 @@

    Для заметок

    - - - + + + сохранить
    - - - {% if team_orders %} - -
    -
    -
    -

    Заказы

    - {% for torder in team_orders %} -
    - -

    - {{ torder }} -

    -
    -

    -{# Заказчик: {{ torder.project.customer }}#} - Исполнитель: {{ torder.team.name }} -

    -
      - {% for tuser in torder.team.users.all %} -
    • {{ tuser }}
    • - {% endfor %} -
    - -

    - Чаты: - {% for tuser in torder.team.users.all %} - {% if request.user.pk != tuser.pk %} - {{ tuser.username }}, - {% endif %} - {% endfor %} -

    - - - Полное описание заказа - -
    + + + {% if team_orders %} + +
    +
    +
    +

    Заказы

    + {% for torder in team_orders %} +
    + +

    + {{ torder }} +

    +
    +

    + {# Заказчик: {{ torder.project.customer }}#} + Исполнитель: {{ torder.team.name }} +

    +
      + {% for tuser in torder.team.users.all %} +
    • {{ tuser }}
    • + {% endfor %} +
    + +

    + Чаты: + {% for tuser in torder.team.users.all %} + {% if request.user.pk != tuser.pk %} + {{ tuser.username }}, + {% endif %} + {% endfor %} +

    + + + Полное описание заказа + +
    +
    + {% endfor %}
    - {% endfor %}
    -
    -
    -
    -
    - - - - - - -
    -
    - -

    Прикрепить файл

    -
    -
    -
    -
    +
    +
    + + + + + + + +
    +
    + +

    Прикрепить файл

    +
    +
    +
    +
    - + отправить +
    +
    - -
    -
    +
    +
    -
    - - {% endif %} + + {% endif %}
    {% include 'partials/footer.html' %}
    @@ -256,7 +274,7 @@ var domain = '{{ request.META.HTTP_HOST }}'; var port = '{{ request.META.SERVER_PORT }}'; domain = domain.replace(':' + port, ''); - var url = 'ws://' + domain +':8888/chat/' + userId + '/'; + var url = 'ws://' + domain + ':8888/chat/' + userId + '/'; var sock = new WebSocket(url); var intervalId; sock.onopen = function () { @@ -274,7 +292,7 @@ inbox = document.getElementById('message-chat-space'); } else if (message.answer_type == 'order' || message.answer_type == 'add_message_order') { inbox = document.getElementById('message-chat-order-space'); - } else if(message.answer_type == 'add_message_team'){ + } else if (message.answer_type == 'add_message_team') { inbox = document.getElementById('message-chat-team-space'); } console.log(message.answer_type); @@ -294,7 +312,7 @@ console.log(data); }; - this.add_team_message = function(messageData){ + this.add_team_message = function (messageData) { console.log(messageData); sock.send(JSON.stringify(messageData)); @@ -327,16 +345,16 @@ var form = document.getElementById('message_form'); var csrftoken = getCookie('csrftoken'); - setTimeout(function(){ - $(".user-block").first().trigger('click'); + setTimeout(function () { + $(".user-block").first().trigger('click'); }, 10); - setTimeout(function(){ - $(".order-block").first().trigger('click'); + setTimeout(function () { + $(".order-block").first().trigger('click'); }, 100); - setTimeout(function(){ - $(".team-order-block").first().trigger('click'); + setTimeout(function () { + $(".team-order-block").first().trigger('click'); }, 1000); @@ -354,12 +372,13 @@ } }, dataType: 'json', - done: function (e, data) {; + done: function (e, data) { + ; $.each(data.result.files, function (index, file) { var currentValue = $("#documentSendIds").val(); currentValue += file.id + ';'; $("#documentSendIds").val(currentValue); - var htmlImg = '

    '+ file.name+'

    '; + var htmlImg = '

    ' + file.name + '

    '; var document_send = $(htmlImg).appendTo("#document-send"); }); }, @@ -374,23 +393,23 @@ .parent().addClass($.support.fileInput ? undefined : 'disabled'); - $("#order-stages").on('click',"#approve-stages",function(e){ + $("#order-stages").on('click', "#approve-stages", function (e) { e.preventDefault(); - $(".stage-block-approve").each(function(){ - var stageId = $(this).attr('data-id'); + $(".stage-block-approve").each(function () { + var stageId = $(this).attr('data-id'); $.ajax({ url: '/api/stages/' + stageId + '/', type: 'PATCH', - beforeSend: function(xhr){ + beforeSend: function (xhr) { xhr.setRequestHeader("X-CSRFToken", getCookie('csrftoken')) }, data: "status=in_process", - dataType:'json', - success: function(json){ + dataType: 'json', + success: function (json) { console.log(json); }, - error: function(e){ + error: function (e) { console.log('error'); console.log(e); } @@ -399,13 +418,13 @@ }); }); - $(".team-chat-user").on('click',function(e){ + $(".team-chat-user").on('click', function (e) { e.stopPropagation(); var recipentId = $(this).attr('data-id'); $("#team-chat-form #recipentId").val(recipentId); }); - $(".team-order-block").on('click', function(){ + $(".team-order-block").on('click', function () { $('.team-order-block').each(function () { $(this).removeClass('orAct'); @@ -423,7 +442,7 @@ $.ajax({ url: '/api/message', type: 'GET', - data: {csrfmiddlewaretoken: csrftoken, 'team': teamId,'order': orderId}, + data: {csrfmiddlewaretoken: csrftoken, 'team': teamId, 'order': orderId}, dataType: 'json', success: function (json) { $.each(json.results, function (i, v) { @@ -489,7 +508,7 @@ console.log(json.results); var noteHtmlInbox = ''; $.each(json.results, function (i, v) { - noteHtmlInbox += '
  • '+ v.text +'
  • '; + noteHtmlInbox += '
  • ' + v.text + '
  • '; }); $(".notes-block").html(noteHtmlInbox); @@ -508,15 +527,15 @@ if (json.results.length > 0) { $.each(json.results, function (i, v) { - if(v.is_paid){ - stagesReservedHtml += '
  • Сумма за этап '+ i +'.Зарезервирована.
  • '; - }else{ - stagesReservedHtml += '
  • Сумма за этап '+ i +'.Не зарезервирована.
  • '; + if (v.is_paid) { + stagesReservedHtml += '
  • Сумма за этап ' + i + '.Зарезервирована.
  • '; + } else { + stagesReservedHtml += '
  • Сумма за этап ' + i + '.Не зарезервирована.
  • '; } htmlInbox += '
    ' + '

    Этап ' + v.pos + '' + v.name + '

    ' + '

    Результаты этапа:' + v.result + '

    ' + - '

    '+ v.status+'

    ' + v.cost + '
    '; + '

    ' + v.status + '

    ' + v.cost + '
    '; }); htmlInbox += ''; @@ -529,21 +548,21 @@ }); - $('#add-note-button').on('click', function(){ + $('#add-note-button').on('click', function () { $.ajax({ url: '/api/note/', type: 'POST', beforeSend: function (xhr) { - xhr.setRequestHeader("X-CSRFToken", getCookie('csrftoken')) + xhr.setRequestHeader("X-CSRFToken", getCookie('csrftoken')) }, - data:$("#add-form-order-note").serialize(), + data: $("#add-form-order-note").serialize(), dataType: 'json', success: function (json) { console.log(json); $("#add-form-order-note #chat2").val(""); }, - error: function(e){ + error: function (e) { console.log('error'); console.log(e); } @@ -586,7 +605,7 @@ //Добавить сообщение для исполнителей в группе - $("#add-team-chat-message").on('click', function(){ + $("#add-team-chat-message").on('click', function () { var chatMessage = $("#team-chat-form #chatText").val(); var recipentId = $("#team-chat-form #recipentId").val(); var senderId = $("#team-chat-form #senderId").val(); diff --git a/chat/templates/chat_customer.html b/chat/templates/chat_customer.html index e7f4089..8faf966 100644 --- a/chat/templates/chat_customer.html +++ b/chat/templates/chat_customer.html @@ -32,14 +32,21 @@ {% for contact in contacts_users %}
    - {% thumbnail contact.avatar "60x60" crop="center" as im %} - mess-image - {% endthumbnail %} + {% if contact.avatar %} + {% thumbnail contact.avatar "60x60" crop="center" as im %} + mess-image + {% endthumbnail %} + {% else %} + mess-image + {% endif %}

    - {{ contact.username }} {{ contact.username }} +

    {{ contact.username }} {{ contact.username }}

    - Контакты + + Контакты + 0 Удалить контакт @@ -49,6 +56,20 @@
    +
    @@ -209,7 +230,7 @@
    -
    {% csrf_token %} + {% csrf_token %}
    @@ -236,7 +259,9 @@ @@ -494,8 +519,8 @@ $("#chat").val(""); }); - $('#order-review-add').on('click', function(){ - alert('add review'); + $('#order-review-add').on('click', function () { + alert('add review'); }); $('#order-chat-add-message').on('click', function () { @@ -526,7 +551,7 @@ var domain = '{{ request.META.HTTP_HOST }}'; var port = '{{ request.META.SERVER_PORT }}'; domain = domain.replace(':' + port, ''); - var url = 'ws://' + domain +':8888/chat/' + userId + '/'; + var url = 'ws://' + domain + ':8888/chat/' + userId + '/'; var sock = new WebSocket(url); var intervalId; sock.onopen = function () { diff --git a/chat/views.py b/chat/views.py index 7dfb274..0ac8ecb 100644 --- a/chat/views.py +++ b/chat/views.py @@ -2,6 +2,7 @@ from django.shortcuts import render from django.views.generic import View from django.db.models import Q from django.forms import formset_factory +from django.contrib.auth.mixins import LoginRequiredMixin from .models import Message from .forms import ArticleForm @@ -9,7 +10,7 @@ from reviews.forms import Review from users.models import User -class ChatUserView(View): +class ChatUserView(LoginRequiredMixin, View): template_name = '' def get(self, request, *args, **kwargs): diff --git a/common/models.py b/common/models.py index e05368f..61edfd9 100644 --- a/common/models.py +++ b/common/models.py @@ -43,6 +43,7 @@ class Settings(models.Model): document_send_time_remove = models.IntegerField(default=14) recalculation_spec_time = models.TimeField() recalculation_rating_time = models.TimeField() + # worksell_count = models.PositiveIntegerField(default=20) def __str__(self): return 'Настройки сайта' diff --git a/projects/migrations/0006_merge.py b/projects/migrations/0006_merge.py new file mode 100644 index 0000000..2f56753 --- /dev/null +++ b/projects/migrations/0006_merge.py @@ -0,0 +1,16 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9.7 on 2016-08-15 10:48 +from __future__ import unicode_literals + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('projects', '0005_auto_20160812_1931'), + ('projects', '0005_auto_20160812_1956'), + ] + + operations = [ + ] diff --git a/templates/partials/footer.html b/templates/partials/footer.html index ded4e4c..39583e9 100644 --- a/templates/partials/footer.html +++ b/templates/partials/footer.html @@ -24,15 +24,15 @@
  • - Регистрация + Регистрация
  • - Востановить доступ + Востановить доступ
  • - Опубликовать проект + Опубликовать проект
  • diff --git a/templates/partials/header.html b/templates/partials/header.html index d125373..1b34556 100644 --- a/templates/partials/header.html +++ b/templates/partials/header.html @@ -47,7 +47,7 @@
  • - Работы на продажу + Работы на продажу
  • diff --git a/templates/registration/login.html b/templates/registration/login.html index 473f966..1147c9f 100644 --- a/templates/registration/login.html +++ b/templates/registration/login.html @@ -11,11 +11,11 @@ {{ form.errors }}
    {% csrf_token %}
    -
    - +
    diff --git a/work_sell/forms.py b/work_sell/forms.py index f14f6fb..54a829b 100644 --- a/work_sell/forms.py +++ b/work_sell/forms.py @@ -1,7 +1,9 @@ +import itertools from django import forms from common.models import Location from .models import WorkSell +from specializations.models import Specialization class ContractorWorkSellTrashForm(forms.Form): @@ -41,12 +43,33 @@ class WorkSellForm(forms.ModelForm): def __init__(self, *args, **kwargs): # self.request = kwargs.pop('request') super().__init__(*args, **kwargs) - + + self.fields['specialization'].queryset = Specialization.objects.root_nodes()[0].get_descendants() self.fields['location'].queryset = Location.objects.root_nodes()[0].get_descendants() # self.fields['location'].queryset = Location.objects # Migrate with this enabled -# class WorkSellFilterForm(forms.ModelForm): -# -# class Meta: -# model = WorkSell +class WorkSellFilterForm(forms.ModelForm): + keywords = forms.CharField(required=False, max_length=255) + + class Meta: + model = WorkSell + fields = ( + 'location', + 'building_classification', + 'construction_type', + 'specialization', + ) + + widgets = { + 'building_classification': forms.Select(attrs={'class': 'selectpicker'}), + 'construction_type': forms.Select(attrs={'class': 'selectpicker'}), + } + + def __init__(self, *args, **kwargs): + self.request = kwargs.pop('request') + super().__init__(*args, **kwargs) + + self.fields['specialization'].required = False + + self.fields['specialization'].queryset = Specialization.objects.root_nodes()[0].get_descendants() diff --git a/work_sell/templates/worksell_detail.html b/work_sell/templates/worksell_detail.html index 1980456..8a46e71 100644 --- a/work_sell/templates/worksell_detail.html +++ b/work_sell/templates/worksell_detail.html @@ -25,16 +25,19 @@

    {{ object.budget }}

    + {% if request.user.is_authenticated %} + + {% endif %}
    - {% form.ins %} +
    - +
    - -
    -
    Тип работы
    -
    -
    -
    - {{ form.work_type }} -
    -
    - -
    @@ -104,11 +93,11 @@
    - {{ realty_form.building_classification }} + {{ form.building_classification }}
    - {{ realty_form.construction_type }} + {{ form.construction_type }}
    @@ -138,12 +127,7 @@
    -
    -
    - -

    Требуется допуск (СРО)

    -
    -
    +
    @@ -153,7 +137,7 @@
    - {% for work in object_list %} + {% for work in work_sells %}
    diff --git a/work_sell/urls.py b/work_sell/urls.py index 90a7d6d..c5a74ba 100644 --- a/work_sell/urls.py +++ b/work_sell/urls.py @@ -11,13 +11,14 @@ from .views import ( BasicCreateView, PictureCreateView, ContractorWorkSellTrashView, + WorkSellFilterView, ) app_name = 'work_sell' urlpatterns = [ - urls.url(r'^$', WorkSellsView.as_view(), name='list'), + urls.url(r'^$', WorkSellFilterView.as_view(), name='list'), # urls.url(r'^create/$', WorkSellCreateView.as_view(), name='create'), urls.url(r'^upload/$', UploadView.as_view(), name='upload'), urls.url(r'^(?P\d+)/edit/$',WorkSellUpdateView.as_view(), name='edit'), diff --git a/work_sell/views.py b/work_sell/views.py index a760489..86c46d6 100644 --- a/work_sell/views.py +++ b/work_sell/views.py @@ -1,12 +1,16 @@ import json +import re import pydash as _; _.map = _.map_; _.filter = _.filter_ from pprint import pprint, pformat from django.shortcuts import render, redirect +from django.conf import settings from django.contrib import messages +from django.db.models import Q from django.core.urlresolvers import reverse +from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger from django.http import JsonResponse, HttpResponse from django.core.files.base import ContentFile from django.views.generic import ListView, DetailView, CreateView, View, \ @@ -14,10 +18,10 @@ from django.views.generic import ListView, DetailView, CreateView, View, \ from projects.models import BuildingClassfication, ConstructionType from .models import WorkSell, Picture, WorkSellPhoto -from .forms import WorkSellForm, ContractorWorkSellTrashForm +from .forms import WorkSellForm, WorkSellFilterForm, ContractorWorkSellTrashForm from .serialize import serialize from .response import JSONResponse, response_mimetype - +from archilance.mixins import BaseMixin class PictureCreateView(CreateView): model = Picture @@ -63,15 +67,69 @@ class WorkSellsView(ListView): return context -class WorkSellFilterView(View): +class WorkSellFilterView(BaseMixin,View): template_name = 'worksells_list.html' + form_class = WorkSellFilterForm def get(self, request, *args, **kwargs): - context = {} + form = self.form_class(request.GET, request=request) + context = self.get_context_data(**_.merge({}, request.GET,kwargs)) + work_sells = WorkSell.objects + if form.is_valid(): + keywords = form.cleaned_data.get('keywords') + specialization = form.cleaned_data.get('specialization') + building_classification = form.cleaned_data.get('building_classification') + construction_type = form.cleaned_data.get('construction_type') + location = form.cleaned_data.get('location') + + if keywords: + keywords = tuple(filter(None, re.split(r'\s|,|;', keywords))) + + for k in keywords: + work_sells = work_sells.filter(Q(name__icontains=k) | Q(text__icontains=k)) + + if specialization: + work_sells = work_sells.filter( + specialization__lft__gte=specialization.lft, + specialization__rght__lte=specialization.rght, + ) + + if building_classification: + work_sells = work_sells.filter(building_classification=building_classification) + + if construction_type: + work_sells = work_sells.filter(construction_type=construction_type) + + if location: + work_sells = work_sells.filter( + location__lft__gte=location.lft, + location__rght__lte=location.rght, + ) + + + paginator = Paginator(work_sells.all(), settings.PAGE_SIZE) + page = request.GET.get('page') + + try: + work_sells = paginator.page(page) + except PageNotAnInteger: + work_sells = paginator.page(1) + except EmptyPage: + work_sells = paginator.page(paginator.num_pages) + + context.update({ + 'form': form, + 'work_sells': work_sells, + 'is_paginated': True, + 'page_obj': work_sells, + }) + return render(request, self.template_name, context) + + class WorkSellDetail(DetailView): model = WorkSell template_name = 'worksell_detail.html' @@ -87,7 +145,9 @@ def work_sell_create(request): form = WorkSellForm(data=request.POST) if form.is_valid(): instance = form.save(commit=False) + # import code; code.interact(local=dict(globals(), **locals())) instance.save() + form.save_m2m() images_ids = request.POST.get('images-ids').split(';')[:-1] for pk in images_ids: picture = Picture.objects.get(pk=pk)