def get_sub_location_from_request(request): try: #subl = request.REQUEST.get('sub_location', '[]') subl = dputils.get_request_var(request, 'sub_location', '[]') ret = json.loads(subl) except: ret = [] return ret
def set_fields(self, faceted_search): ''' set self.fields = array of faceted fields such that: self.fields[0] = field for X dimensions (e.g. { hi_date }) self.fields[1] = field for bands (e.g. { hi_type } ) Return True if the fields have been set properly. E.g. False if the Content Type has no possible candidate Y field ''' ret = False #faceted_search = self.faceted_search context = self.context possible_categories = self.settings['categories'] # generate the list of vertical categories # we take all the fields of the current result type # minus those not found in the global 'categories' list # minus those with vcat = False context['vcats'] = [ field for field in faceted_search.get_fields() if field.get('vcat', True) and ( not possible_categories or field['key'] in possible_categories) ] category_field = faceted_search.get_field_by_key( utils.get_request_var(self.request, 'vcat', 'hi_type')) if category_field is None: category_field = faceted_search.get_field_by_key('hi_type') if category_field is None: category_field = faceted_search.get_field_by_key('text_type') if category_field is None and context['vcats']: category_field = context['vcats'][0] if category_field: context['vcat'] = category_field fields = [self.get_x_field_key(), category_field['key']] self.fields = [ faceted_search.get_field_by_key(field) for field in fields ] ret = all(self.fields) return ret
def set_fields(self, faceted_search): ''' set self.fields = array of faceted fields such that: self.fields[0] = field for X dimensions (e.g. { hi_date }) self.fields[1] = field for bands (e.g. { hi_type } ) Return True if the fields have been set properly. E.g. False if the Content Type has no possible candidate Y field ''' ret = False #faceted_search = self.faceted_search context = self.context possible_categories = self.settings['categories'] # generate the list of vertical categories # we take all the fields of the current result type # minus those not found in the global 'categories' list # minus those with vcat = False context['vcats'] = [field for field in faceted_search.get_fields() if field.get( 'vcat', True) and (not possible_categories or field['key'] in possible_categories)] category_field = faceted_search.get_field_by_key( utils.get_request_var(self.request, 'vcat', 'hi_type')) if category_field is None: category_field = faceted_search.get_field_by_key('hi_type') if category_field is None: category_field = faceted_search.get_field_by_key('text_type') if category_field is None and context['vcats']: category_field = context['vcats'][0] if category_field: context['vcat'] = category_field fields = [ self.get_x_field_key(), category_field['key'] ] self.fields = [faceted_search.get_field_by_key( field) for field in fields] ret = all(self.fields) return ret
def process_request_api(self, request, root, path=''): t0 = datetime.now() self.options = request.GET.copy() # what to return? toreturn = dputils.get_request_var(request, 'ret', root).split(',') self.toreturn = toreturn # make sure this is called AFTER self.options is set patterns = self.get_patterns() params = path.strip('/').split('/') data = None if request.body: data = dputils.json_loads(request.body) request_pattern = None request_patterni = None if root == 'patterns': if len(params) == 1: patternid = params[0] for i in range(0, len(patterns)): if patterns[i]['id'] == patternid: request_patterni = i request_pattern = patterns[i] break # Manages modifications modified = False if request.method == 'DELETE': if request_pattern: del patterns[request_patterni] modified = True if request.method == 'PUT': if request_pattern: if data['updated'] < request_pattern['updated']: self.add_message( 'Change cancelled (this pattern was modified in the meantime)', 'error') else: data['updated'] = dputils.now() reorder = (patterns[i]['key'] != data['key']) patterns[i] = data self.auto_correct_pattern(patterns[i]) if reorder: self.auto_correct_pattern_orders_and_numbers() modified = True if self.move_pattern(request, root, data): modified = True # add new pattern if missing and client asked for it # TODO: not restful to change data on GET! # turn this into separate POST request. if 1: title_new = 'New Pattern' if not patterns or patterns[-1]['title'] != title_new: print 'ADD new pattern' patterns.append({ 'id': dputils.get_short_uid(), 'key': slugify(unicode(title_new)), 'title': title_new, 'updated': dputils.now(), 'pattern': '', }) modified = True if root == 'segunits': if request.method == 'POST': if data: self.options.update(data) self.get_segunits() if modified: self.validate_patterns() self.save_patterns() pattern_errors = sum( [1 for pattern in self.patterns if 'error' in pattern]) if pattern_errors: self.add_message('%s invalid patterns' % pattern_errors, 'warn') ret = {} if 'patterns' in toreturn: ret['patterns'] = self.get_patterns() if 'segunits' in toreturn: ret['segunits'] = self.get_json_from_segunits(toreturn) if 'variants' in toreturn: ret['variants'] = self.variants if 'stats' in toreturn: self.stats['duration_response'] = (datetime.now() - t0).total_seconds() ret['stats'] = self.stats ret['messages'] = self.messages ret['format'] = self.options.get('format', 'json') if ret['format'] == 'csv': ret['csv'] = self.get_csv_from_segunits() return ret
def update_text_image_link(request, image, ret): if ret is None: ret = {} ret['newids'] = {} from digipal.models import has_edit_permission, Annotation if not has_edit_permission(request, Annotation): set_message(ret, 'Insufficient rights to edit annotations', 'error') return ret # print 'TEXT IMAGE LINK: image #%s' % image.id links = dputils.get_request_var(request, 'links', None) if links: ''' links = [ [ [["", "clause"], ["type", "address"]], {"type":"Feature","geometry":{"type":"Polygon","coordinates":[[[270,-1632],[270,-984],[3006,-984],[3006,-1632],[270,-1632]]]},"properties":null} ], [...] ] ''' for link in json.loads(links): # print link attrs, geojson = link[0], link[1] clientid = (geojson.get('properties', {}) or {}).pop('clientid', '') serverid = geojson.pop('id', None) action = geojson.pop('action', 'update') # 1. find the annotation if not clientid and not serverid: raise Exception( 'Cannot find annotation, need either "id" or "clientid"') filter = {} if serverid: filter['id'] = serverid else: filter['clientid'] = clientid annotation = Annotation.objects.filter(**filter).first() # 2. delete or create annotation if action == 'deleted': if annotation: # print 'delete annotation' annotation.delete() annotation = None else: # create annotation if not annotation: if serverid: raise Exception( 'Cannot find annotation by server id %s' % serverid) # print 'create annotation' author = request.user annotation = Annotation( clientid=clientid, image=image, author=author, type='text') # update annotation and link # print 'update annotation' annotation.set_geo_json_from_dict(geojson) annotation.save() if not serverid: ret['newids'][clientid] = annotation.id # update the text-annotation from digipal_text.models import TextAnnotation # text_annotation = TextAnnotation(annotation=annotation, element=json.dumps(attrs)) # TODO: assume a single element per annotation for the moment text_annotation = TextAnnotation.objects.filter( annotation=annotation).first() if not attrs: # delete it if text_annotation: # print 'delete link' text_annotation.delete() else: if not text_annotation: # print 'create link' text_annotation = TextAnnotation(annotation=annotation) # print 'update link' text_annotation.elementid = json.dumps(attrs) text_annotation.save() return ret
def text_api_view_image(request, item_partid, content_type, location_type, location, content_type_record, max_size=None, ignore_sublocation=False): ''' location = an identifier for the image. Relative to the item part '#1000' => image with id = 1000 '1r' => image with locus = 1r attached to selected item part ''' ret = {} from digipal.models import Image # ## # The sub_location can override or contradict (location_type, location) # e.g. text: whole -> image: synced with text # user clicks on entry in the text => we need to fetch that part if not ignore_sublocation: sub_location = get_sub_location_from_request(request) new_address = get_address_from_sub_location(sub_location) if new_address: location_type, location = new_address # ## request.visible_images = None visible_images = None def get_visible_images(item_partid, request, visible_images=None): if visible_images is None: ret = Image.objects.filter(item_part_id=item_partid) ret = Image.filter_permissions_from_request(ret, request, True) ret = Image.sort_query_set_by_locus(ret) visible_images = ret return visible_images # return the locus of the images under this item part # return #ID for images which have no locus if location_type == 'default' or utils.get_int_from_request_var(request, 'load_locations'): recs = Image.sort_query_set_by_locus(get_visible_images( item_partid, request, visible_images)).values_list('locus', 'id') ret['locations'] = OrderedDict() if recs: ret['locations']['locus'] = ['%s' % (rec[0] or '#%s' % rec[1]) for rec in recs] # resolve 'default' location request location_type, location = resolve_default_location( location_type, location, ret) # find the image image = find_image(request, item_partid, location_type, location, get_visible_images, visible_images) if not image: set_message(ret, 'Image not found') ret['location_type'] = location_type ret['location'] = location else: if location_type == 'entry': # user asked for entry, we can only return a locus # so we add the entry as a sublocation ret['sub_location'] = ['', 'location'], [ 'loctype', 'entry'], ['@text', location] if request.method == 'POST': # deal with writing annotations update_text_image_link(request, image, ret) else: # display settings ret['presentation_options'] = [ ["highlight", "Highlight Text Units"]] # image dimensions options = {} layout = dputils.get_request_var(request, 'layout', '') if layout == 'width': options['width'] = dputils.get_request_var( request, 'width', '100') # we return the location of the returned fragment # this may not be the same as the requested location # e.g. if the requested location is 'default' we resolve it # ret['location_type'] = location_type ret['location_type'] = 'locus' ret['location'] = image.locus if image else location if image: # ret['content'] = iip_img(image, **options) ret['zoomify_url'] = image.zoomify() ret['width'] = image.width ret['height'] = image.height # add all the elements found on that page in the transcription # ret['text_elements'] = get_text_elements_from_image(request, item_partid, getattr(settings, 'TEXT_IMAGE_MASTER_CONTENT_TYPE', 'transcription'), location_type, location) ret['text_elements'] = get_text_elements_from_image(request, item_partid, getattr( settings, 'TEXT_IMAGE_MASTER_CONTENT_TYPE', 'transcription'), 'locus', get_locus_from_location(location_type, location)) # print ret['text_elements'] # add all the non-graph annotations ret.update(get_annotations_from_image(image)) return ret
def text_api_view(request, item_partid, content_type, location_type=u'default', location=''): format = dputils.get_request_var(request, 'format', 'html').strip().lower() if request.is_ajax(): format = 'json' from digipal.utils import is_model_visible if not is_model_visible('textcontentxml', request): raise Http404('Text view not enabled') max_size = MAX_FRAGMENT_SIZE if format == 'json' else None response = None # DELEGATE TO A CUSTOM VIEW FOR THE GIVEN CONTENT TYPE # Look up the content_type in the function name # e.g. content_type = image => text_api_view_image text_api_view_content_type = globals().get( 'text_api_view_' + content_type, None) content_type_record = None if not text_api_view_content_type: # Look up the content_type in the TextContentType table # e.g. content_type = translation or transcription, we assume it must # be a TextContentXML from digipal_text.models import TextContentType content_type_record = TextContentType.objects.filter( slug=content_type).first() if content_type_record: text_api_view_content_type = text_api_view_text if text_api_view_content_type: response = text_api_view_content_type( request, item_partid, content_type, location_type, location, content_type_record, max_size=max_size) # we didn't find a custom function for this content type if response is None: response = {'status': 'error', 'message': 'Invalid Content Type (%s)' % content_type} # If sublocation is not defined by specific function we just return # the desired sublocation. # If specific function want to remove they can set it to [] response['sub_location'] = response.get( 'sub_location', get_sub_location_from_request(request)) if not response['sub_location']: del response['sub_location'] # HANDLE location_type = sync # We take care of syncing logic here, customisations don't need to worry # about it. # Sync in => sync out. For UI/client logic purpose. # If we don't return sync, client assumes we can't support sync. # Only exception is in resolve_default_location() below. if response.get('location_type', '') == 'sync': response['location_type'] = location_type response['location'] = location response['content'] = 'Synchronising panel...' set_message(response, 'Synchronising panel...', '') ret = None # RESPONSE FORMATTING if format == 'json': ret = HttpResponse(json.dumps(response), content_type='application/json') if format == 'html': context = {'response': response} context['display_classes'] = ' '.join( (dputils.get_request_var(request, 'ds', '').split(','))) context['content_type_key'] = content_type ret = render(request, 'digipal_text/text_view.html', context) if format == 'tei': tei = get_tei_from_text_response(response, item_partid, content_type) ret = HttpResponse(tei, content_type='text/xml; charset=utf-8') if format == 'plain': plain_text = dputils.get_plain_text_from_xmltext( response.get('content', '')) ret = HttpResponse( plain_text, content_type='text/plain; charset=utf-8') if not ret: raise Exception('Unknown output format: "%s"' % format) return ret
for ltype in ['entry', 'locus']: ret['locations'][ltype] = [] if text_content_xml.content: for entry in re.findall(ur'(?:<span data-dpt="location" data-dpt-loctype="' + ltype + '">)([^<]+)', text_content_xml.content): ret['locations'][ltype].append(entry) if not ret['locations'][ltype]: del ret['locations'][ltype] # resolve 'default' location request location_type, location = resolve_default_location( location_type, location, ret) # 3. Save the user fragment new_fragment = None if request: new_fragment = dputils.get_request_var(request, 'content', None) convert = utils.get_int_from_request_var(request, 'convert') save_copy = utils.get_int_from_request_var(request, 'save_copy') ret['content_status'] = text_content_xml.status.id extent = get_fragment_extent(record_content, location_type, location) ret['message'] = '' dry_run = 0 if extent: # make sure we compare with None, as '' is a different case if new_fragment is not None: ret['message'] = 'Content saved' # insert user fragment
def update_text_image_link(request, image, ret): if ret is None: ret = {} ret['newids'] = {} from digipal.models import has_edit_permission, Annotation if not has_edit_permission(request, Annotation): set_message(ret, 'Insufficient rights to edit annotations', 'error') return ret # print 'TEXT IMAGE LINK: image #%s' % image.id links = dputils.get_request_var(request, 'links', None) if links: ''' links = [ [ [["", "clause"], ["type", "address"]], {"type":"Feature","geometry":{"type":"Polygon","coordinates":[[[270,-1632],[270,-984],[3006,-984],[3006,-1632],[270,-1632]]]},"properties":null} ], [...] ] ''' for link in json.loads(links): # print link attrs, geojson = link[0], link[1] clientid = (geojson.get('properties', {}) or {}).pop('clientid', '') serverid = geojson.pop('id', None) action = geojson.pop('action', 'update') # 1. find the annotation if not clientid and not serverid: raise Exception( 'Cannot find annotation, need either "id" or "clientid"') filter = {} if serverid: filter['id'] = serverid else: filter['clientid'] = clientid annotation = Annotation.objects.filter(**filter).first() # 2. delete or create annotation if action == 'deleted': if annotation: # print 'delete annotation' annotation.delete() annotation = None else: # create annotation if not annotation: if serverid: raise Exception( 'Cannot find annotation by server id %s' % serverid) # print 'create annotation' author = request.user annotation = Annotation(clientid=clientid, image=image, author=author, type='text') # update annotation and link # print 'update annotation' annotation.set_geo_json_from_dict(geojson) annotation.save() if not serverid: ret['newids'][clientid] = annotation.id # update the text-annotation from digipal_text.models import TextAnnotation # text_annotation = TextAnnotation(annotation=annotation, element=json.dumps(attrs)) # TODO: assume a single element per annotation for the moment text_annotation = TextAnnotation.objects.filter( annotation=annotation).first() if not attrs: # delete it if text_annotation: # print 'delete link' text_annotation.delete() else: if not text_annotation: # print 'create link' text_annotation = TextAnnotation(annotation=annotation) # print 'update link' text_annotation.elementid = json.dumps(attrs) text_annotation.save() return ret
def text_api_view_image(request, item_partid, content_type, location_type, location, content_type_record, max_size=None, ignore_sublocation=False): ''' location = an identifier for the image. Relative to the item part '#1000' => image with id = 1000 '1r' => image with locus = 1r attached to selected item part ''' ret = {} from digipal.models import Image # ## # The sub_location can override or contradict (location_type, location) # e.g. text: whole -> image: synced with text # user clicks on entry in the text => we need to fetch that part if not ignore_sublocation: sub_location = get_sub_location_from_request(request) new_address = get_address_from_sub_location(sub_location) if new_address: location_type, location = new_address # ## request.visible_images = None visible_images = None def get_visible_images(item_partid, request, visible_images=None): if visible_images is None: ret = Image.objects.filter(item_part_id=item_partid) ret = Image.filter_permissions_from_request(ret, request, True) ret = Image.sort_query_set_by_locus(ret) visible_images = ret return visible_images # return the locus of the images under this item part # return #ID for images which have no locus if location_type == 'default' or utils.get_int_from_request_var( request, 'load_locations'): recs = Image.sort_query_set_by_locus( get_visible_images(item_partid, request, visible_images)).values_list('locus', 'id') ret['locations'] = OrderedDict() if recs: ret['locations']['locus'] = [ '%s' % (rec[0] or '#%s' % rec[1]) for rec in recs ] # resolve 'default' location request location_type, location = resolve_default_location(location_type, location, ret) # find the image image = find_image(request, item_partid, location_type, location, get_visible_images, visible_images) if not image: set_message(ret, 'Image not found') ret['location_type'] = location_type ret['location'] = location else: if location_type == 'entry': # user asked for entry, we can only return a locus # so we add the entry as a sublocation ret['sub_location'] = ['', 'location'], ['loctype', 'entry'], ['@text', location] if request.method == 'POST': # deal with writing annotations update_text_image_link(request, image, ret) else: # display settings ret['presentation_options'] = [[ "highlight", "Highlight Text Units" ]] # image dimensions options = {} layout = dputils.get_request_var(request, 'layout', '') if layout == 'width': options['width'] = dputils.get_request_var( request, 'width', '100') # we return the location of the returned fragment # this may not be the same as the requested location # e.g. if the requested location is 'default' we resolve it # ret['location_type'] = location_type ret['location_type'] = 'locus' ret['location'] = image.locus if image else location if image: # ret['content'] = iip_img(image, **options) ret['zoomify_url'] = image.zoomify() ret['width'] = image.width ret['height'] = image.height # add all the elements found on that page in the transcription # ret['text_elements'] = get_text_elements_from_image(request, item_partid, getattr(settings, 'TEXT_IMAGE_MASTER_CONTENT_TYPE', 'transcription'), location_type, location) ret['text_elements'] = get_text_elements_from_image( request, item_partid, getattr(settings, 'TEXT_IMAGE_MASTER_CONTENT_TYPE', 'transcription'), 'locus', get_locus_from_location(location_type, location)) # print ret['text_elements'] # add all the non-graph annotations ret.update(get_annotations_from_image(image)) return ret
def text_api_view(request, item_partid, content_type, location_type=u'default', location=''): format = dputils.get_request_var(request, 'format', 'html').strip().lower() if request.is_ajax(): format = 'json' from digipal.utils import is_model_visible if not is_model_visible('textcontentxml', request): raise Http404('Text view not enabled') max_size = MAX_FRAGMENT_SIZE if format == 'json' else None response = None # DELEGATE TO A CUSTOM VIEW FOR THE GIVEN CONTENT TYPE # Look up the content_type in the function name # e.g. content_type = image => text_api_view_image text_api_view_content_type = globals().get('text_api_view_' + content_type, None) content_type_record = None if not text_api_view_content_type: # Look up the content_type in the TextContentType table # e.g. content_type = translation or transcription, we assume it must # be a TextContentXML from digipal_text.models import TextContentType content_type_record = TextContentType.objects.filter( slug=content_type).first() if content_type_record: text_api_view_content_type = text_api_view_text if text_api_view_content_type: response = text_api_view_content_type(request, item_partid, content_type, location_type, location, content_type_record, max_size=max_size) # we didn't find a custom function for this content type if response is None: response = { 'status': 'error', 'message': 'Invalid Content Type (%s)' % content_type } # If sublocation is not defined by specific function we just return # the desired sublocation. # If specific function want to remove they can set it to [] response['sub_location'] = response.get( 'sub_location', get_sub_location_from_request(request)) if not response['sub_location']: del response['sub_location'] # HANDLE location_type = sync # We take care of syncing logic here, customisations don't need to worry # about it. # Sync in => sync out. For UI/client logic purpose. # If we don't return sync, client assumes we can't support sync. # Only exception is in resolve_default_location() below. if response.get('location_type', '') == 'sync': response['location_type'] = location_type response['location'] = location response['content'] = 'Synchronising panel...' set_message(response, 'Synchronising panel...', '') ret = None # RESPONSE FORMATTING if format == 'json': ret = HttpResponse(json.dumps(response), content_type='application/json') if format == 'html': context = {'response': response} context['display_classes'] = ' '.join( (dputils.get_request_var(request, 'ds', '').split(','))) context['content_type_key'] = content_type ret = render(request, 'digipal_text/text_view.html', context) if format == 'tei': tei = get_tei_from_text_response(response, item_partid, content_type) ret = HttpResponse(tei, content_type='text/xml; charset=utf-8') if format == 'plain': plain_text = dputils.get_plain_text_from_xmltext( response.get('content', '')) ret = HttpResponse(plain_text, content_type='text/plain; charset=utf-8') if not ret: raise Exception('Unknown output format: "%s"' % format) return ret
if text_content_xml.content: for entry in re.findall( ur'(?:<span data-dpt="location" data-dpt-loctype="' + ltype + '">)([^<]+)', text_content_xml.content): ret['locations'][ltype].append(entry) if not ret['locations'][ltype]: del ret['locations'][ltype] # resolve 'default' location request location_type, location = resolve_default_location(location_type, location, ret) # 3. Save the user fragment new_fragment = None if request: new_fragment = dputils.get_request_var(request, 'content', None) convert = utils.get_int_from_request_var(request, 'convert') save_copy = utils.get_int_from_request_var(request, 'save_copy') ret['content_status'] = text_content_xml.status.id extent = get_fragment_extent(record_content, location_type, location) ret['message'] = '' dry_run = 0 if extent: # make sure we compare with None, as '' is a different case if new_fragment is not None: ret['message'] = 'Content saved' # insert user fragment
def process_request_api(self, request, root, path=''): t0 = datetime.now() self.options = request.GET.copy() # what to return? toreturn = dputils.get_request_var(request, 'ret', root).split(',') self.toreturn = toreturn # make sure this is called AFTER self.options is set patterns = self.get_patterns() params = path.strip('/').split('/') data = None if request.body: data = dputils.json_loads(request.body) request_pattern = None request_patterni = None if root == 'patterns': if len(params) == 1: patternid = params[0] for i in range(0, len(patterns)): if patterns[i]['id'] == patternid: request_patterni = i request_pattern = patterns[i] break # Manages modifications modified = False if request.method == 'DELETE': if request_pattern: del patterns[request_patterni] modified = True if request.method == 'PUT': if request_pattern: if data['updated'] < request_pattern['updated']: self.add_message( 'Change cancelled (this pattern was modified in the meantime)', 'error') else: data['updated'] = dputils.now() reorder = (patterns[i]['key'] != data['key']) patterns[i] = data self.auto_correct_pattern(patterns[i]) if reorder: self.auto_correct_pattern_orders_and_numbers() modified = True if self.move_pattern(request, root, data): modified = True # add new pattern if missing and client asked for it # TODO: not restful to change data on GET! # turn this into separate POST request. if 1: title_new = 'New Pattern' if not patterns or patterns[-1]['title'] != title_new: print 'ADD new pattern' patterns.append({ 'id': dputils.get_short_uid(), 'key': slugify(unicode(title_new)), 'title': title_new, 'updated': dputils.now(), 'pattern': '', }) modified = True if root == 'segunits': if request.method == 'POST': if data: self.options.update(data) self.get_segunits() if modified: self.validate_patterns() self.save_patterns() pattern_errors = sum( [1 for pattern in self.patterns if 'error' in pattern]) if pattern_errors: self.add_message('%s invalid patterns' % pattern_errors, 'warn') ret = {} if 'patterns' in toreturn: ret['patterns'] = self.get_patterns() if 'segunits' in toreturn: ret['segunits'] = self.get_json_from_segunits(toreturn) if 'variants' in toreturn: ret['variants'] = self.variants if 'stats' in toreturn: self.stats['duration_response'] = ( datetime.now() - t0).total_seconds() ret['stats'] = self.stats ret['messages'] = self.messages ret['format'] = self.options.get('format', 'json') if ret['format'] == 'csv': ret['csv'] = self.get_csv_from_segunits() return ret