121 lines
4.6 KiB
Python
121 lines
4.6 KiB
Python
# -*- coding: utf-8 -*-
|
|
# Copyright (C) 2014-2016 Andrey Antukh <niwi@niwi.nz>
|
|
# Copyright (C) 2014-2016 Jesús Espino <jespinog@gmail.com>
|
|
# Copyright (C) 2014-2016 David Barragán <bameda@dbarragan.com>
|
|
# Copyright (C) 2014-2016 Alejandro Alonso <alejandro.alonso@kaleidos.net>
|
|
# This program is free software: you can redistribute it and/or modify
|
|
# it under the terms of the GNU Affero General Public License as
|
|
# published by the Free Software Foundation, either version 3 of the
|
|
# License, or (at your option) any later version.
|
|
#
|
|
# This program is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU Affero General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU Affero General Public License
|
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
# The code is partially taken (and modified) from django rest framework
|
|
# that is licensed under the following terms:
|
|
#
|
|
# Copyright (c) 2011-2014, Tom Christie
|
|
# All rights reserved.
|
|
#
|
|
# Redistribution and use in source and binary forms, with or without
|
|
# modification, are permitted provided that the following conditions are met:
|
|
#
|
|
# Redistributions of source code must retain the above copyright notice, this
|
|
# list of conditions and the following disclaimer.
|
|
# Redistributions in binary form must reproduce the above copyright notice, this
|
|
# list of conditions and the following disclaimer in the documentation and/or
|
|
# other materials provided with the distribution.
|
|
#
|
|
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
|
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
"""
|
|
Utility functions to return a formatted name and description for a given view.
|
|
"""
|
|
from django.utils.html import escape
|
|
from django.utils.safestring import mark_safe
|
|
|
|
from taiga.base.api.settings import api_settings
|
|
|
|
from textwrap import dedent
|
|
import re
|
|
|
|
# Markdown is optional
|
|
try:
|
|
import markdown
|
|
|
|
def apply_markdown(text):
|
|
"""
|
|
Simple wrapper around :func:`markdown.markdown` to set the base level
|
|
of '#' style headers to <h2>.
|
|
"""
|
|
extensions = ["headerid(level=2)"]
|
|
safe_mode = False
|
|
md = markdown.Markdown(extensions=extensions, safe_mode=safe_mode)
|
|
return md.convert(text)
|
|
|
|
except ImportError:
|
|
apply_markdown = None
|
|
|
|
|
|
def remove_trailing_string(content, trailing):
|
|
"""
|
|
Strip trailing component `trailing` from `content` if it exists.
|
|
Used when generating names from view classes.
|
|
"""
|
|
if content.endswith(trailing) and content != trailing:
|
|
return content[:-len(trailing)]
|
|
return content
|
|
|
|
|
|
def dedent(content):
|
|
"""
|
|
Remove leading indent from a block of text.
|
|
Used when generating descriptions from docstrings.
|
|
|
|
Note that python's `textwrap.dedent` doesn't quite cut it,
|
|
as it fails to dedent multiline docstrings that include
|
|
unindented text on the initial line.
|
|
"""
|
|
whitespace_counts = [len(line) - len(line.lstrip(" "))
|
|
for line in content.splitlines()[1:] if line.lstrip()]
|
|
|
|
# unindent the content if needed
|
|
if whitespace_counts:
|
|
whitespace_pattern = "^" + (" " * min(whitespace_counts))
|
|
content = re.sub(re.compile(whitespace_pattern, re.MULTILINE), "", content)
|
|
|
|
return content.strip()
|
|
|
|
def camelcase_to_spaces(content):
|
|
"""
|
|
Translate 'CamelCaseNames' to 'Camel Case Names'.
|
|
Used when generating names from view classes.
|
|
"""
|
|
camelcase_boundry = "(((?<=[a-z])[A-Z])|([A-Z](?![A-Z]|$)))"
|
|
content = re.sub(camelcase_boundry, " \\1", content).strip()
|
|
return " ".join(content.split("_")).title()
|
|
|
|
def markup_description(description):
|
|
"""
|
|
Apply HTML markup to the given description.
|
|
"""
|
|
if apply_markdown:
|
|
description = apply_markdown(description)
|
|
else:
|
|
description = escape(description).replace("\n", "<br />")
|
|
return mark_safe(description)
|