Merge branch 'feature/job-ads' into 'develop'

Add Job-ad DB object and serializer

See merge request sahkoinsinoorikilta/vtmk/web2.0-backend!29
This commit is contained in:
Toni Lyttinen
2020-11-07 13:41:37 +00:00
13 changed files with 324 additions and 5062 deletions
Binary file not shown.
File diff suppressed because it is too large Load Diff
Binary file not shown.
File diff suppressed because it is too large Load Diff
+3 -2
View File
@@ -1,7 +1,7 @@
"""File containing webapp app admin registers."""
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 modeltranslation.admin import TranslationAdmin
from django.contrib.auth.models import Permission
@@ -19,4 +19,5 @@ admin.site.register(TemplateQuestion, TranslationAdmin)
admin.site.register(Committee, TranslationAdmin)
admin.site.register(Official)
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):
"""Model for tag."""
slug = models.SlugField(unique=True)
name = models.CharField(max_length=127)
icon = models.ImageField()
class Meta:
verbose_name = _('Tag')
verbose_name_plural = _('Tags')
slug = models.SlugField(unique=True)
name = models.CharField(max_length=127)
icon = models.ImageField()
def __str__(self):
return _('Tag: {}').format(self.slug)
@@ -48,6 +48,10 @@ class BaseFeed(models.Model):
class Feed(BaseFeed):
"""Model representing feed."""
class Meta:
verbose_name = _('Feed')
verbose_name_plural = _('Feeds')
publish_time = models.DateTimeField(default=timezone.now)
autohide = models.DateTimeField(default=month_from_now)
autohide_enabled = models.BooleanField(default=False)
@@ -55,13 +59,13 @@ class Feed(BaseFeed):
def __str__(self):
return _('Feed: {}').format(self.title)
class Meta:
verbose_name = _('Feed')
verbose_name_plural = _('Feeds')
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)
end_time = models.DateTimeField(default=timezone.now)
@@ -72,26 +76,30 @@ class Event(BaseFeed):
def __str__(self):
return _('Event: {}').format(self.title)
class Meta:
verbose_name = _('Event')
verbose_name_plural = _('Events')
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)
question = JSONField()
def __str__(self):
return _('Template questions: {}').format(self.name)
class Meta:
verbose_name = _('Template question')
verbose_name_plural = _('Template questions')
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)
start_time = models.DateTimeField(default=timezone.now)
@@ -114,12 +122,15 @@ class SignupForm(models.Model):
now = timezone.now()
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):
"""
In
"""
class Meta:
verbose_name = _('Sign-up')
verbose_name_plural = _('Sign-ups')
signupForm = models.ForeignKey('SignupForm', on_delete=models.CASCADE)
time = models.DateTimeField(default=timezone.now)
answer = JSONField()
@@ -133,10 +144,6 @@ class Signup(models.Model):
def __str__(self):
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)
def email_on_signup(sender, instance, created, **kwargs):
@@ -166,7 +173,6 @@ class BaseRole(models.Model):
class PresetRole(BaseRole):
"""Model representing a preset occupation in the guild."""
description = models.TextField(_('Description'))
@@ -177,8 +183,6 @@ class Committee(models.Model):
"""
class Meta:
"""Meta class for Committee class."""
verbose_name = _('Committee')
verbose_name_plural = _('Committees')
@@ -194,15 +198,11 @@ class Committee(models.Model):
class Role(PresetRole):
"""
Model for Role.
Model representing an active or historical occupation
in the guild.
"""
class Meta:
"""Meta class for Role model."""
verbose_name = _('Role')
verbose_name_plural = _('Roles')
@@ -241,8 +241,6 @@ class Official(models.Model):
"""Model representing a guild official."""
class Meta:
"""Meta class for Official class."""
verbose_name = _('Official')
verbose_name_plural = _('Officials')
@@ -272,10 +270,30 @@ def save_user_official(sender, instance, **kwargs):
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(Feed)
auditlog.register(Event)
auditlog.register(SignupForm)
auditlog.register(Signup)
auditlog.register(PresetRole)
auditlog.register(Role)
auditlog.register(Committee)
auditlog.register(Occupation)
auditlog.register(Official)
auditlog.register(JobAd)
+6
View File
@@ -169,3 +169,9 @@ class OccupationSerializer(serializers.ModelSerializer):
class Meta:
model = Occupation
fields = ('role', 'start_date', 'end_date', 'officials')
class JobAdSerializer(serializers.ModelSerializer):
class Meta:
model = JobAd
fields = ('id', 'title_fi', 'title_en', 'description_fi', 'description_en', 'content_fi', 'content_en', 'visible', 'autohide_at', 'autohide_enabled')
+5 -7
View File
@@ -27,11 +27,9 @@ class FeedTestCase(APITestCase):
self.assertTrue(status.is_success(response.status_code))
feeds = Feed.objects.all()
serializer = FeedSerializer(
feeds, many=True,
context={
"request": APIRequestFactory().get(r"http://testserver/api/events/")
})
serializer = FeedSerializer(feeds, many=True, context={
"request": APIRequestFactory().get(r"http://testserver/api/feed/")
})
self.assertEqual(response.data["results"], serializer.data)
def test_post_feed(self):
@@ -50,13 +48,13 @@ class FeedTestCase(APITestCase):
}
# Try post without authentication
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)
# Authenticate
self.client.force_authenticate(user=self.authClient)
response = self.client.post("/api/feed/", data, format="json")
# 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)
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)
class BaseFeedTranslationOptions(TranslationOptions):
"""Class for base feed translation options."""
fields = ('title', 'description', 'content')
@register(Feed)
class FeedTranslationOptions(TranslationOptions):
"""Class for feed translation options."""
fields = ()
@register(Tag)
class TagTranslationOptions(TranslationOptions):
"""Class for tag translation options."""
fields = ('name',)
@register(Event)
class EventTranslationOptions(TranslationOptions):
"""Class for event translation options."""
fields = ('location',)
@register(Signup)
class SignupTranslationOptions(TranslationOptions):
"""Class for registration translation options."""
fields = ()
@register(SignupForm)
class SignupFormTranslationOptions(TranslationOptions):
"""Class for registration translation options."""
fields = ('title',)
@register(TemplateQuestion)
class TemplateQuestionTranslationOptions(TranslationOptions):
"""Class for registration translation options."""
fields = ()
@register(BaseRole)
class BaseRoleTranslationOptions(TranslationOptions):
"""Class for base role translation options"""
fields = ('name',)
@register(PresetRole)
class PresetRoleTranslationOptions(TranslationOptions):
"""Class for PresetRole translation options."""
fields = ('description',)
@register(Role)
class RoleTranslationOptions(TranslationOptions):
fields = ()
@register(Committee)
class CommitteeTranslationOptions(TranslationOptions):
"""Class for PresetRole translation options."""
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'questions', SavedQuestionsViewSet)
router.register(r'tags', TagsViewSet)
router.register(r'jobads', JobAdViewSet)
urlpatterns = [
url(r'^api/', include(router.urls)),
+13 -4
View File
@@ -19,10 +19,8 @@ from rest_framework.permissions import IsAuthenticatedOrReadOnly, BasePermission
from jsonschema import validate
from jsonschema.exceptions import ValidationError
from webapp.models import Event, SignupForm, Signup, TemplateQuestion, Feed, Committee, Occupation, Tag
from webapp.serializers import (EventSerializer, SignupFormSerializer, SignupSerializer,
SavedQuestionsSerializer, FeedSerializer, CommitteeSerializer,
OccupationSerializer, TagSerializer)
from webapp.models import *
from webapp.serializers import *
from webapp.utils import decode_base64_file
@@ -215,6 +213,17 @@ class TagsViewSet(ReadOnlyModelViewSet):
permission_classes = [IsAuthenticatedOrReadOnly]
class JobAdViewSet(ModelViewSet):
queryset = JobAd.objects.all()
serializer_class = JobAdSerializer
permission_classes = [IsAuthenticatedOrReadOnly]
def get_queryset(self):
if self.request.user.is_authenticated:
return JobAd.objects.all()
return JobAd.objects.filter(visible=True, autohide_at__gt=timezone.now())
@require_http_methods(["GET"])
def about_view(request, *args, **kwargs):
"""Render about page."""