bedrock/careers/models.py (83 lines of code) (raw):
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at https://mozilla.org/MPL/2.0/.
from datetime import datetime
from itertools import chain
from django.conf import settings
from django.core.cache import cache
from django.db import models
from django.urls import reverse
class Position(models.Model):
job_id = models.CharField(max_length=10)
title = models.CharField(max_length=100)
department = models.CharField(max_length=100)
location = models.CharField(max_length=500)
job_locations = models.CharField(max_length=500, default="")
# TODO remove this as there is more than just mofo
is_mofo = models.BooleanField(default=False)
description = models.TextField()
apply_url = models.URLField()
source = models.CharField(max_length=100)
position_type = models.CharField(max_length=100)
updated_at = models.DateTimeField(default=datetime.utcnow)
# Store the Greenhouse internal ID for grouping the same jobs with multiple
# listings per location.
internal_job_id = models.PositiveIntegerField()
NON_MOCO_DEPTS = [
"Pan Mozilla",
"Mozilla Foundation",
"MZLA/Thunderbird",
]
class Meta:
ordering = (
"department",
"title",
)
def __str__(self):
return f"{self.job_id}@{self.source}"
def get_absolute_url(self):
return reverse("careers.position", kwargs={"source": self.source, "job_id": self.job_id})
@classmethod
def _get_cache_key(cls, name):
return f"careers_position__{name}"
@property
def is_moco(self):
return self.department not in self.NON_MOCO_DEPTS
@property
def location_list(self):
_key = self._get_cache_key("location_list")
location_list = cache.get(_key)
if location_list is None:
location_list = sorted(self.location.split(","))
cache.set(_key, location_list, settings.CACHE_TIME_LONG)
return location_list
@classmethod
def position_types(cls):
_key = cls._get_cache_key("position_types")
position_types = cache.get(_key)
if position_types is None:
position_types = sorted(set(cls.objects.values_list("position_type", flat=True)))
cache.set(_key, position_types, settings.CACHE_TIME_LONG)
return position_types
@classmethod
def locations(cls):
_key = cls._get_cache_key("locations")
locations = cache.get(_key)
if locations is None:
locations = sorted(
{
location.strip()
for location in chain(
*[locations.split(",") for locations in cls.objects.exclude(job_locations="Remote").values_list("job_locations", flat=True)]
)
}
)
cache.set(_key, locations, settings.CACHE_TIME_LONG)
return locations
@classmethod
def categories(cls):
_key = cls._get_cache_key("categories")
categories = cache.get(_key)
if categories is None:
categories = sorted(set(cls.objects.values_list("department", flat=True)))
cache.set(_key, categories, settings.CACHE_TIME_LONG)
return categories
@property
def cover(self):
# Try to get the job posting of the same `internal_job_id` with "Remote"
# job location to use as the "cover" posting.
if cover := Position.objects.filter(internal_job_id=self.internal_job_id, job_locations="Remote").first():
return cover
# Fallback to returning `self` if there is no "Remote" location.
return self