add lib
This commit is contained in:
		
							
								
								
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @ -182,7 +182,6 @@ dmypy.json | ||||
| # http://iamzed.com/2009/05/07/a-primer-on-virtualenv/ | ||||
| [Bb]in | ||||
| [Ii]nclude | ||||
| [Ll]ib | ||||
| [Ll]ib64 | ||||
| [Ll]ocal | ||||
| [Ss]cripts | ||||
|  | ||||
							
								
								
									
										2
									
								
								passbook/lib/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								passbook/lib/__init__.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,2 @@ | ||||
| """passbook lib""" | ||||
| default_app_config = 'passbook.lib.apps.PassbookLibConfig' | ||||
							
								
								
									
										22
									
								
								passbook/lib/admin.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								passbook/lib/admin.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,22 @@ | ||||
| """passbook core admin""" | ||||
|  | ||||
| from django.apps import apps | ||||
| from django.contrib import admin | ||||
| from django.contrib.admin.sites import AlreadyRegistered | ||||
| from django.contrib.auth.admin import UserAdmin | ||||
|  | ||||
| from passbook.core.models import User | ||||
|  | ||||
|  | ||||
| def admin_autoregister(app): | ||||
|     """Automatically register all models from app""" | ||||
|     app_models = apps.get_app_config(app).get_models() | ||||
|     for model in app_models: | ||||
|         try: | ||||
|             admin.site.register(model) | ||||
|         except AlreadyRegistered: | ||||
|             pass | ||||
|  | ||||
|  | ||||
| admin.site.register(User, UserAdmin) | ||||
| admin_autoregister('passbook_core') | ||||
							
								
								
									
										9
									
								
								passbook/lib/apps.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								passbook/lib/apps.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,9 @@ | ||||
| """passbook lib app config""" | ||||
| from django.apps import AppConfig | ||||
|  | ||||
|  | ||||
| class PassbookLibConfig(AppConfig): | ||||
|     """passbook lib app config""" | ||||
|  | ||||
|     name = 'passbook.lib' | ||||
|     label = 'passbook_lib' | ||||
							
								
								
									
										128
									
								
								passbook/lib/config.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										128
									
								
								passbook/lib/config.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,128 @@ | ||||
| """supervisr core config loader""" | ||||
| import os | ||||
| from collections import Mapping | ||||
| from contextlib import contextmanager | ||||
| from glob import glob | ||||
| from logging import getLogger | ||||
| from typing import Any | ||||
|  | ||||
| import yaml | ||||
| from django.conf import ImproperlyConfigured | ||||
|  | ||||
| SEARCH_PATHS = [ | ||||
|     'passbook/lib/default.yml', | ||||
|     '/etc/passbook/config.yml', | ||||
|     '.', | ||||
| ] + glob('/etc/passbook/config.d/*.yml', recursive=True) | ||||
| LOGGER = getLogger(__name__) | ||||
| ENVIRONMENT = os.getenv('PASSBOOK_ENV', 'local') | ||||
|  | ||||
|  | ||||
| class ConfigLoader: | ||||
|     """Search through SEARCH_PATHS and load configuration""" | ||||
|  | ||||
|     __config = {} | ||||
|     __context_default = None | ||||
|     __sub_dicts = [] | ||||
|  | ||||
|     def __init__(self): | ||||
|         super().__init__() | ||||
|         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): | ||||
|                 path = os.path.join(base_dir, path) | ||||
|             if os.path.isfile(path) and os.path.exists(path): | ||||
|                 # Path is an existing file, so we just read it and update our config with it | ||||
|                 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')] | ||||
|                 for env_file in env_paths: | ||||
|                     if os.path.isfile(env_file) and os.path.exists(env_file): | ||||
|                         # Update config with env file | ||||
|                         self.update_from_file(env_file) | ||||
|         self.handle_secret_key() | ||||
|  | ||||
|     def handle_secret_key(self): | ||||
|         """Handle `secret_key_file`""" | ||||
|         if 'secret_key_file' in self.__config: | ||||
|             secret_key_file = self.__config.get('secret_key_file') | ||||
|             if os.path.isfile(secret_key_file) and os.path.exists(secret_key_file): | ||||
|                 with open(secret_key_file) as file: | ||||
|                     self.__config['secret_key'] = file.read().replace('\n', '') | ||||
|  | ||||
|     def update(self, root, updatee): | ||||
|         """Recursively update dictionary""" | ||||
|         for key, value in updatee.items(): | ||||
|             if isinstance(value, Mapping): | ||||
|                 root[key] = self.update(root.get(key, {}), value) | ||||
|             else: | ||||
|                 root[key] = value | ||||
|         return root | ||||
|  | ||||
|     def update_from_file(self, path: str): | ||||
|         """Update config from file contents""" | ||||
|         try: | ||||
|             with open(path) as file: | ||||
|                 try: | ||||
|                     self.update(self.__config, yaml.safe_load(file)) | ||||
|                 except yaml.YAMLError as exc: | ||||
|                     raise ImproperlyConfigured from exc | ||||
|         except PermissionError as exc: | ||||
|             LOGGER.warning('Permission denied while reading %s', path) | ||||
|  | ||||
|     def update_from_dict(self, update: dict): | ||||
|         """Update config from dict""" | ||||
|         self.__config.update(update) | ||||
|  | ||||
|     @contextmanager | ||||
|     def default(self, value: Any): | ||||
|         """Contextmanage that sets default""" | ||||
|         self.__context_default = value | ||||
|         yield | ||||
|         self.__context_default = None | ||||
|  | ||||
|     @contextmanager | ||||
|     # pylint: disable=invalid-name | ||||
|     def cd(self, sub: str): | ||||
|         """Contextmanager that descends into sub-dict. Can be chained.""" | ||||
|         self.__sub_dicts.append(sub) | ||||
|         yield | ||||
|         self.__sub_dicts.pop() | ||||
|  | ||||
|     def get(self, key: str, default=None) -> Any: | ||||
|         """Get value from loaded config file""" | ||||
|         if default is None: | ||||
|             default = self.__context_default | ||||
|         config_copy = self.raw | ||||
|         for sub in self.__sub_dicts: | ||||
|             config_copy = config_copy.get(sub, None) | ||||
|         return config_copy.get(key, default) | ||||
|  | ||||
|     @property | ||||
|     def raw(self) -> dict: | ||||
|         """Get raw config dictionary""" | ||||
|         return self.__config | ||||
|  | ||||
|     # pylint: disable=invalid-name | ||||
|     def y(self, path: str, default=None, sep='.') -> Any: | ||||
|         """Access attribute by using yaml path""" | ||||
|         if default is None: | ||||
|             default = self.__context_default | ||||
|         # Walk sub_dicts before parsing path | ||||
|         root = self.raw | ||||
|         for sub in self.__sub_dicts: | ||||
|             root = root.get(sub, None) | ||||
|         # Walk each component of the path | ||||
|         for comp in path.split(sep): | ||||
|             if comp in root: | ||||
|                 root = root.get(comp) | ||||
|             else: | ||||
|                 return default | ||||
|         return root | ||||
|  | ||||
|  | ||||
| CONFIG = ConfigLoader() | ||||
							
								
								
									
										0
									
								
								passbook/lib/decorators.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								passbook/lib/decorators.py
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										97
									
								
								passbook/lib/default.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										97
									
								
								passbook/lib/default.yml
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,97 @@ | ||||
| # This is the default configuration file | ||||
| databases: | ||||
|   default: | ||||
|     engine: 'django.db.backends.sqlite3' | ||||
|     name: 'db.sqlite3' | ||||
| log: | ||||
|   level: | ||||
|     console: DEBUG | ||||
|     file: DEBUG | ||||
|   file: /dev/null | ||||
|   syslog: | ||||
|     host: 127.0.0.1 | ||||
|     port: 514 | ||||
| email: | ||||
|   host: localhost | ||||
|   port: 25 | ||||
|   user: '' | ||||
|   password: '' | ||||
|   use_tls: false | ||||
|   use_ssl: false | ||||
|   from: passbook <passbook@domain.tld> | ||||
| web: | ||||
|   listen: 0.0.0.0 | ||||
|   port: 8000 | ||||
|   threads: 30 | ||||
| debug: true | ||||
| secure_proxy_header: | ||||
|   HTTP_X_FORWARDED_PROTO: https | ||||
| redis: localhost | ||||
| # Error reporting, sends stacktrace to sentry.services.beryju.org | ||||
| error_report_enabled: true | ||||
|  | ||||
| passbook: | ||||
|   sign_up: | ||||
|     # Enables signup, created users are stored in internal Database and created in LDAP if ldap.create_users is true | ||||
|     enabled: true | ||||
|   password_reset: | ||||
|     # Enable password reset, passwords are reset in internal Database and in LDAP if ldap.reset_password is true | ||||
|     enabled: true | ||||
|     # Verification the user has to provide in order to be able to reset passwords. Can be any combination of `email`, `2fa`, `security_questions` | ||||
|     verification: | ||||
|       - email | ||||
|   # Text used in title, on login page and multiple other places | ||||
|   branding: passbook | ||||
|   login: | ||||
|     # Override URL used for logo | ||||
|     logo_url: null | ||||
|     # Override URL used for Background on Login page | ||||
|     bg_url: null | ||||
|     # Optionally add a subtext, placed below logo on the login page | ||||
|     subtext: This is placeholder text, only. Use this area to place any information or introductory message about your application that may be relevant for users. | ||||
|   footer: | ||||
|     links: | ||||
|       # Optionally add links to the footer on the login page | ||||
|       #  - name: test | ||||
|       #    href: https://test | ||||
|   # Specify which fields can be used to authenticate. Can be any combination of `username` and `email` | ||||
|   uid_fields: | ||||
|     - username | ||||
|   session: | ||||
|     remember_age: 2592000 # 60 * 60 * 24 * 30, one month | ||||
| # Provider-specific settings | ||||
| ldap: | ||||
|   # Completely enable or disable LDAP provider | ||||
|   enabled: false | ||||
|   # AD Domain, used to generate `userPrincipalName` | ||||
|   domain: corp.contoso.com | ||||
|   # Base DN in which passbook should look for users | ||||
|   base_dn: dn=corp,dn=contoso,dn=com | ||||
|   # LDAP field which is used to set the django username | ||||
|   username_field: sAMAccountName | ||||
|   # LDAP server to connect to, can be set to `<domain_name>` | ||||
|   server: | ||||
|     name: corp.contoso.com | ||||
|     use_tls: false | ||||
|   # Bind credentials, used for account creation | ||||
|   bind: | ||||
|     username: Administraotr@corp.contoso.com | ||||
|     password: VerySecurePassword! | ||||
|   # Which field from `uid_fields` maps to which LDAP Attribute | ||||
|   login_field_map: | ||||
|     username: sAMAccountName | ||||
|     email: mail # or userPrincipalName | ||||
|   # Create new users in LDAP upon sign-up | ||||
|   create_users: true | ||||
|   # Reset LDAP password when user reset their password | ||||
|   reset_password: true | ||||
| oauth_client: | ||||
|   # List of python packages with sources types to load. | ||||
|   source_tyoes: | ||||
|     - passbook.oauth_client.source_types.discord | ||||
|     - passbook.oauth_client.source_types.facebook | ||||
|     - passbook.oauth_client.source_types.github | ||||
|     - passbook.oauth_client.source_types.google | ||||
|     - passbook.oauth_client.source_types.reddit | ||||
|     - passbook.oauth_client.source_types.supervisr | ||||
|     - passbook.oauth_client.source_types.twitter | ||||
							
								
								
									
										0
									
								
								passbook/lib/fields.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								passbook/lib/fields.py
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										22
									
								
								passbook/lib/models.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								passbook/lib/models.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,22 @@ | ||||
| """Generic models""" | ||||
| from uuid import uuid4 | ||||
|  | ||||
| from django.db import models | ||||
|  | ||||
|  | ||||
| class CreatedUpdatedModel(models.Model): | ||||
|     """Base Abstract Model to save created and update""" | ||||
|     created = models.DateField(auto_now_add=True) | ||||
|     last_updated = models.DateTimeField(auto_now=True) | ||||
|  | ||||
|     class Meta: | ||||
|         abstract = True | ||||
|  | ||||
|  | ||||
| class UUIDModel(models.Model): | ||||
|     """Abstract base model which uses a UUID as primary key""" | ||||
|  | ||||
|     uuid = models.UUIDField(primary_key=True, editable=False, default=uuid4) | ||||
|  | ||||
|     class Meta: | ||||
|         abstract = True | ||||
							
								
								
									
										56
									
								
								passbook/lib/templatetags/is_active.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										56
									
								
								passbook/lib/templatetags/is_active.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,56 @@ | ||||
| """passbook lib navbar Templatetag""" | ||||
| from logging import getLogger | ||||
|  | ||||
| from django import template | ||||
| from django.urls import reverse | ||||
|  | ||||
| register = template.Library() | ||||
|  | ||||
| LOGGER = getLogger(__name__) | ||||
|  | ||||
|  | ||||
| @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) | ||||
|     if not request.resolver_match: | ||||
|         return '' | ||||
|     for url in args: | ||||
|         short_url = url.split(':')[1] if ':' in url else url | ||||
|         # Check if resolve_match matches | ||||
|         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' | ||||
|             if app_name is None: | ||||
|                 return 'active' | ||||
|     return '' | ||||
|  | ||||
|  | ||||
| @register.simple_tag(takes_context=True) | ||||
| def is_active_url(context, view, *args, **kwargs): | ||||
|     """Return whether a navbar link is active or not.""" | ||||
|  | ||||
|     matching_url = reverse(view, args=args, kwargs=kwargs) | ||||
|     request = context.get('request') | ||||
|     if not request.resolver_match: | ||||
|         return '' | ||||
|     if matching_url == request.path: | ||||
|         return 'active' | ||||
|     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') | ||||
|     if not request.resolver_match: | ||||
|         return '' | ||||
|     for app_name in args: | ||||
|         if request.resolver_match.app_name == app_name: | ||||
|             return 'active' | ||||
|     return '' | ||||
							
								
								
									
										93
									
								
								passbook/lib/templatetags/reflection.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										93
									
								
								passbook/lib/templatetags/reflection.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,93 @@ | ||||
| """Supervisr Core Reflection templatetags Templatetag""" | ||||
| from logging import getLogger | ||||
|  | ||||
| from django import template | ||||
| from django.apps import AppConfig | ||||
| from django.core.cache import cache | ||||
| from django.urls import reverse | ||||
| from django.urls.exceptions import NoReverseMatch | ||||
|  | ||||
| register = template.Library() | ||||
| LOGGER = getLogger(__name__) | ||||
|  | ||||
|  | ||||
| def get_key_unique(context): | ||||
|     """Get a unique key for cache based on user""" | ||||
|     uniq = '' | ||||
|     if 'request' in context: | ||||
|         user = context.get('request').user | ||||
|         if user.is_authenticated: | ||||
|             uniq = context.get('request').user.email | ||||
|         else: | ||||
|             # This should never be reached as modlist requires admin rights | ||||
|             uniq = 'anon'  # pragma: no cover | ||||
|     return uniq | ||||
|  | ||||
| # @register.simple_tag(takes_context=True) | ||||
| # def sv_reflection_admin_modules(context): | ||||
| #     """Get a list of all modules and their admin page""" | ||||
| #     key = 'sv_reflection_admin_modules_%s' % get_key_unique(context) | ||||
| #     if not cache.get(key): | ||||
| #         view_list = [] | ||||
| #         for app in get_apps(): | ||||
| #             title = app.title_modifier(context.request) | ||||
| #             url = app.admin_url_name | ||||
| #             view_list.append({ | ||||
| #                 'url': url, | ||||
| #                 'default': True if url == SupervisrAppConfig.admin_url_name else False, | ||||
| #                 'name': title, | ||||
| #             }) | ||||
| #         sorted_list = sorted(view_list, key=lambda x: x.get('name')) | ||||
| #         cache.set(key, sorted_list, 1000) | ||||
| #         return sorted_list | ||||
| #     return cache.get(key)  # pragma: no cover | ||||
|  | ||||
|  | ||||
| # @register.simple_tag(takes_context=True) | ||||
| # def sv_reflection_user_modules(context): | ||||
| #     """Get a list of modules that have custom user settings""" | ||||
| #     key = 'sv_reflection_user_modules_%s' % get_key_unique(context) | ||||
| #     if not cache.get(key): | ||||
| #         app_list = [] | ||||
| #         for app in get_apps(): | ||||
| #             if not app.name.startswith('supervisr.mod'): | ||||
| #                 continue | ||||
| #             view = app.view_user_settings | ||||
| #             if view is not None: | ||||
| #                 app_list.append({ | ||||
| #                     'title': app.title_modifier(context.request), | ||||
| #                     'view': '%s:%s' % (app.label, view) | ||||
| #                 }) | ||||
| #         sorted_list = sorted(app_list, key=lambda x: x.get('title')) | ||||
| #         cache.set(key, sorted_list, 1000) | ||||
| #         return sorted_list | ||||
| #     return cache.get(key)  # pragma: no cover | ||||
|  | ||||
|  | ||||
| # @register.simple_tag(takes_context=True) | ||||
| # def sv_reflection_navbar_modules(context): | ||||
| #     """Get a list of subapps for the navbar""" | ||||
| #     key = 'sv_reflection_navbar_modules_%s' % get_key_unique(context) | ||||
| #     if not cache.get(key): | ||||
| #         app_list = [] | ||||
| #         for app in get_apps(): | ||||
| #             LOGGER.debug("Considering %s for Navbar", app.label) | ||||
| #             title = app.title_modifier(context.request) | ||||
| #             if app.navbar_enabled(context.request): | ||||
| #                 index = getattr(app, 'index', None) | ||||
| #                 if not index: | ||||
| #                     index = '%s:index' % app.label | ||||
| #                 try: | ||||
| #                     reverse(index) | ||||
| #                     LOGGER.debug("Module %s made it with '%s'", app.name, index) | ||||
| #                     app_list.append({ | ||||
| #                         'label': app.label, | ||||
| #                         'title': title, | ||||
| #                         'index': index | ||||
| #                     }) | ||||
| #                 except NoReverseMatch: | ||||
| #                     LOGGER.debug("View '%s' not reversable, ignoring %s", index, app.name) | ||||
| #         sorted_list = sorted(app_list, key=lambda x: x.get('label')) | ||||
| #         cache.set(key, sorted_list, 1000) | ||||
| #         return sorted_list | ||||
| #     return cache.get(key)  # pragma: no cover | ||||
							
								
								
									
										158
									
								
								passbook/lib/templatetags/utils.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										158
									
								
								passbook/lib/templatetags/utils.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,158 @@ | ||||
| """passbook lib Templatetags""" | ||||
| import glob | ||||
| import os | ||||
| import socket | ||||
| from urllib.parse import urljoin | ||||
|  | ||||
| from django import template | ||||
| from django.apps import apps | ||||
| from django.conf import settings | ||||
| from django.db.models import Model | ||||
| from django.template.loaders.app_directories import get_app_template_dirs | ||||
| from django.urls import reverse | ||||
| from django.utils.translation import ugettext as _ | ||||
|  | ||||
| from passbook.lib.utils.reflection import path_to_class | ||||
| from passbook.lib.utils.urls import is_url_absolute | ||||
|  | ||||
| register = template.Library() | ||||
|  | ||||
|  | ||||
| @register.simple_tag(takes_context=True) | ||||
| 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') | ||||
|  | ||||
|     if not is_url_absolute(url): | ||||
|         return url | ||||
|     return '' | ||||
|  | ||||
|  | ||||
| @register.filter('fieldtype') | ||||
| def fieldtype(field): | ||||
|     """Return classname""" | ||||
|     # if issubclass(field.__class__, CastableModel): | ||||
|     #     field = field.cast() | ||||
|     if isinstance(field.__class__, Model) or issubclass(field.__class__, Model): | ||||
|         return field._meta.verbose_name | ||||
|     return field.__class__.__name__ | ||||
|  | ||||
|  | ||||
| @register.simple_tag | ||||
| def setting(key, default=''): | ||||
|     """Returns a setting from the settings.py file. If Key is blocked, return default""" | ||||
|     return getattr(settings, key, default) | ||||
|  | ||||
|  | ||||
| @register.simple_tag | ||||
| def hostname(): | ||||
|     """Return the current Host's short hostname""" | ||||
|     return socket.gethostname() | ||||
|  | ||||
|  | ||||
| @register.simple_tag | ||||
| def fqdn(): | ||||
|     """Return the current Host's FQDN.""" | ||||
|     return socket.getfqdn() | ||||
|  | ||||
|  | ||||
| @register.filter('pick') | ||||
| def pick(cont, arg, fallback=''): | ||||
|     """Iterate through arg and return first choice which is not None""" | ||||
|     choices = arg.split(',') | ||||
|     for choice in choices: | ||||
|         if choice in cont and cont[choice] is not None: | ||||
|             return cont[choice] | ||||
|     return fallback | ||||
|  | ||||
|  | ||||
| @register.simple_tag(takes_context=True) | ||||
| def title(context, *title): | ||||
|     """Return either just branding or title - branding""" | ||||
|     branding = Setting.get('branding', default='supervisr') | ||||
|     if not title: | ||||
|         return branding | ||||
|     # Include App Title in title | ||||
|     app = '' | ||||
|     if context.request.resolver_match and context.request.resolver_match.namespace != '': | ||||
|         dj_app = None | ||||
|         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) | ||||
|         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, | ||||
|     }) | ||||
|  | ||||
|  | ||||
| @register.simple_tag | ||||
| def supervisr_setting(key, namespace='supervisr.core', default=''): | ||||
|     """Get a setting from the database. Returns default is setting doesn't exist.""" | ||||
|     return Setting.get(key=key, namespace=namespace, default=default) | ||||
|  | ||||
|  | ||||
| @register.simple_tag() | ||||
| def media(*args): | ||||
|     """Iterate through arg and return full media URL""" | ||||
|     urls = [] | ||||
|     for arg in args: | ||||
|         urls.append(urljoin(settings.MEDIA_URL, str(arg))) | ||||
|     if len(urls) == 1: | ||||
|         return urls[0] | ||||
|     return urls | ||||
|  | ||||
|  | ||||
| @register.simple_tag | ||||
| def url_unpack(view, kwargs): | ||||
|     """Reverses a URL with kwargs which are stored in a dict""" | ||||
|     return reverse(view, kwargs=kwargs) | ||||
|  | ||||
|  | ||||
| @register.simple_tag | ||||
| def template_wildcard(*args): | ||||
|     """Return a list of all templates in dir""" | ||||
|     templates = [] | ||||
|     for tmpl_dir in args: | ||||
|         for app_templates in get_app_template_dirs('templates'): | ||||
|             path = os.path.join(app_templates, tmpl_dir) | ||||
|             if os.path.isdir(path): | ||||
|                 files = sorted(glob.glob(path + '*.html')) | ||||
|                 for file in files: | ||||
|                     templates.append(os.path.relpath(file, start=app_templates)) | ||||
|     return templates | ||||
|  | ||||
|  | ||||
| @register.simple_tag(takes_context=True) | ||||
| def related_models(context, model_path): | ||||
|     """Return list of models which have a Relationship to current user""" | ||||
|  | ||||
|     request = context.get('request', None) | ||||
|     if not request: | ||||
|         # No Request -> no user -> return empty | ||||
|         return [] | ||||
|     user = request.user | ||||
|  | ||||
|     model = path_to_class(model_path) | ||||
|     if not issubclass(model, UserAcquirable): | ||||
|         # model_path is not actually a module | ||||
|         # so we can't assume that it's usable | ||||
|         return [] | ||||
|  | ||||
|     return model.objects.filter(users__in=[user]) | ||||
|  | ||||
|  | ||||
| @register.filter('unslug') | ||||
| def unslug(_input): | ||||
|     """Convert slugs back into normal strings""" | ||||
|     return _input.replace('-', ' ').replace('_', ' ') | ||||
							
								
								
									
										0
									
								
								passbook/lib/utils/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								passbook/lib/utils/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										17
									
								
								passbook/lib/utils/reflection.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								passbook/lib/utils/reflection.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,17 @@ | ||||
| """passbook lib reflection utilities""" | ||||
| 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__) | ||||
|  | ||||
|  | ||||
| def path_to_class(path): | ||||
|     """Import module and return class""" | ||||
|     if not path: | ||||
|         return None | ||||
|     parts = path.split('.') | ||||
|     package = '.'.join(parts[:-1]) | ||||
|     _class = getattr(import_module(package), parts[-1]) | ||||
|     return _class | ||||
							
								
								
									
										7
									
								
								passbook/lib/utils/urls.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								passbook/lib/utils/urls.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,7 @@ | ||||
| """URL-related utils""" | ||||
| from urllib.parse import urlparse | ||||
|  | ||||
|  | ||||
| def is_url_absolute(url): | ||||
|     """Check if domain is absolute to prevent user from being redirect somewhere else""" | ||||
|     return bool(urlparse(url).netloc) | ||||
		Reference in New Issue
	
	Block a user
	 Jens Langhammer
					Jens Langhammer