def test_get_categories_summary_respects_job_board(self):
        self.categories[1].subcategories.add(
            self.subcategories[1]
        )  # this subcategory has 1 job

        summary = JobCategory.get_categories_summary(homepage=self.homepage)
        self.assertEqual(summary.count(), 1)

        # Should return nothing since the jobs in setup are all external jobs (JOB_BOARD_CHOICES[0])
        summary = JobCategory.get_categories_summary(homepage=self.homepage_internal)
        self.assertEqual(summary.count(), 0)

        # Create internal job
        job = TalentLinkJobFactory(homepage=self.homepage_internal)
        job.subcategory = self.subcategories[1]
        job.save()

        summary = JobCategory.get_categories_summary(homepage=self.homepage_internal)
        self.assertEqual(summary.count(), 1)
Пример #2
0
def get_school_and_early_years_count(search_results):
    schools_and_early_years_categories = (
        JobCategory.get_school_and_early_years_categories()
    )
    if len(schools_and_early_years_categories):
        search_results = search_results.filter(
            subcategory__categories__slug__in=schools_and_early_years_categories
        )

    return len(search_results)
    def test_get_categories_summary(self):
        # Assign categories
        self.categories[0].subcategories.add(
            self.subcategories[0]
        )  # this subcategory has 0 jobs
        self.categories[1].subcategories.add(
            self.subcategories[1]
        )  # this subcategory has 1 job

        # Should return just self.categories[1] since self.categories[0] has 0 jobs.
        summary = JobCategory.get_categories_summary()
        self.assertEqual(summary.count(), 1)
        self.assertEqual(summary[0]["category"], self.categories[1].id)
        self.assertEqual(summary[0]["count"], 1)
    def test_get_categories_summary_ranking(self):
        # Assign categories
        self.categories[0].subcategories.add(
            self.subcategories[2]
        )  # this subcategory has 2 jobs
        self.categories[1].subcategories.add(
            self.subcategories[3]
        )  # this subcategory has 3 jobs

        summary = JobCategory.get_categories_summary()
        self.assertEqual(summary.count(), 2)
        self.assertEqual(summary[0]["category"], self.categories[1].id)
        self.assertEqual(summary[0]["count"], 3)
        self.assertEqual(summary[1]["category"], self.categories[0].id)
        self.assertEqual(summary[1]["count"], 2)
 def test_get_categories_summary_when_subcategory_has_no_job(self):
     self.categories[0].subcategories.add(
         self.subcategories[0]
     )  # this subcategory has 0 jobs
     self.assertEqual(JobCategory.get_categories_summary().count(), 0)
 def test_get_categories_summary_when_empty_subcategory(self):
     # We haven't assigned any subcategory to the categories yet, so should return empty
     self.assertEqual(JobCategory.get_categories_summary().count(), 0)
 def test_get_categories_summary_when_no_category_exists(self):
     self.categories[0].delete()
     self.categories[1].delete()
     self.assertEqual(JobCategory.get_categories_summary().count(), 0)
def jobs_search_filters(request, unfiltered_results=None):
    search_postcode = request.GET.get("postcode", None)
    homepage = Site.find_for_request(request).root_page.specific

    if not unfiltered_results:
        # Provide a default queryset for Pattern Library
        unfiltered_results = TalentLinkJob.objects.filter(homepage=homepage).all()

    hide_schools_and_early_years = request.GET.get(
        "hide_schools_and_early_years", False
    )

    job_categories = JobCategory.get_categories_summary(
        unfiltered_results, homepage=homepage
    ).order_by("sort_order")

    return {
        "hide_schools_and_early_years": {
            "label": "Hide all schools and early years jobs",
            "count": get_school_and_early_years_count(unfiltered_results),
            "selected": hide_schools_and_early_years,
        },
        "filters": [
            {
                "title": "Job categories",
                "options": job_categories,
                "selected": request.GET.getlist("category"),
                "key": "category",
            },
            {
                "title": "Job subcategories",
                "options": unfiltered_results.values("subcategory__title")
                .annotate(key=F("subcategory__title"), label=F("subcategory__title"),)
                .order_by("subcategory__title")
                .distinct(),
                "selected": request.GET.getlist("subcategory"),
                "key": "subcategory",
            },
            {
                "title": "Contract type",
                "options": unfiltered_results.values("contract_type")
                .annotate(key=F("contract_type"), label=F("contract_type"))
                .order_by("contract_type")
                .distinct(),
                "selected": request.GET.getlist("contract"),
                "key": "contract",
            },
            {
                "title": "Working hours",
                "options": unfiltered_results.values("working_hours")
                .annotate(key=F("working_hours"), label=F("working_hours"),)
                .order_by("working_hours")
                .distinct(),
                "selected": request.GET.getlist("working_hours"),
                "key": "working_hours",
            },
            {
                # Because these are database values, they're not ordered in code. The
                # following code imposes ordering:
                # - first, by the reverse string index of the first encountered "£"
                #   character
                # - then by the rest of the value alphabetically
                #
                # This gives the following ordering:
                #
                # 1. Bellerophon £
                # 2. Aeneas £
                # 3. £Aeneas
                # 4. £Bellerophon
                # 5. Aeneas
                # 6. Bellerophon
                #
                # It works to order the currently seen API salary values meaningfully,
                # but could be broken by future changes to those values.
                "title": "Salary range",
                "options": unfiltered_results.exclude(searchable_salary__exact="")
                .values("searchable_salary")
                .annotate(
                    pound_index=StrIndex("searchable_salary", Value("£")),
                    key=F("searchable_salary"),
                    label=F("searchable_salary"),
                )
                .order_by("-pound_index", "searchable_salary")
                .distinct(),
                "selected": request.GET.getlist("searchable_salary"),
                "key": "searchable_salary",
            },
        ],
        "search_postcode": search_postcode,
    }
Пример #9
0
def get_job_search_results(querydict, homepage, queryset=None):
    if queryset is None:
        queryset = TalentLinkJob.objects.all()

    queryset = queryset.filter(homepage=homepage)

    search_query = querydict.get("query", None)

    if search_query:
        vector = (
            SearchVector("title", weight="A")
            + SearchVector("job_number", weight="A")
            # + SearchVector("short_description", weight="A")
            + SearchVector("location_name", weight="B")
            + SearchVector("location_city", weight="B")
            + SearchVector("description", weight="C")
        )
        query = SearchQuery(search_query, search_type="phrase")
        search_results = (
            queryset.annotate(rank=SearchRank(vector, query))
            .filter(rank__gte=0.1)
            .order_by("-rank")
        )

    else:
        # Order by newest job at top
        search_results = queryset.order_by("posting_start_date")

    # Process 'hide schools and early years job'
    if querydict.get("hide_schools_and_early_years", False):
        schools_and_early_years_categories = (
            JobCategory.get_school_and_early_years_categories()
        )
        search_results = search_results.exclude(
            subcategory__categories__slug__in=schools_and_early_years_categories
        )

    # Process filters
    for filter in JOB_FILTERS:
        # QueryDict.update() used in send_job_alerts.py adds the values as list instead of multivalue dict.
        if isinstance(querydict.get(filter["name"]), list):
            selected = querydict.get(filter["name"])
        else:
            selected = querydict.getlist(
                filter["name"]
            )  # will return empty list if not found

        try:
            selected = [forms.CharField().clean(value) for value in selected]
        except ValidationError:
            # Abort any invalid string literals, e.g. SQL injection attempts
            continue

        if selected:
            search_results = search_results.filter(
                **{
                    filter["filter_key"] + "__in": selected
                }  # TODO: make case insensitive
            )

    # Process postcode search
    search_postcode = querydict.get("postcode", None)
    if search_postcode:
        postcode_response = requests.get(
            "https://api.postcodes.io/postcodes/" + search_postcode
        )
        if postcode_response.status_code == 200:
            postcode_response_json = postcode_response.json()
            search_lon = postcode_response_json["result"]["longitude"]
            search_lat = postcode_response_json["result"]["latitude"]

            search_results = search_results.annotate(
                distance=GetDistance(search_lat, search_lon)
            ).order_by("distance")

            if search_query:
                # Rank is only used when there is a search query
                search_results = search_results.order_by("distance", "-rank")

    return search_results