GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.

SearchJobsController.index()   F
last analyzed

Complexity

Conditions 9

Size

Total Lines 44

Duplication

Lines 0
Ratio 0 %

Importance

Changes 10
Bugs 1 Features 0
Metric Value
cc 9
c 10
b 1
f 0
dl 0
loc 44
rs 3
1
# -*- coding: utf-8 -*-
2
import json
3
import logging
4
from elasticsearch_dsl import Q, SF
5
6
from sqlalchemy.orm.exc import NoResultFound
7
from tg.decorators import expose, redirect, paginate
8
from tg.exceptions import HTTPNotFound
9
10
from pyjobsweb.model import JobAlchemy
11
from pyjobsweb.model import JobElastic
12
from pyjobsweb.model.data import SOURCES
13
from pyjobsweb.lib.base import BaseController
14
from pyjobsweb.lib.elasticsearch_ import PaginatedSearch
15
from pyjobsweb.forms.research_forms import JobsResearchForm
16
17
18
class SearchJobsController(BaseController):
19
    items_per_page = 10
20
21
    def __init__(self, items_per_page=10):
22
        self.items_per_page = items_per_page
23
24
    @staticmethod
25
    def _compute_keyword_queries(terms):
26
        search_on = dict(
27
            description=[
28
                'description',
29
                'description.technologies'
30
            ],
31
            title=[
32
                'title',
33
                'title.technologies'
34
             ],
35
            company=['company']
36
        )
37
38
        description_query = Q(
39
            'multi_match',
40
            type='most_fields',
41
            query=terms,
42
            fields=search_on['description'],
43
            fuzziness='AUTO',
44
            operator='or',
45
            minimum_should_match='1<2 2<2 3<3 4<3 5<4 6<5 7<5 8<6 9<6',
46
            boost=len(terms.split(','))
47
        )
48
49
        title_query = Q(
50
            'multi_match',
51
            type='most_fields',
52
            query=terms,
53
            fields=search_on['title'],
54
            fuzziness='AUTO',
55
            operator='or',
56
            minimum_should_match='1<1',
57
            boost=20 - len(terms.split(',')) + 1
58
        )
59
60
        company_name_query = Q(
61
            'multi_match',
62
            type='best_fields',
63
            query=terms,
64
            fields=search_on['company'],
65
            fuzziness='AUTO',
66
            operator='or',
67
            minimum_should_match='1<1',
68
            boost=50
69
        )
70
71
        keyword_queries = Q(
72
            'bool',
73
            must=[
74
                company_name_query
75
            ],
76
            should=[
77
                title_query,
78
                description_query
79
            ]
80
        ) | Q(
81
            'bool',
82
            must=[
83
                description_query
84
            ],
85
            should=[
86
                title_query,
87
                company_name_query
88
            ]
89
        )
90
        return keyword_queries
91
92
    @staticmethod
93
    def _compute_decay_functions():
94
        decay_function = SF(
95
            'gauss',
96
            publication_datetime=dict(
97
                origin='now',
98
                scale='30d',
99
                offset='7d',
100
                decay='0.1'
101
            )
102
        )
103
104
        return [decay_function]
105
106
    @staticmethod
107
    def _apply_geolocation_filters(query, (lat, lon), radius):
108
        query = query.filter(
109
            'geo_distance',
110
            geolocation=[lon, lat],
111
            distance='%skm' % float(radius)
112
        )
113
114
        query = query.filter(
115
            'term',
116
            geolocation_is_valid=True
117
        )
118
119
        return query
120
121
    @staticmethod
122
    def _apply_date_sort(query):
123
        query = query.sort(
124
            '-publication_datetime',
125
            '-_score'
126
        )
127
128
        return query
129
130
    @expose('pyjobsweb.templates.jobs.list')
131
    @paginate('jobs', items_per_page=items_per_page)
132
    def index(self, query=None, radius=None, center=None, sort_by=None,
133
              *args, **kwargs):
134
        if not query and not radius and not center:
135
            redirect('/jobs')
136
137
        search_query = JobElastic().search()
138
        relevance_sort = sort_by == 'scores'
139
140
        if query:
141
            keyword_queries = self._compute_keyword_queries(query)
142
            decay_functions = self._compute_decay_functions()
143
144
            search_query.query = Q(
145
                'function_score',
146
                query=keyword_queries,
147
                functions=decay_functions
148
            )
149
        else:
150
            relevance_sort = False
151
152
        try:
153
            geoloc_query = json.loads(center)
154
            coordinates = geoloc_query['coordinates']
155
            lat, lon = (coordinates['lat'], coordinates['lon'])
156
        except (ValueError, TypeError):
157
            # One of the following case has occurred:
158
            #     - Center wasn't a valid json string
159
            #     - Radius couldn't be converted to float
160
            # Since both these information are required to set a geolocation
161
            # filter are required, we ignore it.
162
            pass
163
        else:
164
            search_query = self._apply_geolocation_filters(
165
                search_query, (lat, lon), radius if radius else 5.0)
166
167
        date_sort = not relevance_sort
168
169
        if date_sort:
170
            search_query = self._apply_date_sort(search_query)
171
172
        return dict(sources=SOURCES, jobs=PaginatedSearch(search_query),
173
                    job_offer_search_form=JobsResearchForm)
174
175
176
class JobsController(BaseController):
177
    items_per_page = 10
178
    search = SearchJobsController(items_per_page)
179
180
    @expose('pyjobsweb.templates.jobs.list')
181
    @paginate('jobs', items_per_page=items_per_page)
182
    def index(self, *args, **kwargs):
183
        try:
184
            job_offers = JobAlchemy.get_all_job_offers()
185
        except NoResultFound:
186
            job_offers = None
187
188
        return dict(sources=SOURCES, jobs=job_offers,
189
                    job_offer_search_form=JobsResearchForm)
190
191
    @expose('pyjobsweb.templates.jobs.details')
192
    def details(self, offer_id, *args, **kwargs):
193
        try:
194
            job = JobAlchemy.get_job_offer(offer_id)
195
        except NoResultFound:
196
            raise HTTPNotFound()
197
        except Exception as exc:
198
            logging.getLogger(__name__).log(logging.ERROR, exc)
199
            raise HTTPNotFound()
200
        else:
201
            return dict(
202
                job=job,
203
                sources=SOURCES
204
            )
205
206