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/ | # http://iamzed.com/2009/05/07/a-primer-on-virtualenv/ | ||||||
| [Bb]in | [Bb]in | ||||||
| [Ii]nclude | [Ii]nclude | ||||||
| [Ll]ib |  | ||||||
| [Ll]ib64 | [Ll]ib64 | ||||||
| [Ll]ocal | [Ll]ocal | ||||||
| [Ss]cripts | [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