Beispiel #1
0
def get_object_or_error(model_cls, query_or_pk, request, display_name=None):
    obj = query = None
    select_for_update = check_select_for_update(request)
    if isinstance(query_or_pk, basestring):
        # they passed a 5-char guid as a string
        if issubclass(model_cls, GuidMixin):
            # if it's a subclass of GuidMixin we know it's primary_identifier_name
            query = {'guids___id': query_or_pk}
        else:
            if hasattr(model_cls, 'primary_identifier_name'):
                # primary_identifier_name gives us the natural key for the model
                query = {model_cls.primary_identifier_name: query_or_pk}
            else:
                # fall back to modmcompatiblity's load method since we don't know their PIN
                obj = model_cls.load(query_or_pk,
                                     select_for_update=select_for_update)
    else:
        # they passed a query
        try:
            obj = model_cls.objects.filter(query_or_pk).select_for_update(
            ).get() if select_for_update else model_cls.objects.get(
                query_or_pk)
        except model_cls.DoesNotExist:
            raise NotFound

    if not obj:
        if not query:
            # if we don't have a query or an object throw 404
            raise NotFound
        try:
            # TODO This could be added onto with eager on the queryset and the embedded fields of the api
            if isinstance(query, dict):
                obj = model_cls.objects.get(
                    **query
                ) if not select_for_update else model_cls.objects.filter(
                    **query).select_for_update().get()
            else:
                obj = model_cls.objects.get(
                    query
                ) if not select_for_update else model_cls.objects.filter(
                    query).select_for_update().get()
        except ObjectDoesNotExist:
            raise NotFound

    # For objects that have been disabled (is_active is False), return a 410.
    # The User model is an exception because we still want to allow
    # users who are unconfirmed or unregistered, but not users who have been
    # disabled.
    if model_cls is OSFUser and obj.is_disabled:
        raise UserGone(user=obj)
    elif model_cls is not OSFUser and not getattr(
            obj, 'is_active', True) or getattr(
                obj, 'is_deleted', False) or getattr(obj, 'deleted', False):
        if display_name is None:
            raise Gone
        else:
            raise Gone(
                detail='The requested {name} is no longer available.'.format(
                    name=display_name))
    return obj
Beispiel #2
0
def _get_current_user():
    from osf.models import OSFUser
    current_user_id = get_current_user_id()
    if current_user_id:
        return OSFUser.load(current_user_id, select_for_update=check_select_for_update(request))
    else:
        return None
Beispiel #3
0
def _get_current_user():
    from osf.models import OSFUser
    current_user_id = get_current_user_id()
    if current_user_id:
        return OSFUser.load(current_user_id, select_for_update=check_select_for_update(request))
    else:
        return None
Beispiel #4
0
def osfstorage_update_metadata(payload, **kwargs):
    """Metadata received from WaterButler, is built incrementally via latent task calls to this endpoint.

    The basic metadata response looks like::

        {
            "metadata": {
                # file upload
                "name": "file.name",
                "md5": "d41d8cd98f00b204e9800998ecf8427e",
                "path": "...",
                "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
                "version": "2",
                "downloads": "1",
                "checkout": "...",
                "latestVersionSeen": {"userId": "abc12", "seen": true},
                "modified": "a date",
                "modified_utc": "a date in utc",

                # glacier vault (optional)
                "archive": "glacier_key",
                "vault": "glacier_vault_name",

                # parity files
                "parity": {
                    "redundancy": "5",
                    "files": [
                        {"name": "foo.txt.par2","sha256": "abc123"},
                        {"name": "foo.txt.vol00+01.par2","sha256": "xyz321"},
                    ]
                }
            },
        }
    """
    try:
        version_id = payload['version']
        metadata = payload['metadata']
    except KeyError:
        raise HTTPError(http_status.HTTP_400_BAD_REQUEST)

    if check_select_for_update():
        version = FileVersion.objects.filter(
            _id=version_id).select_for_update().first()
    else:
        version = FileVersion.objects.filter(_id=version_id).first()

    if version is None:
        raise HTTPError(http_status.HTTP_404_NOT_FOUND)

    version.update_metadata(metadata)

    return {'status': 'success'}
Beispiel #5
0
def osfstorage_update_metadata(node_addon, payload, **kwargs):
    """Metadata received from WaterButler, is built incrementally via latent task calls to this endpoint.

    The basic metadata response looks like::

        {
            "metadata": {
                # file upload
                "name": "file.name",
                "md5": "d41d8cd98f00b204e9800998ecf8427e",
                "path": "...",
                "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
                "version": "2",
                "downloads": "1",
                "checkout": "...",
                "latestVersionSeen": {"userId": "abc12", "seen": true},
                "modified": "a date",
                "modified_utc": "a date in utc",

                # glacier vault (optional)
                "archive": "glacier_key",
                "vault": "glacier_vault_name",

                # parity files
                "parity": {
                    "redundancy": "5",
                    "files": [
                        {"name": "foo.txt.par2","sha256": "abc123"},
                        {"name": "foo.txt.vol00+01.par2","sha256": "xyz321"},
                    ]
                }
            },
        }
    """
    try:
        version_id = payload['version']
        metadata = payload['metadata']
    except KeyError:
        raise HTTPError(httplib.BAD_REQUEST)

    if check_select_for_update():
        version = FileVersion.objects.filter(_id=version_id).select_for_update().first()
    else:
        version = FileVersion.objects.filter(_id=version_id).first()

    if version is None:
        raise HTTPError(httplib.NOT_FOUND)

    version.update_metadata(metadata)

    return {'status': 'success'}
Beispiel #6
0
    def get_preprint(self, check_object_permissions=True):
        qs = PreprintService.objects.filter(guids___id=self.kwargs[self.preprint_lookup_url_kwarg])
        try:
            preprint = qs.select_for_update().get() if check_select_for_update(self.request) else qs.select_related('node').get()
        except PreprintService.DoesNotExist:
            raise NotFound

        if preprint.node.is_deleted:
            raise NotFound
        # May raise a permission denied
        if check_object_permissions:
            self.check_object_permissions(self.request, preprint)

        return preprint
Beispiel #7
0
    def get_preprint(self, check_object_permissions=True):
        qs = PreprintService.objects.filter(guids___id=self.kwargs[self.preprint_lookup_url_kwarg])
        try:
            preprint = qs.select_for_update().get() if check_select_for_update(self.request) else qs.select_related('node').get()
        except PreprintService.DoesNotExist:
            raise NotFound

        if preprint.node.is_deleted:
            raise NotFound
        # May raise a permission denied
        if check_object_permissions:
            self.check_object_permissions(self.request, preprint)

        return preprint
Beispiel #8
0
def _get_current_user():
    from osf.models import OSFUser
    from framework.auth import cas
    current_user_id = get_current_user_id()
    header_token = request.headers.get('Authorization', None)
    if current_user_id:
        return OSFUser.load(current_user_id,
                            select_for_update=check_select_for_update(request))
    elif header_token and 'bearer' in header_token.lower():
        # instead of querying directly here, let CAS deal with the authentication
        client = cas.get_client()
        auth_token = cas.parse_auth_header(header_token)

        try:
            cas_auth_response = client.profile(auth_token)
        except cas.CasHTTPError:
            return None

        return OSFUser.load(cas_auth_response.user,
                            select_for_update=check_select_for_update(request)
                            ) if cas_auth_response.authenticated else None

    else:
        return None
Beispiel #9
0
def get_object_or_error(model_cls, query_or_pk, request, display_name=None):
    obj = query = None
    select_for_update = check_select_for_update(request)
    if isinstance(query_or_pk, basestring):
        # they passed a 5-char guid as a string
        if issubclass(model_cls, GuidMixin):
            # if it's a subclass of GuidMixin we know it's primary_identifier_name
            query = {'guids___id': query_or_pk}
        else:
            if hasattr(model_cls, 'primary_identifier_name'):
                # primary_identifier_name gives us the natural key for the model
                query = {model_cls.primary_identifier_name: query_or_pk}
            else:
                # fall back to modmcompatiblity's load method since we don't know their PIN
                obj = model_cls.load(query_or_pk, select_for_update=select_for_update)
    else:
        # they passed a query
        try:
            obj = model_cls.objects.filter(query_or_pk).select_for_update().get() if select_for_update else model_cls.objects.get(query_or_pk)
        except model_cls.DoesNotExist:
            raise NotFound

    if not obj:
        if not query:
            # if we don't have a query or an object throw 404
            raise NotFound
        try:
            # TODO This could be added onto with eager on the queryset and the embedded fields of the api
            if isinstance(query, dict):
                obj = model_cls.objects.get(**query) if not select_for_update else model_cls.objects.filter(**query).select_for_update().get()
            else:
                obj = model_cls.objects.get(query) if not select_for_update else model_cls.objects.filter(query).select_for_update().get()
        except ObjectDoesNotExist:
            raise NotFound

    # For objects that have been disabled (is_active is False), return a 410.
    # The User model is an exception because we still want to allow
    # users who are unconfirmed or unregistered, but not users who have been
    # disabled.
    if model_cls is OSFUser and obj.is_disabled:
        raise UserGone(user=obj)
    elif model_cls is not OSFUser and not getattr(obj, 'is_active', True) or getattr(obj, 'is_deleted', False) or getattr(obj, 'deleted', False):
        if display_name is None:
            raise Gone
        else:
            raise Gone(detail='The requested {name} is no longer available.'.format(name=display_name))
    return obj
def get_or_http_error(Model, pk_or_query, allow_deleted=False, display_name=None):
    """Load an instance of Model by primary key or query. Raise an appropriate
    HTTPError if no record is found or if the query fails to find a unique record
    :param type Model: StoredObject subclass to query
    :param pk_or_query:
    :type pk_or_query: either
      - a <str> representation of the record's primary key, e.g. 'abcdef'
      - a <QueryBase> subclass query to uniquely select a record, e.g.
        Q('title', 'eq', 'Entitled') & Q('version', 'eq', 1)
    :param bool allow_deleted: allow deleleted records?
    :param str display_name:
    :raises: HTTPError(404) if the record does not exist
    :raises: HTTPError(400) if no unique record is found
    :raises: HTTPError(410) if the resource is deleted and allow_deleted = False
    :return: Model instance
    """

    display_name = display_name or ''
    # FIXME: Not everything that uses this decorator needs to be markupsafe, but OsfWebRenderer error.mako does...
    safe_name = markupsafe.escape(display_name)
    select_for_update = check_select_for_update(request)

    if isinstance(pk_or_query, Q):
        try:
            instance = Model.objects.filter(pk_or_query).select_for_update().get() if select_for_update else Model.objects.get(pk_or_query)
        except Model.DoesNotExist:
            raise HTTPError(http_status.HTTP_404_NOT_FOUND, data=dict(
                message_long='No {name} record matching that query could be found'.format(name=safe_name)
            ))
        except Model.MultipleObjectsReturned:
            raise HTTPError(http_status.HTTP_400_BAD_REQUEST, data=dict(
                message_long='The query must match exactly one {name} record'.format(name=safe_name)
            ))
    else:
        instance = Model.load(pk_or_query, select_for_update=select_for_update)
        if not instance:
            raise HTTPError(http_status.HTTP_404_NOT_FOUND, data=dict(
                message_long='No {name} record with that primary key could be found'.format(name=safe_name)
            ))
    if getattr(instance, 'is_deleted', False) and getattr(instance, 'suspended', False):
        raise HTTPError(451, data=dict(  # 451 - Unavailable For Legal Reasons
            message_short='Content removed',
            message_long='This content has been removed'
        ))
    if not allow_deleted and getattr(instance, 'is_deleted', False):
        raise HTTPError(http_status.HTTP_410_GONE)
    return instance
Beispiel #11
0
def get_or_http_error(Model, pk_or_query, allow_deleted=False, display_name=None):
    """Load an instance of Model by primary key or query. Raise an appropriate
    HTTPError if no record is found or if the query fails to find a unique record
    :param type Model: StoredObject subclass to query
    :param pk_or_query:
    :type pk_or_query: either
      - a <basestring> representation of the record's primary key, e.g. 'abcdef'
      - a <QueryBase> subclass query to uniquely select a record, e.g.
        Q('title', 'eq', 'Entitled') & Q('version', 'eq', 1)
    :param bool allow_deleted: allow deleleted records?
    :param basestring display_name:
    :raises: HTTPError(404) if the record does not exist
    :raises: HTTPError(400) if no unique record is found
    :raises: HTTPError(410) if the resource is deleted and allow_deleted = False
    :return: Model instance
    """

    display_name = display_name or ''
    # FIXME: Not everything that uses this decorator needs to be markupsafe, but OsfWebRenderer error.mako does...
    safe_name = markupsafe.escape(display_name)
    select_for_update = check_select_for_update(request)

    if isinstance(pk_or_query, Q):
        try:
            instance = Model.objects.filter(pk_or_query).select_for_update().get() if select_for_update else Model.objects.get(pk_or_query)
        except Model.DoesNotExist:
            raise HTTPError(http.NOT_FOUND, data=dict(
                message_long='No {name} record matching that query could be found'.format(name=safe_name)
            ))
        except Model.MultipleObjectsReturned:
            raise HTTPError(http.BAD_REQUEST, data=dict(
                message_long='The query must match exactly one {name} record'.format(name=safe_name)
            ))
    else:
        instance = Model.load(pk_or_query, select_for_update=select_for_update)
        if not instance:
            raise HTTPError(http.NOT_FOUND, data=dict(
                message_long='No {name} record with that primary key could be found'.format(name=safe_name)
            ))
    if getattr(instance, 'is_deleted', False) and getattr(instance, 'suspended', False):
        raise HTTPError(451, data=dict(  # 451 - Unavailable For Legal Reasons
            message_short='Content removed',
            message_long='This content has been removed'
        ))
    if not allow_deleted and getattr(instance, 'is_deleted', False):
        raise HTTPError(http.GONE)
    return instance
Beispiel #12
0
    def get_preprint(self, check_object_permissions=True, ignore_404=False):
        qs = Preprint.objects.filter(guids___id=self.kwargs[self.preprint_lookup_url_kwarg], guids___id__isnull=False)
        try:
            preprint = qs.select_for_update().get() if check_select_for_update(self.request) else qs.select_related('node').get()
        except Preprint.DoesNotExist:
            if ignore_404:
                return
            raise NotFound

        if preprint.deleted is not None:
            raise NotFound

        # May raise a permission denied
        if check_object_permissions:
            self.check_object_permissions(self.request, preprint)

        return preprint
Beispiel #13
0
    def get_preprint(self, check_object_permissions=True, ignore_404=False):
        qs = Preprint.objects.filter(
            guids___id=self.kwargs[self.preprint_lookup_url_kwarg],
            guids___id__isnull=False)
        try:
            preprint = qs.select_for_update().get() if check_select_for_update(
                self.request) else qs.select_related('node').get()
        except Preprint.DoesNotExist:
            if ignore_404:
                return
            raise NotFound

        if preprint.deleted is not None:
            raise NotFound

        # May raise a permission denied
        if check_object_permissions:
            self.check_object_permissions(self.request, preprint)

        return preprint
Beispiel #14
0
def confirm_email_get(token, auth=None, **kwargs):
    """
    View for email confirmation links. Authenticates and redirects to user settings page if confirmation is successful,
    otherwise shows an "Expired Link" error.
    HTTP Method: GET
    """

    is_merge = 'confirm_merge' in request.args

    try:
        if not is_merge or not check_select_for_update():
            user = OSFUser.objects.get(guids___id=kwargs['uid'])
        else:
            user = OSFUser.objects.filter(
                guids___id=kwargs['uid']).select_for_update().get()
    except OSFUser.DoesNotExist:
        raise HTTPError(http.NOT_FOUND)

    is_initial_confirmation = not user.date_confirmed
    log_out = request.args.get('logout', None)

    # if the user is merging or adding an email (they already are an osf user)
    if log_out:
        return auth_email_logout(token, user)

    if auth and auth.user and (auth.user._id == user._id
                               or auth.user._id == user.merged_by._id):
        if not is_merge:
            # determine if the user registered through a campaign
            campaign = campaigns.campaign_for_user(user)
            if campaign:
                return redirect(campaigns.campaign_url_for(campaign))

            # go to home page with push notification
            if auth.user.emails.count() == 1 and len(
                    auth.user.email_verifications) == 0:
                status.push_status_message(language.WELCOME_MESSAGE,
                                           kind='default',
                                           jumbotron=True,
                                           trust=True)
            if token in auth.user.email_verifications:
                status.push_status_message(
                    language.CONFIRM_ALTERNATE_EMAIL_ERROR,
                    kind='danger',
                    trust=True)
            return redirect(web_url_for('index'))

        status.push_status_message(language.MERGE_COMPLETE,
                                   kind='success',
                                   trust=False)
        return redirect(web_url_for('user_account'))

    try:
        user.confirm_email(token, merge=is_merge)
    except exceptions.EmailConfirmTokenError as e:
        raise HTTPError(http.BAD_REQUEST,
                        data={
                            'message_short': e.message_short,
                            'message_long': e.message_long
                        })

    if is_initial_confirmation:
        user.update_date_last_login()
        user.save()

        # send out our welcome message
        mails.send_mail(to_addr=user.username,
                        mail=mails.WELCOME,
                        mimetype='html',
                        user=user)

    # new random verification key, allows CAS to authenticate the user w/o password one-time only.
    user.verification_key = generate_verification_key()
    user.save()
    # redirect to CAS and authenticate the user with a verification key.
    return redirect(
        cas.get_login_url(request.url,
                          username=user.username,
                          verification_key=user.verification_key))
Beispiel #15
0
def confirm_email_get(token, auth=None, **kwargs):
    """
    View for email confirmation links. Authenticates and redirects to user settings page if confirmation is successful,
    otherwise shows an "Expired Link" error.
    HTTP Method: GET
    """

    is_merge = 'confirm_merge' in request.args

    try:
        if not is_merge or not check_select_for_update():
            user = OSFUser.objects.get(guids___id=kwargs['uid'], guids___id__isnull=False)
        else:
            user = OSFUser.objects.filter(guids___id=kwargs['uid'], guids___id__isnull=False).select_for_update().get()
    except OSFUser.DoesNotExist:
        raise HTTPError(http.NOT_FOUND)

    is_initial_confirmation = not user.date_confirmed
    log_out = request.args.get('logout', None)

    # if the user is merging or adding an email (they already are an osf user)
    if log_out:
        return auth_email_logout(token, user)

    if auth and auth.user and (auth.user._id == user._id or auth.user._id == user.merged_by._id):
        if not is_merge:
            # determine if the user registered through a campaign
            campaign = campaigns.campaign_for_user(user)
            if campaign:
                return redirect(campaigns.campaign_url_for(campaign))

            # go to home page with push notification
            if auth.user.emails.count() == 1 and len(auth.user.email_verifications) == 0:
                status.push_status_message(language.WELCOME_MESSAGE, kind='default', jumbotron=True, trust=True, id='welcome_message')
            if token in auth.user.email_verifications:
                status.push_status_message(language.CONFIRM_ALTERNATE_EMAIL_ERROR, kind='danger', trust=True, id='alternate_email_error')
            return redirect(web_url_for('index'))

        status.push_status_message(language.MERGE_COMPLETE, kind='success', trust=False)
        return redirect(web_url_for('user_account'))

    try:
        user.confirm_email(token, merge=is_merge)
    except exceptions.EmailConfirmTokenError as e:
        raise HTTPError(http.BAD_REQUEST, data={
            'message_short': e.message_short,
            'message_long': e.message_long
        })

    if is_initial_confirmation:
        user.update_date_last_login()
        user.save()

        # send out our welcome message
        mails.send_mail(
            to_addr=user.username,
            mail=mails.WELCOME,
            mimetype='html',
            user=user,
            domain=settings.DOMAIN,
            osf_support_email=settings.OSF_SUPPORT_EMAIL
        )

    # new random verification key, allows CAS to authenticate the user w/o password one-time only.
    user.verification_key = generate_verification_key()
    user.save()
    # redirect to CAS and authenticate the user with a verification key.
    return redirect(cas.get_login_url(
        request.url,
        username=user.username,
        verification_key=user.verification_key
    ))