def new_node(category, title, user, description=None, project=None): """Create a new project or component. :param str category: Node category :param str title: Node title :param User user: User object :param str description: Node description :param Node project: Optional parent object :return Node: Created node """ category = category.strip().lower() title = sanitize(title.strip()) if description: description = sanitize(description.strip()) node = Node( title=title, category=category, creator=user, description=description, project=project, ) node.save() return node
def render_content(content, node): html_output = build_html_output(content, node) # linkify gets called after santize, because we're adding rel="nofollow" # to <a> elements - but don't want to allow them for other elements. sanitized_content = sanitize(html_output, **settings.WIKI_WHITELIST) return sanitized_content
def new_private_link(name, user, nodes, anonymous): """Create a new private link. :param str name: private link name :param User user: User object :param list Node node: a list of node object :param bool anonymous: make link anonymous or not :return PrivateLink: Created private link """ key = str(uuid.uuid4()).replace("-", "") if name: name = sanitize(name.strip()) else: name = "Shared project link" private_link = PrivateLink( key=key, name=name, creator=user, nodes=nodes, anonymous=anonymous ) private_link.save() return private_link
def new_private_link(name, user, nodes, anonymous): """Create a new private link. :param str name: private link name :param User user: User object :param list Node node: a list of node object :param bool anonymous: make link anonymous or not :return PrivateLink: Created private link """ key = str(uuid.uuid4()).replace("-", "") if name: name = sanitize(name.strip()) else: name = "Shared project link" private_link = PrivateLink(key=key, name=name, creator=user, nodes=nodes, anonymous=anonymous) private_link.save() return private_link
def add_comment(**kwargs): auth = kwargs['auth'] node = kwargs['node'] or kwargs['project'] if not node.comment_level: raise HTTPError(http.BAD_REQUEST) if not node.can_comment(auth): raise HTTPError(http.FORBIDDEN) guid = request.json.get('target') target = resolve_target(node, guid) content = request.json.get('content').strip() content = sanitize(content) if not content: raise HTTPError(http.BAD_REQUEST) if len(content) > settings.COMMENT_MAXLENGTH: raise HTTPError(http.BAD_REQUEST) comment = Comment.create( auth=auth, node=node, target=target, user=auth.user, content=content, ) comment.save() return { 'comment': serialize_comment(comment, auth) }, http.CREATED
def add_comment(auth, node, **kwargs): if not node.comment_level: raise HTTPError(http.BAD_REQUEST) if not node.can_comment(auth): raise HTTPError(http.FORBIDDEN) guid = request.json.get('target') target = resolve_target(node, guid) content = request.json.get('content').strip() content = sanitize(content) if not content: raise HTTPError(http.BAD_REQUEST) if len(content) > settings.COMMENT_MAXLENGTH: raise HTTPError(http.BAD_REQUEST) comment = Comment.create( auth=auth, node=node, target=target, user=auth.user, content=content, ) comment.save() context = dict( gravatar_url=auth.user.gravatar_url, content=content, target_user=target.user if is_reply(target) else None, parent_comment=target.content if is_reply(target) else "", url=node.absolute_url ) time_now = datetime.utcnow().replace(tzinfo=pytz.utc) sent_subscribers = notify( uid=node._id, event="comments", user=auth.user, node=node, timestamp=time_now, **context ) if is_reply(target): if target.user and target.user not in sent_subscribers: notify( uid=target.user._id, event='comment_replies', user=auth.user, node=node, timestamp=time_now, **context ) return { 'comment': serialize_comment(comment, auth) }, http.CREATED
def show_diff(seqm): """Unify operations between two compared strings seqm is a difflib.SequenceMatcher instance whose a & b are strings""" output = [] insert_el = '<span style="background:#4AA02C; font-size:1.5em; ">' ins_el_close = "</span>" del_el = '<span style="background:#D16587; font-size:1.5em;">' del_el_close = "</span>" for opcode, a0, a1, b0, b1 in seqm.get_opcodes(): content_a = sanitize(seqm.a[a0:a1]) content_b = sanitize(seqm.b[b0:b1]) if opcode == "equal": output.append(content_a) elif opcode == "insert": output.append(insert_el + content_b + ins_el_close) elif opcode == "delete": output.append(del_el + content_a + del_el_close) elif opcode == "replace": output.append(del_el + content_a + del_el_close + insert_el + content_b + ins_el_close) else: raise RuntimeError("unexpected opcode") return "".join(output)
def show_diff(seqm): """Unify operations between two compared strings seqm is a difflib.SequenceMatcher instance whose a & b are strings""" output = [] insert_el = '<span style="background:#4AA02C; font-size:1.5em; ">' ins_el_close = '</span>' del_el = '<span style="background:#D16587; font-size:1.5em;">' del_el_close = '</span>' for opcode, a0, a1, b0, b1 in seqm.get_opcodes(): content_a = sanitize(seqm.a[a0:a1]) content_b = sanitize(seqm.b[b0:b1]) if opcode == 'equal': output.append(content_a) elif opcode == 'insert': output.append(insert_el + content_b + ins_el_close) elif opcode == 'delete': output.append(del_el + content_a + del_el_close) elif opcode == 'replace': output.append(del_el + content_a + del_el_close + insert_el + content_b + ins_el_close) else: raise RuntimeError("unexpected opcode") return ''.join(output)
def new_folder(title, user): """Create a new folder project. :param str title: Node title :param User user: User object :return Node: Created node """ title = sanitize(title.strip()) node = Node(title=title, creator=user, category='project', is_folder=True) node.save() return node
def edit_comment(auth, **kwargs): cid = kwargs.get('cid') comment = get_comment(cid, auth, owner=True) content = request.json.get('content').strip() content = sanitize(content) if not content: raise HTTPError(http.BAD_REQUEST) if len(content) > settings.COMMENT_MAXLENGTH: raise HTTPError(http.BAD_REQUEST) comment.edit(content=content, auth=auth, save=True) return serialize_comment(comment, auth)
def new_folder(title, user): """Create a new folder project. :param str title: Node title :param User user: User object :return Node: Created node """ title = sanitize(title.strip()) node = Node(title=title, creator=user, category="project", is_folder=True) node.save() return node
def render_content(content, node): html_output = markdown.markdown( content, extensions=[ wikilinks.WikiLinkExtension( configs=[("base_url", ""), ("end_url", ""), ("build_url", functools.partial(build_wiki_url, node))] ), fenced_code.FencedCodeExtension(), codehilite.CodeHiliteExtension([("css_class", "highlight")]), ], ) # linkify gets called after santize, because we're adding rel="nofollow" # to <a> elements - but don't want to allow them for other elements. sanitized_content = sanitize(html_output, **settings.WIKI_WHITELIST) return sanitized_content
def render_content(content, node): html_output = markdown.markdown( content, extensions=[ wikilinks.WikiLinkExtension( configs=[('base_url', ''), ( 'end_url', ''), ('build_url', functools.partial(build_wiki_url, node))]), fenced_code.FencedCodeExtension(), codehilite.CodeHiliteExtension([('css_class', 'highlight')]) ]) # linkify gets called after santize, because we're adding rel="nofollow" # to <a> elements - but don't want to allow them for other elements. sanitized_content = sanitize(html_output, **settings.WIKI_WHITELIST) return sanitized_content
def edit_comment(auth, **kwargs): cid = kwargs.get('cid') comment = get_comment(cid, auth, owner=True) content = request.json.get('content').strip() content = sanitize(content) if not content: raise HTTPError(http.BAD_REQUEST) if len(content) > settings.COMMENT_MAXLENGTH: raise HTTPError(http.BAD_REQUEST) comment.edit( content=content, auth=auth, save=True ) return serialize_comment(comment, auth)
def raw_text(self, node): """ The raw text of the page, suitable for using in a test search""" return sanitize(self.html(node), tags=[], strip=True)
def add_poster_by_email(conf, recipient, address, fullname, subject, message, attachments, tags=None, system_tags=None, is_spam=False): # Fail if no attachments if not attachments: send_mail( address, CONFERENCE_FAILED, fullname=fullname, ) return # Use address as name if name missing fullname = fullname or address.split('@')[0] created = [] user, user_created = get_or_create_user(fullname, address, is_spam) if user_created: created.append(user) set_password_url = web_url_for( 'reset_password', verification_key=user.verification_key, ) else: set_password_url = None auth = Auth(user=user) # Find or create node node = Node.find(Q('title', 'iexact', subject)) node = node[0] if node.count() else None if node is None or not node.is_contributor(user): node = new_node('project', subject, user) created.append(node) # Add admin to project if conf.admins: for admin in conf.admins: node.add_contributor( contributor=admin, visible=False, log=False, save=True ) # Make public if confident that this is not spam and projects made public if is_spam: logger.warn( 'Possible spam detected in email modification of ' 'user {0} / node {1}'.format( user._id, node._id, ) ) elif conf.public_projects: node.set_privacy('public', auth=auth) # Add body node.update_node_wiki('home', sanitize(message), auth) # Add tags presentation_type = 'talk' if 'talk' in recipient else 'poster' tags = tags or [] tags.append(presentation_type) for tag in tags: node.add_tag(tag, auth=auth) # Add system tags system_tags = system_tags or [] system_tags.append(presentation_type) system_tags.append('emailed') if is_spam: system_tags.append('spam') for tag in system_tags: if tag not in node.system_tags: node.system_tags.append(tag) # Save changes node.save() from website.addons.osfstorage import utils as storage_utils # Add files for attachment in attachments: name, content, content_type, size = prepare_file(attachment) upload_url = storage_utils.get_upload_url(node, user, size, content_type, name) requests.put( upload_url, data=content, headers={'Content-Type': content_type}, ) download_url = node.web_url_for( 'osf_storage_view_file', path=attachments[0].filename, action='download', ) # Add mail record mail_record = MailRecord( data=request_to_data(), records=created, ) mail_record.save() # Send confirmation email send_mail( address, CONFERENCE_SUBMITTED, conf_full_name=conf.name, conf_view_url=urlparse.urljoin( settings.DOMAIN, os.path.join('view', conf.endpoint) ), fullname=fullname, user_created=user_created, set_password_url=set_password_url, profile_url=user.absolute_url, node_url=urlparse.urljoin(settings.DOMAIN, node.url), file_url=urlparse.urljoin(settings.DOMAIN, download_url), presentation_type=presentation_type, is_spam=is_spam, )
def add_poster_by_email(conf, recipient, address, fullname, subject, message, attachments, tags=None, system_tags=None, is_spam=False): # Fail if no attachments if not attachments: send_mail( address, CONFERENCE_FAILED, fullname=fullname, ) return # Use address as name if name missing fullname = fullname or address.split('@')[0] created = [] user, user_created = get_or_create_user(fullname, address, is_spam) if user_created: created.append(user) set_password_url = web_url_for( 'reset_password', verification_key=user.verification_key, ) else: set_password_url = None auth = Auth(user=user) # Find or create node node = Node.find(Q('title', 'iexact', subject)) node = node[0] if node.count() else None if node is None or not node.is_contributor(user): node = new_node('project', subject, user) created.append(node) # Add admin to project if conf.admins: for admin in conf.admins: node.add_contributor(contributor=admin, visible=False, log=False, save=True) # Make public if confident that this is not spam and projects made public if is_spam: logger.warn('Possible spam detected in email modification of ' 'user {0} / node {1}'.format( user._id, node._id, )) elif conf.public_projects: node.set_privacy('public', auth=auth) # Add body node.update_node_wiki('home', sanitize(message), auth) # Add tags presentation_type = 'talk' if 'talk' in recipient else 'poster' tags = tags or [] tags.append(presentation_type) for tag in tags: node.add_tag(tag, auth=auth) # Add system tags system_tags = system_tags or [] system_tags.append(presentation_type) system_tags.append('emailed') if is_spam: system_tags.append('spam') for tag in system_tags: if tag not in node.system_tags: node.system_tags.append(tag) # Save changes node.save() from website.addons.osfstorage import utils as storage_utils # Add files for attachment in attachments: name, content, content_type, size = prepare_file(attachment) upload_url = storage_utils.get_upload_url(node, user, size, content_type, name) requests.put( upload_url, data=content, headers={'Content-Type': content_type}, ) download_url = node.web_url_for( 'osf_storage_view_file', path=attachments[0].filename, action='download', ) # Add mail record mail_record = MailRecord( data=request_to_data(), records=created, ) mail_record.save() # Send confirmation email send_mail( address, CONFERENCE_SUBMITTED, conf_full_name=conf.name, conf_view_url=urlparse.urljoin(settings.DOMAIN, os.path.join('view', conf.endpoint)), fullname=fullname, user_created=user_created, set_password_url=set_password_url, profile_url=user.absolute_url, node_url=urlparse.urljoin(settings.DOMAIN, node.url), file_url=urlparse.urljoin(settings.DOMAIN, download_url), presentation_type=presentation_type, is_spam=is_spam, )