diff --git a/archilance/settings/dev.py b/archilance/settings/dev.py
index 9488b9b..0ad6f0c 100644
--- a/archilance/settings/dev.py
+++ b/archilance/settings/dev.py
@@ -2,7 +2,7 @@ from .base import *
AUTH_PASSWORD_VALIDATORS = []
-INSTALLED_APPS += ['debug_toolbar',]
+# INSTALLED_APPS += ['debug_toolbar',]
try:
from .local import *
diff --git a/projects/forms.py b/projects/forms.py
index ace9a58..e8d6dcf 100644
--- a/projects/forms.py
+++ b/projects/forms.py
@@ -1,4 +1,5 @@
from django import forms
+from django.db.models import Q
from django.forms import ModelForm, HiddenInput, Form, Select
from django.forms.models import inlineformset_factory
from mptt.forms import TreeNodeChoiceField
@@ -117,13 +118,34 @@ class ProjectTrashForm(Form):
self.req = kwargs.pop('req')
super().__init__(*args, **kwargs)
- if self.req.user.is_authenticated():
- self.fields['pk'].queryset = self.req.user.projects
+ self.fields['pk'].queryset = self.req.user.projects.filter(state='active')
+
+
+class ProjectRestoreForm(Form):
+ pk = forms.ModelChoiceField(queryset=Project.objects.none())
- def clean(self):
- cleaned_data = super().clean()
+ def __init__(self, *args, **kwargs):
+ self.req = kwargs.pop('req')
+ super().__init__(*args, **kwargs)
- if not self.req.user.is_authenticated():
- raise forms.ValidationError('Пользователь не залогинен')
+ self.fields['pk'].queryset = self.req.user.projects.filter(state='trashed')
+
+
+class ProjectDeleteForm(Form):
+ pk = forms.ModelChoiceField(queryset=Project.objects.none())
+
+ def __init__(self, *args, **kwargs):
+ self.req = kwargs.pop('req')
+ super().__init__(*args, **kwargs)
+
+ self.fields['pk'].queryset = self.req.user.projects.filter(Q(state='active') | Q(state='trashed'))
+
+
+class ProjectEditForm(Form):
+ pk = forms.ModelChoiceField(queryset=Project.objects.none())
+
+ def __init__(self, *args, **kwargs):
+ self.req = kwargs.pop('req')
+ super().__init__(*args, **kwargs)
- return cleaned_data
+ self.fields['pk'].queryset = self.req.user.projects.filter(state='active')
diff --git a/projects/templates/project_edit_test.html b/projects/templates/project_edit_test.html
new file mode 100644
index 0000000..1f782b5
--- /dev/null
+++ b/projects/templates/project_edit_test.html
@@ -0,0 +1,12 @@
+{% extends 'partials/base.html' %}
+
+{% block content %}
+
+{% endblock %}
diff --git a/projects/templates/projects/project_list.html b/projects/templates/project_list.html
similarity index 100%
rename from projects/templates/projects/project_list.html
rename to projects/templates/project_list.html
diff --git a/projects/templates/projects/portfolio_form.html b/projects/templates/projects/portfolio_form.html
deleted file mode 100644
index 95b8a4e..0000000
--- a/projects/templates/projects/portfolio_form.html
+++ /dev/null
@@ -1,18 +0,0 @@
-{% extends 'partials/base.html' %}
-{% block content %}
- Добавление
-
-{% endblock %}s
diff --git a/projects/templates/projects/project_detail.html b/projects/templates/projects/project_detail.html
deleted file mode 100644
index 8821bfa..0000000
--- a/projects/templates/projects/project_detail.html
+++ /dev/null
@@ -1,275 +0,0 @@
-{% extends 'partials/base.html' %}
-
-{% load staticfiles %}
-{% load humanize %}
-
-
-{% block content %}
- {% include 'partials/header.html' %}
-
-
-
-
- {% if request.user.is_contractor %}
-
-
{{ object.price | intcomma }}
-
- {% endif %}
-
-
-
-
-
-
- Специализации:
-
-
- {{ object.specialization }}
-
-
-
-
-
- -
- {{ object.created }}
-
- -
- {{ object.type_work }}
-
-
- {% if object.secure_transaction %}
-
-
-
-
Есть допуск СРО
-
-
- {% endif %}
-
-
-
-
-
-
- -
- Местоположение: {{ object.realty.country }},{{ object.realty.city }}
-
- -
- Классификация здания: {{ object.realty.building_classification }}
-
- -
- Вид строительства: {{ object.realty.type_construction }}
-
-
-
-
-
- {{ object.text }}
-
-
-
-
- {% if perms.projects.add_answer %}
-
- {% endif %}
-
-
-
-
- {% if request.user.is_customer %}
-
-
-
-
- {% endif %}
-
-
- {% for answer in object.answers.all %}
-
-
-
-
-
Цена: {{ answer.cost| intcomma }}
-
-
-
- Срок: {{ answer.term }} {{ answer.term_type }}
-
-
Опубликован: {{ answer.created }}
-
-
-
-
-
-
- Иванов Петр Иванович
-
-
13.0.2016 / 21:05
-
-
-
-
-
-
-
-
- Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean euismod bibendum
- laoreet.
-
-
-
-
-
- {% endfor %}
-
-
-
- {% include 'partials/pagination.html' %}
-
-
- {% include 'partials/footer.html' %}
-{% endblock %}
diff --git a/projects/templates/projects/project_form.html b/projects/templates/projects/project_form.html
deleted file mode 100644
index 63d0ed9..0000000
--- a/projects/templates/projects/project_form.html
+++ /dev/null
@@ -1,278 +0,0 @@
-{% extends 'partials/base.html' %}
-
-{% block content %}
-
-
-
-
-{% endblock %}
-{% block js_block %}
-
-{% endblock %}
diff --git a/projects/templates/projects/testport.html b/projects/templates/projects/testport.html
deleted file mode 100644
index b21ecc8..0000000
--- a/projects/templates/projects/testport.html
+++ /dev/null
@@ -1,18 +0,0 @@
-{% csrf_token %}
- {{ form.as_p }}
-
-
-
-
diff --git a/projects/urls.py b/projects/urls.py
index 9187e7b..67985ae 100644
--- a/projects/urls.py
+++ b/projects/urls.py
@@ -7,19 +7,25 @@ from .views import (
OfferOrderView,
ProjectComparisonView,
ProjectCreateView,
+ ProjectDeleteView,
+ ProjectEditView,
+ ProjectRestoreView,
ProjectsView,
ProjectTrashView,
ProjectView,
- ProjectTestView,
)
app_name = 'projects'
urlpatterns = [
urls.url(r'^$', ProjectsView.as_view(), name='list'),
+
urls.url(r'^(?P\d+)/$', ProjectView.as_view(), name='detail'),
- # urls.url(r'^(?P\d+)/$', ProjectTestView.as_view(), name='detail'),
urls.url(r'^(?P\d+)/trash/$', ProjectTrashView.as_view(), name='trash'),
+ urls.url(r'^(?P\d+)/restore/$', ProjectRestoreView.as_view(), name='restore'),
+ urls.url(r'^(?P\d+)/delete/$', ProjectDeleteView.as_view(), name='delete'),
+ urls.url(r'^(?P\d+)/edit/$', ProjectEditView.as_view(), name='edit'),
+
urls.url(r'^candidate/add/(?P(\d+))/(?P(\d+))/$', add_candidate, name='add-candidate'),
urls.url(r'^candidate/comparison/(?P\d+)$', ProjectComparisonView.as_view(), name='comparison'),
urls.url(r'^create/$', ProjectCreateView.as_view(), name='project-create'),
diff --git a/projects/views.py b/projects/views.py
index 75316f2..815a678 100644
--- a/projects/views.py
+++ b/projects/views.py
@@ -9,7 +9,18 @@ import pydash as _
from users.models import User
from .models import Project, Portfolio, Candidate, Answer, Realty, Order
-from .forms import ProjectForm, PortfolioForm, AnswerForm, RealtyForm, ProjectTrashForm
+
+from .forms import (
+ AnswerForm,
+ PortfolioForm,
+ ProjectDeleteForm,
+ ProjectEditForm,
+ ProjectForm,
+ ProjectRestoreForm,
+ ProjectTrashForm,
+ RealtyForm,
+)
+
from .mixins import LastAccessMixin
@@ -21,16 +32,16 @@ class ProjectView(LastAccessMixin, View):
model = Project
form_class = AnswerForm
template_name = 'contractor_project_detail.html'
-
+
def get_success_url(self):
return reverse('projects:detail', kwargs={'pk': self.object.pk})
-
+
def get(self, request, *args, **kwargs):
if request.user.is_customer():
self.template_name = 'customer_project_detail.html'
project = get_object_or_404(Project, pk=kwargs.get('pk'))
return render(request, self.template_name, {'project': project, 'form': self.form_class})
-
+
def post(self, request, *args, **kwargs):
if not request.user.is_authenticated():
return HttpResponseForbidden()
@@ -39,7 +50,7 @@ class ProjectView(LastAccessMixin, View):
if form.is_valid():
return self.form_valid(request, form, project)
return render(request, self.template_name, {'project': project, 'form': self.form_class})
-
+
def form_valid(self, request, form, project):
answer = form.save(commit=False)
answer.contractor = request.user
@@ -95,22 +106,96 @@ class ProjectCreateView(PermissionRequiredMixin, View):
class ProjectTrashView(View):
+ form_class = ProjectTrashForm
+
def post(self, req, *args, **kwargs):
- form = ProjectTrashForm(_.merge({}, req.POST, kwargs), req=req)
+ if req.user.is_authenticated():
+ form = self.form_class(_.merge({}, req.POST, kwargs), req=req)
+
+ if form.is_valid():
+ project = form.cleaned_data.get('pk')
+ project.state = 'trashed'
+ project.save()
+
+ messages.info(req, 'Проект перемещён в корзину')
+ else:
+ messages.info(req, 'Произошла ошибка: {msg}'.format(msg=pformat(form.errors)))
+ else:
+ return HttpResponseForbidden('403 Forbidden')
+
+ redirect_to = req.POST.get('next')
+ return redirect(redirect_to)
- if form.is_valid():
- project = form.cleaned_data.get('pk')
- project.state = 'trashed'
- project.save()
- messages.info(req, 'Form valid')
+class ProjectRestoreView(View):
+ form_class = ProjectRestoreForm
+
+ def post(self, req, *args, **kwargs):
+ if req.user.is_authenticated():
+ form = self.form_class(_.merge({}, req.POST, kwargs), req=req)
+
+ if form.is_valid():
+ project = form.cleaned_data.get('pk')
+ project.state = 'active'
+ project.save()
+
+ messages.info(req, 'Проект восстановлен из корзины')
+ else:
+ messages.info(req, 'Произошла ошибка: {msg}'.format(msg=pformat(form.errors)))
else:
- messages.info(req, 'Form invalid: {msg}'.format(msg=pformat(form.errors)))
+ return HttpResponseForbidden('403 Forbidden')
+
+ redirect_to = req.POST.get('next')
+ return redirect(redirect_to)
+
+class ProjectDeleteView(View):
+ form_class = ProjectDeleteForm
+
+ def post(self, req, *args, **kwargs):
+ if req.user.is_authenticated():
+ form = self.form_class(_.merge({}, req.POST, kwargs), req=req)
+
+ if form.is_valid():
+ project = form.cleaned_data.get('pk')
+ project.state = 'deleted'
+ project.save()
+
+ messages.info(req, 'Проект удалён навсегда')
+ else:
+ messages.info(req, 'Произошла ошибка: {msg}'.format(msg=pformat(form.errors)))
+ else:
+ return HttpResponseForbidden('403 Forbidden')
+
redirect_to = req.POST.get('next')
return redirect(redirect_to)
+class ProjectEditView(View):
+ form_class = ProjectEditForm
+ template_name = 'project_edit_test.html' # 'project_edit.html'
+
+ def get(self, req, *args, **kwargs):
+ form = self.form_class()
+ return render(req, self.template_name, {'form': form})
+
+ def post(self, req, *args, **kwargs):
+ form = self.form_class(_.merge({}, req.POST, kwargs), req=req)
+
+ if req.user.is_authenticated():
+ if form.is_valid():
+ #...
+
+ messages.info(req, 'Проект (как будто) успешно отредактирован')
+ redirect_to = req.POST.get('next')
+ return redirect(redirect_to)
+ else:
+ messages.info(req, 'Произошла ошибка: {msg}'.format(msg=pformat(form.errors)))
+ return render(req, self.template_name, {'form': form})
+ else:
+ return HttpResponseForbidden('403 Forbidden')
+
+
class TestView(View):
template_name = 'test_form.html'
form_class = RealtyForm
diff --git a/users/models.py b/users/models.py
index 2444a2e..b8ab0ac 100644
--- a/users/models.py
+++ b/users/models.py
@@ -38,6 +38,7 @@ class User(AbstractBaseUser, PermissionsMixin):
('free', 'Свободен'),
('busy', 'Занят'),
)
+
nickname = models.CharField(max_length=50, blank=True,null=True)
first_name = models.CharField(max_length=255, blank=True)
last_name = models.CharField(max_length=255, blank=True)
diff --git a/users/templates/customer_profile_open_projects.html b/users/templates/customer_profile_open_projects.html
index 8badf6f..51cb31d 100644
--- a/users/templates/customer_profile_open_projects.html
+++ b/users/templates/customer_profile_open_projects.html
@@ -35,11 +35,11 @@
- {% for proj in object.projects.all %}
+ {% for proj in projects %}
@@ -71,7 +71,13 @@
- - Редактировать
+ -
+
+ {% csrf_token %}
+
+
+
+
-
diff --git a/users/templates/customer_profile_trashed_projects.html b/users/templates/customer_profile_trashed_projects.html
index b52c6eb..4750dab 100644
--- a/users/templates/customer_profile_trashed_projects.html
+++ b/users/templates/customer_profile_trashed_projects.html
@@ -33,231 +33,62 @@
-
-
-
- Создание дизайна интерьера квартиры 200m2
-
-
- -
- Объект "Карточный домик"
-
- -
- 2 ответ от имени группы
-
-
-
- Компьютерная 3D-визуализация помещений (разработка эксклюзивных художественных решений, тщательная проработка утвержденного варианта, подбор цветовой гаммы и текстуры отделочных материалов). Развертка и разрез стен, декоративные элементы (при необходимости)...
-
-
- -
- 13.02.2016
-
- -
- 523
-
- -
- 523
-
- -
- Александр Новиков
-
-
-
-
-
- 35 000
-
-
- -
- Восстановить из корзины
-
- -
- Удалить навсегда
-
-
-
-
-
-
-
- Создание дизайна интерьера квартиры 200m2
-
-
- -
- Объект "Карточный домик"
-
- -
- 2 ответ от имени группы
-
-
-
- Компьютерная 3D-визуализация помещений (разработка эксклюзивных художественных решений, тщательная проработка утвержденного варианта, подбор цветовой гаммы и текстуры отделочных материалов). Развертка и разрез стен, декоративные элементы (при необходимости)...
-
-
- -
- 13.02.2016
-
- -
- 523
-
- -
- 523
-
- -
- Александр Новиков
-
-
-
-
-
- 35 000
-
-
- -
- Восстановить из корзины
-
- -
- Удалить навсегда
-
-
-
-
-
-
-
- Создание дизайна интерьера квартиры 200m2
-
-
- -
- Объект "Карточный домик"
-
- -
- 2 ответ от имени группы
-
-
-
- Компьютерная 3D-визуализация помещений (разработка эксклюзивных художественных решений, тщательная проработка утвержденного варианта, подбор цветовой гаммы и текстуры отделочных материалов). Развертка и разрез стен, декоративные элементы (при необходимости)...
-
-
- -
- 13.02.2016
-
- -
- 523
-
- -
- 523
-
- -
- Александр Новиков
-
-
-
-
-
- 35 000
-
-
- -
- Восстановить из корзины
-
- -
- Удалить навсегда
-
-
-
-
-
-
-
- Создание дизайна интерьера квартиры 200m2
-
-
- -
- Объект "Карточный домик"
-
- -
- 2 ответ от имени группы
-
-
-
- Компьютерная 3D-визуализация помещений (разработка эксклюзивных художественных решений, тщательная проработка утвержденного варианта, подбор цветовой гаммы и текстуры отделочных материалов). Развертка и разрез стен, декоративные элементы (при необходимости)...
-
-
- -
- 13.02.2016
-
- -
- 523
-
- -
- 523
-
- -
- Александр Новиков
-
-
-
-
-
- 35 000
-
-
- -
- Восстановить из корзины
-
- -
- Удалить навсегда
-
-
-
-
-
-
-
- Создание дизайна интерьера квартиры 200m2
-
-
- -
- Объект "Карточный домик"
-
- -
- 2 ответ от имени группы
-
-
-
- Компьютерная 3D-визуализация помещений (разработка эксклюзивных художественных решений, тщательная проработка утвержденного варианта, подбор цветовой гаммы и текстуры отделочных материалов). Развертка и разрез стен, декоративные элементы (при необходимости)...
-
-
- -
- 13.02.2016
-
- -
- 523
-
- -
- 523
-
- -
- Александр Новиков
-
-
-
-
-
- 35 000
-
-
- -
- Восстановить из корзины
-
- -
- Удалить навсегда
-
-
-
-
+ {% for proj in projects %}
+
+
+
+ {{ proj.name }}
+
+
+ -
+ Объект "{{ proj.realty.name }}"
+
+ -
+ 2 ответ от имени группы
+
+
+
+ {{ proj.text }}
+
+
+ -
+ {{ proj.created}}
+
+ -
+ 523
+
+ -
+ 523
+
+ -
+ {{ customer.get_full_name }}
+
+
+
+
+
+ {{ proj.budget }}
+
+
+ -
+
+ {% csrf_token %}
+
+
+
+
+
+ -
+
+ {% csrf_token %}
+
+
+
+
+
+
+
+ {% endfor %}
{% include 'partials/footer.html' %}
diff --git a/users/views.py b/users/views.py
index a63fc31..bd0ffd0 100644
--- a/users/views.py
+++ b/users/views.py
@@ -16,33 +16,50 @@ class UserListView(ListView):
class ContractorListView(ListView):
model = User
template_name = 'contractor_list.html'
+ context_object_name = 'contractor'
class ContractorProfileDetailView(DetailView):
model = User
template_name = 'contractor_profile.html'
+ context_object_name = 'contractor'
class ContractorOfficeDetailView(DetailView):
model = User
template_name = 'contractor_office.html'
+ context_object_name = 'contractor'
class CustomerProfileOpenProjectsView(BaseMixin, DetailView):
model = User
template_name = 'customer_profile_open_projects.html'
+ context_object_name = 'customer'
+
+ def get_context_data(self, **kwargs):
+ c = super().get_context_data(**kwargs)
+ c['projects'] = self.object.projects.filter(state='active')
+ return c
class CustomerProfileTrashedProjectsView(BaseMixin, DetailView):
model = User
template_name = 'customer_profile_trashed_projects.html'
+ context_object_name = 'customer'
+
+ def get_context_data(self, **kwargs):
+ c = super().get_context_data(**kwargs)
+ c['projects'] = self.object.projects.filter(state='trashed')
+ return c
class CustomerProfileCurrentProjectsView(BaseMixin, DetailView):
model = User
template_name = 'customer_profile_current_projects.html'
+ context_object_name = 'customer'
class CustomerProfileReviewsView(BaseMixin, DetailView):
model = User
template_name = 'customer_profile_reviews.html'
+ context_object_name = 'customer'