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_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
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
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'}
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'}
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
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
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
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
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
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
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
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))
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 ))