Commit e69d6c57 authored by Sébastiaan Versteeg's avatar Sébastiaan Versteeg
Browse files

Merge branch 'fix-579' into 'master'

Add documentation to the partners app

Closes #579

See merge request !1272
parents ae42a29f 396d05d8
......@@ -6,11 +6,15 @@ from utils.translation import TranslatedModelAdmin
class PartnerImageInline(admin.StackedInline):
"""Class to show partner images inline in the admin."""
model = PartnerImage
@admin.register(Partner)
class PartnerAdmin(admin.ModelAdmin):
"""Class to show partners in the admin."""
prepopulated_fields = {"slug": ("name",)}
list_display = ('name', 'is_active', 'is_main_partner',)
inlines = (PartnerImageInline,)
......@@ -31,12 +35,16 @@ class PartnerAdmin(admin.ModelAdmin):
@admin.register(VacancyCategory)
class VacancyCategoryAdmin(TranslatedModelAdmin):
"""Class to show vacancy categories in the admin."""
prepopulated_fields = {"slug": ("name_en",)}
fields = ['name', 'slug']
@admin.register(Vacancy)
class VacancyAdmin(admin.ModelAdmin):
"""Class to show vacancies in the admin."""
list_display = ('title', 'partner', 'company_name', 'expiration_date')
fieldsets = (
......@@ -60,6 +68,8 @@ class VacancyAdmin(admin.ModelAdmin):
@admin.register(PartnerEvent)
class PartnerEventAdmin(TranslatedModelAdmin):
"""Class to show partner events in the admin."""
fields = ['partner', 'other_partner', 'title', 'description', 'location',
'start', 'end', 'url', 'published']
list_display = ('title', 'start', 'end',
......
......@@ -8,7 +8,11 @@ from partners.models import PartnerEvent, Partner
class PartnerEventCalendarJSSerializer(CalenderJSSerializer):
"""Partner event calender serializer."""
class Meta(CalenderJSSerializer.Meta):
"""Meta class for partner event calendar serializer."""
model = PartnerEvent
def _title(self, instance):
......@@ -17,27 +21,39 @@ class PartnerEventCalendarJSSerializer(CalenderJSSerializer):
return "{} ({})".format(instance.title, instance.other_partner)
def _background_color(self, instance):
"""Return the color of the background."""
return 'black'
def _text_color(self, instance):
"""Return the color of the text."""
return '#E62272'
def _url(self, instance):
"""Return the url of the partner event."""
return instance.url
def _target_blank(self, instance):
"""Return whether the anchor tag should have 'target="_blank"'."""
return True
class PartnerSerializer(serializers.ModelSerializer):
"""Partner serializer."""
class Meta:
"""Meta class for partner serializer."""
model = Partner
fields = ('pk', 'name', 'link', 'company_profile', 'address',
'zip_code', 'city', 'logo')
class PartnerEventSerializer(serializers.ModelSerializer):
"""Partner events serializer."""
class Meta:
"""Meta class for partner events serializer."""
model = PartnerEvent
fields = ('pk', 'title', 'description', 'start', 'end', 'location',
'url')
......@@ -45,4 +61,5 @@ class PartnerEventSerializer(serializers.ModelSerializer):
description = serializers.SerializerMethodField('_description')
def _description(self, instance):
"""Return description of partner event."""
return unescape(strip_tags(instance.description))
......@@ -15,11 +15,14 @@ from utils.snippets import extract_date_range
class PartnerViewset(viewsets.ReadOnlyModelViewSet):
"""View set for partners."""
serializer_class = PartnerSerializer
queryset = Partner.objects.filter(is_active=True)
@action(detail=False, permission_classes=(IsAuthenticatedOrReadOnly,))
def calendarjs(self, request):
"""Return response with serialized partner event calender data."""
start, end = extract_date_range(request)
queryset = PartnerEvent.objects.filter(
......@@ -33,6 +36,8 @@ class PartnerViewset(viewsets.ReadOnlyModelViewSet):
class PartnerEventViewset(viewsets.ReadOnlyModelViewSet):
"""View set for partner events."""
queryset = PartnerEvent.objects.filter(end__gte=timezone.now(),
published=True)
permission_classes = [IsAuthenticated]
......
......@@ -3,5 +3,7 @@ from django.utils.translation import gettext_lazy as _
class PartnersConfig(AppConfig):
"""Appconfig for partners app."""
name = 'partners'
verbose_name = _('Partners')
......@@ -8,6 +8,7 @@ from partners.models import Vacancy
def send_vacancy_expiration_notifications(dry_run=False):
"""Send a notification about expiring vacancies."""
# Select vacencies that expire in roughly a month, wherefor
# a mail hasn't been sent yet to Mr/Mrs Extern
expired_vacancies = Vacancy.objects.filter(
......
......@@ -4,8 +4,10 @@ from partners import emails
class Command(BaseCommand):
"""Command class for sendvacancyexpirationnotification command."""
def add_arguments(self, parser):
"""Add --dry-run argument to command."""
parser.add_argument(
'--dry-run',
action='store_true',
......@@ -15,5 +17,6 @@ class Command(BaseCommand):
)
def handle(self, *args, **options):
"""Call the function to handle the sending of emails."""
emails.send_vacancy_expiration_notifications(
bool(options['dry-run']))
......@@ -9,6 +9,8 @@ from utils.translation import ModelTranslateMeta, MultilingualField
class Partner(models.Model):
"""Model describing partner."""
is_active = models.BooleanField(default=False)
is_main_partner = models.BooleanField(default=False)
name = models.CharField(max_length=255)
......@@ -42,12 +44,19 @@ class Partner(models.Model):
city = models.CharField(max_length=100)
def save(self, *args, **kwargs):
"""Save a partner and set main partner."""
if self.is_main_partner:
self._reset_main_partner()
super(Partner, self).save(*args, **kwargs)
def _reset_main_partner(self):
"""
Reset the main partner status.
If this partner is not main partner,
remove the main partner status from the main partner.
"""
try:
current_main_partner = Partner.objects.get(is_main_partner=True)
if self != current_main_partner:
......@@ -57,16 +66,22 @@ class Partner(models.Model):
pass
def __str__(self):
"""Return the name of the partner."""
return self.name
def get_absolute_url(self):
"""Return the url of the partner page."""
return reverse('partners:partner', args=(self.slug,))
class Meta:
"""Meta class for partner model."""
ordering = ('name',)
class PartnerImage(models.Model):
"""Model to save partner image."""
partner = models.ForeignKey(
Partner,
on_delete=models.CASCADE,
......@@ -75,21 +90,29 @@ class PartnerImage(models.Model):
image = models.ImageField(upload_to='public/partners/images/')
def __str__(self):
"""Return string representation of partner name."""
return ugettext('image of {}').format(self.partner.name)
class VacancyCategory(models.Model, metaclass=ModelTranslateMeta):
"""Model describing vacancy categories."""
name = MultilingualField(models.CharField, max_length=30)
slug = models.SlugField()
def __str__(self):
"""Return the category name."""
return self.name
class Meta:
"""Meta class for vacancy category model."""
verbose_name_plural = _('Vacancy Categories')
class Vacancy(models.Model):
"""Model describing vacancies."""
title = models.CharField(max_length=255)
description = HTMLField()
link = models.CharField(
......@@ -122,28 +145,30 @@ class Vacancy(models.Model):
remarks = HTMLField(blank=True, help_text=_('not shown on the page'))
def get_company_name(self):
"""Return company or partner name."""
if self.partner:
return self.partner.name
return self.company_name
def get_company_logo(self):
"""Return company or partner logo."""
if self.partner:
return self.partner.logo
return self.company_logo
def __str__(self):
"""Return vacancy partner or company and title."""
return '{} — {}'.format(self.get_company_name(), self.title)
class Meta:
verbose_name_plural = _('Vacancies')
def get_absolute_url(self):
"""Return partner or vacancy url."""
url = reverse('partners:vacancies')
if self.partner:
url = reverse('partners:partner', args=(self.partner.slug,))
return '{}#vacancy-{}'.format(url, self.pk)
def clean(self):
"""Validate the vacancy."""
super().clean()
errors = {}
......@@ -172,8 +197,15 @@ class Vacancy(models.Model):
if errors:
raise ValidationError(errors)
class Meta:
"""Meta class for vacancy model."""
verbose_name_plural = _('Vacancies')
class PartnerEvent(models.Model, metaclass=ModelTranslateMeta):
"""Model describing partner event."""
partner = models.ForeignKey(
Partner,
on_delete=models.CASCADE,
......@@ -210,6 +242,7 @@ class PartnerEvent(models.Model, metaclass=ModelTranslateMeta):
published = models.BooleanField(_("published"), default=False)
def clean(self):
"""Validate the partner event."""
super().clean()
errors = {}
if ((not self.partner and not self.other_partner) or
......@@ -224,4 +257,5 @@ class PartnerEvent(models.Model, metaclass=ModelTranslateMeta):
raise ValidationError(errors)
def __str__(self):
"""Return the event title."""
return self.title
......@@ -5,29 +5,40 @@ from . import models
class StaticViewSitemap(sitemaps.Sitemap):
"""Sitemap generator for static partner views."""
changefreq = 'daily'
def items(self):
"""Return static partner view names."""
return ['partners:index', 'partners:vacancies']
def location(self, item):
"""Return view url."""
return reverse(item)
class PartnerSitemap(sitemaps.Sitemap):
"""Sitemap generator for partners."""
def items(self):
"""Return all active partners."""
return models.Partner.objects.filter(is_active=True)
def location(self, item):
"""Return the partner url."""
return item.get_absolute_url()
class VacancySitemap(sitemaps.Sitemap):
"""Sitemap generator for vacancies."""
def items(self):
"""Return all vacancies."""
return models.Vacancy.objects.all()
def location(self, item):
"""Return the vacancy url."""
return item.get_absolute_url()
......
......@@ -10,6 +10,7 @@ register = template.Library()
@register.inclusion_tag('partners/banners.html', takes_context=True)
def render_partner_banners(context):
"""Render the partner banner."""
request = context['request']
all_partners = Partner.objects.filter(is_active=True).order_by('id')
ids = [partner.id for partner in all_partners]
......
......@@ -11,6 +11,7 @@ register = template.Library()
@register.inclusion_tag('includes/grid_item.html')
def partner_card(partner):
"""Return grid item showing partner."""
image_url = ''
if partner.logo:
image_url = get_thumbnail_url(partner.logo,
......@@ -30,6 +31,7 @@ def partner_card(partner):
@register.inclusion_tag('includes/grid_item.html')
def partner_image_card(image):
"""Return grid item showing partner image."""
class_name = 'partner-image-card'
image_url = get_thumbnail_url(image, settings.THUMBNAIL_SIZES['medium'])
......@@ -45,6 +47,7 @@ def partner_image_card(image):
@register.inclusion_tag('partners/vacancy_card.html')
def vacancy_card(vacancy):
"""Return grid item showing vacancy."""
image_url = None
if vacancy.get_company_logo():
image_url = get_thumbnail_url(vacancy.get_company_logo(),
......
......@@ -7,6 +7,7 @@ from partners.models import Partner, Vacancy, VacancyCategory
def index(request):
"""View to show overview page of partners."""
partners = Partner.objects.filter(is_active=True, is_main_partner=False)
try:
main_partner = Partner.objects.get(
......@@ -24,6 +25,7 @@ def index(request):
def partner(request, slug):
"""View to show partner page."""
partner = get_object_or_404(Partner, slug=slug)
context = {
'partner': partner,
......@@ -33,6 +35,7 @@ def partner(request, slug):
def vacancies(request):
"""View to show vacancies."""
context = {
'vacancies': Vacancy.objects.exclude(
expiration_date__lte=timezone.now().date()).order_by('?'),
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment