Example #1
0
class ListModelMixin(object):
    """
    Turns the django-rest-framework mixin into an etag-aware one.
    """
    empty_error = "Empty list and '%(class_name)s.allow_empty' is False."

    @method_decorator(etag(etag_func))
    def list_response(self, request, data):
        # Switch between paginated or standard style responses
        page = self.paginate_queryset(self.object_list)
        if page is not None:
            serializer = self.get_pagination_serializer(page)
        else:
            serializer = self.get_serializer(self.object_list, many=True)

        return Response(serializer.data)

    def list(self, request, *args, **kwargs):
        self.object_list = self.filter_queryset(self.get_queryset())

        # Default is to allow empty querysets.  This can be altered by setting
        # `.allow_empty = False`, to raise 404 errors on empty querysets.
        if not self.allow_empty and not self.object_list:
            warnings.warn(
                'The `allow_empty` parameter is due to be deprecated. '
                'To use `allow_empty=False` style behavior, You should override '
                '`get_queryset()` and explicitly raise a 404 on empty querysets.',
                PendingDeprecationWarning)
            class_name = self.__class__.__name__
            error_msg = self.empty_error % {'class_name': class_name}
            raise Http404(error_msg)

        return self.list_response(request, self.object_list)
Example #2
0
    def as_view(cls, **initkwargs):
        def normalize_key_prefix(key_prefix):
            def _key_prefix(request, *args, **kwargs):
                return str(
                    key_prefix(request, *args, **kwargs)
                ).replace(' ', '_')
            return _key_prefix

        patched_view = view = super().as_view(**initkwargs)

        patched_view = http.etag(cls.etag)(patched_view)
        patched_view = http.last_modified(cls.last_modified)(patched_view)
        patched_view = cache_page(
            cache_timeout=cls._expires,
            key_prefix=normalize_key_prefix(cls.last_modified),
        )(patched_view)

        view = decorators.replace_if(
            lambda request, *args, **kwargs: request.method in ('GET', 'HEAD'),
            replacement=patched_view,
        )(view)

        @functools.wraps(cls.as_view)
        def logging_view(request, *args, **kwargs):

            request_logger.debug(
                'request_method: %(request_method)s, '
                'request_path: %(request_path)s, '
                'request_headers: %(request_headers)s, '
                'request_params: %(request_params)s, '
                'request_data: %(request_data)s, ',
                dict(
                    request_method=request.method,
                    request_path=request.path,
                    request_headers=request.META,
                    request_params=request.GET,
                    request_data=request.POST,
                ),
            )

            response = view(request, *args, **kwargs)

            response_logger.debug(
                'response_code: %(response_code)s, '
                'response_headers: %(response_headers)s, '
                'response_data: %(response_data)s',
                dict(
                    response_code=response.status_code,
                    response_headers=response.items(),
                    response_data=response.content,
                ),
            )

            return response

        return logging_view
Example #3
0
    def as_view(cls, **initkwargs):
        def normalize_key_prefix(key_prefix):
            def _key_prefix(request, *args, **kwargs):
                return str(
                    key_prefix(request, *args, **kwargs)
                ).replace(' ', '_')
            return _key_prefix

        patched_view = view = super().as_view(**initkwargs)

        patched_view = http.etag(cls.etag)(patched_view)
        patched_view = http.last_modified(cls.last_modified)(patched_view)
        patched_view = cache_page(
            cache_timeout=cls._expires,
            key_prefix=normalize_key_prefix(cls.last_modified),
        )(patched_view)

        view = decorators.replace_if(
            lambda request, *args, **kwargs: request.method in ('GET', 'HEAD'),
            replacement=patched_view,
        )(view)

        @functools.wraps(cls.as_view)
        def logging_view(request, *args, **kwargs):

            request_logger.debug(
                'request_method: %(request_method)s, '
                'request_path: %(request_path)s, '
                'request_headers: %(request_headers)s, '
                'request_params: %(request_params)s, '
                'request_data: %(request_data)s, ',
                dict(
                    request_method=request.method,
                    request_path=request.path,
                    request_headers=request.META,
                    request_params=request.GET,
                    request_data=request.POST,
                ),
            )

            response = view(request, *args, **kwargs)

            response_logger.debug(
                'response_code: %(response_code)s, '
                'response_headers: %(response_headers)s, '
                'response_data: %(response_data)s',
                dict(
                    response_code=response.status_code,
                    response_headers=response.items(),
                    response_data=response.content,
                ),
            )

            return response

        return logging_view
Example #4
0
class RetrieveModelMixin(object):
    """
    Turns the django-rest-framework mixin into an etag-aware one.
    """
    @method_decorator(etag(etag_func))
    def retrieve_response(self, request, data):
        return Response(data)

    def retrieve(self, request, *args, **kwargs):
        self.object = self.get_object()
        serializer = self.get_serializer(self.object)
        return self.retrieve_response(request, serializer.data)
Example #5
0
def tag_cached(func, tag, *args):
    def tag_func(*args):
        return tag

    def check_cache(*args):
        response = cache.get(tag)
        if response:
            return response

        response = func(*args)
        if response.status_code == 200:
            cache.set(tag, response, 86400)
        return response

    decorator = etag(tag_func)
    view_func = decorator(check_cache)
    return view_func(*args)
Example #6
0
def tag_cached(func, tag, *args):
    def tag_func(*args):
        return tag

    def check_cache(*args):
        response = cache.get(tag)
        if response:
            return response

        response = func(*args)
        if response.status_code == 200:
            cache.set(tag, response, 86400)
        return response

    decorator = etag(tag_func)
    view_func = decorator(check_cache)
    return view_func(*args)
Example #7
0
class ZipContentView(View):
    @xframe_options_exempt
    @add_security_headers
    def options(self, request, *args, **kwargs):
        """
        Handles OPTIONS requests which may be sent as "preflight CORS" requests to check permissions.
        """
        return HttpResponse()

    @method_decorator(etag(calculate_zip_content_etag))
    @cache_forever
    @xframe_options_exempt
    @add_security_headers
    def get(self, request, zipped_filename, embedded_filepath):
        """
        Handles GET requests and serves a static file from within the zip file.
        """
        zipped_path = get_path_or_404(zipped_filename)

        # if client has a cached version, use that (we can safely assume nothing has changed, due to MD5)
        if request.META.get("HTTP_IF_MODIFIED_SINCE"):
            return HttpResponseNotModified()

        with zipfile.ZipFile(zipped_path) as zf:

            # handle H5P files
            if zipped_path.endswith("h5p"):
                if not embedded_filepath or embedded_filepath.startswith("dist/"):
                    response = get_h5p(zf, embedded_filepath)
                else:
                    # Don't bother doing any hashi parsing of HTML content for h5p
                    response = get_embedded_file(
                        request, zf, zipped_filename, embedded_filepath, skip_hashi=True
                    )
            else:
                response = get_embedded_file(
                    request, zf, zipped_filename, embedded_filepath
                )

        # ensure the browser knows not to try byte-range requests, as we don't support them here
        response["Accept-Ranges"] = "none"

        return response
Example #8
0
class UpdateModelMixin(DJRUpdateModelMixin):
    """
    Turns the django-rest-framework mixin into an etag-aware one.
    """
    @method_decorator(etag(etag_func))
    def update_response(self, request, data, serializer, save_kwargs, created,
                        success_status_code):
        self.pre_save(serializer.object)
        self.object = serializer.save(**save_kwargs)
        self.post_save(self.object, created=created)
        return Response(serializer.data, status=success_status_code)

    def update(self, request, *args, **kwargs):
        partial = kwargs.pop('partial', False)
        self.object = self.get_object_or_none()

        if self.object is None:
            created = True
            save_kwargs = {'force_insert': True}
            success_status_code = status.HTTP_201_CREATED
        else:
            created = False
            save_kwargs = {'force_update': True}
            success_status_code = status.HTTP_200_OK

        serializer = self.get_serializer(self.object,
                                         data=request.DATA,
                                         files=request.FILES,
                                         partial=partial)

        if serializer.is_valid():
            request.initial_etag = serializer.object.etag
            return self.update_response(request, serializer.object, serializer,
                                        save_kwargs, created,
                                        success_status_code)

        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
Example #9
0
# This is not a valid Django URL configuration, as the final
# configuration is done by the pretix.multidomain package.
js_info_dict = {
    'packages': ('pretix',),
}

# Yes, we want to regenerate this every time the module has been imported to
# refresh the cache at least at every code deployment
import_date = timezone.now().strftime("%Y%m%d%H%M")

base_patterns = [
    url(r'^download/(?P<id>[^/]+)/$', cachedfiles.DownloadView.as_view(),
        name='cachedfile.download'),
    url(r'^jsi18n/$',
        etag(lambda *s, **k: import_date)(cache_page(3600, key_prefix='js18n-%s' % import_date)(javascript_catalog)),
        js_info_dict, name='javascript-catalog'),
]

control_patterns = [
    url(r'^control/', include(pretix.control.urls, namespace='control')),
]

debug_patterns = []
if settings.DEBUG:
    import debug_toolbar

    debug_patterns.append(url(r'^__debug__/', include(debug_toolbar.urls)))

common_patterns = base_patterns + control_patterns + debug_patterns
Example #10
0
from django.views.decorators.http import condition, etag, last_modified
from django.http import HttpResponse

from .tests import FULL_RESPONSE, LAST_MODIFIED, ETAG


def index(request):
    return HttpResponse(FULL_RESPONSE)
index = condition(lambda r: ETAG, lambda r: LAST_MODIFIED)(index)


def last_modified_view1(request):
    return HttpResponse(FULL_RESPONSE)
last_modified_view1 = condition(last_modified_func=lambda r: LAST_MODIFIED)(last_modified_view1)


def last_modified_view2(request):
    return HttpResponse(FULL_RESPONSE)
last_modified_view2 = last_modified(lambda r: LAST_MODIFIED)(last_modified_view2)


def etag_view1(request):
    return HttpResponse(FULL_RESPONSE)
etag_view1 = condition(etag_func=lambda r: ETAG)(etag_view1)


def etag_view2(request):
    return HttpResponse(FULL_RESPONSE)
etag_view2 = etag(lambda r: ETAG)(etag_view2)
Example #11
0
        results, channel_ids, content_kinds, total_results = self.search(
            value, max_results)
        data = self.serialize(results)
        return Response({
            "channel_ids": channel_ids,
            "content_kinds": content_kinds,
            "results": data,
            "total_results": total_results,
        })


def get_cache_key(*args, **kwargs):
    return str(ContentCacheKey.get_cache_key())


@method_decorator(etag(get_cache_key), name="retrieve")
class ContentNodeGranularViewset(mixins.RetrieveModelMixin,
                                 viewsets.GenericViewSet):
    serializer_class = serializers.ContentNodeGranularSerializer

    def get_queryset(self):
        return (models.ContentNode.objects.all().prefetch_related(
            "files__local_file").filter(
                renderable_contentnodes_q_filter).distinct())

    def get_serializer_context(self):
        context = super(ContentNodeGranularViewset,
                        self).get_serializer_context()
        context.update({"channel_stats": self.channel_stats})
        return context
Example #12
0
# -*- coding:utf-8 -*-
from django.views.decorators.http import condition, etag, last_modified
from django.http import HttpResponse

from models import FULL_RESPONSE, LAST_MODIFIED, ETAG

def index(request):
    return HttpResponse(FULL_RESPONSE)
index = condition(lambda r: ETAG, lambda r: LAST_MODIFIED)(index)

def last_modified_view1(request):
    return HttpResponse(FULL_RESPONSE)
last_modified_view1 = condition(last_modified_func=lambda r: LAST_MODIFIED)(last_modified_view1)

def last_modified_view2(request):
    return HttpResponse(FULL_RESPONSE)
last_modified_view2 = last_modified(lambda r: LAST_MODIFIED)(last_modified_view2)

def etag_view1(request):
    return HttpResponse(FULL_RESPONSE)
etag_view1 = condition(etag_func=lambda r: ETAG)(etag_view1)

def etag_view2(request):
    return HttpResponse(FULL_RESPONSE)
etag_view2 = etag(lambda r: ETAG)(etag_view2)

Example #13
0
from django.conf.urls import url
from django.views.decorators.http import etag
from nextcloudappstore.api.v1.views import AppView, AppReleaseView, \
    CategoryView, SessionObtainAuthToken, RegenerateAuthToken, AppRatingView, \
    AppRegisterView, NextcloudReleaseView
from nextcloudappstore.core.caching import app_ratings_etag, categories_etag, \
    apps_etag, nextcloud_release_etag
from nextcloudappstore.core.versioning import SEMVER_REGEX

urlpatterns = [
    url(r'^platforms\.json$',
        etag(nextcloud_release_etag)(NextcloudReleaseView.as_view()),
        name='platforms'),
    url(r'^platform/(?P<version>\d+\.\d+\.\d+)/apps\.json$',
        etag(apps_etag)(AppView.as_view()), name='app'),
    url(r'^apps/releases/?$', AppReleaseView.as_view(),
        name='app-release-create'),
    url(r'^apps/?$', AppRegisterView.as_view(), name='app-register'),
    url(r'^apps/(?P<pk>[a-z0-9_]+)/?$', AppView.as_view(), name='app-delete'),
    url(r'^ratings.json$',
        etag(app_ratings_etag)(AppRatingView.as_view()),
        name='app-ratings'),
    url(r'^apps/(?P<app>[a-z_]+)/releases/(?:(?P<nightly>nightly)/)?'
        r'(?P<version>' + SEMVER_REGEX + ')/?$',
        AppReleaseView.as_view(), name='app-release-delete'),
    url(r'^token/?$', SessionObtainAuthToken.as_view(), name='user-token'),
    url(r'^token/new/?$', RegenerateAuthToken.as_view(),
        name='user-token-new'),
    url(r'^categories.json$',
        etag(categories_etag)(CategoryView.as_view()), name='category'),
]
Example #14
0
File: views.py Project: heath/OTM2
update_map_feature_detail_view = login_or_401(
    json_api_call(
        instance_request(
            creates_instance_user(update_map_feature_detail))))

delete_tree_view = login_or_401(
    json_api_call(
        instance_request(
            creates_instance_user(delete_tree))))

delete_map_feature_view = login_or_401(
    json_api_call(
        instance_request(
            creates_instance_user(delete_map_feature))))

get_plot_eco_view = instance_request(etag(_map_feature_hash)(
    render_template('treemap/partials/plot_eco.html', plot_detail)))

get_map_feature_sidebar_view = instance_request(etag(_map_feature_hash)(
    render_template('treemap/partials/sidebar.html', plot_detail)))

map_feature_popup_view = instance_request(etag(_map_feature_hash)(
    render_template('treemap/partials/map_feature_popup.html',
                    map_feature_popup)))

plot_accordion_view = instance_request(
    render_template('treemap/plot_accordion.html', plot_detail))

add_map_feature_view = require_http_method("POST")(
    login_or_401(
        json_api_call(
            instance_request(
Example #15
0
        ELSE=do(
            login_or_401,
            json_api_call,
            creates_instance_user,
            route(
                PUT=update_map_feature_detail,
                DELETE=delete_map_feature))))

map_feature_accordion_view = do(
    instance_request,
    render_template('treemap/partials/map_feature_accordion.html'),
    map_feature_detail)

get_map_feature_sidebar_view = do(
    instance_request,
    etag(map_feature_hash),
    render_template('treemap/partials/sidebar.html'),
    map_feature_detail)

map_feature_popup_view = do(
    instance_request,
    etag(map_feature_hash),
    render_template('treemap/partials/map_feature_popup.html'),
    map_feature_popup)

add_map_feature_photo_endpoint = add_map_feature_photo_do(
    add_map_feature_photo)

rotate_map_feature_photo_endpoint = add_map_feature_photo_do(
    rotate_map_feature_photo)
Example #16
0
from django.conf.urls import url
from django.views.decorators.http import etag
from nextcloudappstore.api.v1.views import AppView, AppReleaseView, \
    CategoryView, SessionObtainAuthToken, RegenerateAuthToken, AppRatingView, \
    AppRegisterView
from nextcloudappstore.core.caching import app_ratings_etag, categories_etag, \
    apps_etag
from nextcloudappstore.core.versioning import SEMVER_REGEX

urlpatterns = [
    url(r'^platform/(?P<version>\d+\.\d+\.\d+)/apps\.json$',
        etag(apps_etag)(AppView.as_view()), name='app'),
    url(r'^apps/releases/?$', AppReleaseView.as_view(),
        name='app-release-create'),
    url(r'^apps/?$', AppRegisterView.as_view(), name='app-register'),
    url(r'^apps/(?P<pk>[a-z0-9_]+)/?$', AppView.as_view(), name='app-delete'),
    url(r'^ratings.json$',
        etag(app_ratings_etag)(AppRatingView.as_view()),
        name='app-ratings'),
    url(r'^apps/(?P<app>[a-z_]+)/releases/(?:(?P<nightly>nightly)/)?'
        r'(?P<version>' + SEMVER_REGEX + ')/?$',
        AppReleaseView.as_view(), name='app-release-delete'),
    url(r'^token/?$', SessionObtainAuthToken.as_view(), name='user-token'),
    url(r'^token/new/?$', RegenerateAuthToken.as_view(),
        name='user-token-new'),
    url(r'^categories.json$',
        etag(categories_etag)(CategoryView.as_view()), name='category'),
]
Example #17
0
                PUT=feature_views.update_map_feature_detail,
                DELETE=feature_views.delete_map_feature))))

map_feature_detail_partial = do(
    instance_request,
    require_http_method('GET'),
    feature_views.render_map_feature_detail_partial)

map_feature_accordion = do(
    instance_request,
    render_template('treemap/partials/map_feature_accordion.html'),
    feature_views.context_map_feature_detail)

get_map_feature_sidebar = do(
    instance_request,
    etag(feature_views.map_feature_hash),
    render_template('treemap/partials/sidebar.html'),
    feature_views.context_map_feature_detail)

map_feature_popup = do(
    instance_request,
    etag(feature_views.map_feature_hash),
    render_template('treemap/partials/map_feature_popup.html'),
    feature_views.map_feature_popup)

canopy_popup = do(
    instance_request,
    feature_views.canopy_popup)

add_map_feature_photo = add_map_feature_photo_do(
    feature_views.add_map_feature_photo)
Example #18
0
from django.conf.urls import url
from django.views.decorators.http import etag
from nextcloudappstore.api.v1.views import AppView, AppReleaseView, \
    CategoryView, SessionObtainAuthToken, RegenerateAuthToken, AppRatingView, \
    AppRegisterView, NextcloudReleaseView, AppsView
from nextcloudappstore.core.caching import app_ratings_etag, categories_etag, \
    apps_etag, nextcloud_release_etag, apps_all_etag
from nextcloudappstore.core.versioning import SEMVER_REGEX

app_name = 'v1'

urlpatterns = [
    url(r'^platforms\.json$',
        etag(nextcloud_release_etag)(NextcloudReleaseView.as_view()),
        name='platforms'),
    url(r'^platform/(?P<version>\d+\.\d+\.\d+)/apps\.json$',
        etag(apps_etag)(AppView.as_view()),
        name='app'),
    url(r'^apps\.json$', etag(apps_all_etag)(AppsView.as_view()), name='apps'),
    url(r'^apps/releases/?$',
        AppReleaseView.as_view(),
        name='app-release-create'),
    url(r'^apps/?$', AppRegisterView.as_view(), name='app-register'),
    url(r'^apps/(?P<pk>[a-z0-9_]+)/?$', AppView.as_view(), name='app-delete'),
    url(r'^ratings.json$',
        etag(app_ratings_etag)(AppRatingView.as_view()),
        name='app-ratings'),
    url(r'^apps/(?P<app>[a-z_]+)/releases/(?:(?P<nightly>nightly)/)?'
        r'(?P<version>' + SEMVER_REGEX + ')/?$',
        AppReleaseView.as_view(),
        name='app-release-delete'),
Example #19
0
class ZipContentView(View):
    @xframe_options_exempt
    @add_security_headers
    def options(self, request, *args, **kwargs):
        """
        Handles OPTIONS requests which may be sent as "preflight CORS" requests to check permissions.
        """
        return HttpResponse()

    @method_decorator(etag(calculate_zip_content_etag))
    @cache_forever
    @xframe_options_exempt
    @add_security_headers
    def get(self, request, zipped_filename, embedded_filepath):
        """
        Handles GET requests and serves a static file from within the zip file.
        """
        zipped_path = get_path_or_404(zipped_filename)

        # Sometimes due to URL concatenation, we get URLs with double-slashes in them, like //path/to/file.html.
        # the zipped_filename and embedded_filepath are defined by the regex capturing groups in the URL defined
        # in urls.py in the same folder as this file:
        # r"^zipcontent/(?P<zipped_filename>[^/]+)/(?P<embedded_filepath>.*)"
        # If the embedded_filepath contains a leading slash because of an input URL like:
        # /zipcontent/filename.zip//file.html
        # then the embedded_filepath will have a value of "/file.html"
        # we detect this leading slash in embedded_filepath and remove it.
        if embedded_filepath.startswith("/"):
            embedded_filepath = embedded_filepath[1:]
        # Any double-slashes later in the URL will be present as double-slashes, such as:
        # /zipcontent/filename.zip/path//file.html
        # giving an embedded_filepath value of "path//file.html"
        # Normalize the path by converting double-slashes occurring later in the path to a single slash.
        # This would change our example embedded_filepath to "path/file.html" which will resolve properly.
        embedded_filepath = embedded_filepath.replace("//", "/")

        # if client has a cached version, use that (we can safely assume nothing has changed, due to MD5)
        if request.META.get("HTTP_IF_MODIFIED_SINCE"):
            return HttpResponseNotModified()

        with zipfile.ZipFile(zipped_path) as zf:

            # handle H5P files
            if zipped_path.endswith("h5p"):
                if not embedded_filepath or embedded_filepath.startswith(
                        "dist/"):
                    response = get_h5p(zf, embedded_filepath)
                else:
                    # Don't bother doing any hashi parsing of HTML content for h5p
                    response = get_embedded_file(request,
                                                 zf,
                                                 zipped_filename,
                                                 embedded_filepath,
                                                 skip_hashi=True)
            else:
                response = get_embedded_file(request, zf, zipped_filename,
                                             embedded_filepath)

        # ensure the browser knows not to try byte-range requests, as we don't support them here
        response["Accept-Ranges"] = "none"

        return response
Example #20
0
class InfoView(TemplateView):
    @method_decorator(etag(get_template_etag))
    def get(self, request, *args, **kwargs):
        self.template_name = request.template_name
        response = super(InfoView, self).get(request, *args, **kwargs)
        return response
Example #21
0
        GET=feature_views.render_map_feature_detail,
        ELSE=do(
            json_api_edit,
            return_400_if_validation_errors,
            route(
                PUT=feature_views.update_map_feature_detail,
                DELETE=feature_views.delete_map_feature))))

map_feature_accordion = do(
    instance_request,
    render_template('treemap/partials/map_feature_accordion.html'),
    feature_views.map_feature_detail)

get_map_feature_sidebar = do(
    instance_request,
    etag(feature_views.map_feature_hash),
    render_template('treemap/partials/sidebar.html'),
    feature_views.map_feature_detail)

map_feature_popup = do(
    instance_request,
    etag(feature_views.map_feature_hash),
    render_template('treemap/partials/map_feature_popup.html'),
    feature_views.map_feature_popup)

add_map_feature_photo = add_map_feature_photo_do(
    feature_views.add_map_feature_photo)

rotate_map_feature_photo = add_map_feature_photo_do(
    feature_views.rotate_map_feature_photo)
Example #22
0
map_feature_detail_view = do(
    instance_request,
    route(GET=render_map_feature_detail,
          ELSE=do(
              json_api_edit, return_400_if_validation_errors,
              route(PUT=update_map_feature_detail,
                    DELETE=delete_map_feature))))

map_feature_accordion_view = do(
    instance_request,
    render_template('treemap/partials/map_feature_accordion.html'),
    map_feature_detail)

get_map_feature_sidebar_view = do(
    instance_request, etag(map_feature_hash),
    render_template('treemap/partials/sidebar.html'), map_feature_detail)

map_feature_popup_view = do(
    instance_request, etag(map_feature_hash),
    render_template('treemap/partials/map_feature_popup.html'),
    map_feature_popup)

add_map_feature_photo_endpoint = add_map_feature_photo_do(
    add_map_feature_photo)

rotate_map_feature_photo_endpoint = add_map_feature_photo_do(
    rotate_map_feature_photo)

#####################################
# plot
Example #23
0
    url(r'^developer/apps/releases/new/?$',
        AppUploadView.as_view(),
        name='app-upload'),
    url(r'^developer/apps/new/?$',
        AppRegisterView.as_view(),
        name='app-register'),
    url(r'^apps/(?P<id>[\w_]+)/?$', AppDetailView.as_view(),
        name='app-detail'),
    url(r'^apps/(?P<id>[\w_]+)/releases/?$',
        AppReleasesView.as_view(),
        name='app-releases'),
    url(r'^apps/(?P<id>[\w_]+)/description/?$',
        app_description,
        name='app-description'),
    url(r'^apps/(?P<id>[\w_]+)/ratings.json$',
        etag(app_rating_etag)(AppRatingApi.as_view()),
        name='app-ratings'),
    url(r'^api/', include('nextcloudappstore.api.urls', namespace='api')),
    url(r'^account/', include('nextcloudappstore.user.urls',
                              namespace='user')),
    url(r'^admin/', admin.site.urls),
    url(r'^i18n/', include('django.conf.urls.i18n')),
]

urlpatterns += i18n_patterns(
    url(r'feeds/releases.rss', AppReleaseRssFeed(), name='feeds-releases-rss'),
    url(r'feeds/releases.atom',
        AppReleaseAtomFeed(),
        name='feeds-releases-atom'),
)
Example #24
0
# configuration is done by the pretix.multidomain package.
js_info_dict = {
    'packages': ('pretix',),
}

# Yes, we want to regenerate this every time the module has been imported to
# refresh the cache at least at every code deployment
import_date = timezone.now().strftime("%Y%m%d%H%M")

base_patterns = [
    url(r'^download/(?P<id>[^/]+)/$', cachedfiles.DownloadView.as_view(),
        name='cachedfile.download'),
    url(r'^healthcheck/$', health.healthcheck,
        name='cachedfile.download'),
    url(r'^jsi18n/$',
        etag(lambda *s, **k: import_date)(cache_page(3600, key_prefix='js18n-%s' % import_date)(javascript_catalog)),
        js_info_dict, name='javascript-catalog'),
]

control_patterns = [
    url(r'^control/', include(pretix.control.urls, namespace='control')),
]

debug_patterns = []
if settings.DEBUG:
    try:
        import debug_toolbar

        debug_patterns.append(url(r'^__debug__/', include(debug_toolbar.urls)))
    except ImportError:
        pass
Example #25
0
          ELSE=do(
              json_api_edit, return_400_if_validation_errors,
              route(PUT=feature_views.update_map_feature_detail,
                    DELETE=feature_views.delete_map_feature))))

map_feature_detail_partial = do(
    instance_request, require_http_method('GET'),
    feature_views.render_map_feature_detail_partial)

map_feature_accordion = do(
    instance_request,
    render_template('treemap/partials/map_feature_accordion.html'),
    feature_views.context_map_feature_detail)

get_map_feature_sidebar = do(instance_request,
                             etag(feature_views.map_feature_hash),
                             render_template('treemap/partials/sidebar.html'),
                             feature_views.context_map_feature_detail)

map_feature_popup = do(
    instance_request, etag(feature_views.map_feature_hash),
    render_template('treemap/partials/map_feature_popup.html'),
    feature_views.map_feature_popup)

canopy_popup = do(instance_request, feature_views.canopy_popup)

add_map_feature_photo = add_map_feature_photo_do(
    feature_views.add_map_feature_photo)

delete_photo = do(require_http_method("DELETE"), login_or_401,
                  instance_request,
Example #26
0
        ELSE=do(
            login_or_401,
            json_api_call,
            creates_instance_user,
            route(
                PUT=update_map_feature_detail,
                DELETE=delete_map_feature))))

map_feature_accordion_view = do(
    instance_request,
    render_template('treemap/partials/map_feature_accordion.html'),
    map_feature_detail)

get_map_feature_sidebar_view = do(
    instance_request,
    etag(map_feature_hash),
    render_template('treemap/partials/sidebar.html'),
    map_feature_detail)

map_feature_popup_view = do(
    instance_request,
    etag(map_feature_hash),
    render_template('treemap/partials/map_feature_popup.html'),
    map_feature_popup)

add_map_feature_photo_endpoint = add_map_feature_photo_do(
    add_map_feature_photo)

rotate_map_feature_photo_endpoint = add_map_feature_photo_do(
    rotate_map_feature_photo)
Example #27
0
class TastypieBaseResource(object):
    """
    A TastypieBaseResource for Tastypie.
    """
    def form_errors(self, forms):
        errors = format_form_errors(forms)
        response = http.HttpBadRequest(json.dumps(errors),
                                       content_type='application/json')
        raise ImmediateHttpResponse(response=response)

    def dehydrate(self, bundle):
        bundle.data['resource_pk'] = bundle.obj.pk
        return super(TastypieBaseResource, self).dehydrate(bundle)

    def _handle_500(self, request, exception):
        return handle_500(request, exception)

    def deserialize(self, request, data, format='application/json'):
        result = (super(TastypieBaseResource, self).deserialize(request,
                                                                data,
                                                                format=format))
        if settings.DUMP_REQUESTS:
            formatted_json(result)
        return result

    def dispatch(self, request_type, request, **kw):
        method = request.META['REQUEST_METHOD']
        delay = request.META.get('HTTP_SOLITUDE_ASYNC', False)
        if delay:
            # Move the import here to remove warnings in management commands.
            from lib.delayable.tasks import delayable
            # Only do async on these requests.
            if method not in ['PATCH', 'POST', 'PUT']:
                raise ImmediateHttpResponse(
                    response=http.HttpMethodNotAllowed())

            # Create a delayed dispatch.
            uid = str(uuid.uuid4())
            # We only need a subset of meta.
            whitelist = ['PATH_INFO', 'REQUEST_METHOD', 'QUERY_STRING']
            meta = dict([k, request.META[k]] for k in whitelist)
            # Celery could magically serialise some of this, but I don't
            # trust it that much.
            delayable.delay(self.__class__.__module__, self.__class__.__name__,
                            request_type, meta, request.body, kw, uid)
            content = json.dumps({
                'replay': '/delay/replay/%s/' % uid,
                'result': '/delay/result/%s/' % uid
            })
            return http.HttpResponse(content,
                                     status=202,
                                     content_type='application/json')

        # Log the call with CEF and logging.
        if settings.DUMP_REQUESTS:
            print colorize('brace', method), request.get_full_path()
        else:
            log.info('%s %s' %
                     (colorize('brace', method), request.get_full_path()))

        msg = '%s:%s' % (kw.get('api_name',
                                'unknown'), kw.get('resource_name', 'unknown'))
        log_cef(msg, request, severity=2)

        return super(TastypieBaseResource,
                     self).dispatch(request_type, request, **kw)

    def build_filters(self, filters=None):
        # Override the filters so we can stop Tastypie silently ignoring
        # invalid filters. That will cause an invalid filtering just to return
        # lots of results.
        if filters is None:
            filters = {}
        qs_filters = {}

        for filter_expr, value in filters.items():
            filter_bits = filter_expr.split(LOOKUP_SEP)
            field_name = filter_bits.pop(0)
            filter_type = 'exact'

            if not field_name in self.fields:
                # Don't just ignore this. Tell the world. Shame I have to
                # override all this, just to do this.
                raise InvalidFilterError('Not a valid filtering field: %s' %
                                         field_name)

            if len(filter_bits) and filter_bits[-1] in QUERY_TERMS:
                filter_type = filter_bits.pop()

            lookup_bits = self.check_filtering(field_name, filter_type,
                                               filter_bits)

            if value in ['true', 'True', True]:
                value = True
            elif value in ['false', 'False', False]:
                value = False
            elif value in ('nil', 'none', 'None', None):
                value = None

            # Split on ',' if not empty string and either an in or range
            # filter.
            if filter_type in ('in', 'range') and len(value):
                if hasattr(filters, 'getlist'):
                    value = filters.getlist(filter_expr)
                else:
                    value = value.split(',')

            db_field_name = LOOKUP_SEP.join(lookup_bits)
            qs_filter = '%s%s%s' % (db_field_name, LOOKUP_SEP, filter_type)
            qs_filters[qs_filter] = value

        return dict_strip_unicode_keys(qs_filters)

    def is_valid(self, bundle, request):
        # Tastypie will check is_valid on the object by validating the form,
        # but on PUTes and PATCHes it does so without instantiating the object.
        # Without the object on the model.instance, the uuid check does not
        # exclude the original object being changed and so the validation
        # will fail. This patch will force the object to be added before
        # validation,
        #
        # There are two ways to spot when we should be doing this:
        # 1. When there is a specific resource_pk in the PUT or PATCH.
        # 2. When the request.path resolves to having a pk in it.
        # If either of those match, get_via_uri will do the right thing.
        if 'resource_uri' in bundle.data or 'pk' in resolve(request.path)[2]:
            try:
                bundle.obj = self.get_via_uri(request.path)
                if request.method == 'PUT':
                    # In case of a PUT modification, we need to keep
                    # the initial values for the given object to check
                    # the Etag header.
                    request.initial_etag = getattr(bundle.obj, 'etag', '')
            except ObjectDoesNotExist:
                pass
        return super(TastypieBaseResource, self).is_valid(bundle, request)

    @method_decorator(etag(etag_func))
    def create_response(self,
                        request,
                        data,
                        response_class=HttpResponse,
                        **response_kwargs):
        return super(TastypieBaseResource,
                     self).create_response(request, data, response_class,
                                           **response_kwargs)

    @method_decorator(etag(etag_func))
    def create_patch_response(self, request, original_bundle, new_data):
        self.update_in_place(request, original_bundle, new_data)
        return http.HttpAccepted()

    def patch_detail(self, request, **kwargs):
        request = convert_post_to_patch(request)
        try:
            obj = self.cached_obj_get(request=request,
                                      **self.remove_api_resource_names(kwargs))
        except ObjectDoesNotExist:
            return http.HttpNotFound()
        except MultipleObjectsReturned:
            return http.HttpMultipleChoices('More than one resource'
                                            'is found at this URI.')

        bundle = self.build_bundle(obj=obj, request=request)
        bundle = self.full_dehydrate(bundle)
        bundle = self.alter_detail_data_to_serialize(request, bundle)

        # Now update the bundle in-place.
        deserialized = self.deserialize(request,
                                        request.raw_post_data,
                                        format=request.META.get(
                                            'CONTENT_TYPE',
                                            'application/json'))

        # In case of a patch modification, we need to store
        # the initial values for the given object to check
        # the Etag header.
        request.initial_etag = bundle.obj.etag
        return self.create_patch_response(request, bundle, deserialized)

    def deserialize_body(self, request):
        # Trying to standardize on JSON in the body for most things if we
        # can. Similar to elastic search. Retaining query string for tastypie
        # record filtering.
        data = request.raw_post_data
        if not data:
            # Don't raise an error if the body is empty.
            return {}

        return self.deserialize(request, data, format='application/json')
Example #28
0
from django.conf.urls import url
from django.views.decorators.http import etag
from nextcloudappstore.core.api.v1.views import Apps, AppReleases, app_api_etag

urlpatterns = [
    url(r'^platform/(?P<version>\d+\.\d+\.\d+)/apps\.json$',
        etag(app_api_etag)(Apps.as_view()), name='apps'),
    url(r'^apps/releases/?$', AppReleases.as_view(),
        name='app-release-create'),
    url(r'^apps/(?P<pk>[a-z_]+)/?$', Apps.as_view(), name='app-delete'),
    url(r'^apps/(?P<app>[a-z_]+)/releases/(?P<version>\d+\.\d+\.\d+)/?$',
        AppReleases.as_view(), name='app-release-delete'),
]
Example #29
0
    url(r'^categories/(?P<id>[\w]*)/?$', CategoryAppListView.as_view(),
        name='category-app-list'),
    url(r'^developer/apps/generate/?$', AppScaffoldingView.as_view(),
        name='app-scaffold'),
    url(r'^developer/apps/releases/new/?$', AppUploadView.as_view(),
        name='app-upload'),
    url(r'^developer/apps/new/?$', AppRegisterView.as_view(),
        name='app-register'),
    url(r'^apps/(?P<id>[\w_]+)/?$', AppDetailView.as_view(),
        name='app-detail'),
    url(r'^apps/(?P<id>[\w_]+)/releases/?$', AppReleasesView.as_view(),
        name='app-releases'),
    url(r'^apps/(?P<id>[\w_]+)/description/?$', app_description,
        name='app-description'),
    url(r'^apps/(?P<id>[\w_]+)/ratings.json$',
        etag(app_rating_etag)(AppRatingApi.as_view()), name='app-ratings'),
    url(r'^api/', include('nextcloudappstore.core.api.urls',
                          namespace='api')),
    url(r'^account/',
        include('nextcloudappstore.core.user.urls', namespace='user')),
    url(r'^admin/', admin.site.urls),
    url(r'^i18n/', include('django.conf.urls.i18n')),
]

urlpatterns += i18n_patterns(
    url(r'feeds/releases.rss', AppReleaseRssFeed(), name='feeds-releases-rss'),
    url(r'feeds/releases.atom', AppReleaseAtomFeed(),
        name='feeds-releases-atom'),
)

if settings.DEBUG:
Example #30
0
from django.conf.urls import url
from django.views.decorators.http import etag
from nextcloudappstore.core.api.v1.views import AppView, AppReleaseView, \
    CategoryView, app_api_etag, category_api_etag

urlpatterns = [
    url(r'^platform/(?P<version>\d+\.\d+\.\d+)/apps\.json$',
        etag(app_api_etag)(AppView.as_view()), name='app'),
    url(r'^apps/releases/?$', AppReleaseView.as_view(),
        name='app-release-create'),
    url(r'^apps/(?P<pk>[a-z_]+)/?$', AppView.as_view(), name='app-delete'),
    url(r'^apps/(?P<app>[a-z_]+)/releases/(?P<version>\d+\.\d+\.\d+'
        r'(?:-nightly)?)/?$',
        AppReleaseView.as_view(), name='app-release-delete'),
    url(r'^categories.json$',
        etag(category_api_etag)(CategoryView.as_view()), name='category'),
]
Example #31
0
map_feature_detail = do(
    instance_request,
    route(GET=feature_views.render_map_feature_detail,
          ELSE=do(
              json_api_edit, return_400_if_validation_errors,
              route(PUT=feature_views.update_map_feature_detail,
                    DELETE=feature_views.delete_map_feature))))

map_feature_accordion = do(
    instance_request,
    render_template('treemap/partials/map_feature_accordion.html'),
    feature_views.context_map_feature_detail)

get_map_feature_sidebar = do(instance_request,
                             etag(feature_views.map_feature_hash),
                             render_template('treemap/partials/sidebar.html'),
                             feature_views.context_map_feature_detail)

map_feature_popup = do(
    instance_request, etag(feature_views.map_feature_hash),
    render_template('treemap/partials/map_feature_popup.html'),
    feature_views.map_feature_popup)

add_map_feature_photo = add_map_feature_photo_do(
    feature_views.add_map_feature_photo)

rotate_map_feature_photo = add_map_feature_photo_do(
    feature_views.rotate_map_feature_photo)

map_feature_photo_detail = do(
Example #32
0
    return HttpResponseRedirect(reverse("map", kwargs={"instance_url_name": instance.url_name}))


edits_view = instance_request(requires_feature("recent_edits_report")(render_template("treemap/edits.html", edits)))

index_view = instance_request(index)

map_view = instance_request(render_template("treemap/map.html", _get_map_view_context))

get_plot_detail_view = instance_request(render_template("treemap/plot_detail.html", plot_detail))

edit_plot_detail_view = login_required(
    instance_request(creates_instance_user(render_template("treemap/plot_detail.html", plot_detail)))
)

get_plot_eco_view = instance_request(etag(_plot_hash)(render_template("treemap/partials/plot_eco.html", plot_detail)))

get_plot_sidebar_view = instance_request(
    etag(_plot_hash)(render_template("treemap/partials/sidebar.html", plot_detail))
)

update_plot_detail_view = login_or_401(json_api_call(instance_request(creates_instance_user(update_plot_detail))))

plot_popup_view = instance_request(etag(_plot_hash)(render_template("treemap/partials/plot_popup.html", plot_detail)))

plot_accordion_view = instance_request(render_template("treemap/plot_accordion.html", plot_detail))

add_plot_view = require_http_method("POST")(
    login_or_401(json_api_call(instance_request(creates_instance_user(add_plot))))
)