def reviews_submit_notification_moderators(self, timestamp, context): # imports moved here to avoid AppRegistryNotReady error from osf.models import NotificationSubscription from website.profile.utils import get_profile_image_url from website.notifications import emails from website import settings # Get NotificationSubscription instance, which contains reference to all subscribers provider_subscription = NotificationSubscription.load('{}_new_pending_submissions'.format(context['reviewable'].provider._id)) # Set message context['message'] = u'submitted {}.'.format(context['reviewable'].node.title) # Set url for profile image of the submitter context['profile_image_url'] = get_profile_image_url(context['referrer']) # Set submission url context['reviews_submission_url'] = '{}reviews/preprints/{}/{}'.format(settings.DOMAIN, context['reviewable'].provider._id, context['reviewable']._id) # Store emails to be sent to subscribers instantly (at a 5 min interval) emails.store_emails(provider_subscription.email_transactional.all().values_list('guids___id', flat=True), 'email_transactional', 'new_pending_submissions', context['referrer'], context['reviewable'].node, timestamp, abstract_provider=context['reviewable'].provider, **context) # Store emails to be sent to subscribers daily emails.store_emails(provider_subscription.email_digest.all().values_list('guids___id', flat=True), 'email_digest', 'new_pending_submissions', context['referrer'], context['reviewable'].node, timestamp, abstract_provider=context['reviewable'].provider, **context)
def reviews_submit_notification_moderators(self, timestamp, context): # imports moved here to avoid AppRegistryNotReady error from osf.models import NotificationSubscription from website.profile.utils import get_profile_image_url from website.notifications.emails import store_emails resource = context['reviewable'] provider = resource.provider # Set submission url if provider.type == 'osf.preprintprovider': context['reviews_submission_url'] = ( f'{DOMAIN}reviews/preprints/{provider._id}/{resource._id}') elif provider.type == 'osf.registrationprovider': context[ 'reviews_submission_url'] = f'{DOMAIN}{resource._id}?mode=moderator' else: raise NotImplementedError(f'unsupported provider type {provider.type}') # Set url for profile image of the submitter context['profile_image_url'] = get_profile_image_url(context['referrer']) # Set message revision_id = context.get('revision_id') if revision_id: context['message'] = f'submitted updates to "{resource.title}".' context['reviews_submission_url'] += f'&revisionId={revision_id}' else: context['message'] = f'submitted "{resource.title}".' # Get NotificationSubscription instance, which contains reference to all subscribers provider_subscription, created = NotificationSubscription.objects.get_or_create( _id=f'{provider._id}_new_pending_submissions', provider=provider) # "transactional" subscribers receive notifications "Immediately" (i.e. at 5 minute intervals) # "digest" subscribers receive emails daily recipients_per_subscription_type = { 'email_transactional': list(provider_subscription.email_transactional.all().values_list( 'guids___id', flat=True)), 'email_digest': list(provider_subscription.email_digest.all().values_list('guids___id', flat=True)) } for subscription_type, recipient_ids in recipients_per_subscription_type.items( ): if not recipient_ids: continue store_emails(recipient_ids, subscription_type, 'new_pending_submissions', context['referrer'], resource, timestamp, abstract_provider=provider, **context)
def reviews_submit_notification_moderators(self, timestamp, context): # imports moved here to avoid AppRegistryNotReady error from osf.models import NotificationSubscription from website.profile.utils import get_profile_image_url from website.notifications.emails import store_emails resource = context['reviewable'] provider = resource.provider # Get NotificationSubscription instance, which contains reference to all subscribers provider_subscription, created = NotificationSubscription.objects.get_or_create( _id=f'{provider._id}_new_pending_submissions', provider=provider) # Set message context['message'] = f'submitted "{resource.title}".' # Set url for profile image of the submitter context['profile_image_url'] = get_profile_image_url(context['referrer']) # Set submission url if provider.type == 'osf.preprintprovider': url_segment = 'preprints' flag_suffix = '' elif provider.type == 'osf.registrationprovider': url_segment = 'registries' flag_suffix = '?mode=moderator' else: raise NotImplementedError(f'unsupported provider type {provider.type}') context[ 'reviews_submission_url'] = f'{DOMAIN}reviews/{url_segment}/{provider._id}/{resource._id}{flag_suffix}' email_transactional_ids = list( provider_subscription.email_transactional.all().values_list( 'guids___id', flat=True)) email_digest_ids = list( provider_subscription.email_digest.all().values_list('guids___id', flat=True)) # Store emails to be sent to subscribers instantly (at a 5 min interval) store_emails(email_transactional_ids, 'email_transactional', 'new_pending_submissions', context['referrer'], resource, timestamp, abstract_provider=provider, **context) # Store emails to be sent to subscribers daily store_emails(email_digest_ids, 'email_digest', 'new_pending_submissions', context['referrer'], resource, timestamp, abstract_provider=provider, **context)
def reviews_withdraw_requests_notification_moderators(self, timestamp, context): # imports moved here to avoid AppRegistryNotReady error from osf.models import NotificationSubscription from website.profile.utils import get_profile_image_url from website.notifications.emails import store_emails resource = context['reviewable'] provider = resource.provider # Get NotificationSubscription instance, which contains reference to all subscribers provider_subscription, created = NotificationSubscription.objects.get_or_create( _id=f'{provider._id}_new_pending_withdraw_requests', provider=provider) # Set message context['message'] = f'has requested withdrawal of "{resource.title}".' # Set url for profile image of the submitter context['profile_image_url'] = get_profile_image_url(context['referrer']) # Set submission url context[ 'reviews_submission_url'] = f'{DOMAIN}reviews/registries/{provider._id}/{resource._id}' email_transactional_ids = list( provider_subscription.email_transactional.all().values_list( 'guids___id', flat=True)) email_digest_ids = list( provider_subscription.email_digest.all().values_list('guids___id', flat=True)) # Store emails to be sent to subscribers instantly (at a 5 min interval) store_emails(email_transactional_ids, 'email_transactional', 'new_pending_withdraw_requests', context['referrer'], resource, timestamp, abstract_provider=provider, template='new_pending_submissions', **context) # Store emails to be sent to subscribers daily store_emails(email_digest_ids, 'email_digest', 'new_pending_withdraw_requests', context['referrer'], resource, timestamp, abstract_provider=provider, template='new_pending_submissions', **context)
def reviews_withdrawal_requests_notification(self, timestamp, context): # imports moved here to avoid AppRegistryNotReady error from osf.models import NotificationSubscription from website.notifications.emails import store_emails from website.profile.utils import get_profile_image_url from website import settings # Get NotificationSubscription instance, which contains reference to all subscribers provider_subscription = NotificationSubscription.load( '{}_new_pending_submissions'.format( context['reviewable'].provider._id)) preprint = context['reviewable'] preprint_word = preprint.provider.preprint_word # Set message context['message'] = u'has requested withdrawal of the {} "{}".'.format( preprint_word, preprint.title) # Set url for profile image of the submitter context['profile_image_url'] = get_profile_image_url(context['requester']) # Set submission url context['reviews_submission_url'] = '{}reviews/preprints/{}/{}'.format( settings.DOMAIN, preprint.provider._id, preprint._id) email_transactional_ids = list( provider_subscription.email_transactional.all().values_list( 'guids___id', flat=True)) email_digest_ids = list( provider_subscription.email_digest.all().values_list('guids___id', flat=True)) # Store emails to be sent to subscribers instantly (at a 5 min interval) store_emails(email_transactional_ids, 'email_transactional', 'new_pending_submissions', context['requester'], preprint, timestamp, abstract_provider=preprint.provider, **context) # Store emails to be sent to subscribers daily store_emails(email_digest_ids, 'email_digest', 'new_pending_submissions', context['requester'], preprint, timestamp, abstract_provider=preprint.provider, **context)
def reviews_submit_notification_moderators(self, timestamp, context): # imports moved here to avoid AppRegistryNotReady error from osf.models import NotificationSubscription from website.profile.utils import get_profile_image_url from website.notifications import emails from website import settings # Get NotificationSubscription instance, which contains reference to all subscribers provider_subscription = NotificationSubscription.load( '{}_new_pending_submissions'.format( context['reviewable'].provider._id)) # Set message context['message'] = u'submitted {}.'.format( context['reviewable'].node.title) # Set url for profile image of the submitter context['profile_image_url'] = get_profile_image_url(context['referrer']) # Set submission url context['reviews_submission_url'] = '{}reviews/preprints/{}/{}'.format( settings.DOMAIN, context['reviewable'].provider._id, context['reviewable']._id) # Store emails to be sent to subscribers instantly (at a 5 min interval) emails.store_emails( provider_subscription.email_transactional.all().values_list( 'guids___id', flat=True), 'email_transactional', 'new_pending_submissions', context['referrer'], context['reviewable'].node, timestamp, abstract_provider=context['reviewable'].provider, **context) # Store emails to be sent to subscribers daily emails.store_emails(provider_subscription.email_digest.all().values_list( 'guids___id', flat=True), 'email_digest', 'new_pending_submissions', context['referrer'], context['reviewable'].node, timestamp, abstract_provider=context['reviewable'].provider, **context)
def addon_deleted_file(auth, target, error_type='BLAME_PROVIDER', **kwargs): """Shows a nice error message to users when they try to view a deleted file """ # Allow file_node to be passed in so other views can delegate to this one file_node = kwargs.get('file_node') or TrashedFileNode.load( kwargs.get('trashed_id')) deleted_by, deleted_on, deleted = None, None, None if isinstance(file_node, TrashedFileNode): deleted_by = file_node.deleted_by deleted_by_guid = file_node.deleted_by._id if deleted_by else None deleted_on = file_node.deleted_on.strftime('%c') + ' UTC' deleted = deleted_on if getattr(file_node, 'suspended', False): error_type = 'FILE_SUSPENDED' elif file_node.deleted_by is None or (auth.private_key and auth.private_link.anonymous): if file_node.provider == 'osfstorage': error_type = 'FILE_GONE_ACTOR_UNKNOWN' else: error_type = 'BLAME_PROVIDER' else: error_type = 'FILE_GONE' else: error_type = 'DONT_KNOW' file_path = kwargs.get('path', file_node.path) file_name = file_node.name or os.path.basename(file_path) file_name_title, file_name_ext = os.path.splitext(file_name) provider_full = settings.ADDONS_AVAILABLE_DICT[ file_node.provider].full_name try: file_guid = file_node.get_guid()._id except AttributeError: file_guid = None format_params = dict(file_name=markupsafe.escape(file_name), deleted_by=markupsafe.escape( getattr(deleted_by, 'fullname', None)), deleted_on=markupsafe.escape(deleted_on), provider=markupsafe.escape(provider_full), deleted=markupsafe.escape(deleted)) if deleted_by: format_params['deleted_by_guid'] = markupsafe.escape(deleted_by_guid) error_msg = ERROR_MESSAGES[error_type].format(**format_params) if isinstance(target, AbstractNode): error_msg += format_last_known_metadata(auth, target, file_node, error_type) ret = serialize_node(target, auth, primary=True) ret.update(rubeus.collect_addon_assets(target)) ret.update({ 'error': error_msg, 'urls': { 'render': None, 'sharejs': None, 'mfr': get_mfr_url(target, file_node.provider), 'profile_image': get_profile_image_url(auth.user, 25), 'files': target.web_url_for('collect_file_trees'), }, 'extra': {}, 'size': 9966699, # Prevent file from being edited, just in case 'sharejs_uuid': None, 'file_name': file_name, 'file_path': file_path, 'file_name_title': file_name_title, 'file_name_ext': file_name_ext, 'target_deleted': getattr(target, 'is_deleted', False), 'version_id': None, 'file_guid': file_guid, 'file_id': file_node._id, 'provider': file_node.provider, 'materialized_path': file_node.materialized_path or file_path, 'private': getattr(target.get_addon(file_node.provider), 'is_private', False), 'file_tags': list( file_node.tags.filter(system=False).values_list( 'name', flat=True)) if not file_node._state.adding else [], # Only access ManyRelatedManager if saved 'allow_comments': file_node.provider in settings.ADDONS_COMMENTABLE, }) else: # TODO - serialize deleted metadata for future types of deleted file targets ret = {'error': error_msg} return ret, http_status.HTTP_410_GONE
def addon_view_file(auth, node, file_node, version): # TODO: resolve circular import issue from addons.wiki import settings as wiki_settings if isinstance(version, tuple): version, error = version error = error.replace('\n', '').strip() else: error = None ret = serialize_node(node, auth, primary=True) if file_node._id + '-' + version._id not in node.file_guid_to_share_uuids: node.file_guid_to_share_uuids[file_node._id + '-' + version._id] = uuid.uuid4() node.save() if ret['user']['can_edit']: sharejs_uuid = str(node.file_guid_to_share_uuids[file_node._id + '-' + version._id]) else: sharejs_uuid = None internal_furl = furl.furl(settings.INTERNAL_DOMAIN) download_url = furl.furl(request.url.encode('utf-8')).set( netloc=internal_furl.netloc, args=dict(request.args, **{ 'direct': None, 'mode': 'render', 'action': 'download', 'public_file': node.is_public, }) ) mfr_url = get_mfr_url(node, file_node.provider) render_url = furl.furl(mfr_url).set( path=['render'], args={'url': download_url.url} ) ret.update({ 'urls': { 'render': render_url.url, 'mfr': mfr_url, 'sharejs': wiki_settings.SHAREJS_URL, 'profile_image': get_profile_image_url(auth.user, 25), 'files': node.web_url_for('collect_file_trees'), 'archived_from': get_archived_from_url(node, file_node) if node.is_registration else None, }, 'error': error, 'file_name': file_node.name, 'file_name_title': os.path.splitext(file_node.name)[0], 'file_name_ext': os.path.splitext(file_node.name)[1], 'version_id': version.identifier, 'file_path': file_node.path, 'sharejs_uuid': sharejs_uuid, 'provider': file_node.provider, 'materialized_path': file_node.materialized_path, 'extra': version.metadata.get('extra', {}), 'size': version.size if version.size is not None else 9966699, 'private': getattr(node.get_addon(file_node.provider), 'is_private', False), 'file_tags': list(file_node.tags.filter(system=False).values_list('name', flat=True)) if not file_node._state.adding else [], # Only access ManyRelatedManager if saved 'file_guid': file_node.get_guid()._id, 'file_id': file_node._id, 'allow_comments': file_node.provider in settings.ADDONS_COMMENTABLE, 'checkout_user': file_node.checkout._id if file_node.checkout else None, 'pre_reg_checkout': is_pre_reg_checkout(node, file_node), }) ret.update(rubeus.collect_addon_assets(node)) return ret
def addon_deleted_file(auth, target, error_type='BLAME_PROVIDER', **kwargs): """Shows a nice error message to users when they try to view a deleted file """ # Allow file_node to be passed in so other views can delegate to this one file_node = kwargs.get('file_node') or TrashedFileNode.load(kwargs.get('trashed_id')) deleted_by, deleted_on = None, None if isinstance(file_node, TrashedFileNode): deleted_by = file_node.deleted_by deleted_by_guid = file_node.deleted_by._id if deleted_by else None deleted_on = file_node.deleted_on.strftime('%c') + ' UTC' if getattr(file_node, 'suspended', False): error_type = 'FILE_SUSPENDED' elif file_node.deleted_by is None or (auth.private_key and auth.private_link.anonymous): if file_node.provider == 'osfstorage': error_type = 'FILE_GONE_ACTOR_UNKNOWN' else: error_type = 'BLAME_PROVIDER' else: error_type = 'FILE_GONE' else: error_type = 'DONT_KNOW' file_path = kwargs.get('path', file_node.path) file_name = file_node.name or os.path.basename(file_path) file_name_title, file_name_ext = os.path.splitext(file_name) provider_full = settings.ADDONS_AVAILABLE_DICT[file_node.provider].full_name try: file_guid = file_node.get_guid()._id except AttributeError: file_guid = None format_params = dict( file_name=markupsafe.escape(file_name), deleted_by=markupsafe.escape(getattr(deleted_by, 'fullname', None)), deleted_on=markupsafe.escape(deleted_on), provider=markupsafe.escape(provider_full) ) if deleted_by: format_params['deleted_by_guid'] = markupsafe.escape(deleted_by_guid) error_msg = ERROR_MESSAGES[error_type].format(**format_params) if isinstance(target, AbstractNode): error_msg += format_last_known_metadata(auth, target, file_node, error_type) ret = serialize_node(target, auth, primary=True) ret.update(rubeus.collect_addon_assets(target)) ret.update({ 'error': error_msg, 'urls': { 'render': None, 'sharejs': None, 'mfr': get_mfr_url(target, file_node.provider), 'profile_image': get_profile_image_url(auth.user, 25), 'files': target.web_url_for('collect_file_trees'), }, 'extra': {}, 'size': 9966699, # Prevent file from being edited, just in case 'sharejs_uuid': None, 'file_name': file_name, 'file_path': file_path, 'file_name_title': file_name_title, 'file_name_ext': file_name_ext, 'target_deleted': getattr(target, 'is_deleted', False), 'version_id': None, 'file_guid': file_guid, 'file_id': file_node._id, 'provider': file_node.provider, 'materialized_path': file_node.materialized_path or file_path, 'private': getattr(target.get_addon(file_node.provider), 'is_private', False), 'file_tags': list(file_node.tags.filter(system=False).values_list('name', flat=True)) if not file_node._state.adding else [], # Only access ManyRelatedManager if saved 'allow_comments': file_node.provider in settings.ADDONS_COMMENTABLE, }) else: # TODO - serialize deleted metadata for future types of deleted file targets ret = {'error': error_msg} return ret, httplib.GONE
def test_get_other_user_profile_image(self): profile_image = profile_utils.get_profile_image_url(self.user, size=25) assert_true(profile_image)
def test_get_other_user_profile_image_default_size(self): profile_image = profile_utils.get_profile_image_url(self.user) assert_true(profile_image)
def project_wiki_view(auth, wname, path=None, **kwargs): node = kwargs['node'] or kwargs['project'] anonymous = has_anonymous_link(node, auth) wiki_name = (wname or '').strip() wiki_key = to_mongo_key(wiki_name) wiki_page = WikiPage.objects.get_for_node(node, wiki_name) wiki_version = WikiVersion.objects.get_for_node(node, wiki_name) wiki_settings = node.get_addon('wiki') can_edit = ( auth.logged_in and not node.is_registration and ( node.has_permission(auth.user, 'write') or wiki_settings.is_publicly_editable ) ) versions = _get_wiki_versions(node, wiki_name, anonymous=anonymous) # Determine panels used in view panels = {'view', 'edit', 'compare', 'menu'} if request.args and set(request.args).intersection(panels): panels_used = [panel for panel in request.args if panel in panels] num_columns = len(set(panels_used).intersection({'view', 'edit', 'compare'})) if num_columns == 0: panels_used.append('view') num_columns = 1 else: panels_used = ['view', 'menu'] num_columns = 1 try: view = wiki_utils.format_wiki_version( version=request.args.get('view'), num_versions=len(versions), allow_preview=True, ) compare = wiki_utils.format_wiki_version( version=request.args.get('compare'), num_versions=len(versions), allow_preview=False, ) except InvalidVersionError: raise WIKI_INVALID_VERSION_ERROR # ensure home is always lower case since it cannot be renamed if wiki_name.lower() == 'home': wiki_name = 'home' if wiki_version: version = wiki_version.identifier is_current = wiki_version.is_current content = wiki_version.html(node) rendered_before_update = wiki_version.rendered_before_update else: version = 'NA' is_current = False content = '' rendered_before_update = False if can_edit: if wiki_key not in node.wiki_private_uuids: wiki_utils.generate_private_uuid(node, wiki_name) sharejs_uuid = wiki_utils.get_sharejs_uuid(node, wiki_name) else: if not wiki_page and wiki_key != 'home': raise WIKI_PAGE_NOT_FOUND_ERROR if 'edit' in request.args: if wiki_settings.is_publicly_editable: raise HTTPError(http.UNAUTHORIZED) if node.can_view(auth): return redirect(node.web_url_for('project_wiki_view', wname=wname, _guid=True)) raise HTTPError(http.FORBIDDEN) sharejs_uuid = None # Opens 'edit' panel when home wiki is empty if not content and can_edit and wiki_name == 'home': panels_used.append('edit') # Default versions for view and compare version_settings = { 'view': view or ('preview' if 'edit' in panels_used else 'current'), 'compare': compare or 'previous', } ret = { 'wiki_id': wiki_page._primary_key if wiki_page else None, 'wiki_name': wiki_page.page_name if wiki_page else wiki_name, 'wiki_content': content, 'rendered_before_update': rendered_before_update, 'page': wiki_page, 'version': version, 'versions': versions, 'sharejs_uuid': sharejs_uuid or '', 'sharejs_url': settings.SHAREJS_URL, 'is_current': is_current, 'version_settings': version_settings, 'pages_current': _get_wiki_pages_latest(node), 'category': node.category, 'panels_used': panels_used, 'num_columns': num_columns, 'urls': { 'api': _get_wiki_api_urls(node, wiki_name, { 'content': node.api_url_for('wiki_page_content', wname=wiki_name), 'draft': node.api_url_for('wiki_page_draft', wname=wiki_name), }), 'web': _get_wiki_web_urls(node, wiki_name), 'profile_image': get_profile_image_url(auth.user, 25), }, } ret.update(_view_project(node, auth, primary=True)) ret['user']['can_edit_wiki_body'] = can_edit return ret
def addon_view_file(auth, node, file_node, version): # TODO: resolve circular import issue from addons.wiki import settings as wiki_settings if isinstance(version, tuple): version, error = version error = error.replace('\n', '').strip() else: error = None ret = serialize_node(node, auth, primary=True) if file_node._id + '-' + version._id not in node.file_guid_to_share_uuids: node.file_guid_to_share_uuids[file_node._id + '-' + version._id] = uuid.uuid4() node.save() if ret['user']['can_edit']: sharejs_uuid = str(node.file_guid_to_share_uuids[file_node._id + '-' + version._id]) else: sharejs_uuid = None internal_furl = furl.furl(settings.INTERNAL_DOMAIN) download_url = furl.furl(request.url).set(netloc=internal_furl.netloc, args=dict( request.args, **{ 'direct': None, 'mode': 'render', 'action': 'download', 'public_file': node.is_public, })) mfr_url = get_mfr_url(node, file_node.provider) render_url = furl.furl(mfr_url).set(path=['render'], args={'url': download_url.url}) version_names = BaseFileVersionsThrough.objects.filter( basefilenode_id=file_node.id).order_by('-fileversion_id').values_list( 'version_name', flat=True) ret.update({ 'urls': { 'render': render_url.url, 'mfr': mfr_url, 'sharejs': wiki_settings.SHAREJS_URL, 'profile_image': get_profile_image_url(auth.user, 25), 'files': node.web_url_for('collect_file_trees'), 'archived_from': get_archived_from_url(node, file_node) if node.is_registration else None, }, 'error': error, 'file_name': file_node.name, 'file_name_title': os.path.splitext(file_node.name)[0], 'file_name_ext': os.path.splitext(file_node.name)[1], 'version_id': version.identifier, 'file_path': file_node.path, 'sharejs_uuid': sharejs_uuid, 'provider': file_node.provider, 'materialized_path': file_node.materialized_path, 'extra': version.metadata.get('extra', {}), 'size': version.size if version.size is not None else 9966699, 'private': getattr(node.get_addon(file_node.provider), 'is_private', False), 'file_tags': list( file_node.tags.filter(system=False).values_list('name', flat=True)) if not file_node._state.adding else [], # Only access ManyRelatedManager if saved 'file_guid': file_node.get_guid()._id, 'file_id': file_node._id, 'allow_comments': file_node.provider in settings.ADDONS_COMMENTABLE, 'checkout_user': file_node.checkout._id if file_node.checkout else None, 'version_names': list(version_names) }) ret.update(rubeus.collect_addon_assets(node)) return ret
def project_wiki_view(auth, wname, path=None, **kwargs): node = kwargs['node'] or kwargs['project'] anonymous = has_anonymous_link(node, auth) wiki_name = (wname or '').strip() wiki_key = to_mongo_key(wiki_name) wiki_page = node.get_wiki_page(wiki_name) wiki_version = node.get_wiki_version(wiki_name) wiki_settings = node.get_addon('wiki') can_edit = (auth.logged_in and not node.is_registration and (node.has_permission(auth.user, 'write') or wiki_settings.is_publicly_editable)) versions = _get_wiki_versions(node, wiki_name, anonymous=anonymous) # Determine panels used in view panels = {'view', 'edit', 'compare', 'menu'} if request.args and set(request.args).intersection(panels): panels_used = [panel for panel in request.args if panel in panels] num_columns = len( set(panels_used).intersection({'view', 'edit', 'compare'})) if num_columns == 0: panels_used.append('view') num_columns = 1 else: panels_used = ['view', 'menu'] num_columns = 1 try: view = wiki_utils.format_wiki_version( version=request.args.get('view'), num_versions=len(versions), allow_preview=True, ) compare = wiki_utils.format_wiki_version( version=request.args.get('compare'), num_versions=len(versions), allow_preview=False, ) except InvalidVersionError: raise WIKI_INVALID_VERSION_ERROR # ensure home is always lower case since it cannot be renamed if wiki_name.lower() == 'home': wiki_name = 'home' if wiki_version: version = wiki_version.identifier is_current = wiki_version.is_current content = wiki_version.html(node) rendered_before_update = wiki_version.rendered_before_update else: version = 'NA' is_current = False content = '' rendered_before_update = False if can_edit: if wiki_key not in node.wiki_private_uuids: wiki_utils.generate_private_uuid(node, wiki_name) sharejs_uuid = wiki_utils.get_sharejs_uuid(node, wiki_name) else: if not wiki_page and wiki_key != 'home': raise WIKI_PAGE_NOT_FOUND_ERROR if 'edit' in request.args: if wiki_settings.is_publicly_editable: raise HTTPError(http.UNAUTHORIZED) if node.can_view(auth): return redirect( node.web_url_for('project_wiki_view', wname=wname, _guid=True)) raise HTTPError(http.FORBIDDEN) sharejs_uuid = None # Opens 'edit' panel when home wiki is empty if not content and can_edit and wiki_name == 'home': panels_used.append('edit') # Default versions for view and compare version_settings = { 'view': view or ('preview' if 'edit' in panels_used else 'current'), 'compare': compare or 'previous', } ret = { 'wiki_id': wiki_page._primary_key if wiki_page else None, 'wiki_name': wiki_page.page_name if wiki_page else wiki_name, 'wiki_content': content, 'rendered_before_update': rendered_before_update, 'page': wiki_page, 'version': version, 'versions': versions, 'sharejs_uuid': sharejs_uuid or '', 'sharejs_url': settings.SHAREJS_URL, 'is_current': is_current, 'version_settings': version_settings, 'pages_current': _get_wiki_pages_latest(node), 'category': node.category, 'panels_used': panels_used, 'num_columns': num_columns, 'urls': { 'api': _get_wiki_api_urls( node, wiki_name, { 'content': node.api_url_for('wiki_page_content', wname=wiki_name), 'draft': node.api_url_for('wiki_page_draft', wname=wiki_name), }), 'web': _get_wiki_web_urls(node, wiki_name), 'profile_image': get_profile_image_url(auth.user, 25), }, } ret.update(_view_project(node, auth, primary=True)) ret['user']['can_edit_wiki_body'] = can_edit return ret
def addon_view_file(auth, node, file_node, version): # TODO: resolve circular import issue from addons.wiki import settings as wiki_settings if isinstance(version, tuple): version, error = version error = error.replace('\n', '').strip() else: error = None ret = serialize_node(node, auth, primary=True) if file_node._id + '-' + version._id not in node.file_guid_to_share_uuids: node.file_guid_to_share_uuids[file_node._id + '-' + version._id] = uuid.uuid4() node.save() if ret['user']['can_edit']: sharejs_uuid = str(node.file_guid_to_share_uuids[file_node._id + '-' + version._id]) else: sharejs_uuid = None internal_furl = furl.furl(settings.INTERNAL_DOMAIN) download_url = furl.furl(request.url.encode('utf-8')).set( netloc=internal_furl.netloc, args=dict( request.args, **{ 'direct': None, 'mode': 'render', 'action': 'download', 'public_file': node.is_public, })) # Verify file verify_result = {'verify_result': '', 'verify_result_title': ''} cookie = auth.user.get_or_create_cookie() headers = {'content-type': 'application/json'} file_data_request = requests.get(file_node.generate_waterbutler_url( version=version.identifier, meta='', _internal=True), headers=headers, cookies={settings.COOKIE_NAME: cookie}) if file_data_request.status_code == 200: file_data = file_data_request.json().get('data') file_info = { 'provider': file_node.provider, 'file_id': file_node._id, 'file_name': file_data['attributes'].get('name'), 'file_path': file_data['attributes'].get('materialized'), 'size': file_data['attributes'].get('size'), 'created': file_data['attributes'].get('created_utc'), 'modified': file_data['attributes'].get('modified_utc'), 'version': '' } if file_node.provider == 'osfstorage': file_info['version'] = file_data['attributes']['extra'].get( 'version') verify_result = timestamp.check_file_timestamp(auth.user.id, node, file_info) mfr_url = get_mfr_url(node, file_node.provider) render_url = furl.furl(mfr_url).set(path=['render'], args={'url': download_url.url}) ret.update({ 'urls': { 'render': render_url.url, 'mfr': mfr_url, 'sharejs': wiki_settings.SHAREJS_URL, 'profile_image': get_profile_image_url(auth.user, 25), 'files': node.web_url_for('collect_file_trees'), 'archived_from': get_archived_from_url(node, file_node) if node.is_registration else None, }, 'error': error, 'file_name': file_node.name, 'file_name_title': os.path.splitext(file_node.name)[0], 'file_name_ext': os.path.splitext(file_node.name)[1], 'version_id': version.identifier, 'file_path': file_node.path, 'sharejs_uuid': sharejs_uuid, 'provider': file_node.provider, 'materialized_path': file_node.materialized_path, 'extra': version.metadata.get('extra', {}), 'size': version.size if version.size is not None else 9966699, 'private': getattr(node.get_addon(file_node.provider), 'is_private', False), 'file_tags': list( file_node.tags.filter(system=False).values_list('name', flat=True)) if not file_node._state.adding else [], # Only access ManyRelatedManager if saved 'file_guid': file_node.get_guid()._id, 'file_id': file_node._id, 'allow_comments': file_node.provider in settings.ADDONS_COMMENTABLE, 'checkout_user': file_node.checkout._id if file_node.checkout else None, 'pre_reg_checkout': is_pre_reg_checkout(node, file_node), 'timestamp_verify_result': verify_result['verify_result'], 'timestamp_verify_result_title': verify_result['verify_result_title'], }) ret.update(rubeus.collect_addon_assets(node)) return ret