class PidLog(db.Model): """ Audit log of actions happening to persistent identifiers. This model is primarily used through PersistentIdentifier.log and rarely created manually. """ __tablename__ = 'pidLOG' __table_args__ = (db.Index('idx_action', 'action'), ) id = db.Column(db.Integer(15, unsigned=True), primary_key=True) """ Id of persistent identifier entry """ id_pid = db.Column( db.Integer(15, unsigned=True), db.ForeignKey(PersistentIdentifier.id), nullable=True, ) """ PID """ timestamp = db.Column(db.DateTime(), nullable=False, default=datetime.now) """ Creation datetime of entry """ action = db.Column(db.String(10), nullable=False) """ Action identifier """ message = db.Column(db.Text(), nullable=False) """ Log message """
def do_upgrade(): """ Implement your upgrades here """ m = db.MetaData(bind=db.engine) m.reflect() tpid = db.Table( 'pid', m, db.Column('id', db.Integer(15, unsigned=True), primary_key=True, nullable=False), db.Column('type', db.String(length=6), nullable=False), db.Column('pid', db.String(length=255), nullable=False), db.Column('status', db.Char(length=1), nullable=False), db.Column('created', db.DateTime(), nullable=False), db.Column('last_modified', db.DateTime(), nullable=False), db.Index('uidx_type_pid', 'type', 'pid', unique=True), db.Index('idx_status', 'status'), mysql_engine='MyISAM', ) tpidlog = db.Table( 'pidLOG', m, db.Column('id', db.Integer(15, unsigned=True), primary_key=True, nullable=False), db.Column('id_pid', db.Integer(15, unsigned=True), ForeignKey('pid.id')), db.Column('timestamp', DateTime(), nullable=False), db.Column('action', db.String(length=10), nullable=False), db.Column('message', Text(), nullable=False), db.Index('idx_action', 'action'), mysql_engine='MyISAM', ) tpidregistry = db.Table( 'pidREGISTRY', m, db.Column('object_type', db.String(length=3), primary_key=True, nullable=False), db.Column('object_id', db.String(length=255), nullable=False), db.Column('id_pid', db.Integer(15, unsigned=True), ForeignKey('pid.id'), primary_key=True, nullable=False), db.Index('idx_type_id', 'object_type', 'object_id'), mysql_engine='MyISAM', ) tpid.create() tpidlog.create() tpidregistry.create()
def do_upgrade(): """ Implement your upgrades here """ m = db.MetaData(bind=db.engine) m.reflect() t = db.Table( 'userCOLLECTION', m, db.Column('id', db.String(length=100), primary_key=True, nullable=False), db.Column('id_user', db.Integer(15, unsigned=True), db.ForeignKey('user.id'), nullable=False), db.Column('id_collection', db.MediumInteger(9, unsigned=True), db.ForeignKey('collection.id'), nullable=True), db.Column('id_collection_provisional', db.MediumInteger(9, unsigned=True), db.ForeignKey('collection.id'), nullable=True), db.Column('id_oairepository', db.MediumInteger(9, unsigned=True), db.ForeignKey('oaiREPOSITORY.id'), nullable=True), db.Column('title', db.String(length=255), nullable=False), db.Column('description', db.Text(), nullable=False), db.Column('page', db.Text(), nullable=False), db.Column('curation_policy', db.Text(), nullable=False), db.Column('has_logo', db.Boolean(), nullable=False), db.Column('created', db.DateTime(), nullable=False), db.Column('last_modified', db.DateTime(), nullable=False), mysql_engine='MyISAM', ) t.create()
class UserCollection(db.Model): """ Represents a user collection - a layer around Invenio's collections and portalboxes, that allow end-users to create """ __tablename__ = 'userCOLLECTION' # # Fields # id = db.Column(db.String(100), primary_key=True) """ User collection identifier used to generate the real collection_identifier """ id_user = db.Column(db.Integer(15, unsigned=True), db.ForeignKey(User.id), nullable=False) """ Owner of the collection. """ id_collection = db.Column(db.Integer(15, unsigned=True), db.ForeignKey(Collection.id), nullable=True, default=None) """ Invenio collection generated from this collection """ id_collection_provisional = db.Column(db.Integer(15, unsigned=True), db.ForeignKey(Collection.id), nullable=True, default=None) """ Invenio provisional collection generated from this collection """ id_oairepository = db.Column(db.MediumInteger(9, unsigned=True), db.ForeignKey(OaiREPOSITORY.id), nullable=True, default=None) """ OAI Repository set specification """ title = db.Column(db.String(length=255), nullable=False, default='') """ Title of collection. """ description = db.Column(db.Text(), nullable=False, default='') """ Short description of collection, displayed in portal boxes. """ page = db.Column(db.Text(), nullable=False, default='') """ Long description of collection, displayed on an individual page. """ curation_policy = db.Column(db.Text(), nullable=False, default='') """ """ has_logo = db.Column(db.Boolean(), nullable=False, default=False) """ """ created = db.Column(db.DateTime(), nullable=False, default=datetime.now) """ Creation datetime """ last_modified = db.Column(db.DateTime(), nullable=False, default=datetime.now, onupdate=datetime.now) """ Last modification datetime """ # # Relation ships # owner = db.relationship(User, backref='usercollections', foreign_keys=[id_user]) """ Relation to the owner (User) of the collection """ collection = db.relationship(Collection, uselist=False, backref='usercollection', foreign_keys=[id_collection]) """ Relationship to Invenio collection. """ collection_provisional = db.relationship( Collection, uselist=False, backref='usercollection_provisional', foreign_keys=[id_collection_provisional]) """ Relationship to Invenio restricted collection containing uncurated records. """ oai_set = db.relationship(OaiREPOSITORY, uselist=False, backref='usercollection', foreign_keys=[id_oairepository]) """ Relation to the owner (User) of the collection """ # # Properties # @property def logo_url(self): """ Get URL to collection logo """ # FIXME if self.has_logo: raise NotImplementedError else: return None @property def oai_url(self): """ Get link to OAI-PMH API for this user collection """ return "/oai2d?verb=ListRecords&metadataPrefix=oai_dc&set=%s" % self.get_collection_name( ) @property def collection_url(self): """ Get URL to collection """ return "/collection/%s" % self.get_collection_name() @property def collection_provisional_url(self): """ Get URL to provisional collection """ return "/search?cc=%s" % self.get_collection_name(provisional=True) @property def upload_url(self): """ Get direct upload URL """ return url_for('webdeposit.index', c=self.id) # # # @classmethod def from_recid(cls, recid, provisional=False): """ Get user collections specified in recid """ rec = get_record(recid) prefix = "%s-" % (CFG_USERCOLLECTION_ID_PREFIX_PROVISIONAL if provisional else CFG_USERCOLLECTION_ID_PREFIX) colls = rec.get('980', []) usercolls = [] for c in colls: try: # We are only interested in subfield 'a' code, val = c[0][0] if code == 'a' and val.startswith(prefix): val = val[len(prefix):] u = UserCollection.query.filter_by(id=val).first() if u: usercolls.append(u) except IndexError: pass return usercolls # # Utility methods # def get_collection_name(self, provisional=False): """ Get a unique collection name identifier """ if provisional: return "%s-%s" % (CFG_USERCOLLECTION_ID_PREFIX_PROVISIONAL, self.id) else: return "%s-%s" % (CFG_USERCOLLECTION_ID_PREFIX, self.id) def get_title(self, provisional=False): if provisional: return "Provisional: %s" % self.title else: return self.title def get_collection_dbquery(self, provisional=False): """ Get collection query """ return "%s:%s" % self.get_query(provisional=provisional) def get_query(self, provisional=False): """ Get tuple (field,value) for search engine query """ return ("980__a", self.get_collection_name(provisional=provisional)) def render_portalbox_bodies(self, templates): """ Get a list of rendered portal boxes for this user collection """ ctx = { 'usercollection': self, } return map(lambda t: render_template_to_string(t, **ctx), templates) # # Curation methods # def _modify_record(self, recid, test_func, replace_func, include_func, append_colls=[], replace_colls=[]): """ Generate record a MARCXML file @param test_func: Function to test if a collection id should be changed @param replace_func: Function to replace the collection id. @param include_func: Function to test if collection should be included """ rec = get_record(recid) newcolls = [] dirty = False try: colls = rec['980'] if replace_colls: for c in replace_colls: newcolls.append([('a', c)]) dirty = True else: for c in colls: try: # We are only interested in subfield 'a' code, val = c[0][0] if test_func(code, val): c[0][0] = replace_func(code, val) dirty = True if include_func(code, val): newcolls.append(c[0]) else: dirty = True except IndexError: pass for c in append_colls: newcolls.append([('a', c)]) dirty = True except KeyError: return False if not dirty: return False rec = {} record_add_field(rec, '001', controlfield_value=str(recid)) for subfields in newcolls: record_add_field(rec, '980', subfields=subfields) return rec def _upload_record(self, rec, pretend=False): """ Bibupload one record """ if rec is False: return None if not pretend: bibupload_record( record=rec, file_prefix='usercoll', mode='-c', opts=['-n', '-P5'], alias="usercoll", ) return rec def _upload_collection(self, coll): """ Bibupload many records """ bibupload_record( collection=coll, file_prefix='usercoll', mode='-c', opts=['-n', '-P5'], alias="usercoll", ) return True def accept_record(self, recid, pretend=False): """ Accept a record for inclusion in a user collection @param recid: Record ID """ expected_id = self.get_collection_name(provisional=True) new_id = self.get_collection_name(provisional=False) append_colls, replace_colls = signalresult2list( pre_curation.send(self, action='accept', recid=recid, pretend=pretend)) def test_func(code, val): return code == 'a' and val == expected_id def replace_func(code, val): return (code, new_id) def include_func(code, val): return True rec = self._upload_record(self._modify_record( recid, test_func, replace_func, include_func, append_colls=append_colls, replace_colls=replace_colls), pretend=pretend) post_curation.send(self, action='accept', recid=recid, record=rec, pretend=pretend) return rec def reject_record(self, recid, pretend=False): """ Reject a record for inclusion in a user collection @param recid: Record ID """ expected_id = self.get_collection_name(provisional=True) new_id = self.get_collection_name(provisional=False) append_colls, replace_colls = signalresult2list( pre_curation.send(self, action='reject', recid=recid, pretend=pretend)) def test_func(code, val): return False def replace_func(code, val): return (code, val) def include_func(code, val): return not (code == 'a' and (val == expected_id or val == new_id)) rec = self._upload_record(self._modify_record( recid, test_func, replace_func, include_func, append_colls=append_colls, replace_colls=replace_colls), pretend=pretend) post_curation.send(self, action='reject', recid=recid, record=rec, pretend=pretend) return rec # # Data persistence methods # def save_collectionname(self, collection, title): """ Create or update Collectionname object """ if collection.id: c_name = Collectionname.query.filter_by( id_collection=collection.id, ln=CFG_SITE_LANG, type='ln').first() if c_name: update_changed_fields(c_name, dict(value=title)) return c_name c_name = Collectionname( collection=collection, ln=CFG_SITE_LANG, type='ln', value=title, ) db.session.add(c_name) return c_name def save_collectiondetailedrecordpagetabs(self, collection): """ Create or update Collectiondetailedrecordpagetabs object """ if collection.id: c_tabs = Collectiondetailedrecordpagetabs.query.filter_by( id_collection=collection.id).first() if c_tabs: update_changed_fields(c_tabs, dict(tabs=CFG_USERCOLLCTION_TABS)) return c_tabs c_tabs = Collectiondetailedrecordpagetabs( collection=collection, tabs=CFG_USERCOLLCTION_TABS, ) db.session.add(c_tabs) return c_tabs def save_collectioncollection(self, collection, parent_name): """ Create or update CollectionCollection object """ dad = Collection.query.filter_by(name=parent_name).first() if collection.id: c_tree = CollectionCollection.query.filter_by( id_dad=dad.id, id_son=collection.id).first() if c_tree: update_changed_fields( c_tree, dict(type=CFG_USERCOLLECTION_COLLECTION_TYPE, score=CFG_USERCOLLECTION_COLLECTION_SCORE)) return c_tree c_tree = CollectionCollection( dad=dad, son=collection, type=CFG_USERCOLLECTION_COLLECTION_TYPE, score=CFG_USERCOLLECTION_COLLECTION_SCORE, ) db.session.add(c_tree) return c_tree def save_collectionformat(self, collection, fmt_str): """ Create or update CollectionFormat object """ fmt = Format.query.filter_by(code=fmt_str).first() if collection.id: c_fmt = CollectionFormat.query.filter_by( id_collection=collection.id).first() if c_fmt: update_changed_fields(c_fmt, dict(id_format=fmt.id, score=1)) return c_fmt c_fmt = CollectionFormat( collection=collection, format=fmt, ) db.session.add(c_fmt) return c_fmt def save_collectionportalboxes(self, collection, templates): """ Create or update Portalbox and CollectionPortalbox objects """ # Setup portal boxes bodies = self.render_portalbox_bodies(templates) bodies.reverse() # Highest score is on the top, so we reverse the list objects = [] if collection.id: c_pboxes = CollectionPortalbox.query.filter_by( id_collection=collection.id, ln=CFG_SITE_LANG, ).all() if len(c_pboxes) == len(bodies): for score, elem in enumerate(zip(c_pboxes, bodies)): c_pbox, body = elem pbox = c_pbox.portalbox update_changed_fields(pbox, dict(body=body)) update_changed_fields( c_pbox, dict(score=score, position=CFG_USERCOLLECTION_PORTALBOX_POSITION)) objects.append(c_pbox) return objects else: # Either templates where modified or collection portalboxes # where modified outside of the UserCollection. In either case, # remove existing portalboxes and add new ones. for c_pbox in c_pboxes: db.session.delete(c_pbox.portalbox) db.session.delete(c_pbox) for score, body in enumerate(bodies): p = Portalbox(title='', body=body) c_pbox = CollectionPortalbox() update_changed_fields( c_pbox, dict( collection=collection, portalbox=p, ln=CFG_SITE_LANG, position=CFG_USERCOLLECTION_PORTALBOX_POSITION, score=score, )) db.session.add_all([p, c_pbox]) objects.append(c_pbox) return objects def save_oairepository_set(self, provisional=False): """ Create or update OAI Repository set. """ collection_name = self.get_collection_name(provisional=provisional) (f1, p1) = self.get_query(provisional=provisional) fields = dict( setName='%s set' % collection_name, setSpec=collection_name, setDescription=self.description, p1=p1, f1=f1, m1='e', p2='', f2='', m2='', p3='', f3='', m3='', ) if self.oai_set: update_changed_fields(self.oai_set, fields) else: self.oai_set = OaiREPOSITORY(**fields) db.session.add(self.oai_set) def save_acl(self, collection_id, collection_name): """ Create or update authorization for user to view the provisional collection """ # Role - use collection id, because role name is limited to 32 chars. role_name = 'coll_%s' % collection_id role = AccROLE.query.filter_by(name=role_name).first() if not role: role = AccROLE(name=role_name, description='Curators of collection %s' % collection_name) db.session.add(role) # Argument fields = dict(keyword='collection', value=collection_name) arg = AccARGUMENT.query.filter_by(**fields).first() if not arg: arg = AccARGUMENT(**fields) db.session.add(arg) # Action action = AccACTION.query.filter_by(name='viewrestrcoll').first() # User role alluserroles = UserAccROLE.query.filter_by(role=role).all() userrole = None if alluserroles: # Remove any user which is not the owner for ur in alluserroles: if ur.id_user == self.id_user: db.session.delete(ur) else: userrole = ur if not userrole: userrole = UserAccROLE(user=self.owner, role=role) db.session.add(userrole) # Authorization auth = AccAuthorization.query.filter_by(role=role, action=action, argument=arg).first() if not auth: auth = AccAuthorization(role=role, action=action, argument=arg, argumentlistid=1) def save_collection(self, provisional=False): """ Create or update a new collection with name, tabs, collection tree, collection output formats, portalboxes and OAI repository set """ # Setup collection collection_name = self.get_collection_name(provisional=provisional) c = Collection.query.filter_by(name=collection_name).first() fields = dict( name=collection_name, dbquery=self.get_collection_dbquery(provisional=provisional)) if c: before_save_collection.send(self, is_new=True, provisional=provisional) update_changed_fields(c, fields) else: before_save_collection.send(self, is_new=False, provisional=provisional) c = Collection(**fields) db.session.add(c) db.session.commit() setattr(self, 'collection_provisional' if provisional else 'collection', c) # Setup OAI Repository if provisional: self.save_acl(c.id, collection_name) else: self.save_oairepository_set(provisional=provisional) # Setup title, tabs and collection tree self.save_collectionname(c, self.get_title(provisional=provisional)) self.save_collectiondetailedrecordpagetabs(c) self.save_collectioncollection( c, CFG_USERCOLLCTION_PARENT_NAME_PROVISIONAL if provisional else CFG_USERCOLLCTION_PARENT_NAME) # Setup collection format is needed if not provisional and CFG_USERCOLLCTION_OUTPUTFORMAT: self.save_collectionformat(c, CFG_USERCOLLCTION_OUTPUTFORMAT) elif provisional and CFG_USERCOLLCTION_OUTPUTFORMAT_PROVISIONAL: self.save_collectionformat( c, CFG_USERCOLLCTION_OUTPUTFORMAT_PROVISIONAL) # Setup portal boxes self.save_collectionportalboxes( c, CFG_USERCOLLCTION_PORTALBOXES_PROVISIONAL if provisional else CFG_USERCOLLCTION_PORTALBOXES) db.session.commit() after_save_collection.send(self, collection=c, provisional=provisional) def save_collections(self): """ Create restricted and unrestricted collection """ before_save_collections.send(self) self.save_collection(provisional=False) self.save_collection(provisional=True) after_save_collections.send(self) def delete_record_collection_identifiers(self): """ Remove collection identifiers for this user collection from all records. """ provisional_id = self.get_collection_name(provisional=True) normal_id = self.get_collection_name(provisional=False) def test_func(code, val): return False def replace_func(code, val): return (code, val) def include_func(code, val): return not (code == 'a' and (val == provisional_id or val == normal_id)) coll = [] for r in search_pattern(p="980__a:%s OR 980__a:%s" % (normal_id, provisional_id)): coll.append( self._modify_record(r, test_func, replace_func, include_func)) self._upload_collection(coll) def delete_collection(self, provisional=False): """ Delete all objects related to a single collection """ # Most of the logic in this method ought to be moved to a # Collection.delete() method. c = getattr(self, "collection_provisional" if provisional else "collection") collction_name = self.get_collection_name(provisional=provisional) before_delete_collection.send(self, collection=c, provisional=provisional) if c: # Delete portal boxes for c_pbox in c.portalboxes: if c_pbox.portalbox: db.session.delete(c_pbox.portalbox) db.session.delete(c_pbox) # Delete output formats: CollectionFormat.query.filter_by(id_collection=c.id).delete() # Delete title, tabs, collection tree Collectionname.query.filter_by(id_collection=c.id).delete() CollectionCollection.query.filter_by(id_son=c.id).delete() Collectiondetailedrecordpagetabs.query.filter_by( id_collection=c.id).delete() if provisional: # Delete ACLs AccARGUMENT.query.filter_by(keyword='collection', value=collction_name).delete() role = AccROLE.query.filter_by(name='coll_%s' % c.id).first() if role: UserAccROLE.query.filter_by(role=role).delete() AccAuthorization.query.filter_by(role=role).delete() db.session.delete(role) else: # Delete OAI repository if self.oai_set: db.session.delete(self.oai_set) # Delete collection if c: db.session.delete(c) db.session.commit() after_delete_collection.send(self, provisional=provisional) def delete_collections(self): """ Delete collection and all associated objects. """ before_delete_collections.send(self) self.delete_record_collection_identifiers() self.delete_collection(provisional=False) self.delete_collection(provisional=True) after_delete_collections.send(self)
class PersistentIdentifier(db.Model): """ Store and register persistent identifiers Assumptions: * Persistent identifiers can be represented as a string of max 255 chars. * An object has many persistent identifiers. * A persistent identifier has one and only one object. """ __tablename__ = 'pid' __table_args__ = ( db.Index('uidx_type_pid', 'type', 'pid', unique=True), db.Index('idx_status', 'status'), db.Index('', 'object_type', 'object_id'), ) id = db.Column(db.Integer(15, unsigned=True), primary_key=True) """ Id of persistent identifier entry """ type = db.Column(db.String(6), nullable=False) """ Persistent Identifier Scheme """ pid = db.Column(db.String(length=255), nullable=False) """ Persistent Identifier """ status = db.Column(db.Char(length=1), nullable=False) """ Status of persistent identifier, e.g. registered, reserved, deleted """ object_type = db.Column(db.String(3), nullable=True) """ Object Type - e.g. rec for record """ object_id = db.Column(db.String(length=255), nullable=True) """ Object ID - e.g. a record id """ created = db.Column(db.DateTime(), nullable=False, default=datetime.now) """ Creation datetime of entry """ last_modified = db.Column(db.DateTime(), nullable=False, default=datetime.now, onupdate=datetime.now) """ Last modification datetime of entry """ # # Class methods # @classmethod def create(cls, pid_type, pid, provider=None): """ Internally reserve a new persistent identifier in Invenio. A provider for the given persistent identifier type must exists. By default the system will choose a provider according to the pid type. If desired, the default system provider can be overridden via the provider keyword argument. Returns PID object if successful otherwise None. """ # Ensure provider exists if provider is None: provider = PidProvider.create(pid_type, pid) if not provider: raise Exception("No provider found for %s:%s" % (pid_type, pid)) try: obj = cls(type=provider.pid_type, pid=pid, status=CFG_STATUS_NEW) obj._provider = provider db.session.add(obj) db.session.commit() obj.log("CREATE", "Created") return obj except SQLAlchemyError: db.session.rollback() obj.log("CREATE", "Failed to created. Already exists.") return None @classmethod def get(cls, pid_type, pid, provider=None): """ Get persistent identifier. Returns None if not found. """ pid = to_unicode(pid) obj = cls.query.filter_by(type=pid_type, pid=pid).first() if obj: obj._provider = provider return obj else: return None # # Instance methods # def has_object(self, object_type, object_id): """ Determine if this persistent identifier is assigned to a specific object. """ if object_type not in CFG_OBJECT_TYPES: raise Exception("Invalid object type %s." % object_type) object_id = to_unicode(object_id) return self.object_type == object_type and self.object_id == object_id def get_provider(self): """ Get the provider for this type of persistent identifier """ if self._provider is None: self._provider = PidProvider.create(self.type, self.pid) return self._provider def assign(self, object_type, object_id, overwrite=False): """ Assign this persistent identifier to a given object Note, the persistent identifier must first have been reserved. Also, if an exsiting object is already assigned to the pid, it will raise an exception unless overwrite=True. """ if object_type not in CFG_OBJECT_TYPES: raise Exception("Invalid object type %s." % object_type) object_id = to_unicode(object_id) if not self.id: raise Exception( "You must first create the persistent identifier before you can assign objects to it." ) # FIXME: Desirable to not be able to assign to a deleted? if self.is_deleted(): raise Exception( "You cannot assign objects to a deleted persistent identifier." ) # Check for an existing object assigned to this pid existing_obj_id = self.get_assigned_object(object_type) if existing_obj_id and existing_obj_id != object_id: if not overwrite: raise Exception( "Persistent identifier is already assigned to another object" ) else: self.log( "ASSIGN", "Unassigned object %s:%s (overwrite requested)" % (self.object_type, self.object_id)) self.object_type = None self.object_id = None elif existing_obj_id and existing_obj_id == object_id: # The object is already assigned to this pid. return True self.object_type = object_type self.object_id = object_id db.session.commit() self.log("ASSIGN", "Assigned object %s:%s" % (self.object_type, self.object_id)) return True def update(self, with_deleted=False, *args, **kwargs): """ Update the persistent identifier with the provider. """ if self.is_new() or self.is_reserved(): raise Exception( "Persistent identifier has not yet been registered.") if not with_deleted and self.is_deleted(): raise Exception("Persistent identifier has been deleted.") provider = self.get_provider() if provider is None: self.log("UPDATE", "No provider found.") raise Exception("No provider found.") if provider.update(self, *args, **kwargs): if with_deleted and self.is_deleted(): self.status = CFG_STATUS_REGISTERED db.session.commit() return True return False def reserve(self, *args, **kwargs): """ Reserve the persistent identifier with the provider Note, the reserve method may be called multiple times, even if it was already reserved. """ if not (self.is_new() or self.is_reserved()): raise Exception( "Persistent identifier has already been registered.") provider = self.get_provider() if provider is None: self.log("RESERVE", "No provider found.") raise Exception("No provider found.") if provider.reserve(self, *args, **kwargs): self.status = CFG_STATUS_RESERVED db.session.commit() return True return False def register(self, *args, **kwargs): """ Register the persistent identifier with the provider """ if self.is_registered() or self.is_deleted(): raise Exception( "Persistent identifier has already been registered.") provider = self.get_provider() if provider is None: self.log("REGISTER", "No provider found.") raise Exception("No provider found.") if provider.register(self, *args, **kwargs): self.status = CFG_STATUS_REGISTERED db.session.commit() return True return False def delete(self, *args, **kwargs): """ Delete the persistent identifier """ if self.is_new(): # New DOI which haven't been registered yet. Just delete it # completely but keep log) # Remove links to log entries (but otherwise leave the log entries) PidLog.query.filter_by(id_pid=self.id).update({'id_pid': None}) db.session.delete(self) self.log("DELETE", "Unregistered PID successfully deleted") else: provider = self.get_provider() if not provider.delete(self, *args, **kwargs): return False self.status = CFG_STATUS_DELETED db.session.commit() return True def get_assigned_object(self, object_type=None): if object_type is not None and self.object_type == object_type: return self.object_id return None def is_registered(self): """ Returns true if the persistent identifier has been registered """ return self.status == CFG_STATUS_REGISTERED def is_deleted(self): """ Returns true if the persistent identifier has been deleted """ return self.status == CFG_STATUS_DELETED def is_new(self): """ Returns true if the persistent identifier has not yet been registered or reserved """ return self.status == CFG_STATUS_NEW def is_reserved(self): """ Returns true if the persistent identifier has not yet been reserved. """ return self.status == CFG_STATUS_RESERVED def log(self, action, message): if self.type and self.pid: message = "[%s:%s] %s" % (self.type, self.pid, message) p = PidLog(id_pid=self.id, action=action, message=message) db.session.add(p) db.session.commit()