From 9529067c8ba08c4cc3e01c7005a54a68b0535349 Mon Sep 17 00:00:00 2001 From: William Colmenares Date: Mon, 18 Mar 2019 23:24:37 -0400 Subject: [PATCH 1/6] added messages support, more clean html --- jobs/admin.py | 4 +- jobs/forms.py | 8 +++- jobs/models.py | 12 ++++++ jobs/templates/jobs/application_list.html | 31 ------------- jobs/templates/jobs/conversation.html | 10 +++++ jobs/templates/jobs/job.html | 10 +++++ jobs/templates/jobs/jobmessage_list.html | 43 +++++++++++++++++++ .../jobs/list_applications_others.html | 10 +++++ .../templates/jobs/list_own_applications.html | 10 +++++ 9 files changed, 104 insertions(+), 34 deletions(-) create mode 100644 jobs/templates/jobs/conversation.html create mode 100644 jobs/templates/jobs/job.html create mode 100644 jobs/templates/jobs/jobmessage_list.html create mode 100644 jobs/templates/jobs/list_applications_others.html create mode 100644 jobs/templates/jobs/list_own_applications.html diff --git a/jobs/admin.py b/jobs/admin.py index 862418b..e84b391 100644 --- a/jobs/admin.py +++ b/jobs/admin.py @@ -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]) diff --git a/jobs/forms.py b/jobs/forms.py index 66bb207..c94d06e 100644 --- a/jobs/forms.py +++ b/jobs/forms.py @@ -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: diff --git a/jobs/models.py b/jobs/models.py index 7c16664..2e2efeb 100644 --- a/jobs/models.py +++ b/jobs/models.py @@ -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]) diff --git a/jobs/templates/jobs/application_list.html b/jobs/templates/jobs/application_list.html index 0a8c89c..e69de29 100644 --- a/jobs/templates/jobs/application_list.html +++ b/jobs/templates/jobs/application_list.html @@ -1,31 +0,0 @@ -{% extends 'base.html' %} -{% block body_content %} -
-
-
-

Applications

-

-
- {% for application in applications %} -
-
-

- Submitted by: {{ application.applicant }} -

-

- Submitted: {{ application.created }} -

-

- {{ application.cover_text }} -

-
    - {% for answer in application.answers.all %} -
  1. {{answer.question}}

    {{answer.text}}

  2. - {% endfor %} -
-
-
- {% endfor %} -
-
-{% endblock %} \ No newline at end of file diff --git a/jobs/templates/jobs/conversation.html b/jobs/templates/jobs/conversation.html new file mode 100644 index 0000000..566549b --- /dev/null +++ b/jobs/templates/jobs/conversation.html @@ -0,0 +1,10 @@ + + + + + Title + + + + + \ No newline at end of file diff --git a/jobs/templates/jobs/job.html b/jobs/templates/jobs/job.html new file mode 100644 index 0000000..566549b --- /dev/null +++ b/jobs/templates/jobs/job.html @@ -0,0 +1,10 @@ + + + + + Title + + + + + \ No newline at end of file diff --git a/jobs/templates/jobs/jobmessage_list.html b/jobs/templates/jobs/jobmessage_list.html new file mode 100644 index 0000000..0cbec48 --- /dev/null +++ b/jobs/templates/jobs/jobmessage_list.html @@ -0,0 +1,43 @@ +{% extends 'base.html' %} +{% block body_content %} +
+
+
+

{{ title }}

+

+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
#FirstLastHandle
1MarkOtto@mdo
2JacobThornton@fat
3Larry the Bird@twitter
+
+{% endblock %} + +{% for jobmessage in jobmessages %} +{% endfor %} \ No newline at end of file diff --git a/jobs/templates/jobs/list_applications_others.html b/jobs/templates/jobs/list_applications_others.html new file mode 100644 index 0000000..f7e5884 --- /dev/null +++ b/jobs/templates/jobs/list_applications_others.html @@ -0,0 +1,10 @@ + + + + + $Title$ + + +$END$ + + \ No newline at end of file diff --git a/jobs/templates/jobs/list_own_applications.html b/jobs/templates/jobs/list_own_applications.html new file mode 100644 index 0000000..566549b --- /dev/null +++ b/jobs/templates/jobs/list_own_applications.html @@ -0,0 +1,10 @@ + + + + + Title + + + + + \ No newline at end of file From 318feb7e977b626b543e5db6f9df56d248af49bf Mon Sep 17 00:00:00 2001 From: William Colmenares Date: Mon, 18 Mar 2019 23:25:32 -0400 Subject: [PATCH 2/6] added messages support, more clean html --- jobs/migrations/0004_jobmessage.py | 26 ++++++++++++++++++++++++++ jobs/migrations/0005_job_active.py | 18 ++++++++++++++++++ 2 files changed, 44 insertions(+) create mode 100644 jobs/migrations/0004_jobmessage.py create mode 100644 jobs/migrations/0005_job_active.py diff --git a/jobs/migrations/0004_jobmessage.py b/jobs/migrations/0004_jobmessage.py new file mode 100644 index 0000000..9b8f655 --- /dev/null +++ b/jobs/migrations/0004_jobmessage.py @@ -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)), + ], + ), + ] diff --git a/jobs/migrations/0005_job_active.py b/jobs/migrations/0005_job_active.py new file mode 100644 index 0000000..bb7c165 --- /dev/null +++ b/jobs/migrations/0005_job_active.py @@ -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), + ), + ] From e1f6537165781bffcc52738f47a517741a439223 Mon Sep 17 00:00:00 2001 From: William Colmenares Date: Mon, 18 Mar 2019 23:29:07 -0400 Subject: [PATCH 3/6] added messages support, more clean html/bootstrap --- jobs/templates/base.html | 80 ++++++++--- jobs/templates/jobs/conversation.html | 44 ++++-- jobs/templates/jobs/index.html | 6 +- jobs/templates/jobs/job.html | 50 +++++-- jobs/templates/jobs/job_form.html | 6 +- jobs/templates/jobs/jobmessage_list.html | 35 ++--- .../jobs/list_applications_others.html | 67 +++++++-- .../templates/jobs/list_own_applications.html | 41 ++++-- jobs/urls.py | 22 ++- jobs/views.py | 129 ++++++++++++++++-- templates/registration/login.html | 22 ++- 11 files changed, 385 insertions(+), 117 deletions(-) diff --git a/jobs/templates/base.html b/jobs/templates/base.html index 94d2aa2..7f3a117 100644 --- a/jobs/templates/base.html +++ b/jobs/templates/base.html @@ -13,19 +13,43 @@ {% block title %}{% endblock %} -
+ -
- - Post a job - {% if request.user.is_authenticated %} - Logout - {% endif %} -
{% for message in messages %} @@ -34,23 +58,43 @@ {{ message }}
{% endfor %} - {% block body_content %}{% endblock %} + + {% block body_content %} + + + + {% endblock %}
- © {% now 'Y' %} - This service is provided to you - by ungleich. - IPv6.work is + © {% now 'Y' %} +
+
+
+
+ This service is provided to you + by ungleich. IPv6.work is Open Source.
+ + diff --git a/jobs/templates/jobs/conversation.html b/jobs/templates/jobs/conversation.html index 566549b..e1adeb3 100644 --- a/jobs/templates/jobs/conversation.html +++ b/jobs/templates/jobs/conversation.html @@ -1,10 +1,36 @@ - - - - - Title - - +{% extends 'base.html' %} +{% block body_content %} +{% load crispy_forms_tags %} +
+
+
+

{{ title }}

+

+
+
+
+
+ + + + + + + + {% for message in jobmessage %} + + + + {% endfor %} + +
Conversation with {{ person }}
{{ message.sender }}: {{ message.text }}
+
+ +
+ {% csrf_token %} + + {{ form|crispy }} + +
- - \ No newline at end of file +{% endblock %} diff --git a/jobs/templates/jobs/index.html b/jobs/templates/jobs/index.html index d1dda09..9695386 100644 --- a/jobs/templates/jobs/index.html +++ b/jobs/templates/jobs/index.html @@ -11,12 +11,12 @@
{% for job in jobs %} -
+
-

{{ job.title }}

+

{{ job.title|truncatechars:50 }}

 

-

{{job.description|truncatewords:20}}

+

{{job.description|truncatechars:120}}

Apply

diff --git a/jobs/templates/jobs/job.html b/jobs/templates/jobs/job.html index 566549b..528a404 100644 --- a/jobs/templates/jobs/job.html +++ b/jobs/templates/jobs/job.html @@ -1,10 +1,42 @@ - - - - - Title - - +{% extends 'base.html' %} +{% block body_content %} +
+
+
+

{{ title }}

+

+
+
+
+ +
+ + + + + + + + + + {% for job in jobs %} + + + + + + {% endfor %} + +
Job TitleDateAction
{{ job.title|truncatechars:65 }}{{ job.created.date }} +
{% csrf_token %} + + {% if job.active %} + + {% else %} + + {% endif %} +
+
+
+{% endblock %} - - \ No newline at end of file diff --git a/jobs/templates/jobs/job_form.html b/jobs/templates/jobs/job_form.html index 63aa129..f152232 100644 --- a/jobs/templates/jobs/job_form.html +++ b/jobs/templates/jobs/job_form.html @@ -8,12 +8,12 @@
{% csrf_token %} - {{ form |crispy }} + {{ form|crispy }}

Screening Questions

- {{ question_form |crispy }} + {{ question_form|crispy }} Add More
- +
{{form.media}}
diff --git a/jobs/templates/jobs/jobmessage_list.html b/jobs/templates/jobs/jobmessage_list.html index 0cbec48..cbf384b 100644 --- a/jobs/templates/jobs/jobmessage_list.html +++ b/jobs/templates/jobs/jobmessage_list.html @@ -7,37 +7,24 @@

- + +
+
- - - - + + - - - - - - - - - - - - - - - - + {% for message in jobmessage %} + + + + {% endfor %}
#FirstLastHandleUserLast Message
1MarkOtto@mdo
2JacobThornton@fat
3Larry the Bird@twitter
{{ message.sender }}{{ message.text|truncatechars:40 }}
-{% endblock %} -{% for jobmessage in jobmessages %} -{% endfor %} \ No newline at end of file +{% endblock %} diff --git a/jobs/templates/jobs/list_applications_others.html b/jobs/templates/jobs/list_applications_others.html index f7e5884..e8ef25e 100644 --- a/jobs/templates/jobs/list_applications_others.html +++ b/jobs/templates/jobs/list_applications_others.html @@ -1,10 +1,57 @@ - - - - - $Title$ - - -$END$ - - \ No newline at end of file +{% extends 'base.html' %} +{% load crispy_forms_tags %} +{% block body_content %} +
+
+
+

{{ title }}

+

+
+ {% for application in applications %} +
+
+

+ {{ application.job }} +

+

+ Submitted: {{ application.created }} +

+

+ {{ application.cover_text }} +

+
    + {% for answer in application.answers.all %} +
  1. {{answer.question}}

    {{answer.text}}

  2. + {% endfor %} +
+ + + +
+
+ {% endfor %} +
+
+ +{% endblock %} diff --git a/jobs/templates/jobs/list_own_applications.html b/jobs/templates/jobs/list_own_applications.html index 566549b..3779345 100644 --- a/jobs/templates/jobs/list_own_applications.html +++ b/jobs/templates/jobs/list_own_applications.html @@ -1,10 +1,31 @@ - - - - - Title - - - - - \ No newline at end of file +{% extends 'base.html' %} +{% block body_content %} +
+
+
+

{{ title }}

+

+
+ {% for application in applications %} +
+
+

+ {{ application.job }} +

+

+ Submitted: {{ application.created }} +

+

+ {{ application.cover_text }} +

+
    + {% for answer in application.answers.all %} +
  1. {{answer.question}}

    {{answer.text}}

  2. + {% endfor %} +
+
+
+ {% endfor %} +
+
+{% endblock %} diff --git a/jobs/urls.py b/jobs/urls.py index 526ed99..fd22039 100644 --- a/jobs/urls.py +++ b/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//detail/', views.JobDetail.as_view(), name='job_detail'), + path('jobs/me/', views.MyJobs.as_view(), name='my_jobs'), + path('jobs//detail/', views.JobDetail.as_view(), name='job_detail'), path('jobs//renew/', views.JobRenew.as_view(), name='job_renew'), + path('jobs/messages//', views.Conversation.as_view(), name='conversation'), + path('jobs/toggle/', views.change_status, name='job_toggle'), path('jobs//applications/', views.ApplicationList.as_view(), name='job_applications'), - path( - 'jobs//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//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',), ] \ No newline at end of file diff --git a/jobs/views.py b/jobs/views.py index a61db16..1c58106 100644 --- a/jobs/views.py +++ b/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') diff --git a/templates/registration/login.html b/templates/registration/login.html index d273b60..8cd75a7 100644 --- a/templates/registration/login.html +++ b/templates/registration/login.html @@ -1,10 +1,18 @@ -{% extends 'base.html' %} +{% extends 'base.html' %} +{% load crispy_forms_tags %} {% block title %}Login{% endblock %} {% block body_content %} -

Login

-
- {% csrf_token %} {{ form.as_p }} - -
-Don't have an account? Sign up here. + +
+
+

Login

+
+ {% csrf_token %} {{ form|crispy }} + +
+
+ Don't have an account? Sign up here. +
+
+
{% endblock %} \ No newline at end of file From 1b893ac2f81e82b8e8d34b5714567f6901c78a08 Mon Sep 17 00:00:00 2001 From: William Colmenares Date: Sat, 23 Mar 2019 09:43:55 -0400 Subject: [PATCH 4/6] set active status in navbar --- jobs/templates/base.html | 7 +++---- jobs/views.py | 5 +++++ 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/jobs/templates/base.html b/jobs/templates/base.html index 7f3a117..199f86b 100644 --- a/jobs/templates/base.html +++ b/jobs/templates/base.html @@ -23,19 +23,18 @@