Merge master -> artur

remotes/origin/PR-39
ArturBaybulatov 10 years ago
commit b082d58588
  1. 2
      assets/js/chat.js
  2. 8
      chat/templates/chat_contractor.html
  3. 9
      chat/templates/chat_customer.html
  4. 29
      projects/migrations/0015_auto_20160824_1538.py
  5. 15
      projects/models.py
  6. 151
      projects/templates/portfolio_detail.html
  7. 4
      projects/urls.py
  8. 215
      projects/views.py
  9. 8
      templates/partials/header.html
  10. 6
      update.sh
  11. 2
      users/templates/contractor_filter.html
  12. 5
      users/templates/contractor_office.html
  13. 6
      users/templates/contractor_profile.html
  14. 15
      work_sell/templates/worksell_detail.html
  15. 5
      work_sell/templates/worksells_list.html

@ -1,6 +1,6 @@
var SocketHandler = function () {
domain = domain.replace(':' + port, '');
var url = 'ws://' + domain + ':8888/chat/' + userId + '/';
var url = 'ws://' + domain + '/chat/' + userId + '/';
var sock = new WebSocket(url);
var intervalId;
sock.onopen = function () {

@ -47,7 +47,13 @@
{% endthumbnail %}
</div>
<p class="nameMess">
<div><a href="#" style="color:black;">{{ contact.username }}</a></div>
{% if contact.is_contractor %}
{% url "users:contractor-profile" pk=contact.pk as contact_url %}
{% else %}
{% url "users:customer-profile-open-projects" pk=contact.pk as contact_url %}
{% endif %}
<div><a href="{{ contact_url }}" style="color:black;">{{ contact.username }}</a></div>
</p>
<a href="#" class="conMess">Контакты</a>

@ -41,7 +41,12 @@
{% endif %}
</div>
<p class="nameMess">
<div><a href="#">{{ contact.username }}</a></div>
{% if contact.is_contractor %}
{% url "users:contractor-profile" pk=contact.pk as contact_url %}
{% else %}
{% url "users:customer-profile-open-projects" pk=contact.pk as contact_url %}
{% endif %}
<div><a href="{{ contact_url }}">{{ contact.username }}</a></div>
</p>
<a href="#" data-target="#userModal" data-toggle="modal"
@ -148,7 +153,7 @@
Обсуджение задания и условий выполнения работы. Подтверждение заказа исполнителем.
</p>
</div>
<div id="order-stages" class="stepssBlock"></div>
<div class="stepssBlock box-sizing disTab">

@ -0,0 +1,29 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.7 on 2016-08-24 12:38
from __future__ import unicode_literals
from django.db import migrations, models
import django.utils.timezone
class Migration(migrations.Migration):
dependencies = [
('projects', '0014_auto_20160823_1912'),
]
operations = [
migrations.AlterModelOptions(
name='portfolio',
options={'ordering': ['-created'], 'verbose_name': 'Портфолио', 'verbose_name_plural': 'Портфолио'},
),
migrations.RemoveField(
model_name='project',
name='rejected_answers_count',
),
migrations.AddField(
model_name='portfolio',
name='created',
field=models.DateTimeField(default=django.utils.timezone.now),
),
]

@ -271,11 +271,25 @@ class Portfolio(models.Model):
term_type = models.CharField(max_length=20, choices=TERMS, default='hour', null=True, blank=True)
user = models.ForeignKey(User, related_name='portfolios', null=True, blank=True)
worksell = models.BooleanField(default=False)
created = models.DateTimeField(default=timezone.now)
def __str__(self):
return self.name
def get_prev(self):
try:
return self.get_previous_by_created()
except self.DoesNotExist:
return None
def get_next(self):
try:
return self.get_next_by_created()
except self.DoesNotExist:
return None
class Meta:
ordering = ['-created']
verbose_name = 'Портфолио'
verbose_name_plural = 'Портфолио'
@ -284,6 +298,7 @@ class Portfolio(models.Model):
return photo and photo.img
class PortfolioPhoto(models.Model):
img = models.ImageField(upload_to='projects/portfolio')
portfolio = models.ForeignKey(Portfolio, related_name='photos')

@ -0,0 +1,151 @@
{% extends 'partials/base.html' %}
{% load staticfiles %}
{% load thumbnail %}
{% block content %}
{% include 'partials/header.html' %}
<div class="container mainScore">
<div class="row">
<div class="col-lg-12 allProjects">
<p class="titleScore">{{ object }}</p>
{% if object.get_prev %}
<div class="all all1">
<p><a href="{% url 'projects:contractor-portfolio-detail' object.get_prev.pk %}"> предыдущий</a></p>
</div>
{% endif %}
{% if object.get_next %}
<div class="all all2">
<p><a href="{% url 'projects:contractor-portfolio-detail' object.get_next.pk %}">следующий</a></p>
</div>
{% endif %}
</div>
{# <div class="btnReadyBlock disTab">#}
{# <div class="triangle1"></div>#}
{# <div class="col-lg-3">#}
{# <p class="cenaReady">{{ object.budget }} <i class="fa fa-rub"></i></p>#}
{# </div>#}
{# {% if request.user.is_authenticated %}#}
{# <div class="col-lg-3">#}
{# <a href="{% url 'users:contractor-profile' object.contractor.pk %}" class="linkReady LR1">#}
{# купить#}
{# </a>#}
{# </div>#}
{##}
{# <div class="col-lg-3">#}
{# <a href="{% url 'chat:chat-user' %}?user_id={{ object.contractor.pk }}" class="linkReady LR2">#}
{# Написать сообщение#}
{# </a>#}
{# </div>#}
{# {% endif %}#}
{# <div class="col-lg-3">#}
{# <a href="{% url 'users:contractor-profile' object.contractor.pk %}" class="linkReady LR3">#}
{# посмотреть контакты#}
{# </a>#}
{# </div>#}
{# </div>#}
<div class="desReadyBlock">
{% if object.text %}
<div class="col-lg-10 col-lg-offset-1">
<p class="titleReady">Описание:</p>
</div>
<div class="col-lg-10 col-lg-offset-1">
<p class="textReady">
{{ object.text }}
</p>
</div>
{% endif %}
<div class="col-lg-12 sliderReady">
<div class="arroww prev3"></div>
<div class="arroww next3"></div>
<div class="swiper-container gallery-top">
<div class="swiper-wrapper">
<div class="swiper-slide" style="background-image:url('{% static object.get_cover.url %}')"></div>
{% for photo in object.photos.all %}
<div class="swiper-slide" style="background-image:url('{% static photo.img.url %}')"></div>
{% endfor %}
</div>
</div>
<div class="swiper-container gallery-thumbs">
<div class="swiper-wrapper">
<div class="swiper-slide is-selected"
style="background-image:url('{% static object.get_cover.url %}')"></div>
{% for photo in object.photos.all %}
<div class="swiper-slide" style="background-image:url('{% static photo.img.url %}')"></div>
{% endfor %}
</div>
</div>
</div>
{# <div class="col-lg-12">#}
{# <div class="triangle2"></div>#}
{# <div class="arr arr1"></div>#}
{# <div class="arr arr2"></div>#}
{# </div>#}
</div>
{# <div class="col-lg-12 sibl">#}
{# <p>Похожие работы</p>#}
{# </div>#}
{# <div class="gallMini disTab">#}
{# {% for worksell in worksell_related %}#}
{# <div class="col-lg-3">#}
{##}
{# <div class="insetCol box-sizing disTab">#}
{# {% thumbnail worksell.get_cover "265x265" crop="center" as im %}#}
{# <div class="imgGal" style="background: url('{{ im.url }}') no-repeat center;">#}
{# <div class="imgFigure"></div>#}
{# </div>#}
{# {% endthumbnail %}#}
{# </div>#}
{# </div>#}
{# {% endfor %}#}
{# </div>#}
{% include 'partials/footer.html' %}
</div>
</div>
{% endblock %}
{% block js_block %}
<script src="{% static 'js/swiper.min.js' %}"></script>
<script>
var galleryTop = new Swiper('.gallery-top', {
nextButton: '.next3',
prevButton: '.prev3',
spaceBetween: 10,
});
var galleryTop = new Swiper('.gallery-top', {
nextButton: '.next3',
prevButton: '.prev3',
spaceBetween: 15,
onSlideChangeEnd: function (swiper) {
var activeIndex = swiper.activeIndex;
$(galleryThumbs.slides).removeClass('is-selected');
$(galleryThumbs.slides).eq(activeIndex).addClass('is-selected');
galleryThumbs.slideTo(activeIndex, 300, false);
}
});
var galleryThumbs = new Swiper('.gallery-thumbs', {
spaceBetween: 15,
freeMode: true,
centeredSlides: false,
slidesPerView: 6,
touchRatio: 0.2,
nextButton: '.arr2',
prevButton: '.arr1',
onClick: function (swiper, event) {
var clicked = swiper.clickedIndex
swiper.activeIndex = clicked;
swiper.updateClasses()
$(swiper.slides).removeClass('is-selected');
$(swiper.clickedSlide).addClass('is-selected');
galleryTop.slideTo(clicked, 300, false);
}
});
</script>
{% endblock %}

@ -20,6 +20,7 @@ from .views import (
ProjectFilterView,
RejectProjectAnswerView,
sort_candidates,
PortfolioDetail,
)
app_name = 'projects'
@ -40,8 +41,9 @@ urlpatterns = [
urls.url(r'^reject-project-answer/(?P<pk>\d+)/$', RejectProjectAnswerView.as_view(), name='reject-project-answer'),
urls.url(r'^portfolio/create/$', contractor_portfolio_create, name='contractor-portfolio-create'),
urls.url(r'^portfolio/(?P<pk>\d+)/?$', PortfolioDetail.as_view(), name='contractor-portfolio-detail'),
urls.url(r'^portfolio/(?P<pk>\d+)/edit/$', ContractorPortfolioUpdateView.as_view(), name='contractor-portfolio-edit'),
urls.url(r'^candidate/add/(?P<answer_id>(\d+))/(?P<project_id>(\d+))/$', add_candidate, name='add-candidate'),
urls.url(r'^candidate/delete/(?P<pk>(\d+))/$', CandidateDeleteView.as_view(), name='delete-candidate'),
urls.url(r'^candidate/comparison/sort/$', sort_candidates, name='comparison-sort'),

@ -43,78 +43,78 @@ from .forms import (
class ProjectDetailWithAnswerView(BaseMixin, View):
form_class = ProjectAnswerForm
template_name = 'project_detail.html'
def get(self, request, *args, **kwargs):
context = self.get_context_data(**_.merge({}, request.GET, kwargs))
project = get_object_or_404(Project, pk=kwargs.get('pk'))
context.update({'project': project})
hit_count = HitCount.objects.get_for_object(project)
HitCountMixin.hit_count(request, hit_count)
if request.user.is_authenticated() and request.user.is_contractor():
project_answers = project.answers.filter(rejected=False)
contractor = request.user
answer = _.first(_.filter(project_answers, lambda a: a.author == contractor))
if not answer:
try: team = contractor.team
except Team.DoesNotExist: team = None
if team:
answer = _.first(_.filter(project_answers, lambda a: a.author == team))
context.update({'answer': answer})
if not answer:
try: contractor.team; context.update({'can_answer_as_team': True})
except Team.DoesNotExist: pass
if request.GET.get('answer_as_team') == 'on':
context.update({'answer_as_team': True})
form = self.form_class(request=request, answer_as_team=True, project=project)
else:
form = self.form_class(request=request, project=project)
context.update({'form': form})
return render(request, self.template_name, context)
def post(self, request, *args, **kwargs):
if request.user.is_authenticated() and request.user.is_contractor():
context = self.get_context_data(**kwargs)
answer_as_team = None
project = get_object_or_404(Project, pk=kwargs.get('pk')) # TODO: Does this work?
if request.POST.get('answer_as_team') == 'on':
answer_as_team = True
if answer_as_team:
form = self.form_class(request.POST, request=request, answer_as_team=True, project=project)
else:
form = self.form_class(request.POST, request=request, project=project)
project = get_object_or_404(Project, pk=kwargs.get('pk'))
context.update({'project': project})
if form.is_valid():
answer = form.save(commit=False)
answer.project = project
answer.author = request.user.team if answer_as_team else request.user
answer.save()
form.save_m2m()
for file in request.FILES.getlist('new_files'):
if len(file.name) <= 255:
AnswerFile.objects.create(file=file, name=file.name, answer=answer)
message = AnswerMessage(text=form.cleaned_data.get('text'), is_sender_customer=False)
message.answer = answer
message.contractor_or_team = answer.author
message.save()
messages.info(request, 'Отклик успешно размещён')
redirect_to = request.POST.get('next')
return redirect(redirect_to)
@ -124,7 +124,7 @@ class ProjectDetailWithAnswerView(BaseMixin, View):
'<p>Произошла ошибка (form)</p>'
'<pre>{form}</pre>'
).format(form=pformat(form.errors)))
context.update({'form': form})
return render(request, self.template_name, context)
else:
@ -133,41 +133,41 @@ class ProjectDetailWithAnswerView(BaseMixin, View):
class ProjectAnswerCreateMessageView(BaseMixin, View):
form_class = ProjectAnswerMessageForm
def dispatch(self, request, *args, **kwargs):
if request.user.is_authenticated():
return super().dispatch(request, *args, **kwargs)
else:
return HttpResponseForbidden('403 Forbidden')
def post(self, request, *args, **kwargs):
form = self.form_class(request.POST, request=request)
if form.is_valid():
message = form.save(commit=False)
if request.user.is_contractor():
answer = get_object_or_404(Answer, pk=kwargs.get('pk'))
message.answer = answer
message.is_sender_customer = False
if isinstance(answer.author, User) and answer.author == request.user:
message.contractor_or_team = request.user
elif isinstance(answer.author, Team):
try: team = request.user.team
except Team.DoesNotExist: team = None
if team and answer.author == team:
message.contractor_or_team = team
elif request.user.is_customer():
answer = get_object_or_404(Answer, pk=kwargs.get('pk')) # TODO: Perform additional checks
message.answer = answer
message.is_sender_customer = True
message.save()
form.save_m2m()
messages.info(request, 'Сообщение успешно размещено')
else:
if form.errors:
@ -175,7 +175,7 @@ class ProjectAnswerCreateMessageView(BaseMixin, View):
'<p>Произошла ошибка (form)</p>'
'<pre>{form}</pre>'
).format(form=pformat(form.errors)))
redirect_to = request.POST.get('next')
return redirect(redirect_to)
@ -186,19 +186,19 @@ class RejectProjectAnswerView(BaseMixin, View):
return super().dispatch(request, *args, **kwargs)
else:
raise PermissionDenied
def post(self, request, *args, **kwargs):
if request.user.is_contractor():
answer = get_object_or_404(request.user.contractor_answers, pk=kwargs.get('pk'))
elif request.user.is_customer():
project = get_object_or_404(request.user.projects, answers__pk=kwargs.get('pk'))
answer = get_object_or_404(project.answers, pk=kwargs.get('pk'))
answer.rejected = True
answer.save()
messages.info(request, 'Успешный отказ от проекта')
redirect_to = request.POST.get('next')
return redirect(redirect_to)
@ -207,107 +207,107 @@ class ProjectFilterView(BaseMixin, View):
template_name = 'project_filter.html'
form_class = ProjectFilterForm
realty_form = ProjectFilterRealtyForm
def get(self, request, *args, **kwargs):
form = self.form_class(request.GET, request=request)
realty_form = self.realty_form(request.GET, request=request, prefix='realty_form')
context = self.get_context_data(**_.merge({}, request.GET, kwargs))
projects = Project.objects
if form.is_valid() and realty_form.is_valid():
ord = None
keywords = form.cleaned_data.get('keywords')
cro = form.cleaned_data.get('cro')
work_type = form.cleaned_data.get('work_type')
specialization = form.cleaned_data.get('specialization')
building_classification = realty_form.cleaned_data.get('building_classification')
construction_type = realty_form.cleaned_data.get('construction_type')
location = realty_form.cleaned_data.get('location')
if keywords:
keywords = tuple(filter(None, re.split(r'\s|,|;', keywords)))
for k in keywords:
projects = projects.filter(Q(name__icontains=k) | Q(text__icontains=k))
if cro:
projects = projects.filter(cro=cro)
if work_type:
projects = projects.filter(work_type=work_type)
if specialization:
projects = projects.filter(
specialization__lft__gte=specialization.lft,
specialization__rght__lte=specialization.rght,
)
if building_classification:
projects = projects.filter(realty__building_classification=building_classification)
if construction_type:
projects = projects.filter(realty__construction_type=construction_type)
if location:
projects = projects.filter(
realty__location__lft__gte=location.lft,
realty__location__rght__lte=location.rght,
)
order_by = form.cleaned_data.get('order_by')
last_order_by = form.cleaned_data.get('last_order_by')
reverse_order = form.cleaned_data.get('reverse_order')
if order_by:
reverse_order = not reverse_order if order_by == last_order_by else False
ord = order_by
last_order_by = ord
elif last_order_by:
ord = last_order_by
manual_sort = None
if ord and ord == 'views':
projects = natsort.natsorted(projects.all(), key=lambda p: p.hit_count.hits, reverse=reverse_order)
manual_sort = True
elif ord:
projects = projects.order_by('-%s' % ord if reverse_order else ord)
context.update({
'last_order_by': last_order_by,
'reverse_order': reverse_order,
})
project_count = len(projects) if manual_sort else projects.count()
display_msg = 'Найдено %s проектов' % project_count if project_count > 0 else 'Ничего не найдено'
else:
display_msg = 'Пожалуйста, введите корректные данные'
if form.errors:
messages.info(request, (
'<p>Произошла ошибка (form)</p>'
'<pre>{form}</pre>'
).format(form=pformat(form.errors)))
if realty_form and realty_form.errors:
messages.info(request, (
'<p>Произошла ошибка (realty_form)</p>'
'<pre>{realty_form}</pre>'
).format(realty_form=pformat(realty_form.errors)))
paginator = Paginator(projects if manual_sort else projects.all(), settings.PAGE_SIZE)
page = request.GET.get('page')
try:
projects = paginator.page(page)
except PageNotAnInteger:
projects = paginator.page(1)
except EmptyPage:
projects = paginator.page(paginator.num_pages)
context.update({
'form': form,
'realty_form': realty_form,
@ -316,7 +316,7 @@ class ProjectFilterView(BaseMixin, View):
'page_obj': projects,
'display_msg': display_msg,
})
return render(request, self.template_name, context)
@ -324,44 +324,44 @@ class CustomerProjectCreateView(BaseMixin, View):
form_class = CustomerProjectEditForm
realty_form = RealtyForm
template_name = 'customer_project_create.html'
def dispatch(self, request, *args, **kwargs):
if request.user.is_authenticated() and request.user.is_customer():
return super().dispatch(request, *args, **kwargs)
else:
raise PermissionDenied
def get(self, request, *args, **kwargs):
form = self.form_class(request=request)
realty_form = self.realty_form(request=request, prefix='realty_form')
context = self.get_context_data(**_.merge({}, request.GET, kwargs))
context.update({'form': form, 'realty_form': realty_form})
return render(request, self.template_name, context)
def post(self, request, *args, **kwargs):
form = self.form_class(request.POST, request=request) # Passing `request.FILES` seems unnecessary here. Files are added manually below
form.is_valid()
realty = form.cleaned_data.get('realty')
if realty:
realty_form = self.realty_form(request.POST, instance=realty, request=request, prefix='realty_form')
else:
realty_form = self.realty_form(request.POST, request=request, prefix='realty_form')
if form.is_valid() and realty_form.is_valid():
project = form.save(commit=False)
project.customer = request.user
project.save()
form.save_m2m()
Order.objects.create(project=project)
for file in request.FILES.getlist('new_files'):
ProjectFile.objects.create(file=file, project=project)
if realty:
realty_form.save()
else:
@ -369,10 +369,10 @@ class CustomerProjectCreateView(BaseMixin, View):
realty.user = request.user
realty.save()
realty_form.save_m2m()
project.realty = realty # Connect a realty with a project
project.save()
messages.info(request, 'Проект успешно создан')
redirect_to = reverse('projects:detail', kwargs={'pk': project.pk})
return redirect(redirect_to)
@ -382,13 +382,13 @@ class CustomerProjectCreateView(BaseMixin, View):
'<p>Произошла ошибка (form)</p>'
'<pre>{form}</pre>'
).format(form=pformat(form.errors)))
if realty_form and realty_form.errors:
messages.info(request, (
'<p>Произошла ошибка (realty_form)</p>'
'<pre>{realty_form}</pre>'
).format(realty_form=pformat(realty_form.errors)))
context = self.get_context_data(**kwargs)
context.update({'form': form, 'realty_form': realty_form})
return render(request, self.template_name, context)
@ -398,7 +398,7 @@ class CustomerProjectEditView(BaseMixin, View):
form_class = CustomerProjectEditForm
realty_form = RealtyForm
template_name = 'customer_project_edit.html'
def dispatch(self, request, *args, **kwargs):
if request.user.is_authenticated() and request.user.is_customer():
return super().dispatch(request, *args, **kwargs)
@ -408,42 +408,42 @@ class CustomerProjectEditView(BaseMixin, View):
def get(self, request, *args, **kwargs):
project = get_object_or_404(request.user.projects, pk=kwargs.get('pk'))
form = self.form_class(instance=project, request=request)
realty = project.realty
if realty:
realty_form = self.realty_form(instance=project.realty, request=request, prefix='realty_form')
else:
realty_form = self.realty_form(request=request, prefix='realty_form')
context = self.get_context_data(**_.merge({}, request.GET, kwargs))
context.update({'form': form, 'realty_form': realty_form})
return render(request, self.template_name, context)
def post(self, request, *args, **kwargs):
project = get_object_or_404(request.user.projects, pk=kwargs.get('pk'))
form = self.form_class(request.POST, request.FILES, request=request, instance=project)
form.is_valid()
realty = form.cleaned_data.get('realty')
if realty:
realty_form = self.realty_form(request.POST, instance=realty, request=request, prefix='realty_form')
else:
realty_form = self.realty_form(request.POST, request=request, prefix='realty_form')
if form.is_valid() and realty_form.is_valid():
project = form.save(commit=False)
project.customer = request.user
project.files = form.cleaned_data.get('files') # TODO: Should we somehow get rid of this explicit assignment?
project.save()
form.save_m2m()
for file in request.FILES.getlist('new_files'):
proj_file = ProjectFile.objects.create(file=file, project=project)
proj_file.save()
if realty:
realty_form.save()
else:
@ -451,10 +451,10 @@ class CustomerProjectEditView(BaseMixin, View):
realty.user = request.user
realty.save()
realty_form.save_m2m()
project.realty = realty # Connect a realty with a project
project.save()
messages.info(request, 'Проект успешно отредактирован')
redirect_to = request.POST.get('next')
return redirect(redirect_to)
@ -464,13 +464,13 @@ class CustomerProjectEditView(BaseMixin, View):
'<p>Произошла ошибка (form)</p>'
'<pre>{form}</pre>'
).format(form=pformat(form.errors)))
if realty_form and realty_form.errors:
messages.info(request, (
'<p>Произошла ошибка (realty_form)</p>'
'<pre>{realty_form}</pre>'
).format(realty_form=pformat(realty_form.errors)))
context = self.get_context_data(**kwargs)
context.update({'form': form, 'realty_form': realty_form})
return render(request, self.template_name, context)
@ -506,41 +506,41 @@ class ContractorPortfolioTrashView(View):
class CustomerProjectTrashView(View):
form_class = CustomerProjectTrashForm
def dispatch(self, request, *args, **kwargs):
if request.user.is_authenticated() and request.user.is_customer():
return super().dispatch(request, *args, **kwargs)
else:
return HttpResponseForbidden('403 Forbidden')
def post(self, req, *args, **kwargs):
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, 'Произошла ошибка: <pre>{msg}</pre>'.format(msg=pformat(form.errors)))
redirect_to = req.POST.get('next')
return redirect(redirect_to)
class CustomerProjectRestoreView(View):
form_class = CustomerProjectRestoreForm
def dispatch(self, request, *args, **kwargs):
if request.user.is_authenticated() and request.user.is_customer():
return super().dispatch(request, *args, **kwargs)
else:
return HttpResponseForbidden('403 Forbidden')
def post(self, req, *args, **kwargs):
form = self.form_class(_.merge({}, req.POST, kwargs), req=req)
if form.is_valid():
project = form.cleaned_data.get('pk')
project.state = 'active'
@ -549,23 +549,23 @@ class CustomerProjectRestoreView(View):
messages.info(req, 'Проект восстановлен из корзины')
else:
messages.info(req, 'Произошла ошибка: <pre>{msg}</pre>'.format(msg=pformat(form.errors)))
redirect_to = req.POST.get('next')
return redirect(redirect_to)
class CustomerProjectDeleteView(View):
form_class = CustomerProjectDeleteForm
def dispatch(self, request, *args, **kwargs):
if request.user.is_authenticated() and request.user.is_customer():
return super().dispatch(request, *args, **kwargs)
else:
return HttpResponseForbidden('403 Forbidden')
def post(self, req, *args, **kwargs):
form = self.form_class(_.merge({}, req.POST, kwargs), req=req)
if form.is_valid():
project = form.cleaned_data.get('pk')
project.state = 'deleted'
@ -573,7 +573,7 @@ class CustomerProjectDeleteView(View):
messages.info(req, 'Проект удалён навсегда')
else:
messages.info(req, 'Произошла ошибка: <pre>{msg}</pre>'.format(msg=pformat(form.errors)))
redirect_to = req.POST.get('next')
return redirect(redirect_to)
@ -650,7 +650,7 @@ class OfferOrderView(View):
return HttpResponseRedirect(redirect_url)
def contractor_portfolio_create(request):
def contractor_portfolio_create(request): # TODO: pekopt: shit. rewrite using generic
if request.is_ajax():
form = PortfolioForm(data=request.POST)
# import code; code.interact(local=dict(globals(), **locals()))
@ -707,4 +707,11 @@ class PortfolioDelete(DeleteView):
model = Portfolio
success_url = reverse_lazy('users:contractor-profile')
class PortfolioDetail(DetailView):
model = Portfolio
template_name = 'portfolio_detail.html'
# import code; code.interact(local=dict(globals(), **locals()))

@ -107,12 +107,12 @@
<a href="{% url 'wallets:score-detail' pk=request.user.pk %}">Счет<span></span></a>
</li>
<li class="icon_mm5">
<a href="#">Настройки<span></span></a>
<a href="{% url 'users:user-profile-edit' pk=request.user.pk %}">Настройки<span></span></a>
</li>
<li class="icon_mm6">
<a href="#">FAQ<span></span></a>
</li>
{# <li class="icon_mm6">#}
{# <a href="#">FAQ<span></span></a>#}
{# </li>#}
<li class="icon_mm6">
<a href="{% url 'auth_logout' %}">Выйти<span></span></a>

@ -4,8 +4,10 @@ source ../env/bin/activate &&
pip install -r requirements/base.txt &&
git reset --hard &&
git pull &&
chmod +x update.sh &&
./manage.py migrate --noinput &&
./manage.py collectstatic --noinput &&
supervisorctl restart arch &&
./manage.py recalculation_spec
supervisorctl restart arch_chat &&
./manage.py recalculation_spec &&
chown -R www-data:www-data ./ && chmod -R 775 ./ &&
chmod +x update.sh

@ -176,7 +176,7 @@
<img src="img/profile.jpg" alt="execitor-image">
</div></a>
<p class="nameExecutor">
<a href="#">{{ team.name }}</a>
<a href="">{{ team.name }}</a> {# TODO #}
</p>
<p class="navv2">На сайте 8 лет и 3 месяца</p>
<div class="statusUser">Свободен</div>

@ -164,7 +164,7 @@
</div>
</div>
<div class="insetCol2 box-sizing disTab">
<p>{{ p.name }}</p>
<a href="{% url 'projects:contractor-portfolio-detail' p.pk %}">{{ p }}</a>
<div class="buttonsImg" disTab>
<a href="{% url 'projects:contractor-portfolio-edit' p.pk %}">
<div class="insetBI insetBI1">
@ -209,8 +209,7 @@
</div>
</div>
<div class="insetCol2 box-sizing disTab">
<p>{{ ws }}</p>
<a href="{% url 'work_sell:detail' ws.pk %}">{{ ws }}</a>
</div>
</div>
{% empty %}

@ -176,8 +176,7 @@
{% endthumbnail %}
</div>
<div class="insetCol2 box-sizing disTab">
<p>{{ p.name }}</p>
<a href="{% url 'projects:contractor-portfolio-detail' p.pk %}">{{ p }}</a>
{% if request.user.pk == contractor.pk %}
<div class="buttonsImg" disTab>
<a href="{% url 'projects:contractor-portfolio-edit' p.pk %}">
@ -252,8 +251,7 @@
</div>
</div>
<div class="insetCol2 box-sizing disTab">
<p>{{ ws }}</p>
<a href="{% url 'work_sell:detail' ws.pk %}">{{ ws }}</a>
{% if request.user.pk == contractor.pk %}
<div class="buttonsImg" disTab>
<div class="insetBI insetBI1">

@ -48,20 +48,21 @@
<div class="desReadyBlock">
{% if object.text %}
<div class="col-lg-10 col-lg-offset-1">
<p class="titleReady">Описание:</p>
</div>
<div class="col-lg-10 col-lg-offset-1">
<p class="textReady">
{{ object.text }}
</p>
</p>
</div>
{% endif %}
<div class="col-lg-12 sliderReady">
<div class="arroww prev3"></div>
<div class="arroww next3"></div>
<div class="swiper-container gallery-top">
<div class="swiper-wrapper">
шь
<div class="swiper-slide" style="background-image:url('{% static object.get_cover.url %}')"></div>
{% for photo in object.photos.all %}
<div class="swiper-slide" style="background-image:url('{% static photo.img.url %}')"></div>
@ -77,11 +78,11 @@
</div>
</div>
</div>
<div class="col-lg-12">
<div class="triangle2"></div>
<div class="arr arr1"></div>
<div class="arr arr2"></div>
</div>
{# <div class="col-lg-12">#}
{# <div class="triangle2"></div>#}
{# <div class="arr arr1"></div>#}
{# <div class="arr arr2"></div>#}
{# </div>#}
</div>
<div class="col-lg-12 sibl">
<p>Похожие работы</p>

@ -140,7 +140,7 @@
{% for work in work_sells %}
<div class="col-lg-3">
<div class="insetCol box-sizing disTab">
<a href="{% url 'work_sell:detail' work.pk %}">
<a href="{% url 'work_sell:detail' work.pk %}">
{% thumbnail work.get_cover "265x265" crop="center" as im %}
<div class="imgGal" style="background: url('{{ im.url }}') no-repeat center;">
<div class="imgFigure"></div>
@ -154,8 +154,7 @@
</div>
</div>
<div class="insetCol2 box-sizing disTab">
<p>{{ work }}</p>
<a href="{% url 'work_sell:detail' work.pk %}">{{ work }}</a>
{% if request.user.pk == work.contractor.pk %}
<div class="buttonsImg" disTab>
<a href="{% url 'work_sell:edit' work.pk %}">

Loading…
Cancel
Save