Exemple #1
0
    def to_representation(self, data, envelope='data'):

        if isinstance(data, AbstractNode):
            if data.is_registration:
                serializer = RegistrationSerializer(data, context=self.context)
                return RegistrationSerializer.to_representation(
                    serializer, data)
            serializer = NodeSerializer(data, context=self.context)
            return NodeSerializer.to_representation(serializer, data)

        if isinstance(data, OSFUser):
            serializer = UserSerializer(data, context=self.context)
            return UserSerializer.to_representation(serializer, data)

        if isinstance(data, BaseFileNode):
            serializer = FileSerializer(data, context=self.context)
            return FileSerializer.to_representation(serializer, data)

        if isinstance(data, Institution):
            serializer = InstitutionSerializer(data, context=self.context)
            return InstitutionSerializer.to_representation(serializer, data)

        if isinstance(data, CollectionSubmission):
            serializer = CollectionSubmissionSerializer(data,
                                                        context=self.context)
            return CollectionSubmissionSerializer.to_representation(
                serializer, data)

        return None
Exemple #2
0
    def post(self, request, format='json'):
        serializer = UserSerializer(data=request.data)
        if serializer.is_valid():
            user = serializer.save()
            if user:
                token = Token.objects.create(user=user)
                json = serializer.data
                json['token'] = token.key
                return Response(json, status=status.HTTP_201_CREATED)

        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
Exemple #3
0
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)
Exemple #4
0
class ArticleSerializer(serializers.ModelSerializer):

    author = UserSerializer(read_only=True)
    created = serializers.DateTimeField(format="%Y-%m-%d", required=False, read_only=True)
    updated = serializers.DateTimeField(format="%Y-%m-%d", required=False, read_only=True)
    img_name = serializers.SerializerMethodField()

    def get_img_name(self, obj):
        if obj.image:
            return obj.image.name.split('/')[-1]
        else:
            return False

    class Meta:
        model = Article
        fields = (
            'id',
            'author',
            'headline',
            'description',
            'img_name',
            'created',
            'updated',
        )
        read_only_fields = (
            'id',
            'created',
            'author',
        )
Exemple #5
0
    def to_representation(self, data, envelope='data'):

        if isinstance(data, AbstractNode):
            if data.is_registration:
                serializer = RegistrationSerializer(data, context=self.context)
                return RegistrationSerializer.to_representation(serializer, data)
            serializer = NodeSerializer(data, context=self.context)
            return NodeSerializer.to_representation(serializer, data)

        if isinstance(data, OSFUser):
            serializer = UserSerializer(data, context=self.context)
            return UserSerializer.to_representation(serializer, data)

        if isinstance(data, BaseFileNode):
            serializer = FileSerializer(data, context=self.context)
            return FileSerializer.to_representation(serializer, data)

        if isinstance(data, Institution):
            serializer = InstitutionSerializer(data, context=self.context)
            return InstitutionSerializer.to_representation(serializer, data)

        if isinstance(data, CollectedGuidMetadata):
            serializer = CollectedMetaSerializer(data, context=self.context)
            return CollectedMetaSerializer.to_representation(serializer, data)

        return None
class CommentSerializer(serializers.ModelSerializer):
    content = serializers.CharField(required=True)
    created_at = serializers.DateTimeField(read_only=True)
    user = UserSerializer(read_only=True)

    class Meta:
        model = Comment
        fields = ('user', 'content', 'created_at')
Exemple #7
0
 def post(self, request, *args, **kwargs):
     serializer = self.get_serializer(data=request.data)
     serializer.is_valid(raise_exception=True)
     user = serializer.validated_data
     return Response({
         "user": UserSerializer(user, context=self.get_serializer_context()).data,
         "token": AuthToken.objects.create(user)
     })
Exemple #8
0
 def get_related_count(self, user, related_field, auth):
     req = make_drf_request_with_version(version='2.0')
     req.query_params['related_counts'] = True
     if auth:
         req.user = auth
     result = UserSerializer(user, context={'request': req}).data
     return result['data']['relationships'][related_field]['links'][
         'related']['meta']['count']
Exemple #9
0
class CustomEventSerializer(serializers.ModelSerializer):

    user = UserSerializer()

    class Meta:
        model = CustomEvent
        fields = ('user', 'name', 'description', 'begin_time', 'end_time',
                  'notify_admin')
Exemple #10
0
    def get(self, request, post_id):
        likes = Like.objects.filter(post__id=post_id)
        like_author_id = likes.values('author_id')
        users = User.objects.filter(id__in=like_author_id)

        serializer = UserSerializer(users,
                                    many=True,
                                    context={'request': request})

        return Response(serializer.data, status=status.HTTP_200_OK)
Exemple #11
0
 def get_user_by_email(self, request):
     """
     get user by email
     :param request:
     :return:
     """
     user = get_object_or_404(
         User, email__exact=request.query_params.get('email'))
     serializer = UserSerializer(user)
     return Response(serializer.data)
Exemple #12
0
    def to_representation(self, data, envelope='data'):

        if isinstance(data, AbstractNode):
            if data.is_registration:
                serializer = RegistrationSerializer(data, context=self.context)
                return RegistrationSerializer.to_representation(
                    serializer, data)
            serializer = NodeSerializer(data, context=self.context)
            return NodeSerializer.to_representation(serializer, data)

        if isinstance(data, User):
            serializer = UserSerializer(data, context=self.context)
            return UserSerializer.to_representation(serializer, data)

        if isinstance(data, FileNode):
            serializer = FileSerializer(data, context=self.context)
            return FileSerializer.to_representation(serializer, data)

        return None
class PostSerializer(serializers.ModelSerializer):
    id = serializers.IntegerField(read_only=True)
    title = serializers.CharField(required=True)
    content = serializers.CharField(required=True)
    user = UserSerializer(read_only=True)
    comments = CommentSerializer(many=True, read_only=True)

    created_at = serializers.DateTimeField(read_only=True)

    class Meta:
        model = Post
        fields = ('id', 'user', 'title', 'content', 'comments', 'created_at')
Exemple #14
0
def jwt_response_payload_handler(token, user=None, request=None):
    # 커스텀 토큰 payload 핸들러
    decode = jwt_decode_handler(token)
    response_data = {
        'payload': {
            'token': token,
            'orig_iat': decode['orig_iat'],
            'exp': decode['exp']
        },
        'user': UserSerializer(user, context={'request': request}).data
    }

    return response_data
Exemple #15
0
def root(request, format=None):
    if request.user and not request.user.is_anonymous():
        user = request.user
        current_user = UserSerializer(user).data
    else:
        current_user = None
    return Response({
        'meta': {
            'message': 'Welcome to the OSF API.',
            'version': request.version,
            'current_user': current_user,
        },
        'links': {
            'nodes': absolute_reverse('nodes:node-list'),
            'users': absolute_reverse('users:user-list'),
        }
    })
Exemple #16
0
    def get_view_count(self, user, related_field, auth):
        req = make_drf_request_with_version(version='2.0')
        if auth:
            req.user = auth
        view_name = UserSerializer().fields[related_field].field.view_name
        resolve_match = resolve(
            reverse(view_name, kwargs={
                'version': 'v2',
                'user_id': user._id
            }))
        view = resolve_match.func.view_class(request=req,
                                             kwargs={
                                                 'version': 'v2',
                                                 'user_id': user._id
                                             })

        return view.get_queryset().count()
Exemple #17
0
    def to_representation(self, data, envelope="data"):

        if isinstance(data, Node):
            if data.is_registration:
                serializer = RegistrationSerializer(data, context=self.context)
                return RegistrationSerializer.to_representation(serializer, data)
            serializer = NodeSerializer(data, context=self.context)
            return NodeSerializer.to_representation(serializer, data)

        if isinstance(data, User):
            serializer = UserSerializer(data, context=self.context)
            return UserSerializer.to_representation(serializer, data)

        if isinstance(data, FileNode):
            serializer = FileSerializer(data, context=self.context)
            return FileSerializer.to_representation(serializer, data)

        return None
Exemple #18
0
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:registration-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)
Exemple #19
0
class CommentSerializer(serializers.ModelSerializer):

    author = UserSerializer(read_only=True)
    created = serializers.DateTimeField(format="%Y-%m-%d", required=False, read_only=True)
    updated = serializers.DateTimeField(format="%Y-%m-%d", required=False, read_only=True)

    class Meta:
        model = Comment
        fields = (
            'id',
            'article',
            'author',
            'created',
            'updated',
        )
        read_only_fields = (
            'id',
            'article',
            'created',
            'author',
        )
Exemple #20
0
    def test_user_serializer(self, user):
        req = make_drf_request_with_version(version='2.0')
        result = UserSerializer(user, context={'request': req}).data
        data = result['data']
        assert data['id'] == user._id
        assert data['type'] == 'users'

        # Attributes
        attributes = data['attributes']
        assert attributes['family_name'] == user.family_name
        assert attributes['given_name'] == user.given_name
        assert attributes['active'] == user.is_active
        assert attributes['employment'] == user.jobs
        assert attributes['education'] == user.schools

        # Relationships
        relationships = data['relationships']
        assert 'quickfiles' in relationships
        assert 'nodes' in relationships
        assert 'institutions' in relationships
        assert 'preprints' in relationships
        assert 'registrations' in relationships
Exemple #21
0
def root(request, format=None):
    """
        Welcome to the V2 Open Science Framework API. With this API you can programatically access users,
        projects, components, 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 stores, documents, and archives 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
        Each endpoint will have its own documentation, but there are some general principles.

        ###Filtering
        Collections can be filtered by adding a query parameter in the form:

            filter[<fieldname>]=<matching information>
        For example, if you were trying to find [Lise Meitner](http://en.wikipedia.org/wiki/Lise_Meitner):

            /users?filter[fullname]=meitn
        You can filter on multiple fields, or the same field in different ways, by &-ing the query parameters together.

            /users?filter[fullname]=lise&filter[family_name]=mei
        ###Links
        Responses will generally have associated links which are helpers to keep you from having to construct URLs in
        your code or by hand. If you know the route to a high-level resource, you can go to that route. For example:

            /nodes/<node_id>

        is a good route to create rather than going to /nodes/ and navigating by id filtering. However, if you are
        creating something that crawls the structure of a node going to the child node or gathering children,
        contributors, and similar related resources, then take the link from the object you\'re crawling rather than
        constructing the link yourself.

        In general, links include:

        1. "Related" links, which will give detailed information on individual items or a collection of related resources;
        2. "Self" links, which are used for general REST operations (POST, DELETE, and so on);
        3. Pagination links such as "next", "prev", "first", and "last". Pagination links are great for navigating long
        lists of information.

        Some routes may have extra rules for links, especially if those links work with external services. Collections
        may have counts with them to indicate how many items are in that collection.
    """
    if request.user and not request.user.is_anonymous():
        user = request.user
        current_user = UserSerializer(user, context={'request': request}).data
    else:
        current_user = None

    return Response({
        'meta': {
            'message': 'Welcome to the OSF API.',
            'version': request.version,
            'current_user': current_user,
        },
        'links': {
            'nodes': absolute_reverse('nodes:node-list'),
            'users': absolute_reverse('users:user-list'),
        }
    })
Exemple #22
0
 def retrieve(self, request, *args, **kwargs):
     user = self.get_object()
     serializer = UserSerializer(instance=user)
     return Response(serializer.data)
Exemple #23
0
    def list(self, request) -> Response:
        instance = request.user
        serializer = UserSerializer(instance)

        return Response(serializer.data)
Exemple #24
0
    def list(self, request, *args, **kwargs):
        queryset = self.get_queryset()
        serializer = UserSerializer(queryset, many=True)
        response = Response(serializer.data, content_type='application/json')

        return response
Exemple #25
0
 def get_data(self, user):
     req = make_drf_request_with_version(version='2.0')
     req.query_params['related_counts'] = True
     req.user = user
     result = UserSerializer(user, context={'request': req}).data
     return result['data']
Exemple #26
0
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)