Example #1
0
 def test_legacy_export_marcxml(self):
     """Record - legacy export marxml."""
     # FIXME: use a better way to compare
     from invenio.legacy.bibrecord import create_record, records_identical
     blob = '''
         <record>
           <controlfield tag="001">8</controlfield>
           <datafield tag="100" ind1=" " ind2=" ">
             <subfield code="a">Efstathiou, G P</subfield>
             <subfield code="u">Cambridge University</subfield>
           </datafield>
           <datafield tag="245" ind1=" " ind2=" ">
             <subfield code="a">Title</subfield>
             <subfield code="b">SubTitle</subfield>
           </datafield>
           <datafield tag="700" ind1=" " ind2=" ">
            <subfield code="a">Lasenby, A N</subfield>
           </datafield>
           <datafield tag="980" ind1=" " ind2=" ">
             <subfield code="a">Articles</subfield>
           </datafield>
         </record>
     '''
     rec = Record.create(blob, master_format='marc', namespace='testsuite')
     recstruct, _, _ = create_record(blob)
     json_recstruct, _, _ = create_record(rec.legacy_export_as_marc())
     self.assertTrue(records_identical(json_recstruct, recstruct,
                                       ignore_subfield_order=True))
Example #2
0
 def test_legacy_export_marcxml(self):
     """Record - legacy export marxml."""
     # FIXME: use a better way to compare
     from invenio.legacy.bibrecord import create_record, records_identical
     blob = '''
         <record>
           <controlfield tag="001">8</controlfield>
           <datafield tag="100" ind1=" " ind2=" ">
             <subfield code="a">Efstathiou, G P</subfield>
             <subfield code="u">Cambridge University</subfield>
           </datafield>
           <datafield tag="245" ind1=" " ind2=" ">
             <subfield code="a">Title</subfield>
             <subfield code="b">SubTitle</subfield>
           </datafield>
           <datafield tag="700" ind1=" " ind2=" ">
            <subfield code="a">Lasenby, A N</subfield>
           </datafield>
           <datafield tag="980" ind1=" " ind2=" ">
             <subfield code="a">Articles</subfield>
           </datafield>
         </record>
     '''
     rec = Record.create(blob, master_format='marc', namespace='testsuite')
     recstruct, _, _ = create_record(blob)
     json_recstruct, _, _ = create_record(rec.legacy_export_as_marc())
     self.assertTrue(records_identical(json_recstruct, recstruct,
                                       ignore_subfield_order=True))
Example #3
0
def compare_revisions(rev1, rev2, recid):
    """Compare two revisions of a record."""
    from invenio.legacy.bibedit.engine import (get_marcxml_of_revision_id,
                                               re_revdate_split)
    from invenio.legacy.bibrecord.xmlmarc2textmarc import create_marc_record
    from invenio.legacy.bibrecord import create_record
    from invenio.legacy.bibedit.utils import record_revision_exists
    from invenio.utils.text import show_diff
    person1 = ""
    person2 = ""

    if (not record_revision_exists(recid, rev1)) or \
       (not record_revision_exists(recid, rev2)):
        return render_template("editor/revision_comparison_error.html")
    else:
        xml1 = get_marcxml_of_revision_id(recid, rev1)
        xml2 = get_marcxml_of_revision_id(recid, rev2)
        # Create MARC representations of the records
        marc1 = create_marc_record(
            create_record(xml1)[0], '', {
                "text-marc": 1,
                "aleph-marc": 0
            })
        marc2 = create_marc_record(
            create_record(xml2)[0], '', {
                "text-marc": 1,
                "aleph-marc": 0
            })
        comparison = show_diff(
            marc1,
            marc2,
            prefix="<pre>",
            suffix="</pre>",
            prefix_removed='<strong class="diff_field_deleted">',
            suffix_removed='</strong>',
            prefix_added='<strong class="diff_field_added">',
            suffix_added='</strong>')
        job_date1 = "%s-%s-%s %s:%s:%s" % re_revdate_split.search(
            rev1).groups()
        job_date2 = "%s-%s-%s %s:%s:%s" % re_revdate_split.search(
            rev2).groups()
        # Getting the author of each revision
        info1 = get_info_of_record_revision(recid, job_date1)
        info2 = get_info_of_record_revision(recid, job_date2)
        if info1:
            person1 = info1[0][1]
        if info2:
            person2 = info2[0][1]

        ctx = {
            "job_date1": job_date1,
            "job_date2": job_date2,
            "person1": person1,
            "person2": person2,
            "comparison": comparison
        }

        return render_template("editor/revision_comparison.html", **ctx)
def compare_references(test, a, b):
    from invenio.legacy.bibrecord import create_record, record_xml_output, \
        record_delete_field
    ## Let's normalize records to remove the Invenio refextract signature
    a = create_record(a)[0]
    b = create_record(b)[0]
    record_delete_field(a, '999', 'C', '6')
    a = record_xml_output(a)
    b = record_xml_output(b)
    test.assertEqual(a, b)
Example #5
0
def compare_references(test, a, b):
    from invenio.legacy.bibrecord import create_record, record_xml_output, \
        record_delete_field
    ## Let's normalize records to remove the Invenio refextract signature
    a = create_record(a)[0]
    b = create_record(b)[0]
    record_delete_field(a, '999', 'C', '6')
    a = record_xml_output(a)
    b = record_xml_output(b)
    test.assertEqual(a, b)
Example #6
0
def _get_record_slave(recid, result, mode=None, uid=None):
    """Check if record exists and return it in dictionary format.
       If any kind of error occurs returns None.
       If mode=='revision' then recid parameter is considered as revid."""
    record = None
    if recid == 'none':
        mode = 'none'
    if mode == 'recid':
        record_status = record_exists(recid)
        #check for errors
        if record_status == 0:
            result['resultCode'], result[
                'resultText'] = 1, 'Non-existent record: %s' % recid
        elif record_status == -1:
            result['resultCode'], result[
                'resultText'] = 1, 'Deleted record: %s' % recid
        elif record_locked_by_queue(recid):
            result['resultCode'], result[
                'resultText'] = 1, 'Record %s locked by queue' % recid
        else:
            record = create_record(print_record(recid, 'xm'))[0]

    elif mode == 'tmpfile':
        file_path = '%s_%s.xml' % (_get_file_path(
            recid, uid), cfg['CFG_BIBEDIT_TO_MERGE_SUFFIX'])
        if not os.path.isfile(file_path):  #check if file doesn't exist
            result['resultCode'], result[
                'resultText'] = 1, 'Temporary file doesnt exist'
        else:  #open file
            tmpfile = open(file_path, 'r')
            record = create_record(tmpfile.read())[0]
            tmpfile.close()

    elif mode == 'revision':
        if revision_format_valid_p(recid):
            marcxml = get_marcxml_of_revision_id(recid)
            if marcxml:
                record = create_record(marcxml)[0]
            else:
                result['resultCode'], result[
                    'resultText'] = 1, 'The specified revision does not exist'
        else:
            result['resultCode'], result[
                'resultText'] = 1, 'Invalid revision id'

    elif mode == 'none':
        return {}

    else:
        result['resultCode'], result[
            'resultText'] = 1, 'Invalid record mode for record2'
    record_order_subfields(record)
    return record
Example #7
0
def compare_revisions(rev1, rev2, recid):
    """Compare two revisions of a record."""
    from invenio.legacy.bibedit.engine import (get_marcxml_of_revision_id,
                                               re_revdate_split)
    from invenio.legacy.bibrecord.xmlmarc2textmarc import create_marc_record
    from invenio.legacy.bibrecord import create_record
    from invenio.legacy.bibedit.utils import record_revision_exists
    from invenio.utils.text import show_diff
    person1 = ""
    person2 = ""

    if (not record_revision_exists(recid, rev1)) or \
       (not record_revision_exists(recid, rev2)):
        return render_template("editor/revision_comparison_error.html")
    else:
        xml1 = get_marcxml_of_revision_id(recid, rev1)
        xml2 = get_marcxml_of_revision_id(recid, rev2)
        # Create MARC representations of the records
        marc1 = create_marc_record(
            create_record(xml1)[0], '', {"text-marc": 1, "aleph-marc": 0})
        marc2 = create_marc_record(
            create_record(xml2)[0], '', {"text-marc": 1, "aleph-marc": 0})
        comparison = show_diff(
            marc1,
            marc2,
            prefix="<pre>", suffix="</pre>",
            prefix_removed='<strong class="diff_field_deleted">',
            suffix_removed='</strong>',
            prefix_added='<strong class="diff_field_added">',
            suffix_added='</strong>')
        job_date1 = "%s-%s-%s %s:%s:%s" % re_revdate_split.search(rev1
                                                                  ).groups()
        job_date2 = "%s-%s-%s %s:%s:%s" % re_revdate_split.search(rev2
                                                                  ).groups()
        # Getting the author of each revision
        info1 = get_info_of_record_revision(recid, job_date1)
        info2 = get_info_of_record_revision(recid, job_date2)
        if info1:
            person1 = info1[0][1]
        if info2:
            person2 = info2[0][1]

        ctx = {
            "job_date1": job_date1,
            "job_date2": job_date2,
            "person1": person1,
            "person2": person2,
            "comparison": comparison
        }

        return render_template("editor/revision_comparison.html", **ctx)
Example #8
0
    def doilookup(self, req, form):
        """
        Returns the metadata from the crossref website based on the DOI.
        """
        args = wash_urlargd(form, {'doi': (str, '')})
        response = defaultdict(list)
        if args['doi']:
            doi = args['doi']
            try:
                marcxml_template = get_marcxml_for_doi(doi)
            except CrossrefError:
                # Just ignore Crossref errors
                pass
            else:
                record = create_record(marcxml_template)[0]
                if record:
                    # We need to convert this record structure to a simple dictionary
                    for key, value in record.items(
                    ):  # key, value = (773, [([('0', 'PER:64142'), ...], ' ', ' ', '', 47)])
                        for val in value:  # val = ([('0', 'PER:64142'), ...], ' ', ' ', '', 47)
                            ind1 = val[1].replace(" ", "_")
                            ind2 = val[2].replace(" ", "_")
                            for (k, v) in val[0]:  # k, v = ('0', 'PER:5409')
                                response[key + ind1 + ind2 + k].append(v)
            # The output dictionary is something like:
            # {"100__a": ['Smith, J.'],
            #  "700__a": ['Anderson, J.', 'Someoneelse, E.'],
            #  "700__u": ['University1', 'University2']}

        # return dictionary as JSON
        return json.dumps(response)
Example #9
0
def merge_record_with_template(rec, template_name, is_hp_record=False):
    """ Extend the record rec with the contents of the template and return it"""
    template = get_record_template(template_name)
    if not template:
        return
    template_bibrec = create_record(template)[0]
    # if the record is a holding pen record make all subfields volatile
    if is_hp_record:
        record_make_all_subfields_volatile(template_bibrec)
    for field_tag in template_bibrec:
        if not record_has_field(rec, field_tag):
            for field_instance in template_bibrec[field_tag]:
                record_add_field(rec,
                                 field_tag,
                                 field_instance[1],
                                 field_instance[2],
                                 subfields=field_instance[0])
        else:
            for template_field_instance in template_bibrec[field_tag]:
                subfield_codes_template = field_get_subfield_codes(
                    template_field_instance)
                for field_instance in rec[field_tag]:
                    subfield_codes = field_get_subfield_codes(field_instance)
                    for code in subfield_codes_template:
                        if code not in subfield_codes:
                            field_add_subfield(
                                field_instance, code,
                                field_get_subfield_values(
                                    template_field_instance, code)[0])
    record_order_subfields(rec)
    return rec
Example #10
0
def replace_references(recid, uid=None, txt=None, url=None):
    """Replace references for a record

    The record itself is not updated, the marc xml of the document with updated
    references is returned

    Parameters:
    * recid: the id of the record
    * txt: references in text mode
    * inspire: format of ther references
    """
    # Parse references
    if txt is not None:
        references_xml = extract_references_from_string_xml(txt, is_only_references=True)
    elif url is not None:
        references_xml = extract_references_from_url_xml(url)
    else:
        references_xml = extract_references_from_record_xml(recid)
    references = create_record(references_xml)

    dummy1, dummy2, record, dummy3, dummy4, dummy5, dummy6 = get_cache_contents(recid, uid)
    out_xml = None

    references_to_add = record_get_field_instances(references[0], tag="999", ind1="C", ind2="5")
    refextract_status = record_get_field_instances(references[0], tag="999", ind1="C", ind2="6")

    if references_to_add:
        # Replace 999 fields
        record_delete_fields(record, "999")
        record_add_fields(record, "999", references_to_add)
        record_add_fields(record, "999", refextract_status)
        # Update record references
        out_xml = record_xml_output(record)

    return out_xml
Example #11
0
def replace_references(recid):
    """Replace references for a record

    The record itself is not updated, the marc xml of the document with updated
    references is returned

    Parameters:
    * recid: the id of the record
    """
    # Parse references
    references_xml = extract_references_from_record_xml(recid)
    references = create_record(references_xml)
    # Record marc xml
    record = get_record(recid)

    if references[0]:
        fields_to_add = record_get_field_instances(references[0],
                                                   tag='999',
                                                   ind1='%',
                                                   ind2='%')
        # Replace 999 fields
        record_delete_fields(record, '999')
        record_add_fields(record, '999', fields_to_add)
        # Update record references
        out_xml = record_xml_output(record)
    else:
        out_xml = None

    return out_xml
Example #12
0
    def test_legacy_create_recstruct(self):
        """Record - create recstruct."""
        from invenio.legacy.bibrecord import create_record, records_identical

        blob = """
            <record>
              <controlfield tag="001">8</controlfield>
              <datafield tag="100" ind1=" " ind2=" ">
                <subfield code="a">Efstathiou, G P</subfield>
                <subfield code="u">Cambridge University</subfield>
              </datafield>
              <datafield tag="245" ind1=" " ind2=" ">
                <subfield code="a">Title</subfield>
                <subfield code="b">SubTitle</subfield>
              </datafield>
              <datafield tag="700" ind1=" " ind2=" ">
               <subfield code="a">Lasenby, A N</subfield>
              </datafield>
              <datafield tag="980" ind1=" " ind2=" ">
                <subfield code="a">Articles</subfield>
              </datafield>
            </record>
        """
        rec = Record.create(blob, master_format="marc", namespace="testsuite")
        json_recstruct = rec.legacy_create_recstruct()
        recstruct, _, _ = create_record(blob)
        self.assertTrue(records_identical(json_recstruct, recstruct, ignore_subfield_order=True))
Example #13
0
def merge_record_with_template(rec, template_name, is_hp_record=False):
    """ Extend the record rec with the contents of the template and return it"""
    template = get_record_template(template_name)
    if not template:
        return
    template_bibrec = create_record(template)[0]
    # if the record is a holding pen record make all subfields volatile
    if is_hp_record:
        record_make_all_subfields_volatile(template_bibrec)
    for field_tag in template_bibrec:
        if not record_has_field(rec, field_tag):
            for field_instance in template_bibrec[field_tag]:
                record_add_field(rec, field_tag, field_instance[1], field_instance[2], subfields=field_instance[0])
        else:
            for template_field_instance in template_bibrec[field_tag]:
                subfield_codes_template = field_get_subfield_codes(template_field_instance)
                for field_instance in rec[field_tag]:
                    subfield_codes = field_get_subfield_codes(field_instance)
                    for code in subfield_codes_template:
                        if code not in subfield_codes:
                            field_add_subfield(
                                field_instance, code, field_get_subfield_values(template_field_instance, code)[0]
                            )
    record_order_subfields(rec)
    return rec
Example #14
0
    def doilookup(self, req, form):
        """
        Returns the metadata from the crossref website based on the DOI.
        """
        args = wash_urlargd(form, {
            'doi': (str, '')})
        response = defaultdict(list)
        if args['doi']:
            doi = args['doi']
            try:
                marcxml_template = get_marcxml_for_doi(doi)
            except CrossrefError:
                # Just ignore Crossref errors
                pass
            else:
                record = create_record(marcxml_template)[0]
                if record:
                    # We need to convert this record structure to a simple dictionary
                    for key, value in record.items():  # key, value = (773, [([('0', 'PER:64142'), ...], ' ', ' ', '', 47)])
                        for val in value:  # val = ([('0', 'PER:64142'), ...], ' ', ' ', '', 47)
                            ind1 = val[1].replace(" ", "_")
                            ind2 = val[2].replace(" ", "_")
                            for (k, v) in val[0]:  # k, v = ('0', 'PER:5409')
                                response[key+ind1+ind2+k].append(v)
            # The output dictionary is something like:
            # {"100__a": ['Smith, J.'],
            #  "700__a": ['Anderson, J.', 'Someoneelse, E.'],
            #  "700__u": ['University1', 'University2']}

        # return dictionary as JSON
        return json.dumps(response)
Example #15
0
def cli_clean_revisions(recid, dry_run=True, verbose=True):
    """Clean revisions of the given recid, by removing duplicate revisions
    that do not change the content of the record."""
    if recid == '*':
        recids = intbitset(run_sql("SELECT DISTINCT id_bibrec FROM hstRECORD"))
    else:
        try:
            recids = [int(recid)]
        except ValueError:
            print('ERROR: record ID must be integer, not %s.' % recid)
            sys.exit(1)
    for recid in recids:
        all_revisions = run_sql("SELECT marcxml, job_id, job_name, job_person, job_date FROM hstRECORD WHERE id_bibrec=%s ORDER BY job_date ASC", (recid,))
        previous_rec = {}
        deleted_revisions = 0
        for marcxml, job_id, job_name, job_person, job_date in all_revisions:
            try:
                current_rec = create_record(zlib.decompress(marcxml))[0]
            except Exception:
                print("ERROR: corrupted revisions found. Please run %s --fix-revisions '*'" % sys.argv[0], file=sys.stderr)
                sys.exit(1)
            if records_identical(current_rec, previous_rec):
                deleted_revisions += 1
                if not dry_run:
                    run_sql("DELETE FROM hstRECORD WHERE id_bibrec=%s AND job_id=%s AND job_name=%s AND job_person=%s AND job_date=%s", (recid, job_id, job_name, job_person, job_date))
            previous_rec = current_rec
        if verbose and deleted_revisions:
            print("record %s: deleted %s duplicate revisions out of %s" % (recid, deleted_revisions, len(all_revisions)))
    if verbose:
        print("DONE")
Example #16
0
def get_templates(templatesDir, tmpl_name, tmpl_description, extractContent = False):
    """Return list of templates [filename, name, description, content*]
       the extractContent variable indicated if the parsed content should
       be included"""
    template_fnames = fnmatch.filter(templatesDir, '*.xml')

    templates = []
    for filepath in template_fnames:
        template_file = open(filepath,'r')
        template = template_file.read()
        template_file.close()
        fname = os.path.basename(filepath)
        fname_stripped = os.path.splitext(fname)[0]
        mo_name = tmpl_name.search(template)
        mo_description = tmpl_description.search(template)
        date_modified = time.ctime(os.path.getmtime(filepath))
        if mo_name:
            name = mo_name.group(1)
        else:
            name = fname_stripped
        if mo_description:
            description = mo_description.group(1)
        else:
            description = ''
        if (extractContent):
            parsedTemplate = create_record(template)[0]
            if parsedTemplate != None:
                # If the template was correct
                templates.append([fname_stripped, name, description, parsedTemplate])
            else:
                raise "Problem when parsing the template %s" % (fname, )
        else:
            templates.append([fname_stripped, name, description, date_modified])

    return templates
Example #17
0
    def test_marc_export(self):
        from invenio.modules.records.api import Record
        from invenio.legacy.bibrecord import create_record, record_xml_output

        rec = Record(json=test_record, master_format='marc')

        # Needed to properly set authors when generating MARC
        first = rec['authors'][0]
        additional = rec['authors'][1:]
        rec['_first_author'] = first
        rec['_additional_authors'] = additional

        output_marc = record_xml_output(
            create_record(rec.legacy_export_as_marc())[0]
        )
        try:
            self.assertEqual(test_marc, output_marc)
        except AssertionError:
            # Print diff in case of errors.
            import difflib
            diff = "".join(difflib.unified_diff(
                test_marc.splitlines(1),
                output_marc.splitlines(1)
            ))
            raise AssertionError(diff)

        form_json = rec.produce('json_for_form')
        for k, v in test_form_json.items():
            self.assertEqual(form_json[k], test_form_json[k])
Example #18
0
    def test_marc_export(self):
        from invenio.modules.records.api import Record
        from invenio.legacy.bibrecord import create_record, record_xml_output

        rec = Record(json=test_record, master_format='marc')

        # Needed to properly set authors when generating MARC
        first = rec['authors'][0]
        additional = rec['authors'][1:]
        rec['_first_author'] = first
        rec['_additional_authors'] = additional

        output_marc = record_xml_output(
            create_record(rec.legacy_export_as_marc())[0]
        )
        try:
            self.assertEqual(test_marc, output_marc)
        except AssertionError:
            # Print diff in case of errors.
            import difflib
            diff = "".join(difflib.unified_diff(
                test_marc.splitlines(1),
                output_marc.splitlines(1)
            ))
            raise AssertionError(diff)

        form_json = rec.produce('json_for_form')
        for k, v in test_form_json.items():
            self.assertEqual(form_json[k], test_form_json[k])
Example #19
0
def _get_record_slave(recid, result, mode=None, uid=None):
    """Check if record exists and return it in dictionary format.
       If any kind of error occurs returns None.
       If mode=='revision' then recid parameter is considered as revid."""
    record = None
    if recid == 'none':
        mode = 'none'
    if mode == 'recid':
        record_status = record_exists(recid)
        #check for errors
        if record_status == 0:
            result['resultCode'], result['resultText'] = 1, 'Non-existent record: %s' % recid
        elif record_status == -1:
            result['resultCode'], result['resultText'] = 1, 'Deleted record: %s' % recid
        elif record_locked_by_queue(recid):
            result['resultCode'], result['resultText'] = 1, 'Record %s locked by queue' % recid
        else:
            record = create_record( print_record(recid, 'xm') )[0]
            record_order_subfields(record)

    elif mode == 'tmpfile':
        file_path = '%s_%s.xml' % (_get_file_path(recid, uid),
                                       CFG_BIBEDIT_TO_MERGE_SUFFIX)
        if not os.path.isfile(file_path): #check if file doesn't exist
            result['resultCode'], result['resultText'] = 1, 'Temporary file doesnt exist'
        else: #open file
            tmpfile = open(file_path, 'r')
            record = create_record( tmpfile.read() )[0]
            tmpfile.close()

    elif mode == 'revision':
        if revision_format_valid_p(recid):
            marcxml = get_marcxml_of_revision_id(recid)
            if marcxml:
                record = create_record(marcxml)[0]
            else:
                result['resultCode'], result['resultText'] = 1, 'The specified revision does not exist'
        else:
            result['resultCode'], result['resultText'] = 1, 'Invalid revision id'

    elif mode == 'none':
        return {}

    else:
        result['resultCode'], result['resultText'] = 1, 'Invalid record mode for record2'
    return record
Example #20
0
def get_bibrecord(recid):
    """Return record in BibRecord wrapping."""
    if record_exists(recid):
        record_revision_ids = get_record_revision_ids(recid)
        if record_revision_ids:
            return create_record(get_marcxml_of_revision_id(max(record_revision_ids)))[0]
        else:
            return get_record(recid)
Example #21
0
def get_bibrecord(recid):
    """Return record in BibRecord wrapping."""
    if record_exists(recid):
        record_revision_ids = get_record_revision_ids(recid)
        if record_revision_ids:
            return create_record(get_marcxml_of_revision_id(max(record_revision_ids)))[0]
        else:
            return get_record(recid)
Example #22
0
def save_xml_record(recid, uid, xml_record='', to_upload=True, to_merge=False,
                    task_name="bibedit", sequence_id=None):
    """Write XML record to file. Default behaviour is to read the record from
    a BibEdit cache file, filter out the unchanged volatile subfields,
    write it back to an XML file and then pass this file to BibUpload.

    @param xml_record: give XML as string in stead of reading cache file
    @param to_upload: pass the XML file to BibUpload
    @param to_merge: prepare an XML file for BibMerge to use

    """
    if not xml_record:
        # Read record from cache file.
        cache = get_cache_contents(recid, uid)
        if cache:
            record = cache[2]
            used_changes = cache[4]
            xml_record = record_xml_output(record)
            delete_cache(recid, uid)
            delete_disabled_changes(used_changes)
    else:
        record = create_record(xml_record)[0]

    # clean the record from unfilled volatile fields
    record_strip_empty_volatile_subfields(record)
    record_strip_empty_fields(record)

    # order subfields alphabetically before saving the record
    record_order_subfields(record)

    xml_to_write = wash_for_xml(record_xml_output(record))

    # Write XML file.
    if not to_merge:
        fd, file_path = tempfile.mkstemp(dir=cfg['CFG_BIBEDIT_CACHEDIR'],
                                         prefix="%s_" % cfg['CFG_BIBEDIT_FILENAME'],
                                         suffix="_%s_%s.xml" % (recid, uid))
        f = os.fdopen(fd, 'w')
        f.write(xml_to_write)
        f.close()
    else:
        file_path = '%s_%s.xml' % (_get_file_path(recid, uid),
                                   cfg['CFG_BIBEDIT_TO_MERGE_SUFFIX'])
        xml_file = open(file_path, 'w')
        xml_file.write(xml_to_write)
        xml_file.close()

    user_name = get_user_info(uid)[1]
    if to_upload:
        args = ['bibupload', user_name, '-P', '5', '-r',
                file_path, '-u', user_name]
        if task_name == "bibedit":
            args.extend(['--name', 'bibedit'])
        if sequence_id:
            args.extend(["-I", sequence_id])
        args.extend(['--email-logs-on-error'])
        task_low_level_submission(*args)
    return True
Example #23
0
def save_xml_record(recid, uid, xml_record='', to_upload=True, to_merge=False,
                    task_name="bibedit", sequence_id=None):
    """Write XML record to file. Default behaviour is to read the record from
    a BibEdit cache file, filter out the unchanged volatile subfields,
    write it back to an XML file and then pass this file to BibUpload.

    @param xml_record: give XML as string in stead of reading cache file
    @param to_upload: pass the XML file to BibUpload
    @param to_merge: prepare an XML file for BibMerge to use

    """
    if not xml_record:
        # Read record from cache file.
        cache = get_cache_contents(recid, uid)
        if cache:
            record = cache[2]
            used_changes = cache[4]
            xml_record = record_xml_output(record)
            delete_cache(recid, uid)
            delete_disabled_changes(used_changes)
    else:
        record = create_record(xml_record)[0]

    # clean the record from unfilled volatile fields
    record_strip_empty_volatile_subfields(record)
    record_strip_empty_fields(record)

    # order subfields alphabetically before saving the record
    record_order_subfields(record)

    xml_to_write = wash_for_xml(record_xml_output(record))

    # Write XML file.
    if not to_merge:
        fd, file_path = tempfile.mkstemp(dir=cfg['CFG_BIBEDIT_CACHEDIR'],
                                         prefix="%s_" % cfg['CFG_BIBEDIT_FILENAME'],
                                         suffix="_%s_%s.xml" % (recid, uid))
        f = os.fdopen(fd, 'w')
        f.write(xml_to_write)
        f.close()
    else:
        file_path = '%s_%s.xml' % (_get_file_path(recid, uid),
                                   cfg['CFG_BIBEDIT_TO_MERGE_SUFFIX'])
        xml_file = open(file_path, 'w')
        xml_file.write(xml_to_write)
        xml_file.close()

    user_name = get_user_info(uid)[1]
    if to_upload:
        args = ['bibupload', user_name, '-P', '5', '-r',
                file_path, '-u', user_name]
        if task_name == "bibedit":
            args.extend(['--name', 'bibedit'])
        if sequence_id:
            args.extend(["-I", sequence_id])
        args.extend(['--email-logs-on-error'])
        task_low_level_submission(*args)
    return True
Example #24
0
    def __init__(self, recID, ln=CFG_SITE_LANG, search_pattern=None,
                 xml_record=None, user_info=None, output_format=''):
        """
        Creates a new bibformat object, with given record.

        You can either specify an record ID to format, or give its xml representation.
        if 'xml_record' is not None, use 'xml_record' instead of recID for the record.

        'user_info' allows to grant access to some functionalities on
        a page depending on the user's priviledges. It is a dictionary
        in the following form::

            user_info = {
                'remote_ip' : '',
                'remote_host' : '',
                'referer' : '',
                'uri' : '',
                'agent' : '',
                'uid' : -1,
                'nickname' : '',
                'email' : '',
                'group' : [],
                'guest' : '1'
                }

        :param recID: the id of a record
        :param ln: the language in which the record has to be formatted
        :param search_pattern: list of string representing the request used by the user in web interface
        :param xml_record: a xml string of the record to format
        :param user_info: the information of the user who will view the formatted page
        :param output_format: the output_format used for formatting this record
        """
        self.xml_record = None # *Must* remain empty if recid is given
        if xml_record is not None:
            # If record is given as parameter
            self.xml_record = xml_record
            self.record = create_record(xml_record)[0]
            recID = record_get_field_value(self.record, "001") or None
            recID = int(recID) if recID is not None else recID

        try:
            assert isinstance(recID, (int, long, type(None))), 'Argument of wrong type!'
        except AssertionError:
            register_exception(prefix="recid needs to be an integer in BibFormatObject",
                               alert_admin=True)
            recID = int(recID)
        self.recID = recID
        self.lang = wash_language(ln)
        if search_pattern is None:
            search_pattern = []
        self.search_pattern = search_pattern
        self.output_format = output_format
        self.user_info = user_info
        if self.user_info is None:
            from invenio.ext.login.legacy_user import UserInfo
            self.user_info = UserInfo(None)
Example #25
0
    def test_marc_export(self):
        from invenio.modules.records.api import Record
        from invenio.legacy.bibrecord import create_record

        r = Record(json=test_record, master_format='marc')

        self.assertEqual(
            r.legacy_create_recstruct(),
            create_record(test_marc)[0],
        )
Example #26
0
def _get_record_linking_fields(recid_b, recid_a, tag, ind1, ind2):
    """
    Returns the fields (defined by tag, ind1, ind2) in record (given
    by recid_b) that do not link to another given record (recid_a).
    """
    fields = []
    rec = create_record(format_record(recid_b, "xm"))[0]
    for field_instance in record_get_field_instances(rec, tag=tag, ind1=ind1, ind2=ind2):
        if not ('w', str(recid_a)) in field_instance[0]:
            fields.append(field_instance)
    return fields
Example #27
0
def crossref_process_template(template, change=False):
    """
    Creates record from template based on xml template
    @param change: if set to True, makes changes to the record (translating the
        title, unifying autroh names etc.), if not - returns record without
        any changes
    @return: record
    """
    record = create_record(template)[0]
    if change:
        crossref_translate_title(record)
        crossref_normalize_name(record)
    return record
Example #28
0
def crossref_process_template(template, change=False):
    """
    Creates record from template based on xml template
    @param change: if set to True, makes changes to the record (translating the
        title, unifying autroh names etc.), if not - returns record without
        any changes
    @return: record
    """
    record = create_record(template)[0]
    if change:
        crossref_translate_title(record)
        crossref_normalize_name(record)
    return record
Example #29
0
def modify_record_timestamp(revision_xml, last_revision_ts):
    """ Modify tag 005 to add the revision passed as parameter.
    @param revision_xml: marcxml representation of the record to modify
    @type revision_xml: string
    @param last_revision_ts: timestamp to add to 005 tag
    @type last_revision_ts: string

    @return: marcxml with 005 tag modified
    """
    recstruct = create_record(revision_xml)[0]
    record_modify_controlfield(recstruct, "005", last_revision_ts,
                                field_position_local=0)
    return record_xml_output(recstruct)
Example #30
0
def _get_record_linking_fields(recid_b, recid_a, tag, ind1, ind2):
    """
    Returns the fields (defined by tag, ind1, ind2) in record (given
    by recid_b) that do not link to another given record (recid_a).
    """
    fields = []
    rec = create_record(format_record(recid_b, "xm"))[0]
    for field_instance in record_get_field_instances(rec,
                                                     tag=tag,
                                                     ind1=ind1,
                                                     ind2=ind2):
        if not ('w', str(recid_a)) in field_instance[0]:
            fields.append(field_instance)
    return fields
Example #31
0
    def _next_value(self, recid=None, xml_record=None, start_date=None):
        """
        Returns the next cnum for the given recid

        @param recid: id of the record where the cnum will be generated
        @type recid: int

        @param xml_record: record in xml format
        @type xml_record: string

        @param start_date: use given start date
        @type start_date: string

        @return: next cnum for the given recid. Format is Cyy-mm-dd.[.1n]
        @rtype: string

        @raises ConferenceNoStartDateError: No date information found in the
        given recid
        """
        bibrecord = None
        if recid is None and xml_record is not None:
            bibrecord = create_record(xml_record)[0]
        elif recid is not None:
            bibrecord = get_bibrecord(recid)

        if start_date is None and bibrecord is not None:
            start_date = record_get_field_value(bibrecord,
                                                tag="111",
                                                ind1="",
                                                ind2="",
                                                code="x")

        if not start_date:
            raise ConferenceNoStartDateError

        base_cnum = "C" + start_date[2:]

        record_cnums = self._get_record_cnums(base_cnum)
        if not record_cnums:
            new_cnum = base_cnum
        else:
            # Get the max current revision, cnums are in format Cyy-mm-dd,
            # Cyy-mm-dd.1, Cyy-mm-dd.2
            highest_revision = max([0] + [
                int(rev[0].split('.')[1])
                for rev in record_cnums if '.' in rev[0]
            ])
            new_cnum = base_cnum + '.' + str(highest_revision + 1)

        return new_cnum
Example #32
0
def modify_record_timestamp(revision_xml, last_revision_ts):
    """ Modify tag 005 to add the revision passed as parameter.
    @param revision_xml: marcxml representation of the record to modify
    @type revision_xml: string
    @param last_revision_ts: timestamp to add to 005 tag
    @type last_revision_ts: string

    @return: marcxml with 005 tag modified
    """
    recstruct = create_record(revision_xml)[0]
    if "005" in recstruct:
        record_modify_controlfield(recstruct, "005", last_revision_ts,
                                   field_position_local=0)
    else:
        record_add_field(recstruct, '005', controlfield_value=last_revision_ts)
    return record_xml_output(recstruct)
Example #33
0
    def legacy_create_recstruct(self):
        """Create the `recstruct` representation.

        It uses the producer rules and
        :func:`~invenio.legacy.bibrecord.create_record`.
        """
        # FIXME: it might be a bit overkilling
        from invenio.legacy.bibrecord import create_record

        record, status_code, errors = create_record(self.legacy_export_as_marc())
        if status_code == 0:
            # There was an error
            if isinstance(errors, list):
                errors = "\n".join(errors)
            raise ReaderException("There was an error while parsing MARCXML: %s" % (errors,))
        return record
Example #34
0
    def _next_value(self, recid=None, xml_record=None, start_date=None):
        """
        Returns the next cnum for the given recid

        @param recid: id of the record where the cnum will be generated
        @type recid: int

        @param xml_record: record in xml format
        @type xml_record: string

        @param start_date: use given start date
        @type start_date: string

        @return: next cnum for the given recid. Format is Cyy-mm-dd.[.1n]
        @rtype: string

        @raises ConferenceNoStartDateError: No date information found in the
        given recid
        """
        bibrecord = None
        if recid is None and xml_record is not None:
            bibrecord = create_record(xml_record)[0]
        elif recid is not None:
            bibrecord = get_bibrecord(recid)

        if start_date is None and bibrecord is not None:
            start_date = record_get_field_value(bibrecord,
                                                tag="111",
                                                ind1="",
                                                ind2="",
                                                code="x")

        if not start_date:
            raise ConferenceNoStartDateError

        base_cnum = "C" + start_date[2:]

        record_cnums = self._get_record_cnums(base_cnum)
        if not record_cnums:
            new_cnum = base_cnum
        else:
            # Get the max current revision, cnums are in format Cyy-mm-dd,
            # Cyy-mm-dd.1, Cyy-mm-dd.2
            highest_revision = max([0] + [int(rev[0].split('.')[1]) for rev in record_cnums if '.' in rev[0]])
            new_cnum = base_cnum + '.' + str(highest_revision + 1)

        return new_cnum
Example #35
0
def save_xml_record(recid, uid, xml_record='', to_upload=True, to_merge=False):
    """Write XML record to file. Default behaviour is to read the record from
    a BibEdit cache file, filter out the unchanged volatile subfields,
    write it back to an XML file and then pass this file to BibUpload.

    @param xml_record: give XML as string in stead of reading cache file
    @param to_upload: pass the XML file to BibUpload
    @param to_merge: prepare an XML file for BibMerge to use

    """
    if not xml_record:
        # Read record from cache file.
        cache = get_cache_file_contents(recid, uid)
        if cache:
            record = cache[2]
            used_changes = cache[4]
            xml_record = record_xml_output(record)
            delete_cache_file(recid, uid)
            delete_disabled_changes(used_changes)
    else:
        record = create_record(xml_record)[0]

    # clean the record from unfilled volatile fields
    record_strip_empty_volatile_subfields(record)
    record_strip_empty_fields(record)

    # order subfields alphabetically before saving the record
    record_order_subfields(record)

    xml_to_write = wash_for_xml(record_xml_output(record))

    # Write XML file.
    if not to_merge:
        file_path = '%s.xml' % _get_file_path(recid, uid)
    else:
        file_path = '%s_%s.xml' % (_get_file_path(recid, uid),
                                   CFG_BIBEDIT_TO_MERGE_SUFFIX)
    xml_file = open(file_path, 'w')
    xml_file.write(xml_to_write)
    xml_file.close()

    user_name = get_user_info(uid)[1]
    if to_upload:
        # Pass XML file to BibUpload.
        task_low_level_submission('bibupload', 'bibedit', '-P', '5', '-r',
                                  file_path, '-u', user_name)
    return True
Example #36
0
    def legacy_create_recstruct(self):
        """Create the `recstruct` representation.

        It uses the producer rules and
        :func:`~invenio.legacy.bibrecord.create_record`.
        """
        # FIXME: it might be a bit overkilling
        from invenio.legacy.bibrecord import create_record
        record, status_code, errors = create_record(
            self.legacy_export_as_marc())
        if status_code == 0:
            # There was an error
            if isinstance(errors, list):
                errors = "\n".join(errors)
            raise ReaderException(
                "There was an error while parsing MARCXML: %s" % (errors, ))
        return record
Example #37
0
    def _prepare_blob(self, *args, **kwargs):
        """Transform the incoming blob into recstruct.

        FIXME: stop using recstruct!
        """
        from invenio.legacy.bibrecord import create_record

        class SaveDict(dict):
            __getitem__ = dict.get

        def dict_extend_helper(d, key, value):
            """Helper function.

            If the key is present inside the dictionary it creates a list (if
            not present) and extends it with the new value.
            Almost as in `list.extend`
            """
            if key in d:
                current_value = d.get(key)
                if not isinstance(current_value, list):
                    current_value = [current_value]
                current_value.append(value)
                value = current_value
            d[key] = value

        self.rec_tree = SaveDict()
        record, status_code, errors = create_record(self._blob)
        if status_code == 0:
            if isinstance(errors, list):
                errors = "\n".join(errors)
            # There was an error
            raise ReaderException(
                "There was an error while parsing MARCXML: %s" % (errors, ))
        for key, values in iteritems(record):
            if key < '010' and key.isdigit():
                self.rec_tree[key] = [value[3] for value in values]
            else:
                for value in values:
                    field = SaveDict()
                    for subfield in value[0]:
                        dict_extend_helper(field, subfield[0], subfield[1])
                    dict_extend_helper(self.rec_tree,
                                       (key + value[1] + value[2]).replace(
                                           ' ', '_'), field)
Example #38
0
    def _prepare_blob(self, *args, **kwargs):
        """Transform the incoming blob into recstruct.

        FIXME: stop using recstruct!
        """
        from invenio.legacy.bibrecord import create_record

        class SaveDict(dict):
            __getitem__ = dict.get

        def dict_extend_helper(d, key, value):
            """Helper function.

            If the key is present inside the dictionary it creates a list (if
            not present) and extends it with the new value.
            Almost as in `list.extend`
            """
            if key in d:
                current_value = d.get(key)
                if not isinstance(current_value, list):
                    current_value = [current_value]
                current_value.append(value)
                value = current_value
            d[key] = value
        self.rec_tree = SaveDict()
        record, status_code, errors = create_record(self._blob)
        if status_code == 0:
            if isinstance(errors, list):
                errors = "\n".join(errors)
            # There was an error
            raise ReaderException(
                "There was an error while parsing MARCXML: %s" % (errors,))
        for key, values in iteritems(record):
            if key < '010' and key.isdigit():
                self.rec_tree[key] = [value[3] for value in values]
            else:
                for value in values:
                    field = SaveDict()
                    for subfield in value[0]:
                        dict_extend_helper(field, subfield[0], subfield[1])
                    dict_extend_helper(
                        self.rec_tree,
                        (key + value[1] + value[2]).replace(' ', '_'), field)
Example #39
0
def replace_references(recid, uid=None, txt=None, url=None):
    """Replace references for a record

    The record itself is not updated, the marc xml of the document with updated
    references is returned

    Parameters:
    * recid: the id of the record
    * txt: references in text mode
    * inspire: format of ther references
    """
    # Parse references
    if txt is not None:
        references_xml = extract_references_from_string_xml(
            txt, is_only_references=True)
    elif url is not None:
        references_xml = extract_references_from_url_xml(url)
    else:
        references_xml = extract_references_from_record_xml(recid)
    references = create_record(references_xml)

    dummy1, dummy2, record, dummy3, dummy4, dummy5, dummy6 = get_cache_contents(
        recid, uid)
    out_xml = None

    references_to_add = record_get_field_instances(references[0],
                                                   tag='999',
                                                   ind1='C',
                                                   ind2='5')
    refextract_status = record_get_field_instances(references[0],
                                                   tag='999',
                                                   ind1='C',
                                                   ind2='6')

    if references_to_add:
        # Replace 999 fields
        record_delete_fields(record, '999')
        record_add_fields(record, '999', references_to_add)
        record_add_fields(record, '999', refextract_status)
        # Update record references
        out_xml = record_xml_output(record)

    return out_xml
Example #40
0
def main():
    from invenio.legacy.search_engine import get_record
    from invenio.legacy.bibupload.engine import (
        bibupload,
    )
    from invenio.legacy.bibrecord import (
        create_record,
    )
    from invenio.legacy.bibedit.db_layer import get_record_revisions
    from invenio.legacy.bibedit.utils import (
        get_record_revision_ids,
        get_marcxml_of_revision,
    )

    # Loop through list of records
    for r in RECORDS:
        rec = get_record(r)

        if not rec:
            break

        print('Processing record: {0}'.format(r))
        # pprint(rec)

        print(get_record_revision_ids(r))
        print

        revs = get_record_revisions(r)
        print(revs)
        print

        for id, rev in revs[0:1]:
            marcxml = get_marcxml_of_revision(r, rev)
            # print(marcxml)
            # print
            rec = create_record(marcxml)[0]
            pprint(rec)

            if raw_input('Bibupload (y/n)? ') == 'y':
                # bibupload(rec, 'delete')
                # sleep(5)
                bibupload(rec, 'replace')
Example #41
0
def get_templates(templatesDir,
                  tmpl_name,
                  tmpl_description,
                  extractContent=False):
    """Return list of templates [filename, name, description, content*]
       the extractContent variable indicated if the parsed content should
       be included"""
    template_fnames = fnmatch.filter(templatesDir, '*.xml')

    templates = []
    for fname in template_fnames:
        filepath = fname
        template_file = open(filepath, 'r')
        template = template_file.read()
        template_file.close()
        fname = os.path.basename(filepath)
        fname_stripped = os.path.splitext(fname)[0]
        mo_name = tmpl_name.search(template)
        mo_description = tmpl_description.search(template)
        date_modified = time.ctime(os.path.getmtime(filepath))
        if mo_name:
            name = mo_name.group(1)
        else:
            name = fname_stripped
        if mo_description:
            description = mo_description.group(1)
        else:
            description = ''
        if (extractContent):
            parsedTemplate = create_record(template)[0]
            if parsedTemplate is not None:
                # If the template was correct
                templates.append(
                    [fname_stripped, name, description, parsedTemplate])
            else:
                raise Exception("Problem when parsing the template %s" %
                                (fname, ))
        else:
            templates.append(
                [fname_stripped, name, description, date_modified])

    return templates
Example #42
0
def main():
    from invenio.legacy.search_engine import get_record
    from invenio.legacy.bibupload.engine import (
        bibupload, )
    from invenio.legacy.bibrecord import (
        create_record, )
    from invenio.legacy.bibedit.db_layer import get_record_revisions
    from invenio.legacy.bibedit.utils import (
        get_record_revision_ids,
        get_marcxml_of_revision,
    )

    # Loop through list of records
    for r in RECORDS:
        rec = get_record(r)

        if not rec:
            break

        print('Processing record: {0}'.format(r))
        # pprint(rec)

        print(get_record_revision_ids(r))
        print

        revs = get_record_revisions(r)
        print(revs)
        print

        for id, rev in revs[0:1]:
            marcxml = get_marcxml_of_revision(r, rev)
            # print(marcxml)
            # print
            rec = create_record(marcxml)[0]
            pprint(rec)

            if raw_input('Bibupload (y/n)? ') == 'y':
                # bibupload(rec, 'delete')
                # sleep(5)
                bibupload(rec, 'replace')
Example #43
0
def cli_clean_revisions(recid, dry_run=True, verbose=True):
    """Clean revisions of the given recid, by removing duplicate revisions
    that do not change the content of the record."""
    if recid == '*':
        recids = intbitset(
            run_sql("""SELECT DISTINCT id_bibrec FROM "hstRECORD" """))
    else:
        try:
            recids = [int(recid)]
        except ValueError:
            print('ERROR: record ID must be integer, not %s.' % recid)
            sys.exit(1)
    for recid in recids:
        all_revisions = run_sql(
            """SELECT marcxml, job_id, job_name, job_person, job_date FROM "hstRECORD" WHERE id_bibrec=%s ORDER BY job_date ASC""",
            (recid, ))
        previous_rec = {}
        deleted_revisions = 0
        for marcxml, job_id, job_name, job_person, job_date in all_revisions:
            try:
                current_rec = create_record(zlib.decompress(str(marcxml)))[0]
            except Exception:
                print(
                    "ERROR: corrupted revisions found. Please run %s --fix-revisions '*'"
                    % sys.argv[0],
                    file=sys.stderr)
                sys.exit(1)
            if records_identical(current_rec, previous_rec):
                deleted_revisions += 1
                if not dry_run:
                    run_sql(
                        """DELETE FROM "hstRECORD" WHERE id_bibrec=%s AND job_id=%s AND job_name=%s AND job_person=%s AND job_date=%s""",
                        (recid, job_id, job_name, job_person, job_date))
            previous_rec = current_rec
        if verbose and deleted_revisions:
            print("record %s: deleted %s duplicate revisions out of %s" %
                  (recid, deleted_revisions, len(all_revisions)))
    if verbose:
        print("DONE")
Example #44
0
def merge_record_with_template(rec, template_name):
    """ Extend the record rec with the contents of the template and return it"""
    template = get_record_template(template_name)
    if not template:
        return
    template_bibrec = create_record(template)[0]

    for field_tag in template_bibrec:
        if not record_has_field(rec, field_tag):
            for field_instance in template_bibrec[field_tag]:
                record_add_field(rec, field_tag, field_instance[1],
                                 field_instance[2], subfields=field_instance[0])
        else:
            for template_field_instance in template_bibrec[field_tag]:
                subfield_codes_template = field_get_subfield_codes(template_field_instance)
                for field_instance in rec[field_tag]:
                    subfield_codes = field_get_subfield_codes(field_instance)
                    for code in subfield_codes_template:
                        if code not in subfield_codes:
                            field_add_subfield(field_instance, code,
                                               field_get_subfield_values(template_field_instance,
                                               code)[0])
    return rec
Example #45
0
    def verify_revision(self, verify_record, original_record, opt_mode=None):
        """
        Compares the upload record with the same 005 record from archive.

        Once the changes are identified, The latest revision of the record is fetched
        from the system and the identified changes are applied over the latest.

        Returns record patch in case of non-conflicting addition/modification/deletion
        Conflicting records raise Error and stops the bibupload process
        """

        upload_rev = ''
        original_rev = ''
        r_date = ''
        record_patch = {}

        # No need for revision check for other operations
        if opt_mode not in ['replace', 'correct']:
            return

        if '001' in verify_record:
            self.rec_id = record_get_field_value(verify_record, '001')

        # Retrieving Revision tags for comparison
        if '005' in verify_record:
            upload_rev = record_get_field_value(verify_record, '005')
            r_date = upload_rev.split('.')[0]

            if r_date not in [k[1] for k in get_record_revisions(self.rec_id)]:
                raise InvenioBibUploadInvalidRevisionError(self.rec_id, r_date)
        else:
            raise InvenioBibUploadMissing005Error(self.rec_id)

        if '005' in original_record:
            original_rev = record_get_field_value(original_record, '005')
        else:
            raise InvenioBibUploadMissing005Error(self.rec_id)

        # Retrieving the archived version
        marc_xml = get_marcxml_of_record_revision(self.rec_id, r_date)
        res = create_record(zlib.decompress(marc_xml[0][0]))
        archived_record = res[0]

        # Comparing Upload and Archive record
        curr_patch = self.compare_records(verify_record, archived_record,
                                          opt_mode)

        # No changes in Upload Record compared to Archived Revision
        # Raising Error to skip the bibupload for the record
        if not curr_patch:
            raise InvenioBibUploadUnchangedRecordError(self.rec_id, upload_rev)

        if original_rev == upload_rev:
            # Upload, Archive and Original Records have same Revisions.
            affected_tags = self.retrieve_affected_tags_with_ind(curr_patch)
            return ('correct',
                    self.generate_final_patch(curr_patch,
                                              self.rec_id), affected_tags)

        # Comparing Original and Archive record
        orig_patch = self.compare_records(original_record, archived_record,
                                          opt_mode)

        # Checking for conflicts
        # If no original patch - Original Record same as Archived Record
        if orig_patch:
            curr_patch = self.detect_conflict(verify_record, curr_patch, upload_rev, \
                                                original_record, orig_patch, original_rev)

        record_patch = self.generate_final_patch(curr_patch, self.rec_id)
        affected_tags = self.retrieve_affected_tags_with_ind(curr_patch)

        # Returning patch in case of no conflicting fields
        return ('correct', record_patch, affected_tags)
Example #46
0
def check_doi_status_after_merge(original_recid1, original_recid2, final_record1, final_record_2, record2_marked_as_duplicate_p=False, submit_confirmed_p=False):
    """
    Check that the result of the merge does not removed DOIs managed
    by the system, and that not duplicate DOI would be
    created. Returns a tuple(error_code, message).

    @param original_recid1: the record ID of the original record 1 (master)
    @type original_recid1: int
    @param original_recid2: the record ID of the original record 2 (slave)
    @type original_recid2: int
    @param final_record1: the resulting merged record
    @type final_record1: BibRecord object
    @param final_record_2: the resulting slave "merged" record (optional when record2_marked_as_duplicate_p is False)
    @type final_record_2: BibRecord object
    @param record2_marked_as_duplicate_p: True if the record 2 will be marked as duplicate (and deleted)
    @type record2_marked_as_duplicate_p: bool
    @param submit_confirmed_p: if the user has already confirmed to proceed with submission, according to previous messages displayed. If True, do not ask again confirmation and proceed if all tests pass.
    @type submit_confirmed_p: bool
    """
    errcode = 0
    message = ''
    new_record1_dois = get_dois(final_record1)
    new_record1_managed_dois = get_dois(final_record1, internal_only_p=True)
    original_record1_managed_dois = get_dois(create_record(print_record(original_recid1, 'xm'))[0],
                                             internal_only_p=True)
    original_record2_dois = get_dois(create_record(print_record(original_recid2, 'xm'))[0])

    # Are there any DOI from record 1 (master) lost in the merging?
    lost_dois_in_record1 = [doi for doi in original_record1_managed_dois \
                            if not doi in new_record1_managed_dois]

    # Enough to check for duplicate DOI creation in this record,
    # not whole DB
    duplicate_dois_after_merge = [doi for doi in new_record1_dois if new_record1_dois.count(doi) > 1]

    if record2_marked_as_duplicate_p:
        new_record2_managed_dois = get_dois(final_record_2, internal_only_p=True)
        original_record2_managed_dois = get_dois(create_record(print_record(original_recid2, 'xm'))[0],
                                                 internal_only_p=True)
        # Are there any DOI from record 2 (slave) lost in the merging?
        lost_dois_in_record2 = [doi for doi in original_record2_managed_dois \
                                    if not doi in new_record1_managed_dois]
    else:
        lost_dois_in_record2 = []
        duplicate_dois_after_merge += [doi for doi in new_record1_dois if doi in original_record2_dois]

    if ((lost_dois_in_record1 or lost_dois_in_record2) and \
        CFG_BIBEDIT_INTERNAL_DOI_PROTECTION_LEVEL > 0) or \
        duplicate_dois_after_merge:

        if CFG_BIBEDIT_INTERNAL_DOI_PROTECTION_LEVEL == 1 and \
               not duplicate_dois_after_merge and \
               not submit_confirmed_p:
            errcode = 1
            message = 'The resulting merged record misses DOI(s) managed by the system.<script type="text/javascript">%(check_duplicate_box)sif (confirm(\'The resulting merged record will lose DOI(s) managed by the system.\\n' + \
                      'The following DOI(s) were in the original record (#1) but are not in the final merged one:\\n' + '\\n'.join(lost_dois_in_record1) + \
                      '\\nAre you sure that you want to submit the merged records without the DOI(s)?\')) {onclickSubmitButton(confirm_p=false, additional_data={\'confirmed_submit\': true})}</script>'
        elif duplicate_dois_after_merge and lost_dois_in_record1:
            errcode = 1
            message = 'The changes cannot be submitted because the resulting merged record (a) misses DOI(s) managed by the system and/or (b) will create duplicate DOIs.<script type="text/javascript">%(check_duplicate_box)salert(\'The changes cannot be submitted because the resulting merged record (a) misses DOI(s) managed by the system and (b) will create duplicate DOIs.\\n' + \
                      'The following DOI(s) were in the original record (#1) but are not in the final merged one:\\n' + '\\n'.join(lost_dois_in_record1) + \
                      '\\nThe following DOI(s) would be duplicate after merge:\\n' + '\\n'.join(duplicate_dois_after_merge) + \
                      '\\nMake sure that the mentionned DOI(s) are included in the final merged record and/or no duplicate DOIs are created (suggestion: merge in the other way around).\');</script>'
        elif duplicate_dois_after_merge:
            errcode = 1
            message = 'The changes cannot be submitted because the resulting merged record will create a duplicate DOI.<script type="text/javascript">%(check_duplicate_box)salert(\'The changes cannot be submitted because the resulting merged record will create a duplicate DOI.\\n' + \
                      'The following DOI(s) would be duplicate after merge:\\n' + '\\n'.join(duplicate_dois_after_merge) + \
                      '\\nMake sure that the mentionned DOI(s) are not duplicated (suggestion: merge in the other way around).\');</script>'
        elif not (CFG_BIBEDIT_INTERNAL_DOI_PROTECTION_LEVEL == 1 and submit_confirmed_p):
            # lost DOIs after merge
            errcode = 1
            message = 'The changes cannot be submitted because the resulting merged record misses DOI(s) managed by the system.<script type="text/javascript">%(check_duplicate_box)salert(\'The changes cannot be submitted because the resulting merged record misses the DOI(s) managed by the system.\\n' + \
                      'The following DOI(s) were in the original record (#1) but are not in the final merged one:\\n' + '\\n'.join(lost_dois_in_record1) + \
                          '\\nMake sure that the mentionned DOI(s) are included in the final merged record.\');</script>'

    message = message % {'check_duplicate_box': record2_marked_as_duplicate_p and '$(\'#bibMergeDupeCheckbox\').attr(\'checked\', true);' or ''}

    return (errcode, message)
Example #47
0
def move_drafts_articles_to_ready(journal_name, issue):
    """
    Move draft articles to their final "collection".

    To do so we rely on the convention that an admin-chosen keyword
    must be removed from the metadata
    """
    protected_datafields = ['100', '245', '246', '520', '590', '700']
    keyword_to_remove = get_journal_draft_keyword_to_remove(journal_name)
    collections_to_refresh = {}
    indexes_to_refresh = get_journal_index_to_refresh_on_release(journal_name)
    bibindex_indexes_params = []
    if indexes_to_refresh:
        bibindex_indexes_params = ['-w', ','.join(indexes_to_refresh)]

    categories = get_journal_categories(journal_name, issue)
    task_sequence_id = str(bibtask_allocate_sequenceid())
    for category in categories:
        articles = get_journal_articles(journal_name, issue, category)
        for order, recids in iteritems(articles):
            for recid in recids:
                record_xml = format_record(recid, of='xm')
                if not record_xml:
                    continue
                new_record_xml_path = os.path.join(CFG_TMPSHAREDDIR,
                                                   'webjournal_publish_' + \
                                                   str(recid) + '.xml')
                if os.path.exists(new_record_xml_path):
                    # Do not modify twice
                    continue
                record_struc = create_record(record_xml)
                record = record_struc[0]
                new_record = update_draft_record_metadata(record,
                                                          protected_datafields,
                                                          keyword_to_remove)
                new_record_xml = print_rec(new_record)
                if new_record_xml.find(keyword_to_remove) >= 0:
                    new_record_xml = new_record_xml.replace(keyword_to_remove, '')
                    # Write to file
                    new_record_xml_file = file(new_record_xml_path, 'w')
                    new_record_xml_file.write(new_record_xml)
                    new_record_xml_file.close()
                    # Submit
                    task_low_level_submission('bibupload',
                                              'WebJournal',
                                              '-c', new_record_xml_path,
                                              '-I', task_sequence_id)
                    task_low_level_submission('bibindex',
                                              'WebJournal',
                                              '-i', str(recid),
                                              '-I', task_sequence_id,
                                               *bibindex_indexes_params)
                    for collection in get_all_collections_of_a_record(recid):
                        collections_to_refresh[collection] = ''

    # Refresh collections
    collections_to_refresh.update([(c, '') for c in get_journal_collection_to_refresh_on_release(journal_name)])
    for collection in collections_to_refresh.keys():
        task_low_level_submission('webcoll',
                                  'WebJournal',
                                  '-f', '-P', '2', '-p', '1', '-c', collection,
                                  '-I', task_sequence_id)
Example #48
0
def get_bibrecord(recid):
    """Return record in BibRecord wrapping."""
    if record_exists(recid):
        return create_record(print_record(recid, 'xm'))[0]
Example #49
0
    def verify_revision(self, verify_record, original_record, opt_mode=None):
        """
        Compares the upload record with the same 005 record from archive.

        Once the changes are identified, The latest revision of the record is fetched
        from the system and the identified changes are applied over the latest.

        Returns record patch in case of non-conflicting addition/modification/deletion
        Conflicting records raise Error and stops the bibupload process
        """

        upload_rev = ''
        original_rev = ''
        r_date = ''
        record_patch = {}

        # No need for revision check for other operations
        if opt_mode not in ['replace', 'correct']:
            return

        if '001' in verify_record:
            self.rec_id = record_get_field_value(verify_record, '001')

        # Retrieving Revision tags for comparison
        if '005' in verify_record:
            upload_rev = record_get_field_value(verify_record, '005')
            r_date = upload_rev.split('.')[0]

            if r_date not in [k[1] for k in get_record_revisions(self.rec_id)]:
                raise InvenioBibUploadInvalidRevisionError(self.rec_id, r_date)
        else:
            raise InvenioBibUploadMissing005Error(self.rec_id)

        if '005' in original_record:
            original_rev = record_get_field_value(original_record, '005')
        else:
            raise InvenioBibUploadMissing005Error(self.rec_id)

        # Retrieving the archived version
        marc_xml = get_marcxml_of_record_revision(self.rec_id, r_date)
        res = create_record(zlib.decompress(marc_xml[0][0]))
        archived_record = res[0]

        # Comparing Upload and Archive record
        curr_patch = self.compare_records(verify_record, archived_record, opt_mode)

        # No changes in Upload Record compared to Archived Revision
        # Raising Error to skip the bibupload for the record
        if not curr_patch:
            raise InvenioBibUploadUnchangedRecordError(self.rec_id, upload_rev)

        if original_rev == upload_rev:
            # Upload, Archive and Original Records have same Revisions.
            affected_tags = self.retrieve_affected_tags_with_ind(curr_patch)
            return ('correct', self.generate_final_patch(curr_patch, self.rec_id), affected_tags)

        # Comparing Original and Archive record
        orig_patch = self.compare_records(original_record, archived_record, opt_mode)

        # Checking for conflicts
        # If no original patch - Original Record same as Archived Record
        if orig_patch:
            curr_patch = self.detect_conflict(verify_record, curr_patch, upload_rev, \
                                                original_record, orig_patch, original_rev)

        record_patch = self.generate_final_patch(curr_patch, self.rec_id)
        affected_tags = self.retrieve_affected_tags_with_ind(curr_patch)

        # Returning patch in case of no conflicting fields
        return ('correct', record_patch, affected_tags)
Example #50
0
def move_drafts_articles_to_ready(journal_name, issue):
    """
    Move draft articles to their final "collection".

    To do so we rely on the convention that an admin-chosen keyword
    must be removed from the metadata
    """
    protected_datafields = ['100', '245', '246', '520', '590', '700']
    keyword_to_remove = get_journal_draft_keyword_to_remove(journal_name)
    collections_to_refresh = {}
    indexes_to_refresh = get_journal_index_to_refresh_on_release(journal_name)
    bibindex_indexes_params = []
    if indexes_to_refresh:
        bibindex_indexes_params = ['-w', ','.join(indexes_to_refresh)]

    categories = get_journal_categories(journal_name, issue)
    task_sequence_id = str(bibtask_allocate_sequenceid())
    for category in categories:
        articles = get_journal_articles(journal_name, issue, category)
        for order, recids in iteritems(articles):
            for recid in recids:
                record_xml = format_record(recid, of='xm')
                if not record_xml:
                    continue
                new_record_xml_path = os.path.join(CFG_TMPSHAREDDIR,
                                                   'webjournal_publish_' + \
                                                   str(recid) + '.xml')
                if os.path.exists(new_record_xml_path):
                    # Do not modify twice
                    continue
                record_struc = create_record(record_xml)
                record = record_struc[0]
                new_record = update_draft_record_metadata(record,
                                                          protected_datafields,
                                                          keyword_to_remove)
                new_record_xml = print_rec(new_record)
                if new_record_xml.find(keyword_to_remove) >= 0:
                    new_record_xml = new_record_xml.replace(keyword_to_remove, '')
                    # Write to file
                    new_record_xml_file = file(new_record_xml_path, 'w')
                    new_record_xml_file.write(new_record_xml)
                    new_record_xml_file.close()
                    # Submit
                    task_low_level_submission('bibupload',
                                              'WebJournal',
                                              '-c', new_record_xml_path,
                                              '-I', task_sequence_id)
                    task_low_level_submission('bibindex',
                                              'WebJournal',
                                              '-i', str(recid),
                                              '-I', task_sequence_id,
                                               *bibindex_indexes_params)
                    for collection in get_all_collections_of_a_record(recid):
                        collections_to_refresh[collection] = ''

    # Refresh collections
    collections_to_refresh.update([(c, '') for c in get_journal_collection_to_refresh_on_release(journal_name)])
    for collection in collections_to_refresh.keys():
        task_low_level_submission('webcoll',
                                  'WebJournal',
                                  '-f', '-P', '2', '-p', '1', '-c', collection,
                                  '-I', task_sequence_id)
Example #51
0
def check_doi_status_after_merge(original_recid1,
                                 original_recid2,
                                 final_record1,
                                 final_record_2,
                                 record2_marked_as_duplicate_p=False,
                                 submit_confirmed_p=False):
    """
    Check that the result of the merge does not removed DOIs managed
    by the system, and that not duplicate DOI would be
    created. Returns a tuple(error_code, message).

    @param original_recid1: the record ID of the original record 1 (master)
    @type original_recid1: int
    @param original_recid2: the record ID of the original record 2 (slave)
    @type original_recid2: int
    @param final_record1: the resulting merged record
    @type final_record1: BibRecord object
    @param final_record_2: the resulting slave "merged" record (optional when record2_marked_as_duplicate_p is False)
    @type final_record_2: BibRecord object
    @param record2_marked_as_duplicate_p: True if the record 2 will be marked as duplicate (and deleted)
    @type record2_marked_as_duplicate_p: bool
    @param submit_confirmed_p: if the user has already confirmed to proceed with submission, according to previous messages displayed. If True, do not ask again confirmation and proceed if all tests pass.
    @type submit_confirmed_p: bool
    """
    errcode = 0
    message = ''
    new_record1_dois = get_dois(final_record1)
    new_record1_managed_dois = get_dois(final_record1, internal_only_p=True)
    original_record1_managed_dois = get_dois(create_record(
        print_record(original_recid1, 'xm'))[0],
                                             internal_only_p=True)
    original_record2_dois = get_dois(
        create_record(print_record(original_recid2, 'xm'))[0])

    # Are there any DOI from record 1 (master) lost in the merging?
    lost_dois_in_record1 = [doi for doi in original_record1_managed_dois \
                            if not doi in new_record1_managed_dois]

    # Enough to check for duplicate DOI creation in this record,
    # not whole DB
    duplicate_dois_after_merge = [
        doi for doi in new_record1_dois if new_record1_dois.count(doi) > 1
    ]

    if record2_marked_as_duplicate_p:
        new_record2_managed_dois = get_dois(final_record_2,
                                            internal_only_p=True)
        original_record2_managed_dois = get_dois(create_record(
            print_record(original_recid2, 'xm'))[0],
                                                 internal_only_p=True)
        # Are there any DOI from record 2 (slave) lost in the merging?
        lost_dois_in_record2 = [doi for doi in original_record2_managed_dois \
                                    if not doi in new_record1_managed_dois]
    else:
        lost_dois_in_record2 = []
        duplicate_dois_after_merge += [
            doi for doi in new_record1_dois if doi in original_record2_dois
        ]

    if ((lost_dois_in_record1 or lost_dois_in_record2) and \
        CFG_BIBEDIT_INTERNAL_DOI_PROTECTION_LEVEL > 0) or \
        duplicate_dois_after_merge:

        if CFG_BIBEDIT_INTERNAL_DOI_PROTECTION_LEVEL == 1 and \
               not duplicate_dois_after_merge and \
               not submit_confirmed_p:
            errcode = 1
            message = 'The resulting merged record misses DOI(s) managed by the system.<script type="text/javascript">%(check_duplicate_box)sif (confirm(\'The resulting merged record will lose DOI(s) managed by the system.\\n' + \
                      'The following DOI(s) were in the original record (#1) but are not in the final merged one:\\n' + '\\n'.join(lost_dois_in_record1) + \
                      '\\nAre you sure that you want to submit the merged records without the DOI(s)?\')) {onclickSubmitButton(confirm_p=false, additional_data={\'confirmed_submit\': true})}</script>'
        elif duplicate_dois_after_merge and lost_dois_in_record1:
            errcode = 1
            message = 'The changes cannot be submitted because the resulting merged record (a) misses DOI(s) managed by the system and/or (b) will create duplicate DOIs.<script type="text/javascript">%(check_duplicate_box)salert(\'The changes cannot be submitted because the resulting merged record (a) misses DOI(s) managed by the system and (b) will create duplicate DOIs.\\n' + \
                      'The following DOI(s) were in the original record (#1) but are not in the final merged one:\\n' + '\\n'.join(lost_dois_in_record1) + \
                      '\\nThe following DOI(s) would be duplicate after merge:\\n' + '\\n'.join(duplicate_dois_after_merge) + \
                      '\\nMake sure that the mentionned DOI(s) are included in the final merged record and/or no duplicate DOIs are created (suggestion: merge in the other way around).\');</script>'
        elif duplicate_dois_after_merge:
            errcode = 1
            message = 'The changes cannot be submitted because the resulting merged record will create a duplicate DOI.<script type="text/javascript">%(check_duplicate_box)salert(\'The changes cannot be submitted because the resulting merged record will create a duplicate DOI.\\n' + \
                      'The following DOI(s) would be duplicate after merge:\\n' + '\\n'.join(duplicate_dois_after_merge) + \
                      '\\nMake sure that the mentionned DOI(s) are not duplicated (suggestion: merge in the other way around).\');</script>'
        elif not (CFG_BIBEDIT_INTERNAL_DOI_PROTECTION_LEVEL == 1
                  and submit_confirmed_p):
            # lost DOIs after merge
            errcode = 1
            message = 'The changes cannot be submitted because the resulting merged record misses DOI(s) managed by the system.<script type="text/javascript">%(check_duplicate_box)salert(\'The changes cannot be submitted because the resulting merged record misses the DOI(s) managed by the system.\\n' + \
                      'The following DOI(s) were in the original record (#1) but are not in the final merged one:\\n' + '\\n'.join(lost_dois_in_record1) + \
                          '\\nMake sure that the mentionned DOI(s) are included in the final merged record.\');</script>'

    message = message % {
        'check_duplicate_box':
        record2_marked_as_duplicate_p
        and '$(\'#bibMergeDupeCheckbox\').attr(\'checked\', true);' or ''
    }

    return (errcode, message)
Example #52
0
    def _next_value(self, recid=None, xml_record=None, bibrecord=None):
        """Return the next texkey for the given recid.

        :param recid: id of the record where the texkey will be generated
        :type recid: int

        :param xml_record: record in xml format
        :type xml_record: string

        :return: next texkey for the given recid.
        :rtype: string

        :raises TexkeyNoAuthorError: No main author (100__a) or collaboration
        (710__g) in the given recid
        """
        if recid is None and xml_record is not None:
            bibrecord = create_record(xml_record)[0]
        elif bibrecord is None:
            bibrecord = get_bibrecord(recid)

        main_author = record_get_field_value(bibrecord,
                                             tag="100",
                                             ind1="",
                                             ind2="",
                                             code="a")

        if not main_author:
            # Try with collaboration name
            main_author = record_get_field_value(bibrecord,
                                                 tag="710",
                                                 ind1="",
                                                 ind2="",
                                                 code="g")
            main_author = "".join([p for p in main_author.split()
                                   if p.lower() != "collaboration"])

        if not main_author:
            # Try with corporate author
            main_author = record_get_field_value(bibrecord,
                                                 tag="100",
                                                 ind1="",
                                                 ind2="",
                                                 code="a")
            if not main_author:
                raise TexkeyNoAuthorError

        # Remove utf-8 special characters
        main_author = unidecode(main_author.decode('utf-8'))
        try:
            texkey_first_part = main_author.split(',')[0].replace(" ", "")
        except KeyError:
            texkey_first_part = ""

        year = record_get_field_value(bibrecord,
                                      tag="269",
                                      ind1="",
                                      ind2="",
                                      code="c")
        if not year:
            year = record_get_field_value(bibrecord,
                                          tag="260",
                                          ind1="",
                                          ind2="",
                                          code="c")
            if not year:
                year = record_get_field_value(bibrecord,
                                              tag="773",
                                              ind1="",
                                              ind2="",
                                              code="y")
                if not year:
                    year = record_get_field_value(bibrecord,
                                                  tag="502",
                                                  ind1="",
                                                  ind2="",
                                                  code="d")

                    if not year:
                        raise TexkeyNoYearError

        try:
            texkey_second_part = year.split("-")[0]
        except KeyError:
            texkey_second_part = ""

        texkey_third_part = _texkey_random_chars(recid)

        texkey = texkey_first_part + ":" + \
            texkey_second_part + texkey_third_part

        tries = 0
        while self._value_exists(texkey) and tries < TEXKEY_MAXTRIES:
            # Key is already in the DB, generate a new one
            texkey_third_part = _texkey_random_chars(recid, use_random=True)
            texkey = texkey_first_part + ":" + \
                texkey_second_part + texkey_third_part
            tries += 1

        return texkey
Example #53
0
    def _next_value(self, recid=None, xml_record=None, bibrecord=None):
        """
        Returns the next texkey for the given recid

        @param recid: id of the record where the texkey will be generated
        @type recid: int

        @param xml_record: record in xml format
        @type xml_record: string

        @return: next texkey for the given recid.
        @rtype: string

        @raises TexkeyNoAuthorError: No main author (100__a) or collaboration
        (710__g) in the given recid
        """
        if recid is None and xml_record is not None:
            bibrecord = create_record(xml_record)[0]
        elif bibrecord is None:
            bibrecord = get_bibrecord(recid)

        main_author = record_get_field_value(bibrecord,
                                             tag="100",
                                             ind1="",
                                             ind2="",
                                             code="a")

        if not main_author:
            # Try with collaboration name
            main_author = record_get_field_value(bibrecord,
                                                 tag="710",
                                                 ind1="",
                                                 ind2="",
                                                 code="g")
            main_author = "".join([
                p for p in main_author.split() if p.lower() != "collaboration"
            ])

        if not main_author:
            # Try with corporate author
            main_author = record_get_field_value(bibrecord,
                                                 tag="100",
                                                 ind1="",
                                                 ind2="",
                                                 code="a")
            if not main_author:
                raise TexkeyNoAuthorError

        # Remove utf-8 special characters
        main_author = unidecode(main_author.decode('utf-8'))
        try:
            texkey_first_part = main_author.split(',')[0].replace(" ", "")
        except KeyError:
            texkey_first_part = ""

        year = record_get_field_value(bibrecord,
                                      tag="269",
                                      ind1="",
                                      ind2="",
                                      code="c")
        if not year:
            year = record_get_field_value(bibrecord,
                                          tag="260",
                                          ind1="",
                                          ind2="",
                                          code="c")
            if not year:
                year = record_get_field_value(bibrecord,
                                              tag="773",
                                              ind1="",
                                              ind2="",
                                              code="y")
                if not year:
                    year = record_get_field_value(bibrecord,
                                                  tag="502",
                                                  ind1="",
                                                  ind2="",
                                                  code="d")

                    if not year:
                        raise TexkeyNoYearError

        try:
            texkey_second_part = year.split("-")[0]
        except KeyError:
            texkey_second_part = ""

        texkey_third_part = _texkey_random_chars(recid)

        texkey = texkey_first_part + ":" + texkey_second_part + texkey_third_part

        tries = 0
        while self._value_exists(texkey) and tries < TEXKEY_MAXTRIES:
            # Key is already in the DB, generate a new one
            texkey_third_part = _texkey_random_chars(recid, use_random=True)
            texkey = texkey_first_part + ":" + texkey_second_part + texkey_third_part
            tries += 1

        return texkey