all: implement black as code formatter
This commit is contained in:
@ -5,6 +5,6 @@ from django.apps import AppConfig
|
||||
class PassbookLibConfig(AppConfig):
|
||||
"""passbook lib app config"""
|
||||
|
||||
name = 'passbook.lib'
|
||||
label = 'passbook_lib'
|
||||
verbose_name = 'passbook lib'
|
||||
name = "passbook.lib"
|
||||
label = "passbook_lib"
|
||||
verbose_name = "passbook lib"
|
||||
|
||||
@ -3,7 +3,7 @@ from django.utils.decorators import method_decorator
|
||||
from django.views.decorators.cache import never_cache
|
||||
|
||||
|
||||
class NeverCacheMixin():
|
||||
class NeverCacheMixin:
|
||||
"""Use never_cache as mixin for CBV"""
|
||||
|
||||
@method_decorator(never_cache)
|
||||
|
||||
@ -11,14 +11,12 @@ from django.conf import ImproperlyConfigured
|
||||
from django.utils.autoreload import autoreload_started
|
||||
from structlog import get_logger
|
||||
|
||||
SEARCH_PATHS = [
|
||||
'passbook/lib/default.yml',
|
||||
'/etc/passbook/config.yml',
|
||||
'',
|
||||
] + glob('/etc/passbook/config.d/*.yml', recursive=True)
|
||||
SEARCH_PATHS = ["passbook/lib/default.yml", "/etc/passbook/config.yml", "",] + glob(
|
||||
"/etc/passbook/config.d/*.yml", recursive=True
|
||||
)
|
||||
LOGGER = get_logger()
|
||||
ENV_PREFIX = 'PASSBOOK'
|
||||
ENVIRONMENT = os.getenv(f'{ENV_PREFIX}_ENV', 'local')
|
||||
ENV_PREFIX = "PASSBOOK"
|
||||
ENVIRONMENT = os.getenv(f"{ENV_PREFIX}_ENV", "local")
|
||||
|
||||
|
||||
class ConfigLoader:
|
||||
@ -34,7 +32,7 @@ class ConfigLoader:
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
base_dir = os.path.realpath(os.path.join(os.path.dirname(__file__), '../..'))
|
||||
base_dir = os.path.realpath(os.path.join(os.path.dirname(__file__), "../.."))
|
||||
for path in SEARCH_PATHS:
|
||||
# Check if path is relative, and if so join with base_dir
|
||||
if not os.path.isabs(path):
|
||||
@ -44,8 +42,10 @@ class ConfigLoader:
|
||||
self.update_from_file(path)
|
||||
elif os.path.isdir(path) and os.path.exists(path):
|
||||
# Path is an existing dir, so we try to read the env config from it
|
||||
env_paths = [os.path.join(path, ENVIRONMENT + '.yml'),
|
||||
os.path.join(path, ENVIRONMENT + '.env.yml')]
|
||||
env_paths = [
|
||||
os.path.join(path, ENVIRONMENT + ".yml"),
|
||||
os.path.join(path, ENVIRONMENT + ".env.yml"),
|
||||
]
|
||||
for env_file in env_paths:
|
||||
if os.path.isfile(env_file) and os.path.exists(env_file):
|
||||
# Update config with env file
|
||||
@ -66,7 +66,7 @@ class ConfigLoader:
|
||||
def parse_uri(self, value):
|
||||
"""Parse string values which start with a URI"""
|
||||
url = urlparse(value)
|
||||
if url.scheme == 'env':
|
||||
if url.scheme == "env":
|
||||
value = os.getenv(url.netloc, url.query)
|
||||
return value
|
||||
|
||||
@ -81,7 +81,7 @@ class ConfigLoader:
|
||||
except yaml.YAMLError as exc:
|
||||
raise ImproperlyConfigured from exc
|
||||
except PermissionError as exc:
|
||||
LOGGER.warning('Permission denied while reading file', path=path, error=exc)
|
||||
LOGGER.warning("Permission denied while reading file", path=path, error=exc)
|
||||
|
||||
def update_from_dict(self, update: dict):
|
||||
"""Update config from dict"""
|
||||
@ -94,10 +94,10 @@ class ConfigLoader:
|
||||
for key, value in os.environ.items():
|
||||
if not key.startswith(ENV_PREFIX):
|
||||
continue
|
||||
relative_key = key.replace(f"{ENV_PREFIX}_", '').replace('__', '.').lower()
|
||||
relative_key = key.replace(f"{ENV_PREFIX}_", "").replace("__", ".").lower()
|
||||
# Recursively convert path from a.b.c into outer[a][b][c]
|
||||
current_obj = outer
|
||||
dot_parts = relative_key.split('.')
|
||||
dot_parts = relative_key.split(".")
|
||||
for dot_part in dot_parts[:-1]:
|
||||
if dot_part not in current_obj:
|
||||
current_obj[dot_part] = {}
|
||||
@ -122,7 +122,7 @@ class ConfigLoader:
|
||||
return self.__config
|
||||
|
||||
# pylint: disable=invalid-name
|
||||
def y(self, path: str, default=None, sep='.') -> Any:
|
||||
def y(self, path: str, default=None, sep=".") -> Any:
|
||||
"""Access attribute by using yaml path"""
|
||||
# Walk sub_dicts before parsing path
|
||||
root = self.raw
|
||||
@ -138,7 +138,7 @@ class ConfigLoader:
|
||||
|
||||
def y_bool(self, path: str, default=False) -> bool:
|
||||
"""Wrapper for y that converts value into boolean"""
|
||||
return str(self.y(path, default)).lower() == 'true'
|
||||
return str(self.y(path, default)).lower() == "true"
|
||||
|
||||
|
||||
CONFIG = ConfigLoader()
|
||||
|
||||
@ -7,8 +7,8 @@ from django.urls import reverse
|
||||
from django.utils.functional import wraps
|
||||
from django.utils.http import urlencode
|
||||
|
||||
RE_AUTH_KEY = getattr(settings, 'RE_AUTH_KEY', 'passbook_require_re_auth_done')
|
||||
RE_AUTH_MARGAIN = getattr(settings, 'RE_AUTH_MARGAIN', 300)
|
||||
RE_AUTH_KEY = getattr(settings, "RE_AUTH_KEY", "passbook_require_re_auth_done")
|
||||
RE_AUTH_MARGAIN = getattr(settings, "RE_AUTH_MARGAIN", 300)
|
||||
|
||||
|
||||
def reauth_required(view_function):
|
||||
@ -21,25 +21,31 @@ def reauth_required(view_function):
|
||||
request = args[0] if args else None
|
||||
# Check if user is authenticated at all
|
||||
if not request or not request.user or not request.user.is_authenticated:
|
||||
return redirect(reverse('account-login'))
|
||||
return redirect(reverse("account-login"))
|
||||
|
||||
now = timestamp()
|
||||
|
||||
if RE_AUTH_KEY in request.session and \
|
||||
request.session[RE_AUTH_KEY] < (now - RE_AUTH_MARGAIN):
|
||||
if RE_AUTH_KEY in request.session and request.session[RE_AUTH_KEY] < (
|
||||
now - RE_AUTH_MARGAIN
|
||||
):
|
||||
# Timestamp in session but expired
|
||||
del request.session[RE_AUTH_KEY]
|
||||
|
||||
if RE_AUTH_KEY not in request.session:
|
||||
# Timestamp not in session, force user to reauth
|
||||
return redirect(reverse('account-reauth') + '?' + urlencode({'next': request.path}))
|
||||
return redirect(
|
||||
reverse("account-reauth") + "?" + urlencode({"next": request.path})
|
||||
)
|
||||
|
||||
if RE_AUTH_KEY in request.session and \
|
||||
request.session[RE_AUTH_KEY] >= (now - RE_AUTH_MARGAIN) and \
|
||||
request.session[RE_AUTH_KEY] <= now:
|
||||
if (
|
||||
RE_AUTH_KEY in request.session
|
||||
and request.session[RE_AUTH_KEY] >= (now - RE_AUTH_MARGAIN)
|
||||
and request.session[RE_AUTH_KEY] <= now
|
||||
):
|
||||
# Timestamp in session and valid
|
||||
return view_function(*args, **kwargs)
|
||||
|
||||
# This should never be reached, just return False
|
||||
return False # pragma: no cover
|
||||
|
||||
return wrap
|
||||
|
||||
@ -10,7 +10,9 @@ from passbook.lib.widgets import DynamicArrayWidget
|
||||
class DynamicArrayField(forms.Field):
|
||||
"""Show array field as a dynamic amount of textboxes"""
|
||||
|
||||
default_error_messages = {"item_invalid": "Item %(nth)s in the array did not validate: "}
|
||||
default_error_messages = {
|
||||
"item_invalid": "Item %(nth)s in the array did not validate: "
|
||||
}
|
||||
|
||||
def __init__(self, base_field, **kwargs):
|
||||
self.base_field = base_field
|
||||
@ -28,8 +30,10 @@ class DynamicArrayField(forms.Field):
|
||||
except forms.ValidationError as error:
|
||||
errors.append(
|
||||
prefix_validation_error(
|
||||
error, self.error_messages["item_invalid"],
|
||||
code="item_invalid", params={"nth": index}
|
||||
error,
|
||||
self.error_messages["item_invalid"],
|
||||
code="item_invalid",
|
||||
params={"nth": index},
|
||||
)
|
||||
)
|
||||
if errors:
|
||||
|
||||
@ -6,6 +6,7 @@ from django.db import models
|
||||
|
||||
class CreatedUpdatedModel(models.Model):
|
||||
"""Base Abstract Model to save created and update"""
|
||||
|
||||
created = models.DateTimeField(auto_now_add=True)
|
||||
last_updated = models.DateTimeField(auto_now=True)
|
||||
|
||||
|
||||
@ -12,6 +12,7 @@ def before_send(event, hint):
|
||||
from billiard.exceptions import WorkerLostError
|
||||
from django.core.exceptions import DisallowedHost
|
||||
from botocore.client import ClientError
|
||||
|
||||
ignored_classes = (
|
||||
OperationalError,
|
||||
ConnectionInterrupted,
|
||||
@ -22,10 +23,10 @@ def before_send(event, hint):
|
||||
DisallowedHost,
|
||||
ConnectionResetError,
|
||||
KeyboardInterrupt,
|
||||
ClientError
|
||||
ClientError,
|
||||
)
|
||||
if 'exc_info' in hint:
|
||||
_exc_type, exc_value, _ = hint['exc_info']
|
||||
if "exc_info" in hint:
|
||||
_exc_type, exc_value, _ = hint["exc_info"]
|
||||
if isinstance(exc_value, ignored_classes):
|
||||
LOGGER.info("Supressing error %r", exc_value)
|
||||
return None
|
||||
|
||||
@ -6,8 +6,9 @@ from passbook.root.celery import CELERY_APP
|
||||
|
||||
LOGGER = get_logger()
|
||||
|
||||
|
||||
@CELERY_APP.task()
|
||||
def backup_database():
|
||||
"""Backup database"""
|
||||
management.call_command('dbbackup')
|
||||
LOGGER.info('Successfully backed up database.')
|
||||
management.call_command("dbbackup")
|
||||
LOGGER.info("Successfully backed up database.")
|
||||
|
||||
@ -10,11 +10,11 @@ register = template.Library()
|
||||
@register.simple_tag()
|
||||
def inline_static(path):
|
||||
"""Inline static asset. If file is binary, return b64 representation"""
|
||||
prefix = 'data:image/svg+xml;utf8,'
|
||||
data = ''
|
||||
full_path = settings.STATIC_ROOT + '/' + path
|
||||
prefix = "data:image/svg+xml;utf8,"
|
||||
data = ""
|
||||
full_path = settings.STATIC_ROOT + "/" + path
|
||||
if os.path.exists(full_path):
|
||||
if full_path.endswith('.svg'):
|
||||
if full_path.endswith(".svg"):
|
||||
with open(full_path) as _file:
|
||||
data = _file.read()
|
||||
return prefix + data
|
||||
|
||||
@ -10,22 +10,23 @@ LOGGER = get_logger()
|
||||
@register.simple_tag(takes_context=True)
|
||||
def is_active(context, *args, **kwargs):
|
||||
"""Return whether a navbar link is active or not."""
|
||||
request = context.get('request')
|
||||
app_name = kwargs.get('app_name', None)
|
||||
request = context.get("request")
|
||||
app_name = kwargs.get("app_name", None)
|
||||
if not request.resolver_match:
|
||||
return ''
|
||||
return ""
|
||||
for url in args:
|
||||
short_url = url.split(':')[1] if ':' in url else url
|
||||
short_url = url.split(":")[1] if ":" in url else url
|
||||
# Check if resolver_match matches
|
||||
if request.resolver_match.url_name.startswith(url) or \
|
||||
request.resolver_match.url_name.startswith(short_url):
|
||||
if request.resolver_match.url_name.startswith(
|
||||
url
|
||||
) or request.resolver_match.url_name.startswith(short_url):
|
||||
# Monkeypatch app_name: urls from core have app_name == ''
|
||||
# since the root urlpatterns have no namespace
|
||||
if app_name and request.resolver_match.app_name == app_name:
|
||||
return 'active'
|
||||
return "active"
|
||||
if app_name is None:
|
||||
return 'active'
|
||||
return ''
|
||||
return "active"
|
||||
return ""
|
||||
|
||||
|
||||
@register.simple_tag(takes_context=True)
|
||||
@ -33,26 +34,28 @@ def is_active_url(context, view):
|
||||
"""Return whether a navbar link is active or not."""
|
||||
|
||||
# matching_url = reverse(view, args=args, kwargs=kwargs)
|
||||
request = context.get('request')
|
||||
current_full_url = f"{request.resolver_match.app_name}:{request.resolver_match.url_name}"
|
||||
request = context.get("request")
|
||||
current_full_url = (
|
||||
f"{request.resolver_match.app_name}:{request.resolver_match.url_name}"
|
||||
)
|
||||
|
||||
if not request.resolver_match:
|
||||
return ''
|
||||
return ""
|
||||
if current_full_url == view:
|
||||
return 'active'
|
||||
return "active"
|
||||
# if matching_url == request.path:
|
||||
# return 'active'
|
||||
return ''
|
||||
return ""
|
||||
|
||||
|
||||
@register.simple_tag(takes_context=True)
|
||||
def is_active_app(context, *args):
|
||||
"""Return True if current link is from app"""
|
||||
|
||||
request = context.get('request')
|
||||
request = context.get("request")
|
||||
if not request.resolver_match:
|
||||
return ''
|
||||
return ""
|
||||
for app_name in args:
|
||||
if request.resolver_match.app_name == app_name:
|
||||
return 'active'
|
||||
return ''
|
||||
return "active"
|
||||
return ""
|
||||
|
||||
@ -18,19 +18,19 @@ register = template.Library()
|
||||
def back(context):
|
||||
"""Return a link back (either from GET paramter or referer."""
|
||||
|
||||
request = context.get('request')
|
||||
url = ''
|
||||
if 'HTTP_REFERER' in request.META:
|
||||
url = request.META.get('HTTP_REFERER')
|
||||
if 'back' in request.GET:
|
||||
url = request.GET.get('back')
|
||||
request = context.get("request")
|
||||
url = ""
|
||||
if "HTTP_REFERER" in request.META:
|
||||
url = request.META.get("HTTP_REFERER")
|
||||
if "back" in request.GET:
|
||||
url = request.GET.get("back")
|
||||
|
||||
if not is_url_absolute(url):
|
||||
return url
|
||||
return ''
|
||||
return ""
|
||||
|
||||
|
||||
@register.filter('fieldtype')
|
||||
@register.filter("fieldtype")
|
||||
def fieldtype(field):
|
||||
"""Return classname"""
|
||||
# if issubclass(field.__class__, CastableModel):
|
||||
@ -43,34 +43,40 @@ def fieldtype(field):
|
||||
@register.simple_tag(takes_context=True)
|
||||
def title(context, *title):
|
||||
"""Return either just branding or title - branding"""
|
||||
branding = CONFIG.y('passbook.branding', 'passbook')
|
||||
branding = CONFIG.y("passbook.branding", "passbook")
|
||||
if not title:
|
||||
return branding
|
||||
# Include App Title in title
|
||||
app = ''
|
||||
if context.request.resolver_match and context.request.resolver_match.namespace != '':
|
||||
app = ""
|
||||
if (
|
||||
context.request.resolver_match
|
||||
and context.request.resolver_match.namespace != ""
|
||||
):
|
||||
dj_app = None
|
||||
namespace = context.request.resolver_match.namespace.split(':')[0]
|
||||
namespace = context.request.resolver_match.namespace.split(":")[0]
|
||||
# New label (App URL Namespace == App Label)
|
||||
dj_app = apps.get_app_config(namespace)
|
||||
title_modifier = getattr(dj_app, 'title_modifier', None)
|
||||
title_modifier = getattr(dj_app, "title_modifier", None)
|
||||
if title_modifier:
|
||||
app_title = dj_app.title_modifier(context.request)
|
||||
app = app_title + ' -'
|
||||
return _("%(title)s - %(app)s %(branding)s" % {
|
||||
'title': ' - '.join([str(x) for x in title]),
|
||||
'branding': branding,
|
||||
'app': app,
|
||||
})
|
||||
app = app_title + " -"
|
||||
return _(
|
||||
"%(title)s - %(app)s %(branding)s"
|
||||
% {
|
||||
"title": " - ".join([str(x) for x in title]),
|
||||
"branding": branding,
|
||||
"app": app,
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
@register.simple_tag
|
||||
def config(path, default=''):
|
||||
def config(path, default=""):
|
||||
"""Get a setting from the database. Returns default is setting doesn't exist."""
|
||||
return CONFIG.y(path, default)
|
||||
|
||||
|
||||
@register.filter(name='css_class')
|
||||
@register.filter(name="css_class")
|
||||
def css_class(field, css):
|
||||
"""Add css class to form field"""
|
||||
return field.as_widget(attrs={"class": css})
|
||||
@ -90,16 +96,15 @@ def gravatar(email, size=None, rating=None):
|
||||
{% gravatar someone@example.com 48 pg %}
|
||||
"""
|
||||
# gravatar uses md5 for their URLs, so md5 can't be avoided
|
||||
gravatar_url = "%savatar/%s" % ('https://secure.gravatar.com/',
|
||||
md5(email.encode('utf-8')).hexdigest()) # nosec
|
||||
gravatar_url = "%savatar/%s" % (
|
||||
"https://secure.gravatar.com/",
|
||||
md5(email.encode("utf-8")).hexdigest(),
|
||||
) # nosec
|
||||
|
||||
parameters = [p for p in (
|
||||
('s', size or '158'),
|
||||
('r', rating or 'g'),
|
||||
) if p[1]]
|
||||
parameters = [p for p in (("s", size or "158"), ("r", rating or "g"),) if p[1]]
|
||||
|
||||
if parameters:
|
||||
gravatar_url += '?' + urlencode(parameters, doseq=True)
|
||||
gravatar_url += "?" + urlencode(parameters, doseq=True)
|
||||
|
||||
return escape(gravatar_url)
|
||||
|
||||
@ -108,7 +113,7 @@ def gravatar(email, size=None, rating=None):
|
||||
def verbose_name(obj):
|
||||
"""Return Object's Verbose Name"""
|
||||
if not obj:
|
||||
return ''
|
||||
return ""
|
||||
return obj._meta.verbose_name
|
||||
|
||||
|
||||
@ -116,5 +121,5 @@ def verbose_name(obj):
|
||||
def form_verbose_name(obj):
|
||||
"""Return ModelForm's Object's Verbose Name"""
|
||||
if not obj:
|
||||
return ''
|
||||
return ""
|
||||
return obj._meta.model._meta.verbose_name
|
||||
|
||||
@ -8,9 +8,9 @@ def _get_client_ip_from_meta(meta: Dict[str, Any]) -> Optional[str]:
|
||||
"""Attempt to get the client's IP by checking common HTTP Headers.
|
||||
Returns none if no IP Could be found"""
|
||||
headers = (
|
||||
'HTTP_X_FORWARDED_FOR',
|
||||
'HTTP_X_REAL_IP',
|
||||
'REMOTE_ADDR',
|
||||
"HTTP_X_FORWARDED_FOR",
|
||||
"HTTP_X_REAL_IP",
|
||||
"REMOTE_ADDR",
|
||||
)
|
||||
for _header in headers:
|
||||
if _header in meta:
|
||||
|
||||
@ -4,15 +4,15 @@ from importlib import import_module
|
||||
|
||||
def class_to_path(cls):
|
||||
"""Turn Class (Class or instance) into module path"""
|
||||
return '%s.%s' % (cls.__module__, cls.__name__)
|
||||
return "%s.%s" % (cls.__module__, cls.__name__)
|
||||
|
||||
|
||||
def path_to_class(path):
|
||||
"""Import module and return class"""
|
||||
if not path:
|
||||
return None
|
||||
parts = path.split('.')
|
||||
package = '.'.join(parts[:-1])
|
||||
parts = path.split(".")
|
||||
package = ".".join(parts[:-1])
|
||||
_class = getattr(import_module(package), parts[-1])
|
||||
return _class
|
||||
|
||||
@ -20,11 +20,14 @@ def path_to_class(path):
|
||||
def get_apps():
|
||||
"""Get list of all passbook apps"""
|
||||
from django.apps.registry import apps
|
||||
|
||||
for _app in apps.get_app_configs():
|
||||
if _app.name.startswith('passbook'):
|
||||
if _app.name.startswith("passbook"):
|
||||
yield _app
|
||||
|
||||
|
||||
def app(name):
|
||||
"""Return true if app with `name` is enabled"""
|
||||
from django.conf import settings
|
||||
|
||||
return name in settings.INSTALLED_APPS
|
||||
|
||||
@ -1,7 +1,8 @@
|
||||
"""passbook UI utils"""
|
||||
|
||||
|
||||
def human_list(_list) -> str:
|
||||
"""Convert a list of items into 'a, b or c'"""
|
||||
last_item = _list.pop()
|
||||
result = ', '.join(_list)
|
||||
return '%s or %s' % (result, last_item)
|
||||
result = ", ".join(_list)
|
||||
return "%s or %s" % (result, last_item)
|
||||
|
||||
@ -8,16 +8,18 @@ class CreateAssignPermView(CreateView):
|
||||
"""Assign permissions to object after creation"""
|
||||
|
||||
permissions = [
|
||||
'%s.view_%s',
|
||||
'%s.change_%s',
|
||||
'%s.delete_%s',
|
||||
"%s.view_%s",
|
||||
"%s.change_%s",
|
||||
"%s.delete_%s",
|
||||
]
|
||||
|
||||
def form_valid(self, form):
|
||||
response = super().form_valid(form)
|
||||
for permission in self.permissions:
|
||||
full_permission = permission % (
|
||||
self.object._meta.app_label, self.object._meta.model_name)
|
||||
self.object._meta.app_label,
|
||||
self.object._meta.model_name,
|
||||
)
|
||||
print(full_permission)
|
||||
assign_perm(full_permission, self.request.user, self.object)
|
||||
return response
|
||||
|
||||
Reference in New Issue
Block a user