added messages support, more clean html/bootstrap
This commit is contained in:
parent
318feb7e97
commit
e1f6537165
11 changed files with 385 additions and 117 deletions
|
@ -13,19 +13,43 @@
|
||||||
<title>{% block title %}{% endblock %}</title>
|
<title>{% block title %}{% endblock %}</title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<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">
|
<div class="container">
|
||||||
{% for message in messages %}
|
{% for message in messages %}
|
||||||
|
@ -34,23 +58,43 @@
|
||||||
{{ message }}
|
{{ message }}
|
||||||
</div>
|
</div>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
{% block body_content %}{% endblock %}
|
|
||||||
|
{% block body_content %}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
<footer class="pt-4 my-md-5 pt-md-5 border-top">
|
<footer class="pt-4 my-md-5 pt-md-5 border-top">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-12 text-center">
|
<div class="col-12 text-center">
|
||||||
<small class="text-muted">© {% now 'Y' %}
|
<small class="text-muted">© {% now 'Y' %}</small>
|
||||||
This service is provided to you
|
</div>
|
||||||
by <a href="https://ungleich.ch/"
|
</div>
|
||||||
target="_blank">ungleich</a>.
|
<div class="row">
|
||||||
IPv6.work is
|
<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">
|
<a href="https://code.ungleich.ch/ungleich-public/ipv6-dot-work" target="_blank">
|
||||||
Open Source</a>.</small>
|
Open Source</a>.</small>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</footer>
|
</footer>
|
||||||
|
<style>
|
||||||
|
.my-custom-scrollbar {
|
||||||
|
|
||||||
|
position: relative;
|
||||||
|
height: 400px;
|
||||||
|
overflow: auto;
|
||||||
|
word-break: break-all;
|
||||||
|
}
|
||||||
|
.table-wrapper-scroll-y {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<!-- jQuery first, then Popper.js, then Bootstrap JS -->
|
<!-- 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://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>
|
<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,10 +1,36 @@
|
||||||
<!DOCTYPE html>
|
{% extends 'base.html' %}
|
||||||
<html lang="en">
|
{% block body_content %}
|
||||||
<head>
|
{% load crispy_forms_tags %}
|
||||||
<meta charset="UTF-8">
|
<div class="row">
|
||||||
<title>Title</title>
|
<div class="col-md-12">
|
||||||
</head>
|
<div class="pricing-header px-3 py-3 pt-md-5 pb-md-4 mx-auto text-center">
|
||||||
<body>
|
<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>
|
||||||
|
|
||||||
</body>
|
{% endblock %}
|
||||||
</html>
|
|
||||||
|
|
|
@ -11,12 +11,12 @@
|
||||||
<section class="bg-light-gray">
|
<section class="bg-light-gray">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
{% for job in jobs %}
|
{% 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">
|
<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> </p>
|
||||||
<p class="text-muted"></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>
|
<p class="text-right"><a href="{% url 'jobs:job_apply' job.pk %}">Apply</a></p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,10 +1,42 @@
|
||||||
<!DOCTYPE html>
|
{% extends 'base.html' %}
|
||||||
<html lang="en">
|
{% block body_content %}
|
||||||
<head>
|
<div class="row">
|
||||||
<meta charset="UTF-8">
|
<div class="col-md-12">
|
||||||
<title>Title</title>
|
<div class="pricing-header px-3 py-3 pt-md-5 pb-md-4 mx-auto text-center">
|
||||||
</head>
|
<h1 class="display-4">{{ title }}</h1>
|
||||||
<body>
|
<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 %}
|
||||||
|
|
||||||
</body>
|
|
||||||
</html>
|
|
|
@ -8,12 +8,12 @@
|
||||||
<div class="col-md-12">
|
<div class="col-md-12">
|
||||||
<form method="POST" action=".">
|
<form method="POST" action=".">
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
{{ form |crispy }}
|
{{ form|crispy }}
|
||||||
<h4>Screening Questions</h4>
|
<h4>Screening Questions</h4>
|
||||||
{{ question_form |crispy }}
|
{{ question_form|crispy }}
|
||||||
|
|
||||||
<a id="add_more" href="">Add More</a><br/>
|
<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>
|
||||||
{{form.media}}
|
{{form.media}}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -7,37 +7,24 @@
|
||||||
<p class="lead"></p>
|
<p class="lead"></p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<table class="table table-hover">
|
</div>
|
||||||
|
<div class="table-wrapper-scroll-y my-custom-scrollbar">
|
||||||
|
<table class="table table-hover table-bordered">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th scope="col">#</th>
|
<th scope="col">User</th>
|
||||||
<th scope="col">First</th>
|
<th scope="col">Last Message</th>
|
||||||
<th scope="col">Last</th>
|
|
||||||
<th scope="col">Handle</th>
|
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr>
|
{% for message in jobmessage %}
|
||||||
<th scope="row">1</th>
|
<tr onclick="window.location.href = '{{ message.sender_id }}';">
|
||||||
<td>Mark</td>
|
<td>{{ message.sender }}</td>
|
||||||
<td>Otto</td>
|
<td>{{ message.text|truncatechars:40 }}</td>
|
||||||
<td>@mdo</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">2</th>
|
|
||||||
<td>Jacob</td>
|
|
||||||
<td>Thornton</td>
|
|
||||||
<td>@fat</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">3</th>
|
|
||||||
<td colspan="2">Larry the Bird</td>
|
|
||||||
<td>@twitter</td>
|
|
||||||
</tr>
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% for jobmessage in jobmessages %}
|
{% endblock %}
|
||||||
{% endfor %}
|
|
||||||
|
|
|
@ -1,10 +1,57 @@
|
||||||
<!DOCTYPE html>
|
{% extends 'base.html' %}
|
||||||
<html lang="en">
|
{% load crispy_forms_tags %}
|
||||||
<head>
|
{% block body_content %}
|
||||||
<meta charset="UTF-8">
|
<div class="row">
|
||||||
<title>$Title$</title>
|
<div class="col-md-12">
|
||||||
</head>
|
<div class="pricing-header px-3 py-3 pt-md-5 pb-md-4 mx-auto text-center">
|
||||||
<body>
|
<h1 class="h2 text-center">{{ title }}</h1>
|
||||||
$END$
|
<p class="lead"></p>
|
||||||
</body>
|
</div>
|
||||||
</html>
|
{% 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 %}
|
||||||
|
|
|
@ -1,10 +1,31 @@
|
||||||
<!DOCTYPE html>
|
{% extends 'base.html' %}
|
||||||
<html lang="en">
|
{% block body_content %}
|
||||||
<head>
|
<div class="row">
|
||||||
<meta charset="UTF-8">
|
<div class="col-md-12">
|
||||||
<title>Title</title>
|
<div class="pricing-header px-3 py-3 pt-md-5 pb-md-4 mx-auto text-center">
|
||||||
</head>
|
<h1 class="h2 text-center">{{ title }}</h1>
|
||||||
<body>
|
<p class="lead"></p>
|
||||||
|
</div>
|
||||||
</body>
|
{% for application in applications %}
|
||||||
</html>
|
<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 = [
|
urlpatterns = [
|
||||||
path('', views.Index.as_view(), name='index'),
|
path('', views.Index.as_view(), name='index'),
|
||||||
path('jobs/create/', views.JobCreate.as_view(), name='job_create'),
|
path('jobs/create/', views.JobCreate.as_view(), name='job_create'),
|
||||||
path('jobs/', views.JobList.as_view(), name='job_list'),
|
path('jobs/me/', views.MyJobs.as_view(), name='my_jobs'),
|
||||||
path(
|
path('jobs/<int:pk>/detail/', views.JobDetail.as_view(), name='job_detail'),
|
||||||
'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/<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>/applications/', views.ApplicationList.as_view(), name='job_applications'),
|
||||||
path(
|
path('jobs/applications/me/', views.ListOwnApplications.as_view(), name='my_applications'),
|
||||||
'jobs/<int:job_pk>/apply/',
|
path('jobs/applications/', views.ListJobApplications.as_view(), name='applications_others'),
|
||||||
views.ApplicationCreate.as_view(),
|
path('jobs/messages/', views.MesssageInbox.as_view(), name='messages_inbox'),
|
||||||
name='job_apply'),
|
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
|
# autocomplete endpoints
|
||||||
urlpatterns += [
|
urlpatterns += [
|
||||||
path(
|
path('tag-autocomplete/', autocomplete_views.TagAutocomplete.as_view(create_field='name'), name='tag-autocomplete',),
|
||||||
'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.urls import reverse_lazy
|
||||||
from django.http import HttpResponseRedirect
|
from django.http import HttpResponseRedirect
|
||||||
from django.contrib.auth.mixins import LoginRequiredMixin
|
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||||
from django.views.generic import (View, TemplateView, ListView, CreateView,
|
from django.views.generic import (View, TemplateView, ListView, CreateView, DetailView)
|
||||||
DetailView)
|
|
||||||
from django.views.generic.detail import SingleObjectMixin
|
from django.views.generic.detail import SingleObjectMixin
|
||||||
from django.contrib import messages
|
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 rules.contrib.views import PermissionRequiredMixin
|
||||||
|
from django.contrib.auth import get_user_model
|
||||||
|
|
||||||
from .models import Job, Application, Question
|
from .models import Job, Application, Question, JobMessage
|
||||||
from .forms import JobForm, QuestionFormSet, ApplicationForm, AnswerForm
|
from .forms import JobForm, QuestionFormSet, ApplicationForm, AnswerForm, MessageForm
|
||||||
|
|
||||||
|
|
||||||
|
User = get_user_model()
|
||||||
|
|
||||||
class Index(TemplateView):
|
class Index(TemplateView):
|
||||||
template_name = 'jobs/index.html'
|
template_name = 'jobs/index.html'
|
||||||
|
|
||||||
def get_context_data(self, *args, **kwargs):
|
def get_context_data(self, *args, **kwargs):
|
||||||
context = super().get_context_data(*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
|
return context
|
||||||
|
|
||||||
|
|
||||||
class JobList(ListView):
|
|
||||||
context_object_name = 'jobs'
|
|
||||||
model = Job
|
|
||||||
|
|
||||||
|
|
||||||
class JobDetail(DetailView):
|
class JobDetail(DetailView):
|
||||||
context_object_name = 'job'
|
context_object_name = 'job'
|
||||||
model = Job
|
model = Job
|
||||||
|
@ -88,7 +85,7 @@ class ApplicationCreate(LoginRequiredMixin, CreateView):
|
||||||
# TODO: restrict users from re-application
|
# TODO: restrict users from re-application
|
||||||
model = Application
|
model = Application
|
||||||
form_class = ApplicationForm
|
form_class = ApplicationForm
|
||||||
success_url = reverse_lazy("jobs:job_list")
|
success_url = reverse_lazy("jobs:index")
|
||||||
|
|
||||||
def get_question_queryset(self):
|
def get_question_queryset(self):
|
||||||
# filter questions for particular job and order it so same queryset
|
# 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'])
|
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):
|
class ApplicationDetail(LoginRequiredMixin, DetailView):
|
||||||
model = Application
|
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,10 +1,18 @@
|
||||||
{% extends 'base.html' %}
|
{% extends 'base.html' %}
|
||||||
|
{% load crispy_forms_tags %}
|
||||||
{% block title %}Login{% endblock %}
|
{% block title %}Login{% endblock %}
|
||||||
{% block body_content %}
|
{% block body_content %}
|
||||||
<h2>Login</h2>
|
|
||||||
<form method="post">
|
<div class="row justify-content-md-center">
|
||||||
{% csrf_token %} {{ form.as_p }}
|
<div class="col-lg-6">
|
||||||
<button type="submit">Login</button>
|
<h1 class="my-3 text-center">Login</h1>
|
||||||
</form>
|
<form method="post">
|
||||||
Don't have an account? Sign up <a href="{% url 'signup' %}">here</a>.
|
{% 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 %}
|
{% endblock %}
|
Loading…
Reference in a new issue