def __init__(self): self.logger = logger("") begin() self.settings = Settings(self) self.worlds = {} self.default_world = None self.level = Level.engine self.logger.info("CocoMUD engine started")
def getMetadata(identifier, user=ezidapp.models.AnonymousUser, prefixMatch=False): """ Returns all metadata for a given qualified identifier, e.g., "doi:10.5060/FOO". 'user' is the requestor and should be an authenticated StoreUser object. The successful return is a pair (status, dictionary) where 'status' is a string that includes the canonical, qualified form of the identifier, as in: success: doi:10.5060/FOO and 'dictionary' contains element (name, value) pairs. Unsuccessful returns include the strings: error: forbidden error: bad request - subreason... error: internal server error error: concurrency limit exceeded If 'prefixMatch' is true, prefix matching is enabled and the returned identifier is the longest identifier that matches a (possibly proper) prefix of the requested identifier. In such a case, the status string resembles: success: doi:10.5060/FOO in_lieu_of doi:10.5060/FOOBAR """ nqidentifier = util.normalizeIdentifier(identifier) if nqidentifier == None: return "error: bad request - invalid identifier" tid = uuid.uuid1() if not _acquireIdentifierLock(nqidentifier, user.username): return "error: concurrency limit exceeded" try: log.begin(tid, "getMetadata", nqidentifier, user.username, user.pid, user.group.groupname, user.group.pid, str(prefixMatch)) si = ezidapp.models.getIdentifier(nqidentifier, prefixMatch) if not policy.authorizeView(user, si): log.forbidden(tid) return "error: forbidden" d = si.toLegacy() util2.convertLegacyToExternal(d) if si.isDoi: d["_shadowedby"] = si.arkAlias log.success(tid) if prefixMatch and si.identifier != nqidentifier: return ("success: %s in_lieu_of %s" % (si.identifier, nqidentifier), d) else: return ("success: " + nqidentifier, d) except ezidapp.models.StoreIdentifier.DoesNotExist: log.badRequest(tid) return "error: bad request - no such identifier" except Exception, e: log.error(tid, e) return "error: internal server error"
def mintIdentifier(shoulder, user, metadata={}): """ Mints an identifier under the given qualified shoulder, e.g., "doi:10.5060/". 'user' is the requestor and should be an authenticated StoreUser object. 'metadata' should be a dictionary of element (name, value) pairs. If an initial target URL is not supplied, the identifier is given a self-referential target URL. The successful return is a string that includes the canonical, qualified form of the new identifier, as in: success: ark:/95060/fk35717n0h For DOI identifiers, the string also includes the qualified shadow ARK, as in: success: doi:10.5060/FK35717N0H | ark:/b5060/fk35717n0h Unsuccessful returns include the strings: error: forbidden error: bad request - subreason... error: internal server error error: concurrency limit exceeded """ tid = uuid.uuid1() try: log.begin(tid, "mintIdentifier", shoulder, user.username, user.pid, user.group.groupname, user.group.pid) s = ezidapp.models.getExactShoulderMatch(shoulder) if s == None: log.badRequest(tid) return "error: bad request - no such shoulder" if s.isUuid: identifier = "uuid:" + str(uuid.uuid1()) else: if s.minter == "": log.badRequest(tid) return "error: bad request - shoulder does not support minting" # Minters always return unqualified ARKs. ark = noid_nog.getMinter(s.minter).mintIdentifier() if s.isArk: identifier = "ark:/" + ark elif s.isDoi: doi = util.shadow2doi(ark) assert util.doi2shadow(doi) == ark, "invalid DOI shadow ARK" identifier = "doi:" + doi else: assert False, "unhandled case" assert identifier.startswith(s.prefix),\ "minted identifier does not match shoulder" except Exception, e: log.error(tid, e) return "error: internal server error"
def executeSearch( user, constraints, from_, to, orderBy=None, selectRelated=defaultSelectRelated, defer=defaultDefer, ): """ Executes a search database query, returning an evaluated QuerySet. 'user' is the requestor, and should be an authenticated StoreUser object or AnonymousUser. 'from_' and 'to' are range bounds, and must be supplied. 'constraints', 'orderBy', 'selectRelated', and 'defer' are as in formulateQuery above. """ tid = uuid.uuid1() try: _modifyActiveCount(1) qs = formulateQuery(constraints, orderBy=orderBy, selectRelated=selectRelated, defer=defer) log.begin( tid, "search/results", "-", user.username, user.pid, user.group.groupname, user.group.pid, str(orderBy), str(from_), str(to), *reduce(operator.__concat__, [[k, unicode(v)] for k, v in constraints.items()])) qs = qs[from_:to] c = len(qs) except Exception, e: # MySQL's FULLTEXT engine chokes on a too-frequently-occurring # word (call it a "bad" word) that is not on its own stopword # list. We weed out bad words using our own stopword list, but # not if they're quoted, and unfortunately MySQL chokes on bad # words quoted or not. Furthermore, we are unable to add to # MySQL's stopword list. If MySQL chokes, we retry the query # without any quotes in the hopes that any quoted bad words will # be removed by our own processing. if _isMysqlFulltextError(e) and any('"' in constraints.get(f, "") for f in _fulltextFields): constraints2 = constraints.copy() for f in _fulltextFields: if f in constraints2: constraints2[f] = constraints2[f].replace('"', " ") log.success(tid, "-1") return executeSearch(user, constraints2, from_, to, orderBy, selectRelated, defer) else: log.error(tid, e) raise
def __init__(self, config_dir="."): self.logger = logger("") begin() self.config_dir = config_dir if config_dir != ".": self.logger.info(f"Using an alternative config directory: {config_dir}") self.settings = Settings(self, config_dir) self.sounds = True self.worlds = {} self.default_world = None self.level = Level.engine self.logger.info("CocoMUD engine started")
def deleteIdentifier(identifier, user, updateExternalServices=True): """ Deletes an identifier having the given qualified name, e.g., "doi:10.5060/FOO". 'user' is the requestor and should be an authenticated StoreUser object. The successful return is a string that includes the canonical, qualified form of the now-nonexistent identifier, as in: success: doi:/10.5060/FOO Unsuccessful returns include the strings: error: forbidden error: bad request - subreason... error: internal server error error: concurrency limit exceeded """ nqidentifier = util.normalizeIdentifier(identifier) if nqidentifier == None: return "error: bad request - invalid identifier" tid = uuid.uuid1() if not _acquireIdentifierLock(nqidentifier, user.username): return "error: concurrency limit exceeded" try: log.begin( tid, "deleteIdentifier", nqidentifier, user.username, user.pid, user.group.groupname, user.group.pid, ) si = ezidapp.models.getIdentifier(nqidentifier) if not policy.authorizeDelete(user, si): log.forbidden(tid) return "error: forbidden" if not si.isReserved and not user.isSuperuser: log.badRequest(tid) return "error: bad request - identifier status does not support deletion" with django.db.transaction.atomic(): si.delete() ezidapp.models.update_queue.enqueue(si, "delete", updateExternalServices) except ezidapp.models.StoreIdentifier.DoesNotExist: log.badRequest(tid) return "error: bad request - no such identifier" except Exception, e: log.error(tid, e) return "error: internal server error"
def setMetadata(identifier, user, metadata, updateExternalServices=True, internalCall=False): """ Sets metadata elements of a given qualified identifier, e.g., "doi:10.5060/FOO". 'user' is the requestor and should be an authenticated StoreUser object. 'metadata' should be a dictionary of element (name, value) pairs. If an element being set already exists, it is overwritten, if not, it is created; existing elements not set are left unchanged. Of the reserved metadata elements, only "_owner", "_target", "_profile", "_status", and "_export" may be set (unless the user is the EZID administrator). The "_crossref" element may be set only in certain situations. The successful return is a string that includes the canonical, qualified form of the identifier, as in: success: doi:10.5060/FOO Unsuccessful returns include the strings: error: forbidden error: bad request - subreason... error: internal server error error: concurrency limit exceeded """ nqidentifier = util.normalizeIdentifier(identifier) if nqidentifier == None: return "error: bad request - invalid identifier" tid = uuid.uuid1() if not internalCall: if not _acquireIdentifierLock(nqidentifier, user.username): return "error: concurrency limit exceeded" try: log.begin(tid, "setMetadata", nqidentifier, user.username, user.pid, user.group.groupname, user.group.pid, *[a for p in metadata.items() for a in p]) si = ezidapp.models.getIdentifier(nqidentifier) if not policy.authorizeUpdate(user, si): log.forbidden(tid) return "error: forbidden" previousOwner = si.owner si.updateFromUntrustedLegacy(metadata, allowRestrictedSettings=user.isSuperuser) if si.isCrossref and not si.isReserved and updateExternalServices: si.crossrefStatus = ezidapp.models.StoreIdentifier.CR_WORKING si.crossrefMessage = "" if "_updated" not in metadata: si.updateTime = "" si.my_full_clean() if si.owner != previousOwner: if not policy.authorizeOwnershipChange(user, previousOwner, si.owner): log.badRequest(tid) return "error: bad request - ownership change prohibited" with django.db.transaction.atomic(): si.save() ezidapp.models.update_queue.enqueue(si, "update", updateExternalServices) except ezidapp.models.StoreIdentifier.DoesNotExist: log.badRequest(tid) return "error: bad request - no such identifier" except django.core.exceptions.ValidationError, e: log.badRequest(tid) return "error: bad request - " + util.formatValidationError(e)
def createIdentifier(identifier, user, metadata={}, updateIfExists=False): """ Creates an identifier having the given qualified name, e.g., "doi:10.5060/FOO". 'user' is the requestor and should be an authenticated StoreUser object. 'metadata' should be a dictionary of element (name, value) pairs. If an initial target URL is not supplied, the identifier is given a self-referential target URL. The successful return is a string that includes the canonical, qualified form of the new identifier, as in: success: ark:/95060/foo For DOI identifiers, the string also includes the qualified shadow ARK, as in: success: doi:10.5060/FOO | ark:/b5060/foo Unsuccessful returns include the strings: error: forbidden error: bad request - subreason... error: internal server error error: concurrency limit exceeded If 'updateIfExists' is true, an "identifier already exists" error falls through to a 'setMetadata' call. """ nqidentifier = util.normalizeIdentifier(identifier) if nqidentifier == None: return "error: bad request - invalid identifier" tid = uuid.uuid1() if not _acquireIdentifierLock(nqidentifier, user.username): return "error: concurrency limit exceeded" try: log.begin(tid, "createIdentifier", nqidentifier, user.username, user.pid, user.group.groupname, user.group.pid, *[a for p in metadata.items() for a in p]) if not policy.authorizeCreate(user, nqidentifier): log.forbidden(tid) return "error: forbidden" si = ezidapp.models.StoreIdentifier( identifier=nqidentifier, owner=(None if user == ezidapp.models.AnonymousUser else user)) si.updateFromUntrustedLegacy(metadata, allowRestrictedSettings=user.isSuperuser) if si.isDoi: s = ezidapp.models.getLongestShoulderMatch(si.identifier) # Should never happen. assert s != None, "no matching shoulder found" if s.isDatacite: if si.datacenter == None: si.datacenter = s.datacenter elif s.isCrossref: if not si.isCrossref: if si.isReserved: si.crossrefStatus = ezidapp.models.StoreIdentifier.CR_RESERVED else: si.crossrefStatus = ezidapp.models.StoreIdentifier.CR_WORKING else: assert False, "unhandled case" si.my_full_clean() if si.owner != user: if not policy.authorizeOwnershipChange(user, user, si.owner): log.badRequest(tid) return "error: bad request - ownership change prohibited" with django.db.transaction.atomic(): si.save() ezidapp.models.update_queue.enqueue(si, "create") except django.core.exceptions.ValidationError, e: log.badRequest(tid) return "error: bad request - " + util.formatValidationError(e)
def _mintIdentifier(shoulder, user, metadata={}): """ Mints an identifier under the given qualified shoulder, e.g., "doi:10.5060/". 'user' is the requestor and should be an authenticated StoreUser object. 'metadata' should be a dictionary of element (name, value) pairs. If an initial target URL is not supplied, the identifier is given a self-referential target URL. The successful return is a string that includes the canonical, qualified form of the new identifier, as in: success: ark:/95060/fk35717n0h For DOI identifiers, the string also includes the qualified shadow ARK, as in: success: doi:10.5060/FK35717N0H | ark:/b5060/fk35717n0h Unsuccessful returns include the strings: error: forbidden error: bad request - subreason... error: internal server error error: concurrency limit exceeded """ tid = uuid.uuid1() # TODO: We want to be able to support rendering error messages to end users in # production like current version of EZID does without breaking rendering of # Django's exception diagnostics page in debug mode and without # having to wrap large sections of code in exception handlers just for redirecting # to a logger. log.begin( tid, "mintIdentifier", shoulder, user.username, user.pid, user.group.groupname, user.group.pid, ) shoulder_model = ezidapp.models.getExactShoulderMatch(shoulder) if shoulder_model is None: log.badRequest(tid) # TODO: Errors should be raised, not returned. return "error: bad request - no such shoulder" if shoulder_model.isUuid: identifier = "uuid:" + str(uuid.uuid1()) else: if shoulder_model.minter == "": log.badRequest(tid) return "error: bad request - shoulder does not support minting" identifier = minter.mint_id(shoulder_model) logger.debug('Minter returned identifier: {}'.format(identifier)) if shoulder_model.prefix.startswith('doi:'): identifier = shoulder_model.prefix + identifier.upper() elif shoulder_model.prefix.startswith('ark:/'): identifier = shoulder_model.prefix + identifier.lower() else: raise False, 'Expected ARK or DOI prefix, not "{}"'.format( shoulder_model.prefix) logger.debug('Final shoulder + identifier: {}'.format(identifier)) log.success(tid, identifier) return createIdentifier(identifier, user, metadata)