Passed
Pull Request — develop (#968)
by
unknown
01:36
created

atramhasis.views.views.provider_is_external()   A

Complexity

Conditions 1

Size

Total Lines 4
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 3
nop 1
dl 0
loc 4
rs 10
c 0
b 0
f 0
1
import os
2
import urllib
3
4
from pyramid.httpexceptions import HTTPFound
5
from pyramid.i18n import TranslationStringFactory
6
from pyramid.response import FileResponse
7
from pyramid.response import Response
8
from pyramid.threadlocal import get_current_registry
9
from pyramid.view import view_config
10
from pyramid.view import view_defaults
11
from skosprovider_sqlalchemy.models import Collection
12
from skosprovider_sqlalchemy.models import Concept
13
from skosprovider_sqlalchemy.models import LabelType
14
from skosprovider_sqlalchemy.models import NoteType
15
from sqlalchemy.exc import NoResultFound
16
17
from atramhasis.audit import audit
18
from atramhasis.cache import invalidate_cache
19
from atramhasis.cache import invalidate_scheme_cache
20
from atramhasis.cache import list_region
21
from atramhasis.cache import tree_region
22
from atramhasis.errors import ConceptNotFoundException
23
from atramhasis.errors import ConceptSchemeNotFoundException
24
from atramhasis.errors import SkosRegistryNotFoundException
25
from atramhasis.utils import update_last_visited_concepts
26
27
28
def labels_to_string(labels, ltype):
29
    labelstring = ''
30
    for label in (label for label in labels if label.labeltype_id == ltype):
31
        labelstring += label.label + ' (' + label.language_id + '), '
32
    return labelstring[:-2]
33
34
35
def get_definition(notes):
36
    for note in notes:
37
        if note.notetype_id == 'definition':
38
            return note.note
39
40
41
def sort_by_labels(concepts, locale, reverse=False):
42
    return sorted((x for x in concepts if x.label(locale)),
43
                  reverse=reverse,
44
                  key=lambda child: child.label(locale).label.lower()
45
                  ) + [x for x in concepts if not x.label(locale)]
46
47
def get_public_conceptschemes(skos_registry):
48
    """
49
    Get all conceptschemes that are visible through the public UI.
50
    """
51
    conceptschemes = [
52
        {'id': x.get_metadata()['id'],
53
         'conceptscheme': x.concept_scheme}
54
        for x in skos_registry.get_providers() if not any([not_shown in x.get_metadata()['subject']
55
                                                           for not_shown in ['external', 'hidden']])
56
        ]
57
58
    return conceptschemes
59
60
61
def provider_is_external(provider):
62
    """Check if a provider is marked as external via its metadata."""
63
    subjects = provider.get_metadata().get('subject') or []
64
    return any(str(subject).lower() == 'external' for subject in subjects)
65
66
67
@view_defaults(accept='text/html', request_method='GET')
68
class AtramhasisView:
69
    """
70
    This object groups HTML views part of the public user interface.
71
    """
72
73
    def __init__(self, request):
74
        self.request = request
75
        self.skos_manager = self.request.data_managers['skos_manager']
76
        self.conceptscheme_manager = self.request.data_managers['conceptscheme_manager']
77
        if hasattr(request, 'skos_registry') and request.skos_registry is not None:
78
            self.skos_registry = self.request.skos_registry
79
        else:
80
            raise SkosRegistryNotFoundException()
81
82
    def _read_request_param(self, param):
83
        value = None
84
        if param in self.request.params:
85
            value = self.request.params.getone(param).strip()
86
            if not value:
87
                value = None  # pragma: no cover
88
        return value
89
90
    @view_config(name='favicon.ico')
91
    def favicon_view(self):
92
        """
93
        Return the favicon when requested from the web root.
94
        """
95
        here = os.path.dirname(__file__)
96
        icon = os.path.join(os.path.dirname(here), 'static', 'img', 'favicon.ico')
97
        response = FileResponse(
98
            icon,
99
            request=self.request,
100
            content_type='image/x-icon'
101
        )
102
        return response
103
104
105
    @view_config(route_name='home', renderer='atramhasis:templates/home.jinja2')
106
    def home_view(self):
107
        """
108
        Display the homepage.
109
        """
110
        return {'conceptschemes': get_public_conceptschemes(self.skos_registry)}
111
112
    @view_config(route_name='skosprovider.conceptschemes', renderer='atramhasis:templates/conceptschemes.jinja2')
113
    def conceptschemes_view(self):
114
        """
115
        Display a list of available conceptschemes.
116
        """
117
        return {'conceptschemes': get_public_conceptschemes(self.skos_registry)}
118
119
    @audit
120
    @view_config(route_name='skosprovider.conceptscheme', renderer='atramhasis:templates/conceptscheme.jinja2')
121
    def conceptscheme_view(self):
122
        """
123
        Display a single conceptscheme.
124
        """
125
        conceptschemes = get_public_conceptschemes(self.skos_registry)
126
127
        scheme_id = self.request.matchdict['scheme_id']
128
129
        provider = self.request.skos_registry.get_provider(scheme_id)
130
        if provider is False:
131
            raise ConceptSchemeNotFoundException(scheme_id)
132
133
        conceptscheme = provider.concept_scheme
134
        if 'atramhasis.force_display_label_language' in provider.metadata:
135
            locale = provider.metadata['atramhasis.force_display_label_language']
136
        else:
137
            locale = self.request.locale_name
138
        title = (conceptscheme.label(locale).label if (conceptscheme.label())
139
                 else scheme_id)
140
141
        scheme = {
142
            'scheme_id': scheme_id,
143
            'title': title,
144
            'uri': conceptscheme.uri,
145
            'labels': conceptscheme.labels,
146
            'notes': conceptscheme.notes,
147
            'sources': conceptscheme.sources,
148
            'top_concepts': provider.get_top_concepts(),
149
        }
150
151
        return {
152
            'conceptscheme': scheme,
153
            'conceptschemes': conceptschemes,
154
            'locale': locale,
155
            'show_tree': not provider_is_external(provider),
156
        }
157
158
    @audit
159
    @view_config(route_name='skosprovider.c', renderer='atramhasis:templates/concept.jinja2')
160
    def concept_view(self):
161
        """
162
        Display all about a single concept or collection.
163
        """
164
        conceptschemes = [
165
            {'id': x.get_metadata()['id'],
166
             'conceptscheme': x.concept_scheme}
167
            for x in self.skos_registry.get_providers() if not any([not_shown in x.get_metadata()['subject']
168
                                                                    for not_shown in ['external', 'hidden']])
169
            ]
170
171
        scheme_id = self.request.matchdict['scheme_id']
172
        c_id = self.request.matchdict['c_id']
173
        provider = self.request.skos_registry.get_provider(scheme_id)
174
        label = self._read_request_param('label')
175
        requested_type = self._read_request_param('type')
176
177
        if not provider:
178
            raise ConceptSchemeNotFoundException(scheme_id)
179
        if 'atramhasis.force_display_label_language' in provider.metadata:
180
            locale = provider.metadata['atramhasis.force_display_label_language']
181
        else:
182
            locale = self.request.locale_name
183
        try:
184
            c = self.skos_manager.get_thing(c_id, provider.conceptscheme_id)
185
            if isinstance(c, Concept):
186
                concept_type = "Concept"
187
            elif isinstance(c, Collection):
188
                concept_type = "Collection"
189
            else:
190
                return Response('Thing without type: ' + str(c_id), status_int=500)
191
            url = self.request.route_url('skosprovider.c', scheme_id=scheme_id, c_id=c_id)
192
            update_last_visited_concepts(self.request, {'label': c.label(locale).label, 'url': url})
193
            return {
194
                'concept': c, 
195
                'conceptType': concept_type, 
196
                'scheme_id': scheme_id,
197
                'conceptschemes': conceptschemes, 
198
                'provider': provider,
199
                'locale': locale,
200
                'type': requested_type,
201
                'label': label,
202
                'show_tree': not provider_is_external(provider)
203
            }
204
        except NoResultFound:
205
            raise ConceptNotFoundException(c_id)
206
207
    @view_config(route_name='skosprovider.conceptscheme.cs', renderer='atramhasis:templates/search_result.jinja2')
208
    def search_result(self):
209
        """
210
        Display search results
211
        """
212
        conceptschemes = [
213
            {'id': x.get_metadata()['id'],
214
             'conceptscheme': x.concept_scheme}
215
            for x in self.skos_registry.get_providers() if not any([not_shown in x.get_metadata()['subject']
216
                                                                    for not_shown in ['external', 'hidden']])
217
            ]
218
219
        scheme_id = self.request.matchdict['scheme_id']
220
        label = self._read_request_param('label')
221
        requested_type = self._read_request_param('type')
222
        provider = self.skos_registry.get_provider(scheme_id)
223
        if provider:
224
            if 'atramhasis.force_display_label_language' in provider.metadata:
225
                locale = provider.metadata['atramhasis.force_display_label_language']
226
            else:
227
                locale = self.request.locale_name
228
            if label is not None:
229
                concepts = provider.find(
230
                    {'label': label, 'type': requested_type},
231
                    language=locale,
232
                    sort='label'
233
                )
234
            elif (label is None) and (requested_type is not None):
235
                concepts = provider.find(
236
                    {'type': requested_type}, language=locale, sort='label'
237
                )
238
            else:
239
                concepts = provider.get_all(language=locale, sort='label')
240
            return {
241
                'concepts': concepts,
242
                'scheme_id': scheme_id,
243
                'conceptschemes': conceptschemes,
244
                'type': requested_type,
245
                'label': label
246
            }
247
        return Response(content_type='text/plain', status_int=404)
248
249
    @view_config(route_name='locale')
250
    def set_locale_cookie(self):
251
        """
252
        Set a language cookie to remember what language a user requested.
253
        """
254
        settings = get_current_registry().settings
255
        default_lang = settings.get('pyramid.default_locale_name')
256
        available_languages = settings.get('available_languages', default_lang).split()
257
        [x.lower() for x in available_languages]
258
        language = self.request.GET.get('language', default_lang).lower()
259
        if language not in available_languages:
260
            language = default_lang
261
262
        referer = self.request.referer
263
        if referer is not None:
264
            response = HTTPFound(location=referer)
265
        else:
266
            response = HTTPFound(location=self.request.route_url('home'))
267
268
        response.set_cookie('_LOCALE_',
269
                            value=language,
270
                            max_age=31536000)  # max_age = year
271
        return response
272
273
    @audit
274
    @view_config(route_name='skosprovider.conceptscheme.csv', renderer='csv')
275
    def results_csv(self):
276
        """
277
        Download search results in CSV format, allowing further processing.
278
        """
279
        header = ['conceptscheme', 'id', 'uri', 'type', 'label', 'prefLabels', 'altLabels', 'definition', 'broader',
280
                  'narrower', 'related']
281
        rows = []
282
        scheme_id = self.request.matchdict['scheme_id']
283
        label = self._read_request_param('label')
284
        requested_type = self._read_request_param('type')
285
        provider = self.skos_registry.get_provider(scheme_id)
286
        if provider:
287
            if label is not None:
288
                concepts = self.conceptscheme_manager.find(
289
                    provider.conceptscheme_id, {'label': label, 'type': requested_type}
290
                )
291
            elif (label is None) and (requested_type is not None):
292
                concepts = self.conceptscheme_manager.find(
293
                    provider.conceptscheme_id, {'type': requested_type}
294
                )
295
            else:
296
                concepts = self.conceptscheme_manager.get_all(provider.conceptscheme_id)
297
            for concept in concepts:
298
                if concept.type == 'concept':
299
                    rows.append((
300
                        scheme_id, concept.concept_id, concept.uri, concept.type,
301
                        concept.label(self.request.locale_name).label,
302
                        labels_to_string(concept.labels, 'prefLabel'), labels_to_string(concept.labels, 'altLabel'),
303
                        get_definition(concept.notes), [c.concept_id for c in concept.broader_concepts],
304
                        [c.concept_id for c in concept.narrower_concepts],
305
                        [c.concept_id for c in concept.related_concepts]))
306
                else:
307
                    rows.append((
308
                        scheme_id, concept.concept_id, concept.uri, concept.type,
309
                        concept.label(self.request.locale_name).label,
310
                        labels_to_string(concept.labels, 'prefLabel'), labels_to_string(concept.labels, 'altLabel'),
311
                        get_definition(concept.notes), '', [c.concept_id for c in concept.members], ''))
312
        return {
313
            'header': header,
314
            'rows': rows,
315
            'filename': 'atramhasis_export'
316
        }
317
318
    @view_config(route_name='scheme_tree_html', renderer='scheme_tree.jinja2')
319
    @view_config(route_name='scheme_tree', renderer='json', accept='application/json')
320
    def results_tree_json(self):
321
        scheme_id = self.request.matchdict['scheme_id']
322
        language = self.request.params.get('language') or self.request.locale_name
323
        dicts = self.get_results_tree(scheme_id, language)
324
        if dicts:
325
            if 'text/html' not in self.request.accept:
326
                return dicts
327
            else:
328
                return {'tree': dicts}
329
        else:
330
            return Response(status_int=404)
331
332
    @tree_region.cache_on_arguments()
333
    def get_results_tree(self, scheme_id, locale):
334
        skostree = self.get_scheme(scheme_id, locale)
335
        return [self.parse_thing(thing, None) for thing in skostree]
336
337
    def get_scheme(self, scheme, locale):
338
        scheme_tree = []
339
        provider = self.skos_registry.get_provider(scheme)
340
        if provider:
341
            conceptscheme_id = provider.conceptscheme_id
342
343
            tco = self.conceptscheme_manager.get_concepts_for_scheme_tree(conceptscheme_id)
344
            tcl = self.conceptscheme_manager.get_collections_for_scheme_tree(conceptscheme_id)
345
346
            scheme_tree = sort_by_labels(tco, locale) + sort_by_labels(tcl, locale)
347
348
        return scheme_tree
349
350
    def parse_thing(self, thing, parent_tree_id):
351
        tree_id = self.create_treeid(parent_tree_id, thing.concept_id)
352
        locale = self.request.params.get('language', self.request.locale_name)
353
354
        if thing.type and thing.type == 'collection':
355
            cs = [member for member in thing.members] if hasattr(thing, 'members') else []
356
        else:
357
            cs = [c for c in thing.narrower_concepts]
358
            cs = cs + [c for c in thing.narrower_collections]
359
360
        sortedcs = sort_by_labels(cs, locale)
361
        children = [self.parse_thing(c, tree_id) for index, c in enumerate(sortedcs, 1)]
362
        dict_thing = {
363
            'id': tree_id,
364
            'concept_id': thing.concept_id,
365
            'type': thing.type,
366
            'label': thing.label(locale).label if thing.label(locale) else None,
367
            'children': children
368
        }
369
370
        return dict_thing
371
372
    @staticmethod
373
    def create_treeid(parent_tree_id, concept_id):
374
        if parent_tree_id is None:
375
            return urllib.parse.quote(str(concept_id), safe="")
376
        else:
377
            return parent_tree_id + "|" + urllib.parse.quote(str(concept_id), safe="")
378
379
380
@view_defaults(accept='application/json', renderer='json')
381
class AtramhasisListView:
382
    """
383
    This object groups list views part for the user interface.
384
    """
385
386
    def __init__(self, request):
387
        self.request = request
388
        self.skos_manager = self.request.data_managers['skos_manager']
389
        self.localizer = request.localizer
390
        self._ = TranslationStringFactory('atramhasis')
391
392
    @view_config(route_name='labeltypes')
393
    def labeltype_list_view(self):
394
        return self.get_list(LabelType)
395
396
    @view_config(route_name='notetypes')
397
    def notetype_list_view(self):
398
        return self.get_list(NoteType)
399
400
    @list_region.cache_on_arguments()
401
    def get_list(self, listtype):
402
        return [{"key": ltype.name, "label": self.localizer.translate(self._(ltype.name))}
403
                for ltype in self.skos_manager.get_by_list_type(listtype)]
404
405
406
@view_defaults(accept='text/html')
407
class AtramhasisAdminView:
408
    """
409
    This object groups HTML views part of the admin user interface.
410
    """
411
412
    def __init__(self, request):
413
        self.request = request
414
        self.logged_in = request.authenticated_userid
415
        if hasattr(request, 'skos_registry') and request.skos_registry is not None:
416
            self.skos_registry = self.request.skos_registry
417
        else:
418
            raise SkosRegistryNotFoundException()
419
420
    @view_config(route_name='admin', renderer='atramhasis:templates/admin.jinja2', permission='edit')
421
    def admin_view(self):
422
        return {'admin': None}
423
424
    @view_config(route_name='scheme_tree_invalidate', renderer='json', accept='application/json', permission='edit')
425
    def invalidate_scheme_tree(self):
426
        scheme_id = self.request.matchdict['scheme_id']
427
        invalidate_scheme_cache(scheme_id)
428
        return Response(status_int=200)
429
430
    @view_config(route_name='tree_invalidate', renderer='json', accept='application/json', permission='edit')
431
    def invalidate_tree(self):
432
        invalidate_cache()
433
        return Response(status_int=200)
434