def edit(self, req, form): argd = wash_urlargd( form, { "projectid": (int, -1), #'delete': (str, ''), "id": (str, ""), "a": (str, "edit"), #'linkproject': (int, -1), #'unlinkproject': (int, -1), # style': (str, None), #'upload': (str, ''), #'dropbox': (str, '') }, ) _ = gettext_set_language(argd["ln"]) # Check if user is authorized to deposit publications user_info = collect_user_info(req) auth_code, auth_message = acc_authorize_action(user_info, "submit", doctype="OpenAIRE") if auth_code: if user_info["guest"] == "1": return redirect_to_url( req, "%s/youraccount/login%s" % ( CFG_SITE_SECURE_URL, make_canonical_urlargd( {"referer": "%s%s" % (CFG_SITE_URL, req.unparsed_uri), "ln": argd["ln"]}, {} ), ), ) else: return page( req=req, body=_("You are not authorized to use OpenAIRE deposition."), title=_("Authorization failure"), navmenuid="submit", ) # Validate action action = argd["a"] if action not in ["edit", "save", "submit", "delete"]: abort(404) uid = user_info["uid"] if not argd["id"]: return redirect("/deposit/") try: pub = OpenAIREPublication(uid, publicationid=argd["id"]) title = pub.metadata.get("title", "Untitled") except ValueError: abort(404) # # Action handling # if action == "delete": pub.delete() flash("Upload '%s' was deleted." % title, "info") return redirect("/deposit/") elif action == "edit": ctx = {"pub": pub, "title": title, "recid": pub.metadata.get("__recid__", None)} ctx["rendered_form"] = openaire_deposit_templates.tmpl_form( pub.metadata["__publicationid__"], -1, "", # projects_information "", # publication_information "", # fulltext_information form=None, metadata_status="empty", warnings=None, errors=None, ln="en", ) # if action == "edit": # elif action == "delete": # pass # if projectid >= 0: # ## There is a project on which we are working good! # publications = get_all_publications_for_project( # uid, projectid, ln=argd['ln'], style=style) # if argd['publicationid'] in publications: # if argd['addproject'] in all_project_ids: # publications[argd['publicationid'] # ].link_project(argd['linkproject']) # if argd['delproject'] in all_project_ids: # publications[argd['publicationid'] # ].unlink_project(argd['unlinkproject']) # if argd['delete'] and argd['delete'] in publications: # ## there was a request to delete a publication # publications[argd['delete']].delete() # del publications[argd['delete']] # forms = "" # submitted_publications = "" # for index, (publicationid, publication) in enumerate(publications.iteritems()): # if req.method.upper() == 'POST': # publication.merge_form(form, ln=argd['ln']) # if publication.status == 'edited': # publication.check_metadata() # publication.check_projects() # if 'submit_%s' % publicationid in form and not "".join(publication.errors.values()).strip(): # ## i.e. if the button submit for the corresponding publication has been pressed... # publication.upload_record() # if publication.status in ('initialized', 'edited'): # forms += publication.get_publication_form(projectid) # else: # submitted_publications += publication.get_publication_preview() # body += openaire_deposit_templates.tmpl_add_publication_data_and_submit(projectid, forms, submitted_publications, project_information=upload_to_project_information, ln=argd['ln']) # body += openaire_deposit_templates.tmpl_upload_publications(projectid=upload_to_projectid, project_information=upload_to_project_information, session=get_session(req).sid.encode('utf8'), style=style, ln=argd['ln']) # else: ctx.update({"myresearch": get_exisiting_publications_for_uid(uid)}) return render_template( "openaire_edit.html", req=req, breadcrumbs=[(_("Home"), ""), (_("Upload"), "deposit"), (title, "")], **ctx ).encode("utf8")
class EngineTest(unittest.TestCase): user_id = None project_id = '283595' def record_marc_output(self, rec): """ Print MARC for a given record. Used to compare a record generated by engine with the content of the record. """ rec = rec.items() rec.sort() marc = "" for field_code, fields in rec: for subfields, ind1, ind2, a, b in fields: line = "\n%s%s%s " % (field_code, ind1 or '_', ind2 or '_') for subcode, subvalue in subfields: line += "$$%s%s" % (subcode, subvalue) marc += line return marc def get_fixture(self, type): """ Retrieve fixutre and expected MARC """ fixture = {} # Append pub id to field name. for field, val in FIXTURES[type].items(): fixture['%s_%s' % (field, self.pub_id)] = val return fixture, MARC_FIXTURES[type] def assertMarcIsEqual(self, expected_marc, marc): """ Assert that two MARC representations are equal, but exclude eg. 001 control fields. """ # Filter out the control field. rm_pat = re.compile("^001.*$") rm_func = lambda x: not rm_pat.match(x) expected_marc_list = filter( rm_func, [x.strip() for x in expected_marc.split('\n')]) marc_list = filter(rm_func, [x.strip() for x in marc.split('\n')]) i = 0 for i in range(0, max(len(expected_marc_list), len(marc_list))): try: l1 = expected_marc_list[i] except IndexError: l1 = '' try: l2 = marc_list[i] except IndexError: l2 = '' i += 1 if l1.startswith("RE:"): if not re.match(l1[3:], l2): raise AssertionError("%s doesn't match %s" % (l1, l2)) else: if l1 != l2: raise AssertionError("%s != %s" % (l1, l2)) # # Tests # def setUp(self): if self.user_id == None: res = run_sql("SELECT id FROM user WHERE nickname='admin'") assert(len(res) == 1, "Couldn't find admin user") self.user_id = int(res[0][0]) self.pub = OpenAIREPublication(self.user_id) self.pub_id = self.pub.publicationid def tearDown(self): self.pub.delete() self.pub = None self.pub_id = None def _test_pubtype(self, type): """ Test MARC generated for a given publication type. """ fixture, expected_marc = self.get_fixture(type) self.pub.merge_form(fixture) self.pub.check_metadata() self.pub.check_projects() self.pub.link_project(self.project_id) rec = self.pub.get_record() marc = self.record_marc_output(rec) self.assertMarcIsEqual(expected_marc, marc) def test_publishedArticle(self): self._test_pubtype('publishedArticle') def test_report(self): self._test_pubtype('report') def test_data(self): self._test_pubtype('data') def test_thesis(self): self._test_pubtype('thesis') def test_book(self): self._test_pubtype('book') def test_bookpart(self): self._test_pubtype('bookpart') def test_conference(self): self._test_pubtype('conferenceContribution') def test_preprint(self): self._test_pubtype('preprint') def test_workingpaper(self): self._test_pubtype('workingPaper')
class EngineTest(unittest.TestCase): user_id = None project_id = "283595" def record_marc_output(self, rec): """ Print MARC for a given record. Used to compare a record generated by engine with the content of the record. """ rec = rec.items() rec.sort() marc = "" for field_code, fields in rec: for subfields, ind1, ind2, a, b in fields: line = "\n%s%s%s " % (field_code, ind1 or "_", ind2 or "_") for subcode, subvalue in subfields: line += "$$%s%s" % (subcode, subvalue) marc += line return marc def get_fixture(self, type): """ Retrieve fixutre and expected MARC """ fixture = {} # Append pub id to field name. for field, val in FIXTURES[type].items(): fixture["%s_%s" % (field, self.pub_id)] = val return fixture, MARC_FIXTURES[type] def assertMarcIsEqual(self, expected_marc, marc): """ Assert that two MARC representations are equal, but exclude eg. 001 control fields. """ # Filter out the control field. rm_pat = re.compile("^001.*$") rm_func = lambda x: not rm_pat.match(x) expected_marc_list = filter(rm_func, [x.strip() for x in expected_marc.split("\n")]) marc_list = filter(rm_func, [x.strip() for x in marc.split("\n")]) i = 0 for i in range(0, max(len(expected_marc_list), len(marc_list))): try: l1 = expected_marc_list[i] except IndexError: l1 = "" try: l2 = marc_list[i] except IndexError: l2 = "" i += 1 if l1.startswith("RE:"): if not re.match(l1[3:], l2): raise AssertionError("%s doesn't match %s" % (l1, l2)) else: if l1 != l2: raise AssertionError("%s != %s" % (l1, l2)) # # Tests # def setUp(self): if self.user_id == None: res = run_sql("SELECT id FROM user WHERE nickname='admin'") assert (len(res) == 1, "Couldn't find admin user") self.user_id = int(res[0][0]) self.pub = OpenAIREPublication(self.user_id) self.pub_id = self.pub.publicationid def tearDown(self): self.pub.delete() self.pub = None self.pub_id = None def _test_pubtype(self, type): """ Test MARC generated for a given publication type. """ fixture, expected_marc = self.get_fixture(type) self.pub.merge_form(fixture) self.pub.check_metadata() self.pub.check_projects() self.pub.link_project(self.project_id) rec = self.pub.get_record() marc = self.record_marc_output(rec) self.assertMarcIsEqual(expected_marc, marc) def test_publishedArticle(self): self._test_pubtype("publishedArticle") def test_report(self): self._test_pubtype("report") def test_data(self): self._test_pubtype("data") def test_thesis(self): self._test_pubtype("thesis") def test_book(self): self._test_pubtype("book") def test_bookpart(self): self._test_pubtype("bookpart") def test_conference(self): self._test_pubtype("conferenceContribution") def test_preprint(self): self._test_pubtype("preprint") def test_workingpaper(self): self._test_pubtype("workingPaper")
class AjaxGatewayTest(unittest.TestCase): """ Testing of AJAX Gateway """ user_id = None """ User for which we want to add publications. """ project_id = '283595' test_full_submit = True """ Set to True if you want to test full submission. By default this is not enabled, since it will pollute your installation. """ # ================================ # Helpers # ================================ def _base_form(self, action='', projectid='0', current_field='', data={}, override_pubid=None): """ Helper for creating required POST form parameters @param action: Name of action (e.g. save, submit, verify_field, ...) @param projectid: Id of project, can be left empty (defaults to NOPROJECT). @param current_field: Name of the current field without publication id suffix (e.g. language). @param data: Dictionary of fields/values for the form (without publication id suffix)/ """ pub_id = override_pubid or self.pub_id form = {} for field in CFG_METADATA_FIELDS: form['%s_%s' % (field, pub_id)] = '' if current_field: current_field_pub_id = ('%s_%s' % (current_field, pub_id)) else: current_field_pub_id = '' form.update({ 'projectid': projectid, 'publicationid': pub_id, 'action': action, 'current_field': current_field_pub_id, 'save_%s' % pub_id: "Save+publication", 'submit_%s' % pub_id: "Submit+publication", }) # Default form values form.update({ 'publication_type_%s' % pub_id: 'publishedArticle', 'access_rights_%s' % pub_id: 'openAccess', 'language_%s' % pub_id: 'eng', }) # Add form data for k, v in data.items(): form['%s_%s' % (k, pub_id)] = v return form # # Actions # def action_verify_field(self, field, value, extra_data={}, **kwargs): """ Helper for creating required POST parameters for verify_field action """ data = {field: value} data.update(extra_data) return self._base_form( action='verify_field', current_field=field, data=data, **kwargs ) def action_save(self, data={}, **kwargs): """ Helper for creating required POST parameters for save action """ return self._base_form( action='save', current_field='save', data=data, **kwargs ) def action_submit(self, data={}, **kwargs): """ Helper for creating required POST parameters for save action """ return self._base_form( action='submit', current_field='submit', data=data, **kwargs ) # # Utility methods # def get_file_fixture(self, type, style): """ Retrieve file fixture for publication type if it exists, or generate a PDF on the file. """ if type in FILE_FIXTURES: name, base64_file = FILE_FIXTURES[type] return (StringIO(binascii.a2b_base64(base64_file)), name) else: return (StringIO(self.make_stringio_pdf("Type: %s Style: %s" % (type, style))), '%s_%s_file.pdf' % (type.lower(), style)) def make_stringio_pdf(self, text): """ Generate a PDF which includes the text given as parameter to this function. """ from reportlab.pdfgen import canvas output = StringIO() c = canvas.Canvas(output) c.drawString(100, 100, text) c.showPage() c.save() return output.getvalue() def get_publications_for_project(self, project_id, style='invenio'): """ Get all publications for a project """ RE_DELETE_LINK = re.compile("/deposit\?projectid=%s&delete=([a-z0-9]+)&ln=" % project_id, re.IGNORECASE) resp = self.client.get("/deposit", query_string={'style': style, 'ln': 'en', 'projectid': project_id}) return filter(lambda x: x != self.pub_id, RE_DELETE_LINK.findall(resp.data)) # Filter out pub from setUp def clear_publications(self, project_id, style='invenio'): """ Clear all publications for a project """ pub_ids = self.get_publications_for_project(project_id, style=style) for pub_id in pub_ids: resp = self.client.get("/deposit", query_string={'projectid': project_id, 'delete': pub_id, 'ln': ''}) self.assertEqual(resp.status_code, 200) def save_metadata(self, project_id, pub_id, fixture): """ Load a fixture and save it for the given publication """ res = self.client.post("/deposit/ajaxgateway", data=self.action_save( data=fixture, override_pubid=pub_id, projectid=project_id)) for field, error in res.json['errors'].items(): self.assertEqual(error, '', msg="Save unsuccessful - %s error: %s" % (field, error)) self.assertPublicationMetadata(pub_id, fixture) def approve_record(self, recid): """ Approve a record to make it publicly available """ # Make MARCXML to approve record rec = {} record_add_field(rec, '001', controlfield_value=str(recid)) record_add_field(rec, '980', subfields=[('a', 'OPENAIRE')]) output = "<collection>%s</collection>" % record_xml_output(rec) # Upload MARCXML run_sql("TRUNCATE schTASK") # Ensures we run bibupload (hdl, marcxml_path) = mkstemp(suffix=".xml", text=True) open(marcxml_path, 'w').write(output) task_low_level_submission( 'bibupload', 'openaire', '-c', marcxml_path, '-P5') task_low_level_submission('bibindex', 'openaire') task_low_level_submission('webcoll', 'openaire') os.system("%s/bin/bibupload 1 > /dev/null" % CFG_PREFIX) os.system("%s/bin/bibindex 2 > /dev/null" % CFG_PREFIX) os.system("%s/bin/webcoll 3 > /dev/null" % CFG_PREFIX) # # Assert methods # def assertPublicationMetadata(self, pub_id, expected_metadata): """ Assert that field values of a publication is equal to those given in the expected_metadata dictionary. """ pub = OpenAIREPublication(self.user_id, publicationid=pub_id) metadata = pub.metadata for field, expected_val in expected_metadata.items(): if field == 'projects': continue expected_val = wash_for_xml(expected_val) real_val = metadata.get(field, None) if field in ['related_publications','related_datasets']: # Remove "doi:" and filter out blank strings. real_val = filter(lambda x: x, real_val.split("\n")) def _map_func(x): if x.startswith("doi:"): return x[4:] else: return x expected_val = filter( lambda x: x, map(_map_func, expected_val.split("\n"))) self.assertEqual(real_val, expected_val, "Field %s: expected %s but got %s" % (field, expected_val, real_val)) # ================================ # Tests # ================================ def setUp(self): """ Create test client, login with the given user and create a new publication. """ if self.user_id == None: res = run_sql("SELECT id FROM user WHERE nickname='admin'") assert(len(res) == 1, "Couldn't find admin user") self.user_id = int(res[0][0]) uname = get_nickname(self.user_id) self.assertEqual(uname, "admin") self.client = TestClient(response_wrapper=JSONResponse) self.client.login(uname, '') self.client_noauth = TestClient(response_wrapper=JSONResponse) self.pub = OpenAIREPublication(self.user_id) self.pub_id = self.pub.publicationid def tearDown(self): """ Remove the publication again. """ self.pub.delete() self.pub = None self.pub_id = None def test_verify_field(self): """ Testing of verify field action python -m unittest invenio.openaire_deposit_webinterface_tests.AjaxGatewayTest.test_verify_field """ # Language res = self.client.post("/deposit/ajaxgateway", data=self.action_verify_field('language', 'eng')) self.assertEqual(res.json['errors']['language_%s' % self.pub_id], '') res = self.client.post("/deposit/ajaxgateway", data=self.action_verify_field('language', '')) self.assertNotEqual( res.json['errors']['language_%s' % self.pub_id], '') # Publication type res = self.client.post("/deposit/ajaxgateway", data=self.action_verify_field('publication_type', 'publishedArticle')) self.assertEqual( res.json['errors']['publication_type_%s' % self.pub_id], '') res = self.client.post("/deposit/ajaxgateway", data=self.action_verify_field('publication_type', 'dfgsdfgsd')) self.assertNotEqual( res.json['errors']['publication_type_%s' % self.pub_id], '') # Report pages no res = self.client.post("/deposit/ajaxgateway", data=self.action_verify_field('report_pages_no', '6545')) self.assertEqual( res.json['errors']['report_pages_no_%s' % self.pub_id], '') res = self.client.post("/deposit/ajaxgateway", data=self.action_verify_field('report_pages_no', 'dfgsdfgsd')) self.assertNotEqual( res.json['errors']['report_pages_no_%s' % self.pub_id], '') # Keywords res = self.client.post("/deposit/ajaxgateway", data=self.action_verify_field('keywords', 'multiline\nkeywords')) self.assertEqual(res.json['errors']['keywords_%s' % self.pub_id], '') self.assertEqual(res.json['warnings']['keywords_%s' % self.pub_id], '') res = self.client.post("/deposit/ajaxgateway", data=self.action_verify_field('keywords', 'this;should;probably;be;separated')) self.assertEqual(res.json['errors']['keywords_%s' % self.pub_id], '') self.assertNotEqual( res.json['warnings']['keywords_%s' % self.pub_id], '') # Accept CC0 license res = self.client.post("/deposit/ajaxgateway", data=self.action_verify_field('accept_cc0_license', 'yes', extra_data={'publication_type': 'data'})) self.assertEqual( res.json['errors']['accept_cc0_license_%s' % self.pub_id], '') self.assertEqual( res.json['warnings']['accept_cc0_license_%s' % self.pub_id], '') res = self.client.post("/deposit/ajaxgateway", data=self.action_verify_field('accept_cc0_license', '', extra_data={'publication_type': 'data'})) self.assertNotEqual( res.json['errors']['accept_cc0_license_%s' % self.pub_id], '') self.assertEqual( res.json['warnings']['accept_cc0_license_%s' % self.pub_id], '') res = self.client.post("/deposit/ajaxgateway", data=self.action_verify_field('accept_cc0_license', '', extra_data={'publication_type': 'report'})) self.assertEqual( res.json['errors']['accept_cc0_license_%s' % self.pub_id], '') self.assertEqual( res.json['warnings']['accept_cc0_license_%s' % self.pub_id], '') # Related publications res = self.client.post("/deposit/ajaxgateway", data=self.action_verify_field('related_publications', '10.1234/1234', extra_data={'publication_type': 'data'})) self.assertEqual( res.json['errors']['related_publications_%s' % self.pub_id], '') self.assertEqual( res.json['warnings']['related_publications_%s' % self.pub_id], '') res = self.client.post("/deposit/ajaxgateway", data=self.action_verify_field('related_publications', '10.1234/1234\n\n12.2323', extra_data={'publication_type': 'data'})) self.assertNotEqual( res.json['errors']['related_publications_%s' % self.pub_id], '') self.assertEqual( res.json['warnings']['related_publications_%s' % self.pub_id], '') res = self.client.post("/deposit/ajaxgateway", data=self.action_verify_field('related_publications', '10.1234/1234\n\n10.1234/12342\n10.1234/12342', extra_data={'publication_type': 'data'})) self.assertEqual( res.json['errors']['related_publications_%s' % self.pub_id], '') self.assertEqual( res.json['warnings']['related_publications_%s' % self.pub_id], '') # Ensure all checks are executed to test for possible runtime errors. Validate is not needed for field in CFG_METADATA_FIELDS_CHECKS: res = self.client.post("/deposit/ajaxgateway", data=self.action_verify_field(field, 'test')) def test_action_save_published_article(self): """ Testing of save action """ data = { 'access_rights': 'openAccess', 'embargo_date': '', 'authors': '', 'title': 'some title', 'abstract': '', 'language': '', 'original_title': '', 'original_abstract': '', 'publication_type': 'publishedArticle', 'publication_date': '', 'journal_title': '', 'doi': '', 'volume': '', 'issue': '', 'pages': '', 'keywords': '', 'notes': '', } res = self.client.post( "/deposit/ajaxgateway", data=self.action_save(data=data)) self.assertPublicationMetadata( self.pub_id, {'publication_type': 'publishedArticle'}) def _submit(self, type, style, submit=True): """ Make a submission """ resp = self.client.get( "/deposit", query_string={'style': style, 'ln': 'en'}) self.assertEqual(resp.status_code, 200) # Check if there's any existing submissions self.clear_publications('0', style=style) self.clear_publications(self.project_id, style=style) # Simple file upload (file_stringio, filename) = self.get_file_fixture(type, style) resp = self.client.post( "/deposit", query_string={'style': style, 'ln': 'en', 'projectid': '0'}, data={'Filedata': (file_stringio, filename), 'upload': 'Upload'}, ) self.assertEqual(resp.status_code, 200) pub_ids = self.get_publications_for_project('0', style=style) self.assertEqual(len(pub_ids), 1) pub_id = pub_ids[0] # Link with project resp = self.client.post( "/deposit/ajaxgateway", data={'projectid': self.project_id, 'publicationid': pub_id, 'action': 'linkproject'}, ) self.assertEqual(resp.json['errors']['projects_%s' % pub_id], '') # Save metadata fixture = FIXTURES[type] self.save_metadata(self.project_id, pub_id, fixture) # Submit publication if submit: run_sql("TRUNCATE schTASK") # Ensures we run bibupload res = self.client.post("/deposit/ajaxgateway", data=self.action_submit(data=fixture, override_pubid=pub_id, projectid=self.project_id)) self.assertIn("This is a preview of the submitted publication. If approved, it will be available at ", res.json['appends']['#submitted_publications']) # Get record id m = re.search("/record/(\d+)\"", res.json[ 'appends']['#submitted_publications']) self.assertIsNotNone(m, "Couldn't find record id.") rec_id = m.group(1) # Run bibupload to get record from invenio.config import CFG_PREFIX os.system("%s/bin/bibupload 1" % CFG_PREFIX) # Approve record so it's publicly available. self.approve_record(rec_id) # Check if record is reachable res = self.client_noauth.get("/record/%s" % rec_id) self.assertEqual(res.status_code, 200) res = self.client_noauth.get("/record/%s/files/%s" % ( rec_id, filename)) if fixture["access_rights"] in ["embargoedAccess", \ "restrictedAccess", "closedAccess"] and \ type not in CFG_OPENAIRE_CC0_PUBLICATION_TYPES: self.assertEqual(res.status_code, 302) # Restricted access. else: self.assertEqual(res.status_code, 200) # Remove submission again self.clear_publications('0', style=style) self.clear_publications(self.project_id, style=style) def test_submission_published_article(self): self._submit('publishedArticle', 'portal', submit=self.test_full_submit) def test_submission_report(self): self._submit('report', 'invenio', submit=self.test_full_submit) def test_submission_data(self): self._submit('data', 'portal', submit=self.test_full_submit) def test_submission_thesis(self): self._submit('thesis', 'invenio', submit=self.test_full_submit) def test_submission_book(self): self._submit('book', 'portal', submit=self.test_full_submit) def test_submission_bookpart(self): self._submit('bookpart', 'portal', submit=self.test_full_submit) def test_submission_conference(self): self._submit('conferenceContribution', 'portal', submit=self.test_full_submit) def test_submission_preprint(self): self._submit('preprint', 'portal', submit=self.test_full_submit) def test_submission_workingpaper(self): self._submit('workingPaper', 'portal', submit=self.test_full_submit)
def edit(self, req, form): argd = wash_urlargd( form, { 'projectid': (int, -1), #'delete': (str, ''), 'id': (str, ''), 'a': (str, 'edit'), #'linkproject': (int, -1), #'unlinkproject': (int, -1), #style': (str, None), #'upload': (str, ''), #'dropbox': (str, '') }) _ = gettext_set_language(argd['ln']) # Check if user is authorized to deposit publications user_info = collect_user_info(req) auth_code, auth_message = acc_authorize_action(user_info, 'submit', doctype='OpenAIRE') if auth_code: if user_info['guest'] == '1': return redirect_to_url( req, "%s/youraccount/login%s" % (CFG_SITE_SECURE_URL, make_canonical_urlargd( { 'referer': "%s%s" % (CFG_SITE_URL, req.unparsed_uri), "ln": argd['ln'] }, {}))) else: return page( req=req, body=_( "You are not authorized to use OpenAIRE deposition."), title=_("Authorization failure"), navmenuid="submit") # Validate action action = argd['a'] if action not in ['edit', 'save', 'submit', 'delete']: abort(404) uid = user_info['uid'] if not argd['id']: return redirect("/deposit/") try: pub = OpenAIREPublication(uid, publicationid=argd['id']) title = pub.metadata.get('title', 'Untitled') except ValueError: abort(404) # # Action handling # if action == 'delete': pub.delete() flash("Upload '%s' was deleted." % title, 'info') return redirect('/deposit/') elif action == 'edit': ctx = { 'pub': pub, 'title': title, 'recid': pub.metadata.get('__recid__', None), } ctx['rendered_form'] = openaire_deposit_templates.tmpl_form( pub.metadata['__publicationid__'], -1, "", # projects_information "", # publication_information "", # fulltext_information form=None, metadata_status='empty', warnings=None, errors=None, ln='en', ) #if action == "edit": #elif action == "delete": # pass # if projectid >= 0: # ## There is a project on which we are working good! # publications = get_all_publications_for_project( # uid, projectid, ln=argd['ln'], style=style) # if argd['publicationid'] in publications: # if argd['addproject'] in all_project_ids: # publications[argd['publicationid'] # ].link_project(argd['linkproject']) # if argd['delproject'] in all_project_ids: # publications[argd['publicationid'] # ].unlink_project(argd['unlinkproject']) # if argd['delete'] and argd['delete'] in publications: # ## there was a request to delete a publication # publications[argd['delete']].delete() # del publications[argd['delete']] # forms = "" # submitted_publications = "" # for index, (publicationid, publication) in enumerate(publications.iteritems()): # if req.method.upper() == 'POST': # publication.merge_form(form, ln=argd['ln']) # if publication.status == 'edited': # publication.check_metadata() # publication.check_projects() # if 'submit_%s' % publicationid in form and not "".join(publication.errors.values()).strip(): # ## i.e. if the button submit for the corresponding publication has been pressed... # publication.upload_record() # if publication.status in ('initialized', 'edited'): # forms += publication.get_publication_form(projectid) # else: # submitted_publications += publication.get_publication_preview() # body += openaire_deposit_templates.tmpl_add_publication_data_and_submit(projectid, forms, submitted_publications, project_information=upload_to_project_information, ln=argd['ln']) # body += openaire_deposit_templates.tmpl_upload_publications(projectid=upload_to_projectid, project_information=upload_to_project_information, session=get_session(req).sid.encode('utf8'), style=style, ln=argd['ln']) # else: ctx.update({ 'myresearch': get_exisiting_publications_for_uid(uid), }) return render_template("openaire_edit.html", req=req, breadcrumbs=[ (_('Home'), ''), (_('Upload'), 'deposit'), (title, ''), ], **ctx).encode('utf8')
class AjaxGatewayTest(unittest.TestCase): """ Testing of AJAX Gateway """ user_id = None """ User for which we want to add publications. """ project_id = '283595' test_full_submit = True """ Set to True if you want to test full submission. By default this is not enabled, since it will pollute your installation. """ # ================================ # Helpers # ================================ def _base_form(self, action='', projectid='0', current_field='', data={}, override_pubid=None): """ Helper for creating required POST form parameters @param action: Name of action (e.g. save, submit, verify_field, ...) @param projectid: Id of project, can be left empty (defaults to NOPROJECT). @param current_field: Name of the current field without publication id suffix (e.g. language). @param data: Dictionary of fields/values for the form (without publication id suffix)/ """ pub_id = override_pubid or self.pub_id form = {} for field in CFG_METADATA_FIELDS: form['%s_%s' % (field, pub_id)] = '' if current_field: current_field_pub_id = ('%s_%s' % (current_field, pub_id)) else: current_field_pub_id = '' form.update({ 'projectid': projectid, 'publicationid': pub_id, 'action': action, 'current_field': current_field_pub_id, 'save_%s' % pub_id: "Save+publication", 'submit_%s' % pub_id: "Submit+publication", }) # Default form values form.update({ 'publication_type_%s' % pub_id: 'publishedArticle', 'access_rights_%s' % pub_id: 'openAccess', 'language_%s' % pub_id: 'eng', }) # Add form data for k, v in data.items(): form['%s_%s' % (k, pub_id)] = v return form # # Actions # def action_verify_field(self, field, value, extra_data={}, **kwargs): """ Helper for creating required POST parameters for verify_field action """ data = {field: value} data.update(extra_data) return self._base_form(action='verify_field', current_field=field, data=data, **kwargs) def action_save(self, data={}, **kwargs): """ Helper for creating required POST parameters for save action """ return self._base_form(action='save', current_field='save', data=data, **kwargs) def action_submit(self, data={}, **kwargs): """ Helper for creating required POST parameters for save action """ return self._base_form(action='submit', current_field='submit', data=data, **kwargs) # # Utility methods # def get_file_fixture(self, type, style): """ Retrieve file fixture for publication type if it exists, or generate a PDF on the file. """ if type in FILE_FIXTURES: name, base64_file = FILE_FIXTURES[type] return (StringIO(binascii.a2b_base64(base64_file)), name) else: return (StringIO( self.make_stringio_pdf("Type: %s Style: %s" % (type, style))), '%s_%s_file.pdf' % (type.lower(), style)) def make_stringio_pdf(self, text): """ Generate a PDF which includes the text given as parameter to this function. """ from reportlab.pdfgen import canvas output = StringIO() c = canvas.Canvas(output) c.drawString(100, 100, text) c.showPage() c.save() return output.getvalue() def get_publications_for_project(self, project_id, style='invenio'): """ Get all publications for a project """ RE_DELETE_LINK = re.compile( "/deposit\?projectid=%s&delete=([a-z0-9]+)&ln=" % project_id, re.IGNORECASE) resp = self.client.get("/deposit", query_string={ 'style': style, 'ln': 'en', 'projectid': project_id }) return filter(lambda x: x != self.pub_id, RE_DELETE_LINK.findall( resp.data)) # Filter out pub from setUp def clear_publications(self, project_id, style='invenio'): """ Clear all publications for a project """ pub_ids = self.get_publications_for_project(project_id, style=style) for pub_id in pub_ids: resp = self.client.get("/deposit", query_string={ 'projectid': project_id, 'delete': pub_id, 'ln': '' }) self.assertEqual(resp.status_code, 200) def save_metadata(self, project_id, pub_id, fixture): """ Load a fixture and save it for the given publication """ res = self.client.post("/deposit/ajaxgateway", data=self.action_save(data=fixture, override_pubid=pub_id, projectid=project_id)) for field, error in res.json['errors'].items(): self.assertEqual(error, '', msg="Save unsuccessful - %s error: %s" % (field, error)) self.assertPublicationMetadata(pub_id, fixture) def approve_record(self, recid): """ Approve a record to make it publicly available """ # Make MARCXML to approve record rec = {} record_add_field(rec, '001', controlfield_value=str(recid)) record_add_field(rec, '980', subfields=[('a', 'OPENAIRE')]) output = "<collection>%s</collection>" % record_xml_output(rec) # Upload MARCXML run_sql("TRUNCATE schTASK") # Ensures we run bibupload (hdl, marcxml_path) = mkstemp(suffix=".xml", text=True) open(marcxml_path, 'w').write(output) task_low_level_submission('bibupload', 'openaire', '-c', marcxml_path, '-P5') task_low_level_submission('bibindex', 'openaire') task_low_level_submission('webcoll', 'openaire') os.system("%s/bin/bibupload 1 > /dev/null" % CFG_PREFIX) os.system("%s/bin/bibindex 2 > /dev/null" % CFG_PREFIX) os.system("%s/bin/webcoll 3 > /dev/null" % CFG_PREFIX) # # Assert methods # def assertPublicationMetadata(self, pub_id, expected_metadata): """ Assert that field values of a publication is equal to those given in the expected_metadata dictionary. """ pub = OpenAIREPublication(self.user_id, publicationid=pub_id) metadata = pub.metadata for field, expected_val in expected_metadata.items(): if field == 'projects': continue expected_val = wash_for_xml(expected_val) real_val = metadata.get(field, None) if field in ['related_publications', 'related_datasets']: # Remove "doi:" and filter out blank strings. real_val = filter(lambda x: x, real_val.split("\n")) def _map_func(x): if x.startswith("doi:"): return x[4:] else: return x expected_val = filter(lambda x: x, map(_map_func, expected_val.split("\n"))) self.assertEqual( real_val, expected_val, "Field %s: expected %s but got %s" % (field, expected_val, real_val)) # ================================ # Tests # ================================ def setUp(self): """ Create test client, login with the given user and create a new publication. """ if self.user_id == None: res = run_sql("SELECT id FROM user WHERE nickname='admin'") assert (len(res) == 1, "Couldn't find admin user") self.user_id = int(res[0][0]) uname = get_nickname(self.user_id) self.assertEqual(uname, "admin") self.client = TestClient(response_wrapper=JSONResponse) self.client.login(uname, '') self.client_noauth = TestClient(response_wrapper=JSONResponse) self.pub = OpenAIREPublication(self.user_id) self.pub_id = self.pub.publicationid def tearDown(self): """ Remove the publication again. """ self.pub.delete() self.pub = None self.pub_id = None def test_verify_field(self): """ Testing of verify field action python -m unittest invenio.openaire_deposit_webinterface_tests.AjaxGatewayTest.test_verify_field """ # Language res = self.client.post("/deposit/ajaxgateway", data=self.action_verify_field( 'language', 'eng')) self.assertEqual(res.json['errors']['language_%s' % self.pub_id], '') res = self.client.post("/deposit/ajaxgateway", data=self.action_verify_field('language', '')) self.assertNotEqual(res.json['errors']['language_%s' % self.pub_id], '') # Publication type res = self.client.post("/deposit/ajaxgateway", data=self.action_verify_field( 'publication_type', 'publishedArticle')) self.assertEqual( res.json['errors']['publication_type_%s' % self.pub_id], '') res = self.client.post("/deposit/ajaxgateway", data=self.action_verify_field( 'publication_type', 'dfgsdfgsd')) self.assertNotEqual( res.json['errors']['publication_type_%s' % self.pub_id], '') # Report pages no res = self.client.post("/deposit/ajaxgateway", data=self.action_verify_field( 'report_pages_no', '6545')) self.assertEqual( res.json['errors']['report_pages_no_%s' % self.pub_id], '') res = self.client.post("/deposit/ajaxgateway", data=self.action_verify_field( 'report_pages_no', 'dfgsdfgsd')) self.assertNotEqual( res.json['errors']['report_pages_no_%s' % self.pub_id], '') # Keywords res = self.client.post("/deposit/ajaxgateway", data=self.action_verify_field( 'keywords', 'multiline\nkeywords')) self.assertEqual(res.json['errors']['keywords_%s' % self.pub_id], '') self.assertEqual(res.json['warnings']['keywords_%s' % self.pub_id], '') res = self.client.post("/deposit/ajaxgateway", data=self.action_verify_field( 'keywords', 'this;should;probably;be;separated')) self.assertEqual(res.json['errors']['keywords_%s' % self.pub_id], '') self.assertNotEqual(res.json['warnings']['keywords_%s' % self.pub_id], '') # Accept CC0 license res = self.client.post("/deposit/ajaxgateway", data=self.action_verify_field( 'accept_cc0_license', 'yes', extra_data={'publication_type': 'data'})) self.assertEqual( res.json['errors']['accept_cc0_license_%s' % self.pub_id], '') self.assertEqual( res.json['warnings']['accept_cc0_license_%s' % self.pub_id], '') res = self.client.post("/deposit/ajaxgateway", data=self.action_verify_field( 'accept_cc0_license', '', extra_data={'publication_type': 'data'})) self.assertNotEqual( res.json['errors']['accept_cc0_license_%s' % self.pub_id], '') self.assertEqual( res.json['warnings']['accept_cc0_license_%s' % self.pub_id], '') res = self.client.post("/deposit/ajaxgateway", data=self.action_verify_field( 'accept_cc0_license', '', extra_data={'publication_type': 'report'})) self.assertEqual( res.json['errors']['accept_cc0_license_%s' % self.pub_id], '') self.assertEqual( res.json['warnings']['accept_cc0_license_%s' % self.pub_id], '') # Related publications res = self.client.post("/deposit/ajaxgateway", data=self.action_verify_field( 'related_publications', '10.1234/1234', extra_data={'publication_type': 'data'})) self.assertEqual( res.json['errors']['related_publications_%s' % self.pub_id], '') self.assertEqual( res.json['warnings']['related_publications_%s' % self.pub_id], '') res = self.client.post("/deposit/ajaxgateway", data=self.action_verify_field( 'related_publications', '10.1234/1234\n\n12.2323', extra_data={'publication_type': 'data'})) self.assertNotEqual( res.json['errors']['related_publications_%s' % self.pub_id], '') self.assertEqual( res.json['warnings']['related_publications_%s' % self.pub_id], '') res = self.client.post( "/deposit/ajaxgateway", data=self.action_verify_field( 'related_publications', '10.1234/1234\n\n10.1234/12342\n10.1234/12342', extra_data={'publication_type': 'data'})) self.assertEqual( res.json['errors']['related_publications_%s' % self.pub_id], '') self.assertEqual( res.json['warnings']['related_publications_%s' % self.pub_id], '') # Ensure all checks are executed to test for possible runtime errors. Validate is not needed for field in CFG_METADATA_FIELDS_CHECKS: res = self.client.post("/deposit/ajaxgateway", data=self.action_verify_field( field, 'test')) def test_action_save_published_article(self): """ Testing of save action """ data = { 'access_rights': 'openAccess', 'embargo_date': '', 'authors': '', 'title': 'some title', 'abstract': '', 'language': '', 'original_title': '', 'original_abstract': '', 'publication_type': 'publishedArticle', 'publication_date': '', 'journal_title': '', 'doi': '', 'volume': '', 'issue': '', 'pages': '', 'keywords': '', 'notes': '', } res = self.client.post("/deposit/ajaxgateway", data=self.action_save(data=data)) self.assertPublicationMetadata( self.pub_id, {'publication_type': 'publishedArticle'}) def _submit(self, type, style, submit=True): """ Make a submission """ resp = self.client.get("/deposit", query_string={ 'style': style, 'ln': 'en' }) self.assertEqual(resp.status_code, 200) # Check if there's any existing submissions self.clear_publications('0', style=style) self.clear_publications(self.project_id, style=style) # Simple file upload (file_stringio, filename) = self.get_file_fixture(type, style) resp = self.client.post( "/deposit", query_string={ 'style': style, 'ln': 'en', 'projectid': '0' }, data={ 'Filedata': (file_stringio, filename), 'upload': 'Upload' }, ) self.assertEqual(resp.status_code, 200) pub_ids = self.get_publications_for_project('0', style=style) self.assertEqual(len(pub_ids), 1) pub_id = pub_ids[0] # Link with project resp = self.client.post( "/deposit/ajaxgateway", data={ 'projectid': self.project_id, 'publicationid': pub_id, 'action': 'linkproject' }, ) self.assertEqual(resp.json['errors']['projects_%s' % pub_id], '') # Save metadata fixture = FIXTURES[type] self.save_metadata(self.project_id, pub_id, fixture) # Submit publication if submit: run_sql("TRUNCATE schTASK") # Ensures we run bibupload res = self.client.post("/deposit/ajaxgateway", data=self.action_submit( data=fixture, override_pubid=pub_id, projectid=self.project_id)) self.assertIn( "This is a preview of the submitted publication. If approved, it will be available at ", res.json['appends']['#submitted_publications']) # Get record id m = re.search("/record/(\d+)\"", res.json['appends']['#submitted_publications']) self.assertIsNotNone(m, "Couldn't find record id.") rec_id = m.group(1) # Run bibupload to get record from invenio.config import CFG_PREFIX os.system("%s/bin/bibupload 1" % CFG_PREFIX) # Approve record so it's publicly available. self.approve_record(rec_id) # Check if record is reachable res = self.client_noauth.get("/record/%s" % rec_id) self.assertEqual(res.status_code, 200) res = self.client_noauth.get("/record/%s/files/%s" % (rec_id, filename)) if fixture["access_rights"] in ["embargoedAccess", \ "restrictedAccess", "closedAccess"] and \ type not in CFG_OPENAIRE_CC0_PUBLICATION_TYPES: self.assertEqual(res.status_code, 302) # Restricted access. else: self.assertEqual(res.status_code, 200) # Remove submission again self.clear_publications('0', style=style) self.clear_publications(self.project_id, style=style) def test_submission_published_article(self): self._submit('publishedArticle', 'portal', submit=self.test_full_submit) def test_submission_report(self): self._submit('report', 'invenio', submit=self.test_full_submit) def test_submission_data(self): self._submit('data', 'portal', submit=self.test_full_submit) def test_submission_thesis(self): self._submit('thesis', 'invenio', submit=self.test_full_submit) def test_submission_book(self): self._submit('book', 'portal', submit=self.test_full_submit) def test_submission_bookpart(self): self._submit('bookpart', 'portal', submit=self.test_full_submit) def test_submission_conference(self): self._submit('conferenceContribution', 'portal', submit=self.test_full_submit) def test_submission_preprint(self): self._submit('preprint', 'portal', submit=self.test_full_submit) def test_submission_workingpaper(self): self._submit('workingPaper', 'portal', submit=self.test_full_submit)
def edit(pub_id=u'', action=u'edit'): """ Edit an upload """ uid = current_user.get_id() if action not in ['edit', 'save', 'delete', 'reserve-doi']: abort(404) try: pub = OpenAIREPublication(uid, publicationid=pub_id) title = pub.metadata.get('title', 'Untitled') or 'Untitled' editable = is_editable(pub) except ValueError: abort(404) # All POST requests change the publication, and are not allowed if the # publication is not editable anymore. if request.method == 'POST': if not editable: flash("You cannot edit an already submitted upload. Please contact %s if you would like to make changes!" % CFG_SITE_SUPPORT_EMAIL) return redirect(url_for('.edit', pub_id=pub.publicationid)) # # Action handling # ctx = {} if action == 'reserve-doi': # # Reserve DOI action (AjAX) # if request.method == 'POST': doi = pub.create_doi() return json.dumps({'doi': doi}) else: abort(405) elif action == 'delete': # # Delete action # if not editable: flash("You cannot delete an already submitted upload. Please contact %s if you would like to have it removed!" % CFG_SITE_SUPPORT_EMAIL) return redirect(url_for('.edit', pub_id=pub.publicationid)) pub.delete() flash("Upload '%s' was deleted." % title, 'success') return redirect(url_for('.index')) elif action == 'edit': # # Edit action # upload_url = url_for('deposit.upload', pub_id=pub.publicationid) dropbox_upload_url = url_for('deposit.dropbox_upload', pub_id=pub.publicationid) ctx = { 'pub': pub, 'recid': pub.metadata.get('__recid__', None), 'title': title, 'is_editable': editable, 'upload_url': upload_url, 'dropbox_upload_url': dropbox_upload_url, } if request.method == 'POST': form = DepositionForm(request.values, crsf_enabled=False) mapper = DepositionFormMapper(pub) pub = mapper.map(form) form._pub = pub if form.validate(): pub.save() pub.upload_record() flash("Upload was successfully submitted - it may take up 5 minutes before it has been fully integrated into %s." % CFG_SITE_NAME, category='success') return redirect(url_for('.index')) else: pub.save() ctx['form'] = form ctx['form_message'] = "The form was saved, but there were errors. Please see below." elif editable: mapper = PublicationMapper() form = DepositionForm(mapper.map(pub), crsf_enabled=False) ctx['form'] = form else: ctx['record_hd'] = format_record(recID=pub.recid, xml_record=pub.marcxml, ln=g.ln, of='hd') ctx['record_hdinfo'] = format_record(recID=pub.recid, xml_record=pub.marcxml, ln=g.ln, of='HDINFO') elif action == 'save': # # Save action (AjAX) # if request.method == 'POST': form = DepositionForm(request.values, crsf_enabled=False) mapper = DepositionFormMapper(pub) pub = mapper.map(form) form._pub = pub if form.validate(): pub.save() return json.dumps({'status': 'success', 'form': 'Successfully saved.'}) else: pub.save() errors = dict([(x, '') for x in form._fields.keys()]) errors.update(form.errors) return json.dumps({ 'status': 'warning', 'form': 'The form was saved, but there were errors. Please see below.', 'fields': errors, }) else: abort(405) return render_template( "openaire_edit.html", myresearch=get_exisiting_publications_for_uid(current_user.get_id()), **ctx )
def edit(pub_id=u'', action=u'edit'): """ Edit an upload """ uid = current_user.get_id() if action not in ['edit', 'save', 'delete', 'reserve-doi']: abort(404) try: pub = OpenAIREPublication(uid, publicationid=pub_id) title = pub.metadata.get('title', 'Untitled') or 'Untitled' editable = is_editable(pub) except ValueError: abort(404) # All POST requests change the publication, and are not allowed if the # publication is not editable anymore. if request.method == 'POST': if not editable: flash( "You cannot edit an already submitted upload. Please contact %s if you would like to make changes!" % CFG_SITE_SUPPORT_EMAIL) return redirect(url_for('.edit', pub_id=pub.publicationid)) # # Action handling # ctx = {} if action == 'reserve-doi': # # Reserve DOI action (AjAX) # if request.method == 'POST': doi = pub.create_doi() return json.dumps({'doi': doi}) else: abort(405) elif action == 'delete': # # Delete action # if not editable: flash( "You cannot delete an already submitted upload. Please contact %s if you would like to have it removed!" % CFG_SITE_SUPPORT_EMAIL) return redirect(url_for('.edit', pub_id=pub.publicationid)) pub.delete() flash("Upload '%s' was deleted." % title, 'success') return redirect(url_for('.index')) elif action == 'edit': # # Edit action # upload_url = url_for('deposit.upload', pub_id=pub.publicationid) dropbox_upload_url = url_for('deposit.dropbox_upload', pub_id=pub.publicationid) ctx = { 'pub': pub, 'recid': pub.metadata.get('__recid__', None), 'title': title, 'is_editable': editable, 'upload_url': upload_url, 'dropbox_upload_url': dropbox_upload_url, } if request.method == 'POST': form = DepositionForm(request.values, crsf_enabled=False) mapper = DepositionFormMapper(pub) pub = mapper.map(form) form._pub = pub if form.validate(): pub.save() pub.upload_record() flash( "Upload was successfully submitted - it may take up 5 minutes before it has been fully integrated into %s." % CFG_SITE_NAME, category='success') return redirect(url_for('.index')) else: pub.save() ctx['form'] = form ctx['form_message'] = "The form was saved, but there were errors. Please see below." elif editable: mapper = PublicationMapper() form = DepositionForm(mapper.map(pub), crsf_enabled=False) ctx['form'] = form else: ctx['record_hd'] = format_record(recID=pub.recid, xml_record=pub.marcxml, ln=g.ln, of='hd') ctx['record_hdinfo'] = format_record(recID=pub.recid, xml_record=pub.marcxml, ln=g.ln, of='HDINFO') elif action == 'save': # # Save action (AjAX) # if request.method == 'POST': form = DepositionForm(request.values, crsf_enabled=False) mapper = DepositionFormMapper(pub) pub = mapper.map(form) form._pub = pub if form.validate(): pub.save() return json.dumps({ 'status': 'success', 'form': 'Successfully saved.' }) else: pub.save() errors = dict([(x, '') for x in form._fields.keys()]) errors.update(form.errors) return json.dumps({ 'status': 'warning', 'form': 'The form was saved, but there were errors. Please see below.', 'fields': errors, }) else: abort(405) return render_template("openaire_edit.html", myresearch=get_exisiting_publications_for_uid( current_user.get_id()), **ctx)