Add Job-ads DB object and serializers

This commit is contained in:
Aarni Halinen
2020-11-03 18:27:46 +02:00
parent b443b39457
commit 1ff188eddd
11 changed files with 318 additions and 5063 deletions
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+3 -2
View File
@@ -1,7 +1,7 @@
"""File containing webapp app admin registers.""" """File containing webapp app admin registers."""
from django.contrib import admin from django.contrib import admin
from webapp.models import Official, Role, Committee, Occupation from webapp.models import JobAd, Official, Role, Committee, Occupation
from webapp.models import Feed, Tag, Event, Signup, SignupForm, TemplateQuestion from webapp.models import Feed, Tag, Event, Signup, SignupForm, TemplateQuestion
from modeltranslation.admin import TranslationAdmin from modeltranslation.admin import TranslationAdmin
from django.contrib.auth.models import Permission from django.contrib.auth.models import Permission
@@ -19,4 +19,5 @@ admin.site.register(TemplateQuestion, TranslationAdmin)
admin.site.register(Committee, TranslationAdmin) admin.site.register(Committee, TranslationAdmin)
admin.site.register(Official) admin.site.register(Official)
admin.site.register(Occupation) admin.site.register(Occupation)
admin.site.register(Role) admin.site.register(Role, TranslationAdmin)
admin.site.register(JobAd, TranslationAdmin)
+38
View File
@@ -0,0 +1,38 @@
# Generated by Django 2.1.5 on 2020-11-03 15:38
from django.db import migrations, models
import django.utils.timezone
import webapp.utils
class Migration(migrations.Migration):
dependencies = [
('webapp', '0071_auto_20201006_1749'),
]
operations = [
migrations.CreateModel(
name='JobAd',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('title', models.CharField(max_length=255)),
('title_fi', models.CharField(max_length=255, null=True)),
('title_en', models.CharField(max_length=255, null=True)),
('description', models.CharField(max_length=255)),
('description_fi', models.CharField(max_length=255, null=True)),
('description_en', models.CharField(max_length=255, null=True)),
('content', models.TextField()),
('content_fi', models.TextField(null=True)),
('content_en', models.TextField(null=True)),
('visible', models.BooleanField(default=True)),
('created_at', models.DateTimeField(default=django.utils.timezone.now)),
('autohide_at', models.DateTimeField(default=webapp.utils.month_from_now)),
('autohide_enabled', models.BooleanField(default=False)),
],
options={
'verbose_name': 'JobAd',
'verbose_name_plural': 'JobAds',
},
),
]
+54 -36
View File
@@ -22,14 +22,14 @@ EMAIL_REGEX = r"(^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$)"
class Tag(models.Model): class Tag(models.Model):
"""Model for tag.""" """Model for tag."""
slug = models.SlugField(unique=True)
name = models.CharField(max_length=127)
icon = models.ImageField()
class Meta: class Meta:
verbose_name = _('Tag') verbose_name = _('Tag')
verbose_name_plural = _('Tags') verbose_name_plural = _('Tags')
slug = models.SlugField(unique=True)
name = models.CharField(max_length=127)
icon = models.ImageField()
def __str__(self): def __str__(self):
return _('Tag: {}').format(self.slug) return _('Tag: {}').format(self.slug)
@@ -48,6 +48,10 @@ class BaseFeed(models.Model):
class Feed(BaseFeed): class Feed(BaseFeed):
"""Model representing feed.""" """Model representing feed."""
class Meta:
verbose_name = _('Feed')
verbose_name_plural = _('Feeds')
publish_time = models.DateTimeField(default=timezone.now) publish_time = models.DateTimeField(default=timezone.now)
autohide = models.DateTimeField(default=month_from_now) autohide = models.DateTimeField(default=month_from_now)
autohide_enabled = models.BooleanField(default=False) autohide_enabled = models.BooleanField(default=False)
@@ -55,13 +59,13 @@ class Feed(BaseFeed):
def __str__(self): def __str__(self):
return _('Feed: {}').format(self.title) return _('Feed: {}').format(self.title)
class Meta:
verbose_name = _('Feed')
verbose_name_plural = _('Feeds')
class Event(BaseFeed): class Event(BaseFeed):
"""Model for event.""" """Model for event in guild calendar"""
class Meta:
verbose_name = _('Event')
verbose_name_plural = _('Events')
start_time = models.DateTimeField(default=timezone.now) start_time = models.DateTimeField(default=timezone.now)
end_time = models.DateTimeField(default=timezone.now) end_time = models.DateTimeField(default=timezone.now)
@@ -72,26 +76,30 @@ class Event(BaseFeed):
def __str__(self): def __str__(self):
return _('Event: {}').format(self.title) return _('Event: {}').format(self.title)
class Meta:
verbose_name = _('Event')
verbose_name_plural = _('Events')
class TemplateQuestion(models.Model): class TemplateQuestion(models.Model):
"""Stores template questions for signup forms as JSONB""" """
NOT IMPLEMENTED!!!
Stores template questions for signup forms as JSON format. Used in signup form creation
"""
class Meta:
verbose_name = _('Template question')
verbose_name_plural = _('Template questions')
name = models.CharField(max_length=255) name = models.CharField(max_length=255)
question = JSONField() question = JSONField()
def __str__(self): def __str__(self):
return _('Template questions: {}').format(self.name) return _('Template questions: {}').format(self.name)
class Meta:
verbose_name = _('Template question')
verbose_name_plural = _('Template questions')
class SignupForm(models.Model): class SignupForm(models.Model):
"""Model for event signup form. Stores questions in JSONB.""" """Model for event signup form. Stores questions in JSON format."""
class Meta:
verbose_name = _('Signup form')
verbose_name_plural = _('Signup forms')
title = models.CharField(max_length=255) title = models.CharField(max_length=255)
start_time = models.DateTimeField(default=timezone.now) start_time = models.DateTimeField(default=timezone.now)
@@ -114,12 +122,15 @@ class SignupForm(models.Model):
now = timezone.now() now = timezone.now()
return self.start_time <= now and now < self.end_time return self.start_time <= now and now < self.end_time
class Meta:
verbose_name = _('Signup form')
verbose_name_plural = _('Signup forms')
class Signup(models.Model): class Signup(models.Model):
"""
In
"""
class Meta:
verbose_name = _('Sign-up')
verbose_name_plural = _('Sign-ups')
signupForm = models.ForeignKey('SignupForm', on_delete=models.CASCADE) signupForm = models.ForeignKey('SignupForm', on_delete=models.CASCADE)
time = models.DateTimeField(default=timezone.now) time = models.DateTimeField(default=timezone.now)
answer = JSONField() answer = JSONField()
@@ -133,10 +144,6 @@ class Signup(models.Model):
def __str__(self): def __str__(self):
return f"{self.signupForm}: {self.list_name} ({self.pk})" return f"{self.signupForm}: {self.list_name} ({self.pk})"
class Meta:
verbose_name = _('Sign-up')
verbose_name_plural = _('Sign-ups')
@receiver(post_save, sender=Signup) @receiver(post_save, sender=Signup)
def email_on_signup(sender, instance, created, **kwargs): def email_on_signup(sender, instance, created, **kwargs):
@@ -166,7 +173,6 @@ class BaseRole(models.Model):
class PresetRole(BaseRole): class PresetRole(BaseRole):
"""Model representing a preset occupation in the guild.""" """Model representing a preset occupation in the guild."""
description = models.TextField(_('Description')) description = models.TextField(_('Description'))
@@ -177,8 +183,6 @@ class Committee(models.Model):
""" """
class Meta: class Meta:
"""Meta class for Committee class."""
verbose_name = _('Committee') verbose_name = _('Committee')
verbose_name_plural = _('Committees') verbose_name_plural = _('Committees')
@@ -194,15 +198,11 @@ class Committee(models.Model):
class Role(PresetRole): class Role(PresetRole):
""" """
Model for Role.
Model representing an active or historical occupation Model representing an active or historical occupation
in the guild. in the guild.
""" """
class Meta: class Meta:
"""Meta class for Role model."""
verbose_name = _('Role') verbose_name = _('Role')
verbose_name_plural = _('Roles') verbose_name_plural = _('Roles')
@@ -241,8 +241,6 @@ class Official(models.Model):
"""Model representing a guild official.""" """Model representing a guild official."""
class Meta: class Meta:
"""Meta class for Official class."""
verbose_name = _('Official') verbose_name = _('Official')
verbose_name_plural = _('Officials') verbose_name_plural = _('Officials')
@@ -272,10 +270,30 @@ def save_user_official(sender, instance, **kwargs):
instance.user.save() instance.user.save()
class JobAd(models.Model):
"""Job advertisements shown on Corporate relations page"""
class Meta:
verbose_name = _('JobAd')
verbose_name_plural = _('JobAds')
title = models.CharField(max_length=255)
description = models.CharField(max_length=255)
content = models.TextField()
visible = models.BooleanField(default=True)
created_at = models.DateTimeField(default=timezone.now)
autohide_at = models.DateTimeField(default=month_from_now)
autohide_enabled = models.BooleanField(default=False)
auditlog.register(Tag) auditlog.register(Tag)
auditlog.register(Feed) auditlog.register(Feed)
auditlog.register(Event) auditlog.register(Event)
auditlog.register(SignupForm)
auditlog.register(Signup) auditlog.register(Signup)
auditlog.register(PresetRole) auditlog.register(PresetRole)
auditlog.register(Role) auditlog.register(Role)
auditlog.register(Committee)
auditlog.register(Occupation)
auditlog.register(Official) auditlog.register(Official)
auditlog.register(JobAd)
+6
View File
@@ -169,3 +169,9 @@ class OccupationSerializer(serializers.ModelSerializer):
class Meta: class Meta:
model = Occupation model = Occupation
fields = ('role', 'start_date', 'end_date', 'officials') fields = ('role', 'start_date', 'end_date', 'officials')
class JobAdSerializer(serializers.ModelSerializer):
class Meta:
model = JobAd
fields = ('title_fi', 'title_en', 'description_fi', 'description_en', 'content_fi', 'content_en', 'visible', 'autohide_at', 'autohide_enabled')
+4 -8
View File
@@ -1,6 +1,6 @@
from django.contrib.auth.models import User from django.contrib.auth.models import User
from rest_framework import status from rest_framework import status
from rest_framework.test import APITestCase, APIRequestFactory from rest_framework.test import APITestCase
from webapp.models import Feed from webapp.models import Feed
from webapp.serializers import FeedSerializer from webapp.serializers import FeedSerializer
@@ -27,11 +27,7 @@ class FeedTestCase(APITestCase):
self.assertTrue(status.is_success(response.status_code)) self.assertTrue(status.is_success(response.status_code))
feeds = Feed.objects.all() feeds = Feed.objects.all()
serializer = FeedSerializer( serializer = FeedSerializer(feeds, many=True)
feeds, many=True,
context={
"request": APIRequestFactory().get(r"http://testserver/api/events/")
})
self.assertEqual(response.data["results"], serializer.data) self.assertEqual(response.data["results"], serializer.data)
def test_post_feed(self): def test_post_feed(self):
@@ -50,13 +46,13 @@ class FeedTestCase(APITestCase):
} }
# Try post without authentication # Try post without authentication
response = self.client.post("/api/feed/", data, format="json") response = self.client.post("/api/feed/", data, format="json")
self.assertTrue(response.status_code, status.HTTP_401_UNAUTHORIZED) self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED)
self.assertEqual(Feed.objects.count(), 1) self.assertEqual(Feed.objects.count(), 1)
# Authenticate # Authenticate
self.client.force_authenticate(user=self.authClient) self.client.force_authenticate(user=self.authClient)
response = self.client.post("/api/feed/", data, format="json") response = self.client.post("/api/feed/", data, format="json")
# Return success and check object was created # Return success and check object was created
self.assertTrue(response.status_code, status.HTTP_201_CREATED) self.assertEqual(response.status_code, status.HTTP_201_CREATED)
self.assertEqual(Feed.objects.count(), 2) self.assertEqual(Feed.objects.count(), 2)
created = Feed.objects.get(title_fi="testtitle") created = Feed.objects.get(title_fi="testtitle")
+54
View File
@@ -0,0 +1,54 @@
from django.contrib.auth.models import User
from rest_framework import status
from rest_framework.test import APITestCase, APIRequestFactory
from webapp.models import JobAd
from webapp.serializers import JobAdSerializer
API = "/api/jobads/"
class JobAdTestCase(APITestCase):
def setUp(self):
self.prefilled_jobad = JobAd.objects.create(
title_fi="ABB Test",
title_en="ABB Test",
visible=True,
description_fi="desc",
description_en="desc",
content_fi="lorem",
content_en="lorem"
)
username, password = "test_admin", "password123"
self.authClient = User.objects.create_superuser(username, "myemail@test.com", password)
def test_get_jobads(self):
response = self.client.get(API, format="json")
expected = JobAdSerializer(self.prefilled_jobad).data
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(response.data["results"][0], expected)
def test_post_jobad(self):
data = {
"title_fi": "testtitle",
"title_en": "testtitle",
"visible": "True",
"description_fi": "liirumlaarum",
"description_en": "liirumlaarum",
"content_fi": "lorem ipsum",
"content_en": "lorem ipsum",
"autohide_enabled": "True"
}
# Try post without authentication
response = self.client.post(API, data, format="json")
self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED)
self.assertEqual(JobAd.objects.count(), 1)
# Authenticate
self.client.force_authenticate(user=self.authClient)
response = self.client.post(API, data, format="json")
# Return success and check object was created
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
self.assertEqual(JobAd.objects.count(), 2)
+10 -20
View File
@@ -6,69 +6,59 @@ from webapp.models import *
@register(BaseFeed) @register(BaseFeed)
class BaseFeedTranslationOptions(TranslationOptions): class BaseFeedTranslationOptions(TranslationOptions):
"""Class for base feed translation options."""
fields = ('title', 'description', 'content') fields = ('title', 'description', 'content')
@register(Feed) @register(Feed)
class FeedTranslationOptions(TranslationOptions): class FeedTranslationOptions(TranslationOptions):
"""Class for feed translation options."""
fields = () fields = ()
@register(Tag) @register(Tag)
class TagTranslationOptions(TranslationOptions): class TagTranslationOptions(TranslationOptions):
"""Class for tag translation options."""
fields = ('name',) fields = ('name',)
@register(Event) @register(Event)
class EventTranslationOptions(TranslationOptions): class EventTranslationOptions(TranslationOptions):
"""Class for event translation options."""
fields = ('location',) fields = ('location',)
@register(Signup) @register(Signup)
class SignupTranslationOptions(TranslationOptions): class SignupTranslationOptions(TranslationOptions):
"""Class for registration translation options."""
fields = () fields = ()
@register(SignupForm) @register(SignupForm)
class SignupFormTranslationOptions(TranslationOptions): class SignupFormTranslationOptions(TranslationOptions):
"""Class for registration translation options."""
fields = ('title',) fields = ('title',)
@register(TemplateQuestion) @register(TemplateQuestion)
class TemplateQuestionTranslationOptions(TranslationOptions): class TemplateQuestionTranslationOptions(TranslationOptions):
"""Class for registration translation options."""
fields = () fields = ()
@register(BaseRole) @register(BaseRole)
class BaseRoleTranslationOptions(TranslationOptions): class BaseRoleTranslationOptions(TranslationOptions):
"""Class for base role translation options"""
fields = ('name',) fields = ('name',)
@register(PresetRole) @register(PresetRole)
class PresetRoleTranslationOptions(TranslationOptions): class PresetRoleTranslationOptions(TranslationOptions):
"""Class for PresetRole translation options."""
fields = ('description',) fields = ('description',)
@register(Role)
class RoleTranslationOptions(TranslationOptions):
fields = ()
@register(Committee) @register(Committee)
class CommitteeTranslationOptions(TranslationOptions): class CommitteeTranslationOptions(TranslationOptions):
"""Class for PresetRole translation options."""
fields = ('name',) fields = ('name',)
@register(JobAd)
class JobAdTranslationOptions(TranslationOptions):
fields = ('title', 'description', 'content',)
+1
View File
@@ -22,6 +22,7 @@ router.register(r'contacts', ContactsViewSet)
router.register(r'committees', CommitteeViewSet) router.register(r'committees', CommitteeViewSet)
router.register(r'questions', SavedQuestionsViewSet) router.register(r'questions', SavedQuestionsViewSet)
router.register(r'tags', TagsViewSet) router.register(r'tags', TagsViewSet)
router.register(r'jobads', JobAdViewSet)
urlpatterns = [ urlpatterns = [
url(r'^api/', include(router.urls)), url(r'^api/', include(router.urls)),
+8 -4
View File
@@ -19,10 +19,8 @@ from rest_framework.permissions import IsAuthenticatedOrReadOnly, BasePermission
from jsonschema import validate from jsonschema import validate
from jsonschema.exceptions import ValidationError from jsonschema.exceptions import ValidationError
from webapp.models import Event, SignupForm, Signup, TemplateQuestion, Feed, Committee, Occupation, Tag from webapp.models import *
from webapp.serializers import (EventSerializer, SignupFormSerializer, SignupSerializer, from webapp.serializers import *
SavedQuestionsSerializer, FeedSerializer, CommitteeSerializer,
OccupationSerializer, TagSerializer)
from webapp.utils import decode_base64_file from webapp.utils import decode_base64_file
@@ -215,6 +213,12 @@ class TagsViewSet(ReadOnlyModelViewSet):
permission_classes = [IsAuthenticatedOrReadOnly] permission_classes = [IsAuthenticatedOrReadOnly]
class JobAdViewSet(ModelViewSet):
queryset = JobAd.objects.all()
serializer_class = JobAdSerializer
permission_classes = [IsAuthenticatedOrReadOnly]
@require_http_methods(["GET"]) @require_http_methods(["GET"])
def about_view(request, *args, **kwargs): def about_view(request, *args, **kwargs):
"""Render about page.""" """Render about page."""