# -*- coding: utf-8 -*- from django.conf import settings from django.contrib.contenttypes.models import ContentType from django.shortcuts import get_object_or_404, redirect from django.views import generic from django.core.exceptions import PermissionDenied from django.template import RequestContext from django.utils.http import urlquote_plus from django.template import loader from django.http import HttpResponse from rapid.models import DocumentTemplate from rapid.officedocs.rtf import RtfTemplate from rapid.wrappers import InstanceData, ModelData from rapid.filters import FilterSet from rapidforms import for_model import math from os import path def _build_uri(request, params): param_string = "&".join(["%s=%s" % (urlquote_plus(k), urlquote_plus(params[k])) for k in params.keys()]) base = request.build_absolute_uri().split("?")[0] return base + "?" + param_string def _copy_dict(dc): d = {} for k in dc.keys(): d[k] = dc[k] return d def _replace_param(request, param_name, param_value): get = _copy_dict(request.GET) get[param_name] = param_value return _build_uri(request, get) def is_ajax_request(request): # X-Requested-With: XMLHttpRequest w = request.META.get('HTTP_X_REQUESTED_WITH') if w: return True return False class ListView(generic.list.ListView): template_name = 'rapid/bare/list.html' action_name = '' registers_per_page = 50 number_of_edge_pages = 5 number_of_middle_pages = 5 fields = None class Pagination(object): def __init__(self, request, page, number_of_edge_pages, number_of_middle_pages, registers_per_page, total_pages): self.request = request self.number_of_edge_pages = number_of_edge_pages self.number_of_middle_pages = number_of_middle_pages self.registers_per_page = registers_per_page self.page = page self.total_pages = total_pages def _page_and_uri(self, pages): get2 = _copy_dict(self.request.GET) for p in pages: get2['page'] = p yield (p, _build_uri(self.request, get2)) def start_numbers(self): """ Page numbers listed at the beginning of the pagination area """ e = self.number_of_edge_pages for i in range(1, min(e+1, self.page)): yield i def start(self): """ Page numbers and URLs listed at the beginning of the pagination area """ return self._page_and_uri(self.start_numbers()) def before_numbers(self): """ Page numbers listed at the pagination area before the current page """ m = self.number_of_middle_pages for i in range(max(self.page - m, m), self.page): yield i def before(self): """ Page numbers and URLs listed at the pagination area before the current page """ return self._page_and_uri(self.before_numbers()) def after_numbers(self): """ Page numbers listed at the pagination area after the current page """ m = self.number_of_middle_pages e = self.number_of_edge_pages for i in range(self.page + 1, min(self.page + m + 1, self.total_pages - e + 1)): yield i def after(self): """ Page numbers and URLs listed at the pagination area after the current page """ return self._page_and_uri(self.after_numbers()) def end_numbers(self): """ Page numbers listed at the end of the pagination area """ e = self.number_of_edge_pages for i in range(max(self.page + 1, self.total_pages - e + 1), self.total_pages + 1): yield i def end(self): """ Page numbers and URLs listed at the end of the pagination area """ return self._page_and_uri(self.end_numbers()) def separate_end(self): """ True if there's a separator between the next pages and the end pages. """ return self.page < self.total_pages - self.number_of_edge_pages - self.number_of_middle_pages def separate_start(self): """ True if there's a separator between the start pages and the before pages. """ return self.page > self.number_of_edge_pages + self.number_of_middle_pages def get_page(self, queryset): return queryset[self.registers_per_page*(self.page-1):self.registers_per_page*self.page] class View(object): order_param = 'order' def __init__(self, request, action_name, model, queryset, fields, pagination): self.request = request self.model = model self.action_name = action_name self._fields = fields q = queryset self.filters = FilterSet.from_request(ModelData(self.model), request) if self.filters: q = q.filter(**self.filters.query_dict()) self.queryset = q total = q.count() pagination.total_pages = int(math.ceil(total / pagination.registers_per_page)) order = request.GET.get(self.order_param) if order: q = q.order_by(order) self.queryset = pagination.get_page(q) def values(self): for o in self.queryset: if self._fields: c = InstanceData(o, request=self.request, fields=self._fields) else: c = InstanceData(o, request=self.request) if c.has_permission(self.request, self.action_name): yield c def fields(self): order_param = self.order_param request = self.request class FieldParams(object): def __init__(self, field): self.field = field def order_up_url(self): return _replace_param(request, order_param, self.field.bare_name()) def order_down_url(self): return _replace_param(request, order_param, u'-' + self.field.bare_name()) def add_filter_url(self): pass def del_filter_url(self): pass for f in ModelData(self.model, request=self.request, fields=self._fields).fields(): f.view = FieldParams(f) yield f def get(self, request, **kwargs): mdt = ModelData(self.model, request) if not mdt.has_permission(request, self.action_name): raise PermissionDenied object_list = self.get_queryset() # Populates the context context = RequestContext(request).flatten() context.update(kwargs) total_pages = int(math.ceil(object_list.count() / self.registers_per_page)) page = int(request.GET.get('page', 1)) p = self.Pagination(request, page, self.number_of_edge_pages, self.number_of_middle_pages, self.registers_per_page, total_pages) context['pages'] = p context['model'] = ModelData(self.model, request, fields=self.fields) context['view'] = self.View(request, self.action_name, self.model, object_list, self.fields, p) offset = (page - 1) * self.registers_per_page self.object_list = object_list[offset: offset + self.registers_per_page] context[self.get_context_object_name(object_list)] = object_list context['object_list'] = object_list context = self.get_context_data(**context) # noinspection PyAttributeOutsideInit self.object_list = object_list return self.render_to_response(context) class ReadView(generic.detail.DetailView): template_name = 'rapid/bare/detail.html' action_name = '' request = None def get_object(self, request=None): return get_object_or_404(self.model, pk=self.kwargs['pk']) # noinspection PyMethodOverriding def get(self, request, pk, **kwargs): context = RequestContext(request).flatten() context.update(kwargs) obj = self.get_object(self.request) context['object'] = obj context[self.get_context_object_name(obj)] = obj cd = InstanceData(obj, request=request) if not cd.has_permission(request, self.action_name): raise PermissionDenied excludes = request.GET.get('exclude') if excludes: cd.excludes = excludes.split(",") # noinspection PyAttributeOutsideInit self.object = cd context['object_data'] = cd context = self.get_context_data(**context) return self.render_to_response(context) class CreateView(generic.edit.CreateView): template_name = 'rapid/bare/create.html' action_name = '' object = None fields = '__all__' def request_form(self, request): return for_model(request, self.model) def get(self, request, **kwargs): context = RequestContext(request).flatten() context.update(kwargs) cd = ModelData(self.model, request=request) if not cd.has_permission(request, self.action_name): raise PermissionDenied context['model_data'] = cd if request.POST: context['form'] = self.request_form(request)(request.POST, request.FILES) else: context['form'] = self.request_form(request)() context = self.get_context_data(**context) return self.render_to_response(context) def post(self, request, **kwargs): m = ModelData(self.model, request=request) if m.has_permission(request, self.action_name): f = self.request_form(request)(request.POST, request.FILES) if f.is_valid(): f.save() return redirect(m.list_url()) return self.get(request, **kwargs) raise PermissionDenied() class UpdateView(generic.edit.UpdateView): template_name = 'rapid/bare/update.html' action_name = '' fields = '__all__' def get_object(self, queryset=None): return get_object_or_404(self.model, pk=self.kwargs['pk']) def request_form(self, request): return for_model(request, self.model) # noinspection PyMethodOverriding def get(self, request, pk, **kwargs): context = RequestContext(request).flatten() context.update(kwargs) obj = self.get_object() context['object'] = obj context[self.get_context_object_name(obj)] = obj cd = InstanceData(obj, request=request) if not cd.has_permission(request, self.action_name): raise PermissionDenied # noinspection PyAttributeOutsideInit self.object = cd context['object_data'] = cd if request.POST: context['form'] = self.request_form(request)(request.POST, request.FILES, instance=obj) else: context['form'] = self.request_form(request)(instance=obj) context = self.get_context_data(**context) return self.render_to_response(context) # noinspection PyMethodOverriding,PyAttributeOutsideInit def post(self, request, pk, **kwargs): obj = self.get_object() m = InstanceData(obj, request=request) if m.has_permission(request, self.action_name): f = self.request_form(request)(request.POST, request.FILES, instance=obj) if f.is_valid(): if f.instance.pk != obj.pk: raise PermissionDenied f.save() return redirect(m.list_url()) self.form = f return self.get(request, pk, **kwargs) raise PermissionDenied class DeleteView(generic.edit.DeleteView): template_name = 'rapid/bare/delete.html' action_name = '' fields = '__all__' def __init__(self, **kwargs): super(DeleteView, self).__init__(**kwargs) self.success_url = ModelData(self.model).list_url() def get_object(self, queryset=None): return get_object_or_404(self.model, pk=self.kwargs['pk']) def has_permission(self, request, instance): return instance.has_permission(request, self.action_name) def get(self, request, *args, **kwargs): obj = InstanceData(self.get_object()) if not self.has_permission(request, obj): raise PermissionDenied return super(DeleteView, self).get(request, *args, **kwargs) def post(self, request, *args, **kwargs): obj = InstanceData(self.get_object()) if not self.has_permission(request, obj): raise PermissionDenied return super(DeleteView, self).post(request, *args, **kwargs) class SelectView(ListView): """ A selectable list of objects. """ template_name = 'rapid/bare/select.html' def bare_or_main(view): main_window_template = "rapid/main_window.html" def vw(request, *args, **kwargs): resp = view(request, *args, **kwargs) bare = is_ajax_request(request) if bare: if 300 <= resp.status_code <= 399: # I'll interpret redirects as successful POST, # thus, the response'll get replaced by something with # a header that says "success!" ret = HttpResponse('') ret['X-FORM-STATUS:'] = 'success' return ret if not bare and resp.status_code == 200 and request.method != "HEAD": if hasattr(resp, 'render'): resp.render() body = resp.content main_win = loader.get_template(main_window_template) context = RequestContext(request) context.update({'body_text': body, 'this_url': request.get_full_path()}) resp.content = main_win.render(context, request) return resp return vw def update_form_class(form): class F(UpdateView): def request_form(self, request): return form return F def add_form_class(form): class F(CreateView): def request_form(self, request): return form return F class RenderDocumentView(generic.View): model = None action_name = None # noinspection PyUnusedLocal def get(self, request, pk, template): inst = get_object_or_404(self.model, pk=pk) ctx = inst.__dict__ tm = get_object_or_404(DocumentTemplate, model=ContentType.objects.get_for_model(self.model), pk=template) f = path.join(settings.MEDIA_ROOT, tm.template.name) t = RtfTemplate(f, ctx) return HttpResponse(t.read(), content_type='application/rtf') def get_delete_document_template_view(model): class DeleteDocumentTemplateView(DeleteView): def get_object(self, queryset=None): return get_object_or_404(DocumentTemplate, pk=self.kwargs['pk']) def has_permission(self, request, instance): if not ModelData(model).has_permission(request, self.action_name): return False return instance.instance.model == ContentType.objects.get_for_model(model) return DeleteDocumentTemplateView