def root(request, format=None, **kwargs): """ The documentation for the Open Science Framework API can be found at [developer.osf.io](https://developer.osf.io). """ if request.user and not request.user.is_anonymous: user = request.user current_user = UserSerializer(user, context={'request': request}).data else: current_user = None kwargs = request.parser_context['kwargs'] return_val = { 'meta': { 'message': 'Welcome to the OSF API.', 'version': request.version, 'current_user': current_user, }, 'links': { 'nodes': utils.absolute_reverse('nodes:node-list', kwargs=kwargs), 'users': utils.absolute_reverse('users:user-list', kwargs=kwargs), 'collections': utils.absolute_reverse('collections:collection-list', kwargs=kwargs), 'registrations': utils.absolute_reverse('registrations:registration-list', kwargs=kwargs), 'institutions': utils.absolute_reverse('institutions:institution-list', kwargs=kwargs), 'licenses': utils.absolute_reverse('licenses:license-list', kwargs=kwargs), 'metaschemas': utils.absolute_reverse('metaschemas:metaschema-list', kwargs=kwargs), 'addons': utils.absolute_reverse('addons:addon-list', kwargs=kwargs), } } if utils.has_admin_scope(request): return_val['meta']['admin'] = True return Response(return_val)
def root(request, format=None, **kwargs): """ The documentation for the Open Science Framework API can be found at [developer.osf.io](https://developer.osf.io). The contents of this endpoint are variable and subject to change without notification. """ if request.user and not request.user.is_anonymous: user = request.user current_user = UserSerializer(user, context={'request': request}).data else: current_user = None flags = [name for name in Flag.objects.values_list('name', flat=True) if flag_is_active(request, name)] kwargs = request.parser_context['kwargs'] return_val = { 'meta': { 'message': 'Welcome to the OSF API.', 'version': request.version, 'current_user': current_user, 'active_flags': flags, }, 'links': { 'nodes': utils.absolute_reverse('nodes:node-list', kwargs=kwargs), 'users': utils.absolute_reverse('users:user-list', kwargs=kwargs), 'collections': utils.absolute_reverse('collections:collection-list', kwargs=kwargs), 'registrations': utils.absolute_reverse('registrations:registration-list', kwargs=kwargs), 'institutions': utils.absolute_reverse('institutions:institution-list', kwargs=kwargs), 'licenses': utils.absolute_reverse('licenses:license-list', kwargs=kwargs), 'schemas': utils.absolute_reverse('schemas:registration-schema-list', kwargs=kwargs), 'addons': utils.absolute_reverse('addons:addon-list', kwargs=kwargs), }, } if utils.has_admin_scope(request): return_val['meta']['admin'] = True return Response(return_val)
def get_absolute_url(self, obj): return absolute_reverse( 'logs:log-detail', kwargs={ 'log_id': obj._id, } )
def self_url(self, obj): return absolute_reverse( 'identifiers:identifier-detail', kwargs={ 'identifier_id': obj._id, 'version': self.context['request'].parser_context['kwargs']['version'], }, )
def get_self_url(self, obj): return absolute_reverse( 'view-only-links:view-only-link-nodes', kwargs={ 'link_id': obj['self']._id } )
def serialize_draft_registration(draft, auth=None): from website.project.utils import serialize_node # noqa from api.base.utils import absolute_reverse node = draft.branched_from return { 'pk': draft._id, 'branched_from': serialize_node(node, auth), 'initiator': serialize_initiator(draft.initiator), 'registration_metadata': draft.registration_metadata, 'registration_schema': serialize_meta_schema(draft.registration_schema), 'initiated': utils.iso8601format(draft.datetime_initiated), 'updated': utils.iso8601format(draft.datetime_updated), 'flags': draft.flags, 'urls': { 'edit': node.web_url_for('edit_draft_registration_page', draft_id=draft._id, _guid=True), 'submit': node.api_url_for('submit_draft_for_review', draft_id=draft._id), 'before_register': node.api_url_for('project_before_register'), 'register': absolute_reverse('nodes:node-registrations', kwargs={'node_id': node._id, 'version': 'v2'}), 'register_page': node.web_url_for('draft_before_register_page', draft_id=draft._id, _guid=True), 'registrations': node.web_url_for('node_registrations', _guid=True) }, 'requires_approval': draft.requires_approval, 'is_pending_approval': draft.is_pending_review, 'is_approved': draft.is_approved, }
def get_wiki_content(self, obj): return absolute_reverse( 'wikis:wiki-content', kwargs={ 'wiki_id': obj._id, 'version': self.context['request'].parser_context['kwargs']['version'], }, )
def get_absolute_url(self, obj): return absolute_reverse( 'nodes:node-view-only-link-detail', kwargs={ 'link_id': obj._id } )
def get_absolute_url(self, obj): return absolute_reverse( 'users:user-detail', kwargs={ 'user_id': obj._id, 'version': self.context['request'].parser_context['kwargs']['version'], }, )
def reset_url(self, obj): return absolute_reverse( 'applications:application-reset', kwargs={ 'client_id': obj.client_id, 'version': self.context['request'].parser_context['kwargs']['version'], }, )
def get_preprints_url(self, obj): return absolute_reverse( 'providers:preprint-providers:preprints-list', kwargs={ 'provider_id': obj._id, 'version': self.context['request'].parser_context['kwargs']['version'], }, )
def get_related_url(self, obj): return absolute_reverse( 'users:user-institutions', kwargs={ 'user_id': obj['self']._id, 'version': self.context['request'].parser_context['kwargs']['version'], }, )
def get_absolute_url(self, obj): return absolute_reverse( view_name='search:search-search', kwargs={ 'version': self.context['request'].parser_context['kwargs']['version'] } )
def get_registration_url(self, obj): return absolute_reverse( 'registrations:registration-detail', kwargs={ 'node_id': obj._id, 'version': self.context['request'].parser_context['kwargs']['version'], }, )
def get_export_link(self, obj): return absolute_reverse( 'users:user-account-export', kwargs={ 'user_id': obj._id, 'version': self.context['request'].parser_context['kwargs']['version'], }, )
def get_absolute_url(self, obj): return absolute_reverse( 'nodes:node-view-only-link-detail', kwargs={ 'link_id': obj._id, 'version': self.context['request'].parser_context['kwargs']['version'] } )
def get_self_url(self, obj): return absolute_reverse( 'view-only-links:view-only-link-nodes', kwargs={ 'link_id': obj['self']._id, 'version': self.context['request'].parser_context['kwargs']['version'] } )
def reset_url(self, obj): return absolute_reverse( "applications:application-reset", kwargs={ "client_id": obj["client_id"], "version": self.context["request"].parser_context["kwargs"]["version"], }, )
def get_download_link(self, obj): return absolute_reverse( 'files:metadata-record-download', kwargs={ 'file_id': obj.file._id, 'record_id': obj._id, 'version': self.context['request'].parser_context['kwargs']['version'], }, )
def get_absolute_url(self, obj): kwargs = self.context['request'].parser_context['kwargs'] kwargs.update({'account_id': obj._id}) return absolute_reverse( 'users:user-external_account-detail', kwargs=kwargs ) return obj.get_absolute_url()
def get_absolute_url(self, obj): return absolute_reverse( 'nodes:node-provider-detail', kwargs={ 'node_id': obj.node._id, 'provider': obj.provider } )
def get_url(self, obj, view_name, request, format): if obj is None: return {} lookup_value = getattr(obj, self.lookup_field) return absolute_reverse(self.view_name, kwargs={ self.lookup_url_kwarg: lookup_value, 'version': self.context['request'].parser_context['kwargs']['version'] })
def self_url(self, obj): return absolute_reverse( 'wikis:wiki-version-detail', kwargs={ 'version_id': obj.identifier, 'wiki_id': obj.wiki_page._id, 'version': self.context['request'].parser_context['kwargs']['version'], }, )
def resolve_url(self, obj): kwarg_values = {key: _get_attr_from_tpl(attr_tpl, obj) for key, attr_tpl in self.kwargs.items()} arg_values = [_get_attr_from_tpl(attr_tpl, obj) for attr_tpl in self.args] query_kwarg_values = {key: _get_attr_from_tpl(attr_tpl, obj) for key, attr_tpl in self.query_kwargs.items()} return absolute_reverse( self.endpoint, args=arg_values, kwargs=kwarg_values, query_kwargs=query_kwarg_values, **self.reverse_kwargs )
def self_url(self, obj): return absolute_reverse( 'files:version-detail', kwargs={ 'version_id': obj.identifier, 'file_id': self.context['view'].kwargs['file_id'], 'version': self.context['request'].parser_context['kwargs']['version'], }, )
def get_absolute_url(self, obj): node_id = self.context['request'].parser_context['kwargs']['node_id'] return absolute_reverse( 'nodes:node-pointer-detail', kwargs={ 'node_id': node_id, 'node_link_id': obj._id } )
def get_absolute_url(self, obj): comment_id = self.context['request'].parser_context['kwargs']['comment_id'] return absolute_reverse( 'comments:report-detail', kwargs={ 'comment_id': comment_id, 'user_id': obj._id } )
def get_absolute_url(self, obj): return absolute_reverse( 'registrations:registration-contributor-detail', kwargs={ 'user_id': obj.user._id, 'node_id': self.context['request'].parser_context['kwargs']['node_id'], 'version': self.context['request'].parser_context['kwargs']['version'] } )
def self_url(self, obj): return absolute_reverse( "files:version-detail", kwargs={ "version_id": obj.identifier, "file_id": self.context["view"].kwargs["file_id"], "version": self.context["request"].parser_context["kwargs"]["version"], }, )
def get_absolute_url(self, obj): return absolute_reverse( 'users:user-addon-detail', kwargs={ 'provider': obj.config.short_name, 'user_id': self.context['request'].parser_context['kwargs']['user_id'], 'version': self.context['request'].parser_context['kwargs']['version'], }, )
def perform_create(self, serializer): target = serializer.validated_data['target'] self.check_object_permissions(self.request, target) if not target.provider.is_reviewed: raise Conflict( '{} is an unmoderated provider. If you are an admin, set up moderation by setting `reviews_workflow` at {}' .format( target.provider.name, absolute_reverse( 'providers:preprint-providers:preprint-provider-detail', kwargs={ 'provider_id': target.provider._id, 'version': self.request.parser_context['kwargs']['version'], }, ), )) serializer.save(user=self.request.user)
def resolve_url(self, obj): kwarg_values = { key: _get_attr_from_tpl(attr_tpl, obj) for key, attr_tpl in self.kwargs.items() } arg_values = [ _get_attr_from_tpl(attr_tpl, obj) for attr_tpl in self.args ] query_kwarg_values = { key: _get_attr_from_tpl(attr_tpl, obj) for key, attr_tpl in self.query_kwargs.items() } # Presumably, if you have are expecting a value but the value is empty, then the link is invalid. for item in kwarg_values: if kwarg_values[item] is None: return None return utils.absolute_reverse(self.endpoint, args=arg_values, kwargs=kwarg_values, query_kwargs=query_kwarg_values, **self.reverse_kwargs)
def reverse(self, viewname, args=None, kwargs=None, request=None, format=None, **extra): url_path_version = self.get_url_path_version(kwargs) query_parameter_version = self.get_query_param_version(request) kwargs = {} if (kwargs is None) else kwargs kwargs[self.version_param] = decimal_version_to_url_path( url_path_version) query_kwargs = { 'version': query_parameter_version } if query_parameter_version else None return utils.absolute_reverse(viewname, query_kwargs=query_kwargs, args=args, kwargs=kwargs)
def serialize_draft_registration(draft, auth=None): from website.project.utils import serialize_node # noqa from api.base.utils import absolute_reverse node = draft.branched_from return { 'pk': draft._id, 'branched_from': serialize_node(node, auth), 'initiator': serialize_initiator(draft.initiator), 'registration_metadata': draft.registration_metadata, 'registration_schema': serialize_meta_schema(draft.registration_schema), 'initiated': utils.iso8601format(draft.datetime_initiated), 'updated': utils.iso8601format(draft.datetime_updated), 'flags': draft.flags, 'urls': { 'edit': node.web_url_for('edit_draft_registration_page', draft_id=draft._id, _guid=True), 'before_register': node.api_url_for('project_before_register'), 'register': absolute_reverse('nodes:node-registrations', kwargs={ 'node_id': node._id, 'version': 'v2' }), 'register_page': node.web_url_for('draft_before_register_page', draft_id=draft._id, _guid=True), 'registrations': node.web_url_for('node_registrations', _guid=True) }, 'requires_approval': draft.requires_approval, 'is_pending_approval': draft.is_pending_review, 'is_approved': draft.is_approved, }
def reverse(self, viewname, args=None, kwargs=None, request=None, format=None, **extra): """ Overrides BaseVersioning.reverse to maybe ignore 'version' arg Requests to private views in the '_' namespace don't have any version associated with them. Related fields in their serializers that point to views in a versioned namespace require a version kwarg to be reversed correctly. This first tries the reverse with one, then without if that fails. """ try: return super(PrivateVersioning, self).reverse(viewname, args=args, kwargs=kwargs, request=request, format=format, **extra) except NoReverseMatch: kwargs = kwargs or {} if kwargs.get('version', False): kwargs.pop('version') return utils.absolute_reverse( viewname, query_kwargs=None, args=args, kwargs=kwargs, ) kwargs['version'] = get_latest_sub_version('2') return super(PrivateVersioning, self).reverse(viewname, args=args, kwargs=kwargs, request=request, format=format, **extra)
def get_absolute_url(self, obj): return absolute_reverse('meetings:meeting-detail', kwargs={'meeting_id': obj.endpoint})
def root(request, format=None, **kwargs): """Welcome to the V2 Open Science Framework API. With this API you can access users, projects, components, logs, and files from the [Open Science Framework](https://osf.io/). The Open Science Framework (OSF) is a free, open-source service maintained by the [Center for Open Science](http://cos.io/). The OSF serves as a repository and archive for study designs, materials, data, manuscripts, or anything else associated with your research during the research process. Every project and file on the OSF has a permanent unique identifier, and every registration (a permanent, time-stamped version of your projects and files) can be assigned a DOI/ARK. You can use the OSF to measure your impact by monitoring the traffic to projects and files you make public. With the OSF you have full control of what parts of your research are public and what remains private. Beta notice: This API is currently a beta service. You are encouraged to use the API and will receive support when doing so, however, while the API remains in beta status, it may change without notice as a result of product updates. The temporary beta status of the API will remain in place while it matures. In a future release, the beta status will be removed, at which point we will provide details on how long we will support the API V2 and under what circumstances it might change. #General API Usage The OSF API generally conforms to the [JSON-API v1.0 spec](http://jsonapi.org/format/1.0/). Where exceptions exist, they will be noted. Each endpoint will have its own documentation, but there are some general principles. Assume undocumented routes/features/fields are unstable. ##Requests ###Canonical URLs All canonical URLs have trailing slashes. A request to an endpoint without a trailing slash will result in a 301 redirect to the canonical URL. There are some exceptions when working with the Files API, so if a URL in a response does not have a slash, do not append one. ###Plurals Endpoints are always pluralized. `/users/`, not `/user/`, `/nodes/`, not `/node/`. ###Common Actions Every endpoint in the OSF API responds to `GET`, `HEAD`, and `OPTION` requests. You must have adequate permissions to interact with the endpoint. Unauthorized use will result in 401 Unauthorized or 403 Forbidden responses. Use `HEAD` to probe an endpoint and make sure your headers are well-formed. `GET` will return a representation of the entity or entity collection referenced by the endpoint. An `OPTIONS` request will return a JSON object that describes the endpoint, including the name, a description, the acceptable request formats, the allowed response formats, and any actions available via the endpoint. ###Versioning Versioning can be specified in three different ways: 1. URL Path Versioning, e.g. `/v2/` or `/v3/` + A version specified via the URL path is a **required** part of the URL. + Only a major version can be specified via the URL path, i.e. `/v2.0.6/` is invalid, additionally, paths such as `/v2.0/` are invalid. + If the default version of the API is within the major version specified in the URL path, the default version will be applied (i.e. if the default version is `2.3` and the URL path is `/v2/`, then version returned will be `2.3`). + If the default version of the API is not within the major version specified in the URL path, the URL path version will be applied (i.e. if the default version is `3.0` and the URL path is `/v2/`, then the version returned will be `2.0`) 2. Query Parameter Versioning, e.g. `/v2/nodes/?version=2.1.6` + Pinning to a specific version via a query parameter is **optional**. + A specific version (major, minor, or patch) for a single request can be specified via the `version` query parameter, as long as it is an allowed version. + If the version specified in the query parameter does not fall within the same major version specified in the URL path, i.e `/v2/nodes/?version=3.1.4` a `409 Conflict` response will be returned. 3. Header Versioning, e.g. `Accept-Header=application/vnd.api+json;version=3.0.1` + Pinning to a specific version via request header is **optional**. + A specific version (major, minor, or patch) for a single request can be specified via the `Accept Header` of the request, as long as it is an allowed version. + If the version specified in the header does not fall within the same major version specified in the URL path a `409 Conflict` response will be returned. + If both a header version and query parameter version are specified, the versions must match exactly or a `409 Conflict` response will be returned (i.e. one does not take precedence over the other). ###Filtering Entity collections can be filtered by adding a query parameter in the form: filter[<fieldname>]=<matching information> String queries are filtered using substring matching. For example, if you were trying to find [Lise Meitner](http://en.wikipedia.org/wiki/Lise_Meitner): /users/?filter[full_name]=meitn You can filter on multiple fields, or the same field in different ways, by &-ing the query parameters together. /users/?filter[full_name]=lise&filter[family_name]=mei Boolean fields should be queried with `true` or `false`. /nodes/?filter[registered]=true You can request multiple resources by filtering on id and placing comma-separated values in your query parameter. /nodes/?filter[id]=aegu6,me23a You can filter with case-sensitivity or case-insensitivity by using `contains` and `icontains`, respectively. /nodes/?filter[tags][icontains]=help ###Embedding All related resources that appear in the `relationships` attribute are embeddable, meaning that by adding a query parameter like: /nodes/?embed=contributors it is possible to fetch a Node and its contributors in a single request. The embedded results will have the following structure: {relationship_name}: {full_embedded_response} Where `full_embedded_response` means the full API response resulting from a GET request to the `href` link of the corresponding related resource. This means if there are no errors in processing the embedded request the response will have the format: data: {response} And if there are errors processing the embedded request the response will have the format: errors: {errors} Multiple embeds can be achieved with multiple query parameters separated by "&". /nodes/?embed=contributors&embed=comments Some endpoints are automatically embedded. ###Pagination All entity collection endpoints respond to the `page` query parameter behavior as described in the [JSON-API pagination spec](http://jsonapi.org/format/1.0/#crud). However, pagination links are provided in the response, and you are encouraged to use that rather than adding query parameters by hand. ###Formatting POST/PUT/PATCH request bodies The OSF API follows the JSON-API spec for [create and update requests](http://jsonapi.org/format/1.0/#crud). This means all request bodies must be wrapped with some metadata. Each request body must be an object with a `data` key containing at least a `type` member. The value of the `type` member must agree with the `type` of the entities represented by the endpoint. If not, a 409 Conflict will be returned. The request should also contain an `attributes` member with an object containing the key-value pairs to be created/updated. PUT/PATCH requests must also have an `id` key that matches the id part of the endpoint. If the `id` key does not match the id path part, a 409 Conflict error will be returned. ####Example 1: Creating a Node via POST POST /v2/nodes/ { "data": { "type": "nodes", "attributes": { "title" : "A Phylogenetic Tree of Famous Internet Cats", "category" : "project", "description" : "How closely related are Grumpy Cat and C.H. Cheezburger? Is memefulness inheritable?" } } } ####Example 2: Updating a User via PUT PUT /v2/users/me/ { "data": { "id": "3rqxc", "type": "users", "attributes": { "full_name" : "Henrietta Swan Leavitt", "given_name" : "Henrietta", "middle_names" : "Swan", "family_name" : "Leavitt" } } } **NB:** If you PUT/PATCH to the `/users/me/` endpoint, you must still provide your full user id in the `id` field of the request. We do not support using the `me` alias in request bodies at this time. ###PUT vs. PATCH For most endpoints that support updates via PUT requests, we also allow PATCH updates. The only difference is that PUT requests require all mandatory attributes to be set, even if their value is unchanged. PATCH requests may omit mandatory attributes, whose value will be unchanged. ###Attribute Validation Endpoints that allow creation or modification of entities generally limit updates to certain attributes of the entity. If you attempt to set an attribute that does not permit updates (such as a `date_created` timestamp), the API will silently ignore that attribute. This will not affect the response from the API: if the request would have succeeded without the updated attribute, it will still report as successful. Likewise, if the request would have failed without the attribute update, the API will still report a failure. Typoed or non-existent attributes will behave the same as non-updatable attributes and be silently ignored. If a request is not working the way you expect, make sure to double check your spelling. ##Responses ###Entities An entity is a single resource that has been retrieved from the API, usually from an endpoint with the entity's id as the final path part. A successful response from an entity request will be a JSON object with a top level `data` key pointing to a sub-object with the following members: + `id` The identifier for the entity. This MUST be included with [PUT and PATCH requests](#formatting-postputpatch-request-bodies). + `type` The type identifier of this entity. This MUST be included with [all create/update requests](#formatting-postputpatch-request-bodies). + `attributes` The properties of the entity. Names, descriptions, etc. + `relationships` Relationships are urls to other entities or entity collections that have a relationship to the entity. For example, the node entity provides a `contributors` relationship that points to the endpoint to retrieve all contributors to that node. It is recommended to use these links rather than to id-filter general entity collection endpoints. They'll be faster, easier, and less error-prone. Generally a relationship will have the following structure: {relationship_name}: { "links": { "related": { "href": {url_to_related_entity_or_entity_collection}, "meta": {} } } } If there are no related entities, `href` will be null. + `embeds` Please see `Embedding` documentation under `Requests`. + `links` Links are urls to alternative representations of the entity or actions that may be performed on the entity. Most entities will provide a `self` link that is the canonical endpoint for the entity where update and delete requests should be sent. In-depth documentation of actions is available by navigating to the `self` link in the Browsable API. Most entities will also provide an `html` link that directs to the entity's page on the [OSF](http://osf.io/). ###Entity Collections Entity collection endpoints return a list of entities and an additional data structure with pagination links, such as "next", "prev", "first", and "last". The OSF API limits all entity collection responses to a maximum of 10 entities. The response object has two keys: + `data` `data` is an array of entities that match the query. Each entity in the array is the same representation that is returned from that entity's `self` link, meaning that refetching the entity is unnecessary. + `links` `links` contains pagination information, including links to the previous, next, first, and last pages of results. The meta key contains the total number of entities available, as well as the current number of results displayed per page. If there are only enough results to fill one page, the `first`, `last`, `prev`, and `next` values will be null. ###Errors When a request fails for whatever reason, the OSF API will return an appropriate HTTP error code and include a descriptive error in the body of the response. The response body will be an object with a key, `errors`, pointing to an array of error objects. Generally, these error objects will consist of a `detail` key with a detailed error message and a `source` object that may contain a field `pointer` that is a [JSON Pointer](https://tools.ietf.org/html/rfc6901) to the error-causing attribute. The `error` objects may include additional information in accordance with the [JSON-API error spec](http://jsonapi.org/format/1.0/#error-objects). ####Example: Error response from an incorrect create node request { "errors": [ { "source": { "pointer": "/data/attributes/category" }, "detail": "This field is required." }, { "source": { "pointer": "/data/type" }, "detail": "This field may not be null." }, { "source": { "pointer": "/data/attributes/title" }, "detail": "This field is required." } ] } ##OSF Enum Fields Some entities in the OSF API have fields that only take a restricted set of values. Those fields are listed here for reference. Fuller descriptions are available on the relevant entity pages. ###OSF Node Categories value description ========================================== project Project hypothesis Hypothesis methods and measures Methods and Measures procedure Procedure instrumentation Instrumentation data Data analysis Analysis communication Communication other Other ###OSF Node Permission keys value description ========================================== read Read-only access write Write access (make changes, cannot delete) admin Admin access (full write, create, delete, contributor add) ###Storage Providers Valid storage providers are: value description ========================================== bitbucket Bitbucket box Box.com dataverse Dataverse dropbox Dropbox figshare figshare github GitHub googledrive Google Drive osfstorage OSF Storage s3 Amazon S3 """ if request.user and not request.user.is_anonymous: user = request.user current_user = UserSerializer(user, context={'request': request}).data else: current_user = None kwargs = request.parser_context['kwargs'] return_val = { 'meta': { 'message': 'Welcome to the OSF API.', 'version': request.version, 'current_user': current_user, }, 'links': { 'nodes': utils.absolute_reverse('nodes:node-list', kwargs=kwargs), 'users': utils.absolute_reverse('users:user-list', kwargs=kwargs), 'collections': utils.absolute_reverse('collections:collection-list', kwargs=kwargs), 'registrations': utils.absolute_reverse('registrations:registration-list', kwargs=kwargs), 'institutions': utils.absolute_reverse('institutions:institution-list', kwargs=kwargs), 'licenses': utils.absolute_reverse('licenses:license-list', kwargs=kwargs), 'metaschemas': utils.absolute_reverse('metaschemas:metaschema-list', kwargs=kwargs), 'addons': utils.absolute_reverse('addons:addon-list', kwargs=kwargs), } } if utils.has_admin_scope(request): return_val['meta']['admin'] = True return Response(return_val)
def get_wiki_content(self, obj): return absolute_reverse('wikis:wiki-content', kwargs={ 'wiki_id': obj._id, })
def get_absolute_url(self, obj): return absolute_reverse('collections:collection-detail', kwargs={'collection_id': obj._id})
def get_storage_addons_url(self, obj): return absolute_reverse('addons:addon-list', query_kwargs={'filter[categories]': 'storage'})
def get_action_url(self, obj): return utils.absolute_reverse('actions:action-detail', kwargs={'action_id': obj._id, 'version': self.context['request'].parser_context['kwargs']['version']})
def get_preprints_url(self, obj): return absolute_reverse('preprint_providers:preprints-list', kwargs={ 'provider_id': obj._id, 'version': self.context['request'].parser_context['kwargs']['version'] })
def self_url(self, obj): return absolute_reverse('identifiers:identifier-detail', kwargs={ 'identifier_id': obj._id, })
def update(self, preprint, validated_data): assert isinstance( preprint, Preprint), 'You must specify a valid preprint to be updated' auth = get_user_auth(self.context['request']) if not preprint.has_permission(auth.user, osf_permissions.WRITE): raise exceptions.PermissionDenied( detail= 'User must have admin or write permissions to update a preprint.' ) published = validated_data.pop('is_published', None) if published and preprint.provider.is_reviewed: raise Conflict( '{} uses a moderation workflow, so preprints must be submitted for review instead of published directly. Submit a preprint by creating a `submit` Action at {}' .format( preprint.provider.name, absolute_reverse( 'preprints:preprint-review-action-list', kwargs={ 'version': self.context['request'].parser_context['kwargs'] ['version'], 'preprint_id': preprint._id, }, ), )) save_preprint = False recently_published = False primary_file = validated_data.pop('primary_file', None) if primary_file: self.set_field(preprint.set_primary_file, primary_file, auth) save_preprint = True old_tags = set(preprint.tags.values_list('name', flat=True)) if 'tags' in validated_data: current_tags = set(validated_data.pop('tags', [])) elif self.partial: current_tags = set(old_tags) else: current_tags = set() for new_tag in (current_tags - old_tags): preprint.add_tag(new_tag, auth=auth) for deleted_tag in (old_tags - current_tags): preprint.remove_tag(deleted_tag, auth=auth) if 'node' in validated_data: node = validated_data.pop('node', None) self.set_field(preprint.set_supplemental_node, node, auth) save_preprint = True if 'subjects' in validated_data: subjects = validated_data.pop('subjects', None) self.set_field(preprint.set_subjects, subjects, auth) save_preprint = True if 'title' in validated_data: title = validated_data['title'] self.set_field(preprint.set_title, title, auth) save_preprint = True if 'description' in validated_data: description = validated_data['description'] self.set_field(preprint.set_description, description, auth) save_preprint = True if 'article_doi' in validated_data: preprint.article_doi = validated_data['article_doi'] save_preprint = True if 'license_type' in validated_data or 'license' in validated_data: license_details = get_license_details(preprint, validated_data) self.set_field(preprint.set_preprint_license, license_details, auth) save_preprint = True if 'original_publication_date' in validated_data: preprint.original_publication_date = validated_data[ 'original_publication_date'] or None save_preprint = True if published is not None: if not preprint.primary_file: raise exceptions.ValidationError( detail= 'A valid primary_file must be set before publishing a preprint.' ) self.set_field(preprint.set_published, published, auth) save_preprint = True recently_published = published preprint.set_privacy('public', log=False, save=True) if save_preprint: preprint.save() if recently_published: for author in preprint.contributors: if author != auth.user: project_signals.contributor_added.send( preprint, contributor=author, auth=auth, email_template='preprint') return preprint
def get_related_url(self, obj): return absolute_reverse('users:user-institutions', kwargs={'user_id': obj['self']._id})
def self_url(self, obj): return absolute_reverse('files:version-detail', kwargs={ 'version_id': obj.identifier, 'file_id': self.context['view'].kwargs['file_id'], 'version': self.context['request'].parser_context['kwargs']['version'] })
def update(self, preprint, validated_data): assert isinstance( preprint, PreprintService), 'You must specify a valid preprint to be updated' assert isinstance( preprint.node, Node ), 'You must specify a preprint with a valid node to be updated.' auth = get_user_auth(self.context['request']) if not preprint.node.has_permission(auth.user, 'admin'): raise exceptions.PermissionDenied( detail='User must be an admin to update a preprint.') published = validated_data.pop('is_published', None) if published and preprint.provider.is_reviewed: raise Conflict( '{} uses a moderation workflow, so preprints must be submitted for review instead of published directly. Submit a preprint by creating a `submit` Action at {}' .format( preprint.provider.name, absolute_reverse( 'actions:create-action', kwargs={ 'version': self.context['request'].parser_context['kwargs'] ['version'] }))) save_node = False save_preprint = False recently_published = False primary_file = validated_data.pop('primary_file', None) if primary_file: self.set_field(preprint.set_primary_file, primary_file, auth) save_node = True old_tags = set(preprint.node.tags.values_list('name', flat=True)) if validated_data.get('node') and 'tags' in validated_data['node']: current_tags = set(validated_data['node'].pop('tags', [])) elif self.partial: current_tags = set(old_tags) else: current_tags = set() for new_tag in (current_tags - old_tags): preprint.node.add_tag(new_tag, auth=auth) for deleted_tag in (old_tags - current_tags): preprint.node.remove_tag(deleted_tag, auth=auth) if 'node' in validated_data: preprint.node.update(fields=validated_data.pop('node')) save_node = True if 'subjects' in validated_data: subjects = validated_data.pop('subjects', None) self.set_field(preprint.set_subjects, subjects, auth) save_preprint = True if 'article_doi' in validated_data: preprint.node.preprint_article_doi = validated_data['article_doi'] save_node = True if 'license_type' in validated_data or 'license' in validated_data: license_details = get_license_details(preprint, validated_data) self.set_field(preprint.set_preprint_license, license_details, auth) save_preprint = True if 'original_publication_date' in validated_data: preprint.original_publication_date = validated_data[ 'original_publication_date'] save_preprint = True if published is not None: if not preprint.primary_file: raise exceptions.ValidationError( detail= 'A valid primary_file must be set before publishing a preprint.' ) self.set_field(preprint.set_published, published, auth) save_preprint = True recently_published = published preprint.node.set_privacy('public') save_node = True if save_node: try: preprint.node.save() except ValidationError as e: # Raised from invalid DOI raise exceptions.ValidationError(detail=e.messages[0]) if save_preprint: preprint.save() # Send preprint confirmation email signal to new authors on preprint! -- only when published # TODO: Some more thought might be required on this; preprints made from existing # nodes will send emails making it seem like a new node. if recently_published: for author in preprint.node.contributors: if author != auth.user: project_signals.contributor_added.send( preprint.node, contributor=author, auth=auth, email_template='preprint') return preprint
def get_root_folder(self, obj): return absolute_reverse( 'nodes:node-addon-folders', kwargs=self.context['request'].parser_context['kwargs'], )
def get_absolute_url(self, obj): return absolute_reverse('guids:guid-detail', kwargs={ 'guids': obj._id, 'version': self.context['request'].parser_context['kwargs']['version'] })
def get_wiki_content(self, obj): return absolute_reverse('wikis:wiki-content', kwargs={ 'wiki_id': obj._id, 'version': self.context['request'].parser_context['kwargs']['version'] })
def get_registration_url(self, obj): return absolute_reverse('registrations:registration-detail', kwargs={'node_id': obj._id})
def get_related_url(self, obj): return absolute_reverse('users:user-institutions', kwargs={ 'user_id': obj['self']._id, 'version': self.context['request'].parser_context['kwargs']['version'] })
def get_absolute_url(self, obj): return absolute_reverse('nodes:node-provider-detail', kwargs={ 'node_id': obj.node._id, 'provider': obj.provider })
def get_search_field_url(self, field, query): view_name = 'search:search-{}'.format(field) return absolute_reverse(view_name, query_kwargs={'q': query})
def absolute_api_v2_url(self): from api.base.utils import absolute_reverse # Avoid circular dependency return absolute_reverse('users:user-detail', kwargs={'user_id': self.pk})
def get_absolute_url(self, obj): return absolute_reverse( 'addons:addon-list', kwargs=self.context['request'].parser_context['kwargs'], )
def get_absolute_url(self, obj): return absolute_reverse('moderators:provider-moderator-detail', kwargs={ 'provider_id': self.context['request'].parser_context['kwargs']['version'], 'moderator_id': obj._id, 'version': self.context['request'].parser_context['kwargs']['version']})
def absolute_api_v2_url(self): from api.base.utils import absolute_reverse return absolute_reverse('institutions:institution-detail', kwargs={'institution_id': self._id, 'version': 'v2'})
def get_absolute_url(self, obj): return absolute_reverse('users:user-detail', kwargs={'user_id': obj._id})
def get_absolute_url(self, obj): return absolute_reverse('licenses:license-detail', kwargs={ 'license_id': obj._id, 'version': self.context['request'].parser_context['kwargs']['version'] })