Commit uncommitted but migrated work on prod
This commit is contained in:
parent
2806ccbb44
commit
a96a6eeb49
18 changed files with 472 additions and 90 deletions
|
@ -1,5 +1,5 @@
|
|||
from django.contrib import admin
|
||||
|
||||
from .models import Job, Application, Tag, Question, Answer
|
||||
from .models import Job, Application, Tag, Question, Answer, JobMessage
|
||||
|
||||
admin.site.register([Job, Application, Tag, Question, Answer])
|
||||
admin.site.register([Job, Application, Tag, Question, Answer, JobMessage])
|
||||
|
|
|
@ -2,7 +2,7 @@ from django import forms
|
|||
from django.forms import inlineformset_factory
|
||||
from dal.autocomplete import ModelSelect2Multiple
|
||||
|
||||
from .models import Job, Question, Application, Answer
|
||||
from .models import Job, Question, Application, Answer, JobMessage
|
||||
|
||||
|
||||
class JobForm(forms.ModelForm):
|
||||
|
@ -13,6 +13,12 @@ class JobForm(forms.ModelForm):
|
|||
'tags': ModelSelect2Multiple(url='jobs:tag-autocomplete')
|
||||
}
|
||||
|
||||
class MessageForm(forms.ModelForm):
|
||||
text = forms.CharField(label='', widget=forms.TextInput(attrs={"placeholder": "Write your message"}))
|
||||
class Meta:
|
||||
model = JobMessage
|
||||
fields = ('text',)
|
||||
|
||||
|
||||
class QuestionForm(forms.ModelForm):
|
||||
class Meta:
|
||||
|
|
26
jobs/migrations/0004_jobmessage.py
Normal file
26
jobs/migrations/0004_jobmessage.py
Normal file
|
@ -0,0 +1,26 @@
|
|||
# Generated by Django 2.1.2 on 2019-03-16 03:23
|
||||
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
('jobs', '0003_auto_20181020_0622'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='JobMessage',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('text', models.TextField()),
|
||||
('date', models.DateTimeField(auto_now_add=True)),
|
||||
('receiver', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='receiver', to=settings.AUTH_USER_MODEL)),
|
||||
('sender', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='sender', to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
),
|
||||
]
|
18
jobs/migrations/0005_job_active.py
Normal file
18
jobs/migrations/0005_job_active.py
Normal file
|
@ -0,0 +1,18 @@
|
|||
# Generated by Django 2.1.2 on 2019-03-17 02:12
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('jobs', '0004_jobmessage'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='job',
|
||||
name='active',
|
||||
field=models.BooleanField(default=True),
|
||||
),
|
||||
]
|
|
@ -42,6 +42,8 @@ class Job(models.Model):
|
|||
posted_by = models.ForeignKey(
|
||||
User, related_name="jobs", on_delete=models.CASCADE)
|
||||
|
||||
active = models.BooleanField(default=True)
|
||||
|
||||
def renew(self):
|
||||
self.expires = after_30_days()
|
||||
self.save()
|
||||
|
@ -96,3 +98,13 @@ class Answer(models.Model):
|
|||
|
||||
def __str__(self):
|
||||
return "Answer for : {0} - {1}".format(self.question, self.application)
|
||||
|
||||
class JobMessage(models.Model):
|
||||
"""Basic user to user messaging app"""
|
||||
sender = models.ForeignKey(User, on_delete=models.CASCADE, related_name="sender")
|
||||
receiver = models.ForeignKey(User, on_delete=models.CASCADE, related_name="receiver")
|
||||
text = models.TextField()
|
||||
date = models.DateTimeField(auto_now_add=True)
|
||||
|
||||
def __str__(self):
|
||||
return '{}, {}'.format(self.sender, self.text[:50])
|
||||
|
|
|
@ -13,19 +13,43 @@
|
|||
<title>{% block title %}{% endblock %}</title>
|
||||
</head>
|
||||
<body>
|
||||
<div class="d-flex flex-column flex-md-row align-items-center p-3 px-md-4 mb-3 bg-white border-bottom shadow-sm">
|
||||
<nav class="navbar navbar-expand-lg navbar-light bg-light">
|
||||
<div class="container">
|
||||
<a class="navbar-brand" href="{% url 'jobs:index' %}"><img src="{% static 'img/logo.svg' %}" alt=""></a>
|
||||
{% if request.user.is_authenticated %}
|
||||
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
|
||||
<div class="collapse navbar-collapse justify-content-end" id="navbarSupportedContent">
|
||||
<ul class="navbar-nav ml-auto">
|
||||
<li class="nav-item dropdown">
|
||||
<a class="nav-link dropdown-toggle" href="#" role="button" id="dropdownMenuLink" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">Applications</a>
|
||||
<ul class="dropdown-menu" aria-labelledby="dropdownMenuLink">
|
||||
<a class="dropdown-item" href="{% url 'jobs:my_applications' %}">Your applications</a>
|
||||
<a class="dropdown-item" href="{% url 'jobs:applications_others' %}">Applications to your jobs</a>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="{% url 'jobs:messages_inbox' %}">Messages</a>
|
||||
</li>
|
||||
<li class="nav-item justify-content-end">
|
||||
<a class="nav-link" href="{% url 'jobs:my_jobs' %}">Your Jobs</a>
|
||||
{# {% url 'jobs:job_list' %}#}
|
||||
</li>
|
||||
<a class="btn btn-outline-primary mx-1" href="{% url 'jobs:job_create' %}">Post a job</a>
|
||||
<div class="dropdown-divider"></div>
|
||||
<a class="btn btn-danger mx-1" href="{% url 'logout' %}">Logout</a>
|
||||
</ul>
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="ml-auto">
|
||||
<a href="{% url 'jobs:job_create' %}" class="btn btn-outline-primary ml-auto" role="button" aria-pressed="true">Post a job</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<h5 class="my-0 mr-md-auto font-weight-normal"><a href="{% url 'jobs:index' %}"><img src="{% static 'img/logo.svg' %}"/></a></h5>
|
||||
<nav class="my-2 my-md-0 mr-md-3">
|
||||
{# <a class="p-2 text-dark" href="#">Search</a>#}
|
||||
{# <a class="p-2 text-dark" href="#">Tags</a>#}
|
||||
<a class="p-2 text-dark" href="{% url 'jobs:job_list' %}">Jobs</a>
|
||||
</nav>
|
||||
<a class="btn btn-outline-primary" href="{% url 'jobs:job_create' %}">Post a job</a>
|
||||
{% if request.user.is_authenticated %}
|
||||
<a class="btn text-dark" href="{% url 'logout' %}">Logout</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<div class="container">
|
||||
{% for message in messages %}
|
||||
|
@ -34,23 +58,43 @@
|
|||
{{ message }}
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% block body_content %}{% endblock %}
|
||||
|
||||
{% block body_content %}
|
||||
|
||||
|
||||
|
||||
{% endblock %}
|
||||
|
||||
<footer class="pt-4 my-md-5 pt-md-5 border-top">
|
||||
<div class="row">
|
||||
<div class="col-12 text-center">
|
||||
<small class="text-muted">© {% now 'Y' %}
|
||||
This service is provided to you
|
||||
by <a href="https://ungleich.ch/"
|
||||
target="_blank">ungleich</a>.
|
||||
IPv6.work is
|
||||
<small class="text-muted">© {% now 'Y' %}</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-12 text-center">
|
||||
<small>This service is provided to you
|
||||
by <a href="https://ungleich.ch/" target="_blank">ungleich</a>. IPv6.work is
|
||||
<a href="https://code.ungleich.ch/ungleich-public/ipv6-dot-work" target="_blank">
|
||||
Open Source</a>.</small>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
<style>
|
||||
.my-custom-scrollbar {
|
||||
|
||||
position: relative;
|
||||
height: 400px;
|
||||
overflow: auto;
|
||||
word-break: break-all;
|
||||
}
|
||||
.table-wrapper-scroll-y {
|
||||
display: block;
|
||||
}
|
||||
</style>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- jQuery first, then Popper.js, then Bootstrap JS -->
|
||||
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.3/umd/popper.min.js" integrity="sha384-ZMP7rVo3mIykV+2+9J3UJ46jBk0WLaUAdn689aCwoqbBJiSnjAK/l8WvCWPIPm49" crossorigin="anonymous"></script>
|
||||
|
|
|
@ -1,31 +0,0 @@
|
|||
{% extends 'base.html' %}
|
||||
{% block body_content %}
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<div class="pricing-header px-3 py-3 pt-md-5 pb-md-4 mx-auto text-center">
|
||||
<h1 class="display-4">Applications</h1>
|
||||
<p class="lead"></p>
|
||||
</div>
|
||||
{% for application in applications %}
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<h4 class="card-title">
|
||||
<a href="{{ application.get_absolute_url }}">Submitted by: {{ application.applicant }}</a>
|
||||
</h4>
|
||||
<p class="card-text">
|
||||
Submitted: {{ application.created }}
|
||||
</p>
|
||||
<p class="card-text">
|
||||
{{ application.cover_text }}
|
||||
</p>
|
||||
<ol>
|
||||
{% for answer in application.answers.all %}
|
||||
<li>{{answer.question}}<p>{{answer.text}}</p></li>
|
||||
{% endfor %}
|
||||
</ol>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
36
jobs/templates/jobs/conversation.html
Normal file
36
jobs/templates/jobs/conversation.html
Normal file
|
@ -0,0 +1,36 @@
|
|||
{% extends 'base.html' %}
|
||||
{% block body_content %}
|
||||
{% load crispy_forms_tags %}
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<div class="pricing-header px-3 py-3 pt-md-5 pb-md-4 mx-auto text-center">
|
||||
<h1 class="h2 text-center">{{ title }}</h1>
|
||||
<p class="lead"></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="table-wrapper-scroll-y my-custom-scrollbar">
|
||||
<table class="table table-hover table-bordered">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col">Conversation with {{ person }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for message in jobmessage %}
|
||||
<tr>
|
||||
<td>{{ message.sender }}: {{ message.text }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="dropdown-divider"></div>
|
||||
<form action="{% url 'jobs:send_message' %}" method="POST">
|
||||
{% csrf_token %}
|
||||
<input type="hidden" value="{{ person.id }}" name="receiver_id">
|
||||
{{ form|crispy }}
|
||||
<input class="btn btn-primary btn-block" type="submit" value="Send Message">
|
||||
</form>
|
||||
|
||||
{% endblock %}
|
|
@ -11,12 +11,12 @@
|
|||
<section class="bg-light-gray">
|
||||
<div class="row">
|
||||
{% for job in jobs %}
|
||||
<div class="col-md-4 col-sm-6 portfolio-item wow fadeInUp" data-wow-delay="0.25s" style="visibility: visible; animation-delay: 0.25s; animation-name: fadeInUp;">
|
||||
<div class="col-md-4 col-sm-6 portfolio-item wow fadeInUp d-flex" data-wow-delay="0.25s" style="visibility: visible; animation-delay: 0.25s; animation-name: fadeInUp;">
|
||||
<div class="portfolio-caption inline-block">
|
||||
<h4><a href="{{ job.get_absolute_url }}" style="color:black;">{{ job.title }}</a></h4>
|
||||
<h4><a href="{{ job.get_absolute_url }}" style="color:black;">{{ job.title|truncatechars:50 }}</a></h4>
|
||||
<p> </p>
|
||||
<p class="text-muted"></p>
|
||||
<p>{{job.description|truncatewords:20}}</p>
|
||||
<p>{{job.description|truncatechars:120}}</p>
|
||||
<p class="text-right"><a href="{% url 'jobs:job_apply' job.pk %}">Apply</a></p>
|
||||
</div>
|
||||
</div>
|
||||
|
|
42
jobs/templates/jobs/job.html
Normal file
42
jobs/templates/jobs/job.html
Normal file
|
@ -0,0 +1,42 @@
|
|||
{% extends 'base.html' %}
|
||||
{% block body_content %}
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<div class="pricing-header px-3 py-3 pt-md-5 pb-md-4 mx-auto text-center">
|
||||
<h1 class="display-4">{{ title }}</h1>
|
||||
<p class="lead"></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="table-responsive">
|
||||
<table class="table table-hover table-bordered">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col">Job Title</th>
|
||||
<th scope="col">Date</th>
|
||||
<th scope="col">Action</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for job in jobs %}
|
||||
<tr>
|
||||
<td style="vertical-align: middle">{{ job.title|truncatechars:65 }}</td>
|
||||
<td style="vertical-align: middle">{{ job.created.date }}</td>
|
||||
<td style="vertical-align: middle">
|
||||
<form action="{% url 'jobs:job_toggle' %}" method="post">{% csrf_token %}
|
||||
<input type="hidden" name="job_id" value="{{ job.id }}">
|
||||
{% if job.active %}
|
||||
<button type="submit" class="btn btn-warning btn-block">Deactivate</button>
|
||||
{% else %}
|
||||
<button type="submit" class="btn btn-success btn-block">Activate</button>
|
||||
{% endif %}
|
||||
</form>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
|
@ -8,12 +8,12 @@
|
|||
<div class="col-md-12">
|
||||
<form method="POST" action=".">
|
||||
{% csrf_token %}
|
||||
{{ form |crispy }}
|
||||
{{ form|crispy }}
|
||||
<h4>Screening Questions</h4>
|
||||
{{ question_form |crispy }}
|
||||
{{ question_form|crispy }}
|
||||
|
||||
<a id="add_more" href="">Add More</a><br/>
|
||||
<input class="btn btn-primary submit" type="submit" value="Post Job"/>
|
||||
<input class="btn btn-primary btn-block my-2" type="submit" value="Post Job"/>
|
||||
</form>
|
||||
{{form.media}}
|
||||
</div>
|
||||
|
|
30
jobs/templates/jobs/jobmessage_list.html
Normal file
30
jobs/templates/jobs/jobmessage_list.html
Normal file
|
@ -0,0 +1,30 @@
|
|||
{% extends 'base.html' %}
|
||||
{% block body_content %}
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<div class="pricing-header px-3 py-3 pt-md-5 pb-md-4 mx-auto text-center">
|
||||
<h1 class="h2 text-center">{{ title }}</h1>
|
||||
<p class="lead"></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="table-wrapper-scroll-y my-custom-scrollbar">
|
||||
<table class="table table-hover table-bordered">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col">User</th>
|
||||
<th scope="col">Last Message</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for message in jobmessage %}
|
||||
<tr onclick="window.location.href = '{{ message.sender_id }}';">
|
||||
<td>{{ message.sender }}</td>
|
||||
<td>{{ message.text|truncatechars:40 }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
57
jobs/templates/jobs/list_applications_others.html
Normal file
57
jobs/templates/jobs/list_applications_others.html
Normal file
|
@ -0,0 +1,57 @@
|
|||
{% extends 'base.html' %}
|
||||
{% load crispy_forms_tags %}
|
||||
{% block body_content %}
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<div class="pricing-header px-3 py-3 pt-md-5 pb-md-4 mx-auto text-center">
|
||||
<h1 class="h2 text-center">{{ title }}</h1>
|
||||
<p class="lead"></p>
|
||||
</div>
|
||||
{% for application in applications %}
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<h4 class="card-title">
|
||||
<a href="{{ application.job.get_absolute_url }}">{{ application.job }}</a>
|
||||
</h4>
|
||||
<p class="card-text">
|
||||
Submitted: {{ application.created }}
|
||||
</p>
|
||||
<p class="card-text">
|
||||
{{ application.cover_text }}
|
||||
</p>
|
||||
<ol>
|
||||
{% for answer in application.answers.all %}
|
||||
<li>{{answer.question}}<p>{{answer.text}}</p></li>
|
||||
{% endfor %}
|
||||
</ol>
|
||||
<button class="btn btn-outline-primary btn-block" data-toggle="modal" data-target="#messageModal">Contact Applicant</button>
|
||||
<div class="modal fade" id="messageModal" tabindex="-1" role="dialog" aria-labelledby="messageModalLabel" aria-hidden="true" style="vertical-align: center">
|
||||
<div class="modal-dialog modal-lg" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="exampleModalLabel">Contact Applicant {{ application.applicant }}</h5>
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<form action="{% url 'jobs:send_message' %}" method="POST">{% csrf_token %}
|
||||
<div class="modal-body">
|
||||
<input type="hidden" value="{{ application.applicant_id }}" name="receiver_id">
|
||||
{{ form|crispy }}
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
|
||||
<input class="btn btn-primary" type="submit" value="Send Message">
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
31
jobs/templates/jobs/list_own_applications.html
Normal file
31
jobs/templates/jobs/list_own_applications.html
Normal file
|
@ -0,0 +1,31 @@
|
|||
{% extends 'base.html' %}
|
||||
{% block body_content %}
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<div class="pricing-header px-3 py-3 pt-md-5 pb-md-4 mx-auto text-center">
|
||||
<h1 class="h2 text-center">{{ title }}</h1>
|
||||
<p class="lead"></p>
|
||||
</div>
|
||||
{% for application in applications %}
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<h4 class="card-title">
|
||||
<a href="{{ application.job.get_absolute_url }}">{{ application.job }}</a>
|
||||
</h4>
|
||||
<p class="card-text">
|
||||
Submitted: {{ application.created }}
|
||||
</p>
|
||||
<p class="card-text">
|
||||
{{ application.cover_text }}
|
||||
</p>
|
||||
<ol>
|
||||
{% for answer in application.answers.all %}
|
||||
<li>{{answer.question}}<p>{{answer.text}}</p></li>
|
||||
{% endfor %}
|
||||
</ol>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
22
jobs/urls.py
22
jobs/urls.py
|
@ -7,22 +7,20 @@ app_name = 'jobs'
|
|||
urlpatterns = [
|
||||
path('', views.Index.as_view(), name='index'),
|
||||
path('jobs/create/', views.JobCreate.as_view(), name='job_create'),
|
||||
path('jobs/', views.JobList.as_view(), name='job_list'),
|
||||
path(
|
||||
'jobs/<int:pk>/detail/', views.JobDetail.as_view(), name='job_detail'),
|
||||
path('jobs/me/', views.MyJobs.as_view(), name='my_jobs'),
|
||||
path('jobs/<int:pk>/detail/', views.JobDetail.as_view(), name='job_detail'),
|
||||
path('jobs/<int:pk>/renew/', views.JobRenew.as_view(), name='job_renew'),
|
||||
path('jobs/messages/<int:pk>/', views.Conversation.as_view(), name='conversation'),
|
||||
path('jobs/toggle/', views.change_status, name='job_toggle'),
|
||||
path('jobs/<int:job_pk>/applications/', views.ApplicationList.as_view(), name='job_applications'),
|
||||
path(
|
||||
'jobs/<int:job_pk>/apply/',
|
||||
views.ApplicationCreate.as_view(),
|
||||
name='job_apply'),
|
||||
path('jobs/applications/me/', views.ListOwnApplications.as_view(), name='my_applications'),
|
||||
path('jobs/applications/', views.ListJobApplications.as_view(), name='applications_others'),
|
||||
path('jobs/messages/', views.MesssageInbox.as_view(), name='messages_inbox'),
|
||||
path('jobs/messages/send/', views.send_message, name='send_message'),
|
||||
path('jobs/<int:job_pk>/apply/', views.ApplicationCreate.as_view(), name='job_apply'),
|
||||
]
|
||||
|
||||
# autocomplete endpoints
|
||||
urlpatterns += [
|
||||
path(
|
||||
'tag-autocomplete/',
|
||||
autocomplete_views.TagAutocomplete.as_view(create_field='name'),
|
||||
name='tag-autocomplete',
|
||||
),
|
||||
path('tag-autocomplete/', autocomplete_views.TagAutocomplete.as_view(create_field='name'), name='tag-autocomplete',),
|
||||
]
|
129
jobs/views.py
129
jobs/views.py
|
@ -1,31 +1,28 @@
|
|||
from django.urls import reverse_lazy
|
||||
from django.http import HttpResponseRedirect
|
||||
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||
from django.views.generic import (View, TemplateView, ListView, CreateView,
|
||||
DetailView)
|
||||
from django.views.generic import (View, TemplateView, ListView, CreateView, DetailView)
|
||||
from django.views.generic.detail import SingleObjectMixin
|
||||
from django.contrib import messages
|
||||
from django.shortcuts import get_object_or_404
|
||||
from django.shortcuts import get_object_or_404, redirect
|
||||
from rules.contrib.views import PermissionRequiredMixin
|
||||
from django.contrib.auth import get_user_model
|
||||
|
||||
from .models import Job, Application, Question
|
||||
from .forms import JobForm, QuestionFormSet, ApplicationForm, AnswerForm
|
||||
from .models import Job, Application, Question, JobMessage
|
||||
from .forms import JobForm, QuestionFormSet, ApplicationForm, AnswerForm, MessageForm
|
||||
|
||||
|
||||
User = get_user_model()
|
||||
|
||||
class Index(TemplateView):
|
||||
template_name = 'jobs/index.html'
|
||||
|
||||
def get_context_data(self, *args, **kwargs):
|
||||
context = super().get_context_data(*args, **kwargs)
|
||||
context['jobs'] = Job.objects.all().order_by('-updated')[:6]
|
||||
context['jobs'] = Job.objects.filter(active=True).order_by('-updated')[:6]
|
||||
return context
|
||||
|
||||
|
||||
class JobList(ListView):
|
||||
context_object_name = 'jobs'
|
||||
model = Job
|
||||
|
||||
|
||||
class JobDetail(DetailView):
|
||||
context_object_name = 'job'
|
||||
model = Job
|
||||
|
@ -88,7 +85,7 @@ class ApplicationCreate(LoginRequiredMixin, CreateView):
|
|||
# TODO: restrict users from re-application
|
||||
model = Application
|
||||
form_class = ApplicationForm
|
||||
success_url = reverse_lazy("jobs:job_list")
|
||||
success_url = reverse_lazy("jobs:index")
|
||||
|
||||
def get_question_queryset(self):
|
||||
# filter questions for particular job and order it so same queryset
|
||||
|
@ -153,5 +150,113 @@ class ApplicationList(LoginRequiredMixin, PermissionRequiredMixin, ListView):
|
|||
return super().get_queryset().filter(job_id=self.kwargs['job_pk'])
|
||||
|
||||
|
||||
class ListOwnApplications(ListView):
|
||||
model = Application
|
||||
context_object_name = 'applications'
|
||||
template_name = 'jobs/list_own_applications.html'
|
||||
|
||||
def get_queryset(self):
|
||||
return Application.objects.filter(applicant=self.request.user)
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super(ListOwnApplications, self).get_context_data(**kwargs)
|
||||
context['title'] = 'Your Applications'
|
||||
return context
|
||||
|
||||
|
||||
class ListJobApplications(ListView):
|
||||
model = Application
|
||||
context_object_name = 'applications'
|
||||
template_name = 'jobs/list_applications_others.html'
|
||||
|
||||
def get_queryset(self):
|
||||
return Application.objects.filter(job__posted_by=self.request.user)
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super(ListJobApplications, self).get_context_data(**kwargs)
|
||||
context['title'] = 'Applications to your jobs'
|
||||
context['form'] = MessageForm
|
||||
return context
|
||||
|
||||
|
||||
class ApplicationDetail(LoginRequiredMixin, DetailView):
|
||||
model = Application
|
||||
|
||||
|
||||
class MesssageInbox(LoginRequiredMixin, ListView):
|
||||
model = JobMessage
|
||||
context_object_name = 'jobmessage'
|
||||
|
||||
def get_queryset(self):
|
||||
qs_list = []
|
||||
qs = JobMessage.objects.filter(receiver=self.request.user).order_by('-date')
|
||||
lookup = set(qs.values_list('sender', flat=True))
|
||||
for sender_id in lookup:
|
||||
for elem in qs:
|
||||
if elem.sender_id == sender_id:
|
||||
qs_list.append(elem.id)
|
||||
break
|
||||
return JobMessage.objects.filter(pk__in=qs_list).order_by('-date')
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super(MesssageInbox, self).get_context_data(**kwargs)
|
||||
context['title'] = 'Messages Inbox'
|
||||
return context
|
||||
|
||||
|
||||
class Conversation(LoginRequiredMixin, ListView):
|
||||
model = JobMessage
|
||||
context_object_name = 'jobmessage'
|
||||
template_name = 'jobs/conversation.html'
|
||||
|
||||
def get_queryset(self):
|
||||
queryset1 = JobMessage.objects.filter(
|
||||
receiver=self.request.user, sender=self.kwargs['pk'])
|
||||
queryset2 = JobMessage.objects.filter(
|
||||
receiver=self.kwargs['pk'], sender=self.request.user)
|
||||
return queryset1.union(queryset2).order_by('date')
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super(Conversation, self).get_context_data(**kwargs)
|
||||
context['form'] = MessageForm
|
||||
context['person'] = User.objects.get(id=self.kwargs['pk'])
|
||||
return context
|
||||
|
||||
|
||||
class MyJobs(LoginRequiredMixin, ListView):
|
||||
model = Job
|
||||
context_object_name = 'jobs'
|
||||
template_name = 'jobs/job.html'
|
||||
|
||||
def get_queryset(self):
|
||||
return Job.objects.filter(posted_by=self.request.user).order_by('expires')
|
||||
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super(MyJobs, self).get_context_data(**kwargs)
|
||||
context['title'] = 'Your jobs'
|
||||
return context
|
||||
|
||||
|
||||
def send_message(request):
|
||||
form = MessageForm(request.POST)
|
||||
if form.is_valid():
|
||||
user = User.objects.get(id=request.POST.get('receiver_id'))
|
||||
JobMessage.objects.create(sender=request.user, receiver=user, text=request.POST.get('text'))
|
||||
else:
|
||||
print("Error")
|
||||
return redirect('jobs:conversation', pk=request.POST.get('receiver_id'))
|
||||
|
||||
def change_status(request):
|
||||
print(request.POST)
|
||||
job_id = request.POST.get('job_id')
|
||||
if job_id is not None:
|
||||
job = Job.objects.get(id=job_id)
|
||||
if job.active:
|
||||
job.active = False
|
||||
else:
|
||||
job.active = True
|
||||
job.save()
|
||||
else:
|
||||
print("Error")
|
||||
return redirect('jobs:my_jobs')
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
Django==2.1.2
|
||||
Django==2.2.16
|
||||
django-auth-ldap==1.7.0
|
||||
django-autocomplete-light==3.3.2
|
||||
django-crispy-forms==1.7.2
|
||||
|
|
|
@ -1,10 +1,18 @@
|
|||
{% extends 'base.html' %}
|
||||
{% extends 'base.html' %}
|
||||
{% load crispy_forms_tags %}
|
||||
{% block title %}Login{% endblock %}
|
||||
{% block body_content %}
|
||||
<h2>Login</h2>
|
||||
<form method="post">
|
||||
{% csrf_token %} {{ form.as_p }}
|
||||
<button type="submit">Login</button>
|
||||
</form>
|
||||
Don't have an account? Sign up <a href="{% url 'signup' %}">here</a>.
|
||||
|
||||
<div class="row justify-content-md-center">
|
||||
<div class="col-lg-6">
|
||||
<h1 class="my-3 text-center">Login</h1>
|
||||
<form method="post">
|
||||
{% csrf_token %} {{ form|crispy }}
|
||||
<button class="btn btn-primary btn-block" type="submit">Login</button>
|
||||
</form>
|
||||
<div class="mt-4 mb-2">
|
||||
Don't have an account? Sign up <a href="{% url 'signup' %}">here</a>.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
Loading…
Reference in a new issue