from __future__ import unicode_literals from binascii import Error as BinaryError from base64 import b16encode, b16decode from django.apps import apps from django.core.exceptions import FieldDoesNotExist from django.http import Http404 from django.shortcuts import get_object_or_404 from .exceptions import B16DecodingFail def spammables(): # Lists all models that are marked flaggable flaggables = [] for model in apps.get_models(): try: model._meta.get_field_by_name('spam_flag') except FieldDoesNotExist: continue flaggables.append(model) return flaggables def is_spammable(app, model): model_class = apps.get_model("{}.{}".format(app, model)) return model_class in spammables() def get_app_name(model_class_or_instance): return model_class_or_instance._meta.app_config.name.split('.')[-1] def b16_slug_to_arguments(b16_slug): """ Raises B16DecodingFail exception on """ try: url = b16decode(b16_slug.decode('utf-8')) except BinaryError: raise B16DecodingFail except TypeError: raise B16DecodingFail('Non-base16 digit found') except AttributeError: raise B16DecodingFail("b16_slug must have a 'decode' method.") try: app, model, pk = url.decode('utf-8').split('/')[0:3] except UnicodeDecodeError: raise B16DecodingFail("Invalid b16_slug passed") return app, model, pk def get_spammable_or_404(app, model, pk): # Does this view have the is_spammable mixin? if is_spammable(app, model): # convert app/model into the actual model class model_class = apps.get_model(app, model) # So we can call meta for details in the template model_class.meta = model_class._meta instance = get_object_or_404(model_class, pk=pk) return model_class, instance raise Http404