calendar-social/calsocial/utils.py

165 lines
4.6 KiB
Python
Raw Normal View History

# Calendar.social
# Copyright (C) 2018 Gergely Polonkai
#
# 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 <https://www.gnu.org/licenses/>.
"""Utility functions for Calendar.social
"""
from contextlib import contextmanager
2018-07-23 10:20:39 +00:00
from functools import wraps
from flask import flash, redirect, url_for
from flask_babelex import gettext as _
from flask_security import current_user
@contextmanager
def force_locale(locale):
"""Temporarily overrides the currently selected locale.
Sometimes it is useful to switch the current locale to different one, do some tasks and then
revert back to the original one. For example, if the user uses German on the web site, but
you want to send them an email in English, you can use this function as a context manager::
with force_locale('en_US'):
send_email(gettext('Hello!'), ...)
Shamelessly extracted from Flask-Babel.
:param locale: The locale to temporary switch to (ex: 'en_US').
:type locale: str
"""
from flask import current_app, has_request_context, request
def _get_current_context():
if has_request_context():
return request
if current_app:
return current_app
return None
ctx = _get_current_context()
if ctx is None:
yield
return
babel = current_app.extensions['babel']
orig_locale_selector_func = babel.locale_selector_func
orig_attrs = {}
for key in ('babel_translations', 'babel_locale'):
orig_attrs[key] = getattr(ctx, key, None)
try:
babel.locale_selector_func = lambda: locale
for key in orig_attrs:
setattr(ctx, key, None)
yield
finally:
babel.locale_selector_func = orig_locale_selector_func
for key, value in orig_attrs.items():
setattr(ctx, key, value)
class RoutedMixin:
"""Mixin to lazily register class methods as routes
Works both for `Flask` and `Blueprint` objects.
Example::
class MyBlueprint(Blueprint, RoutedMixin):
def __init__(self, *args, **kwargs):
do_whatever_you_like()
RoutedMixin.register_routes(self)
@RoutedMixin.route('/')
def index(self):
return 'Hello, World!'
"""
def register_routes(self):
2018-07-23 10:20:12 +00:00
"""Register all routes that were marked with :meth:`route`
"""
for attr_name in self.__dir__():
attr = getattr(self, attr_name)
if not callable(attr):
continue
args, kwargs = getattr(attr, 'routing', (None, None))
if args is None:
continue
self.route(*args, **kwargs)(attr)
@staticmethod
def route(*args, **kwargs):
"""Mark a function as a future route
Such functions will be iterated over when the application is initialised. ``*args`` and
``**kwargs`` will be passed verbatim to `Flask.route()`.
"""
def decorator(func): # pylint: disable=missing-docstring
setattr(func, 'routing', (args, kwargs))
return func
return decorator
2018-07-23 10:20:39 +00:00
def beta(func):
"""Decorator to hide beta features from non-beta testers
"""
@wraps(func)
def decorated(*args, **kwargs): # pylint: disable=missing-docstring
if current_user.settings['beta'] != 'True':
flash(_('Join the beta testers to enable this functionality!'))
return redirect(url_for('account.settings'))
return func(*args, **kwargs)
return decorated
2018-07-23 10:35:46 +00:00
def feature_lock(feature): # pylint: disable=missing-return-doc,missing-return-type-doc
"""Decorator to lock a feature
:param feature: the name of a feature
:type feature: str
"""
def decorator(func): # pylint: disable=missing-docstring
@wraps(func)
def decorated(*args, **kwargs): # pylint: disable=missing-docstring
from calsocial.models import AppState
if AppState[f'feature:{feature}'] == 'true':
return func(*args, **kwargs)
return 'Feature locked'
return decorated
return decorator