예제 #1
0
class SpaceEdit(NotificationMixin, WikiContextMixin, wiki_article.Edit,
                SpaceArticleMixin):
    template_name = "spaces_wiki/edit.html"
    notification_label = 'spaces_wiki_modify'

    @method_decorator(get_article(can_write=True, not_locked=True))
    @method_decorator(permission_required_or_403('access_space'))
    def dispatch(self, request, article, *args, **kwargs):
        # hackish, see SpaceArticleView.dispatch
        kwargs['article_id'] = article.id
        kwargs['path'] = kwargs['urlpath'].path
        return super(SpaceEdit, self).dispatch(request, article, *args,
                                               **kwargs)

    def form_valid(self, form):
        # set title and link for notification mail
        self.notification_object_title = self.article
        self.notification_object_link = self.article.get_absolute_url()
        ret = super(SpaceEdit, self).form_valid(form)
        if isinstance(ret, HttpResponseRedirect):
            # super().form_valid successfully saved the article
            # create dashboard notification
            actstream_action.send(sender=self.request.user,
                                  verb=_("was modified"),
                                  target=self.request.SPACE,
                                  action_object=self.article.wikiarticle)

        return ret

    def get_context_data(self, **kwargs):
        context = super(SpaceEdit, self).get_context_data(**kwargs)
        # most probably the same bug as this:
        # https://github.com/django-wiki/django-wiki/issues/497
        # if bug gets fixed in a proper way, the next line can be removed
        context['edit_form'] = self.get_form(EditForm)
        # set title and link for n12n mails
        context["object_title"] = self.article
        context["object_link"] = self.article.get_absolute_url()
        return context
예제 #2
0
class AttachmentChangeRevisionView(ArticleMixin, View):

    form_class = forms.AttachmentForm
    template_name = "wiki/plugins/attachments/replace.html"

    @method_decorator(get_article(can_write=True, not_locked=True))
    def dispatch(self, request, article, attachment_id, revision_id, *args,
                 **kwargs):
        if article.can_moderate(request.user):
            self.attachment = get_object_or_404(models.Attachment,
                                                id=attachment_id,
                                                articles=article)
        else:
            self.attachment = get_object_or_404(
                models.Attachment.objects.active(),
                id=attachment_id,
                articles=article)
        self.revision = get_object_or_404(models.AttachmentRevision,
                                          id=revision_id,
                                          attachment__articles=article)
        return super(AttachmentChangeRevisionView,
                     self).dispatch(request, article, *args, **kwargs)

    def post(self, request, *args, **kwargs):
        self.attachment.current_revision = self.revision
        self.attachment.save()
        self.article.clear_cache()
        messages.success(
            self.request,
            _('Current revision changed for %s.') %
            self.attachment.original_filename)

        return redirect("wiki:attachments_index",
                        path=self.urlpath.path,
                        article_id=self.article.id)

    def get_context_data(self, **kwargs):
        kwargs['selected_tab'] = 'attachments'
        return ArticleMixin.get_context_data(self, **kwargs)
예제 #3
0
class AttachmentAddView(ArticleMixin, View):
    @method_decorator(get_article(can_write=True))
    def dispatch(self, request, article, attachment_id, *args, **kwargs):
        self.attachment = get_object_or_404(
            models.Attachment.objects.active().can_write(request.user),
            id=attachment_id)
        return super(AttachmentAddView, self).dispatch(request, article, *args,
                                                       **kwargs)

    def post(self, request, *args, **kwargs):
        if self.attachment.articles.filter(id=self.article.id):
            self.attachment.articles.add(self.article)
            self.attachment.save()
        messages.success(
            self.request,
            _(u'Added a reference to "%(att)s" from "%(art)s".') % {
                'att': self.attachment.original_filename,
                'art': self.article.current_revision.title
            })
        return redirect("wiki:attachments_index",
                        path=self.urlpath.path,
                        article_id=self.article.id)
예제 #4
0
class AttachmentSearchView(ArticleMixin, ListView):

    template_name = "wiki/plugins/attachments/search.html"
    allow_empty = True
    context_object_name = 'attachments'
    paginate_by = 10

    @method_decorator(get_article(can_write=True))
    def dispatch(self, request, article, *args, **kwargs):
        return super(AttachmentSearchView, self).dispatch(
            request,
            article,
            *args,
            **kwargs
        )

    def get_queryset(self):
        self.query = self.request.GET.get('query', None)
        if not self.query:
            qs = models.Attachment.objects.none()
        else:
            qs = models.Attachment.objects.active().can_read(self.request.user)
            qs = qs.filter(
                Q(original_filename__contains=self.query) |
                Q(current_revision__description__contains=self.query) |
                Q(article__current_revision__title__contains=self.query))
        return qs

    def get_context_data(self, **kwargs):
        # Is this a bit of a hack? Use better inheritance?
        kwargs_article = ArticleMixin.get_context_data(self, **kwargs)
        kwargs_listview = ListView.get_context_data(self, **kwargs)
        kwargs['search_form'] = forms.SearchForm(self.request.GET)
        kwargs['query'] = self.query
        kwargs.update(kwargs_article)
        kwargs.update(kwargs_listview)
        kwargs['selected_tab'] = 'attachments'
        return kwargs
예제 #5
0
class AttachmentHistoryView(ArticleMixin, TemplateView):

    template_name = "wiki/plugins/attachments/history.html"

    @method_decorator(get_article(can_read=True))
    def dispatch(self, request, article, attachment_id, *args, **kwargs):
        if article.can_moderate(request.user):
            self.attachment = get_object_or_404(models.Attachment,
                                                id=attachment_id,
                                                articles=article)
        else:
            self.attachment = get_object_or_404(
                models.Attachment.objects.active(),
                id=attachment_id,
                articles=article)
        return super().dispatch(request, article, *args, **kwargs)

    def get_context_data(self, **kwargs):
        kwargs["attachment"] = self.attachment
        kwargs["revisions"] = self.attachment.attachmentrevision_set.all(
        ).order_by("-revision_number")
        kwargs["selected_tab"] = "attachments"
        return super().get_context_data(**kwargs)
예제 #6
0
class History(ListView, ArticleMixin):

    template_name = "wiki/history.html"
    allow_empty = True
    context_object_name = 'revisions'
    paginate_by = 10

    def get_queryset(self):
        return models.ArticleRevision.objects.filter(
            article=self.article).order_by('-created')

    def get_context_data(self, **kwargs):
        # Is this a bit of a hack? Use better inheritance?
        kwargs_article = ArticleMixin.get_context_data(self, **kwargs)
        kwargs_listview = ListView.get_context_data(self, **kwargs)
        kwargs.update(kwargs_article)
        kwargs.update(kwargs_listview)
        kwargs['selected_tab'] = 'history'
        return kwargs

    @method_decorator(get_article(can_read=True))
    def dispatch(self, request, article, *args, **kwargs):
        return super(History, self).dispatch(request, article, *args, **kwargs)
예제 #7
0
class QueryUrlPath(View):

    # TODO: get_article does not actually support JSON responses
    @method_decorator(json_view)
    @method_decorator(get_article(can_read=True))
    def dispatch(self, request, article, *args, **kwargs):
        max_num = kwargs.pop('max_num', 20)
        # TODO: Move this import when circularity issue is resolved
        # https://github.com/benjaoming/django-wiki/issues/23
        query = request.GET.get('query', None)

        if query:
            matches = models.URLPath.objects.can_read(
                request.user).active().filter(
                    article__current_revision__title__contains=query,
                    article__current_revision__deleted=False,
                )
            matches = matches.select_related_common()
            return [("[%s](wiki:%s)") %
                    (m.article.current_revision.title, '/' + m.path.strip("/"))
                    for m in matches[:max_num]]

        return []
예제 #8
0
파일: views.py 프로젝트: nert-nlp/Xposition
class MetadataView(LoginRequiredMixin, ArticleMixin, TemplateView):
    template_name = "metadata.html"
    login_url = 'wiki:login'

    @method_decorator(get_article(can_read=True))
    def dispatch(self, request, article, *args, **kwargs):
        self.request = request  # TODO: find out why this is necessary
        return super(MetadataView, self).dispatch(request, article, *args,
                                                  **kwargs)

    def get_context_data(self, **kwargs):
        try:
            models.SimpleMetadata.objects.get(article=Article.objects.get(
                urlpath=URLPath.objects.get(slug='supersenses')))
            models.SimpleMetadata.objects.get(article=Article.objects.get(
                urlpath=URLPath.objects.get(slug='construals')))
            kwargs['install'] = ''
        except (URLPath.DoesNotExist, Article.DoesNotExist,
                models.SimpleMetadata.DoesNotExist):
            kwargs['install'] = mark_safe(
                '<h2><a href="installmetadata">Install metadata</a></h2>')

        return super().get_context_data(**kwargs)
예제 #9
0
파일: views.py 프로젝트: dodo42/web
class EventListView(ListView):
    template_name = "trojsten/events/event_list.html"
    model = EventType
    context_object_name = "event_types"

    # Hodnoty sa pridaju v dispatch()
    article = None
    urlpath = None

    def get_queryset(self):
        return EventType.objects.current_site_only().prefetch_related(
            "event_set")

    @method_decorator(get_article(can_read=True))
    def dispatch(self, request, article, *args, **kwargs):
        self.article = article
        self.urlpath = kwargs.get("urlpath", None)
        return super(EventListView, self).dispatch(request, *args, **kwargs)

    def get_context_data(self, **kwargs):
        context = super(EventListView, self).get_context_data(**kwargs)
        context.update({"article": self.article, "urlpath": self.urlpath})
        return context
예제 #10
0
class Preview(ArticleMixin, TemplateView):
    
    template_name="wiki/preview_inline.html"
    
    @method_decorator(get_article(can_read=True, deleted_contents=True))
    def dispatch(self, request, article, *args, **kwargs):
        revision_id = request.GET.get('r', None)
        self.title = None
        self.content = None
        self.preview = False
        if revision_id:
            self.revision = get_object_or_404(models.ArticleRevision, article=article, id=revision_id)
        else:
            self.revision = None
        return super(Preview, self).dispatch(request, article, *args, **kwargs)
    
    def post(self, request, *args, **kwargs):
        edit_form = forms.EditForm(request, self.article.current_revision, request.POST, preview=True)
        if edit_form.is_valid():
            self.title = edit_form.cleaned_data['title']
            self.content = edit_form.cleaned_data['content']
            self.preview = True
        return super(Preview, self).get(request, *args, **kwargs)
        
    def get(self, request, *args, **kwargs):
        if self.revision and not self.title:
            self.title = self.revision.title
        if self.revision and not self.content:
            self.content = self.revision.content
        return super(Preview, self).get( request, *args, **kwargs)
    
    def get_context_data(self, **kwargs):
        kwargs['title'] = self.title
        kwargs['revision'] = self.revision
        kwargs['content'] = self.content
        kwargs['preview'] = self.preview
        return ArticleMixin.get_context_data(self, **kwargs)
예제 #11
0
class QueryUrlPath(View):

    @method_decorator(get_article(can_read=True))
    def dispatch(self, request, article, *args, **kwargs):
        max_num = kwargs.pop('max_num', 20)
        query = request.GET.get('query', None)

        matches = []

        if query:
            matches = models.URLPath.objects.can_read(
                request.user).active().filter(
                article__current_revision__title__contains=query,
                article__current_revision__deleted=False,
            )
            matches = matches.select_related_common()
            matches = [
                "[{title:s}](wiki:{url:s})".format(
                    title=m.article.current_revision.title,
                    url='/' + m.path.strip("/")
                ) for m in matches[:max_num]
            ]

        return object_to_json_response(matches)
예제 #12
0
class RevisionAddView(ArticleMixin, FormView):

    template_name = "wiki/plugins/images/revision_add.html"
    form_class = forms.RevisionForm

    @method_decorator(get_article(can_write=True, not_locked=True))
    def dispatch(self, request, article, *args, **kwargs):
        self.image = get_object_or_404(models.Image,
                                       article=article,
                                       id=kwargs.get('image_id', None))
        if not self.image.can_write(request.user):
            return redirect(wiki_settings.LOGIN_URL)
        return ArticleMixin.dispatch(self, request, article, *args, **kwargs)

    def get_form_kwargs(self, **kwargs):
        kwargs = super(RevisionAddView, self).get_form_kwargs(**kwargs)
        kwargs['image'] = self.image
        kwargs['request'] = self.request
        return kwargs

    def get_context_data(self, **kwargs):
        kwargs = super(RevisionAddView, self).get_context_data(**kwargs)
        kwargs['image'] = self.image
        return kwargs

    def form_valid(self, form, **kwargs):
        form.save()
        messages.info(
            self.request,
            _('%(file)s has been saved.') % {
                'file':
                self.image.current_revision.imagerevision.get_filename(),
            })
        if self.urlpath:
            return redirect('wiki:edit', path=self.urlpath.path)
        return redirect('wiki:edit', article_id=self.article.id)
예제 #13
0
class AttachmentDownloadView(ArticleMixin, View):
    @method_decorator(get_article(can_read=True))
    def dispatch(self, request, article, attachment_id, *args, **kwargs):
        if article.can_moderate(request.user):
            self.attachment = get_object_or_404(models.Attachment,
                                                id=attachment_id,
                                                articles=article)
        else:
            self.attachment = get_object_or_404(
                models.Attachment.objects.active(),
                id=attachment_id,
                articles=article)
        revision_id = kwargs.get("revision_id", None)
        if revision_id:
            self.revision = get_object_or_404(models.AttachmentRevision,
                                              id=revision_id,
                                              attachment__articles=article)
        else:
            self.revision = self.attachment.current_revision
        return super().dispatch(request, article, *args, **kwargs)

    def get(self, request, *args, **kwargs):
        if self.revision:
            if settings.USE_LOCAL_PATH:
                try:
                    return send_file(
                        request,
                        self.revision.file.path,
                        self.revision.created,
                        self.attachment.original_filename,
                    )
                except OSError:
                    pass
            else:
                return HttpResponseRedirect(self.revision.file.url)
        raise Http404
예제 #14
0
class Edit(ArticleMixin, FormView):
    """Edit an article and process sidebar plugins."""

    form_class = forms.EditForm
    template_name = "wiki/edit.html"

    @method_decorator(get_article(can_write=True, not_locked=True))
    def dispatch(self, request, article, *args, **kwargs):
        self.sidebar_plugins = plugin_registry.get_sidebar()
        self.sidebar = []
        return super(Edit, self).dispatch(request, article, *args, **kwargs)

    def get_initial(self):
        initial = FormView.get_initial(self)

        for field_name in ['title', 'content']:
            session_key = 'unsaved_article_%s_%d' % (field_name,
                                                     self.article.id)
            if session_key in list(self.request.session.keys()):
                content = self.request.session[session_key]
                initial[field_name] = content
                del self.request.session[session_key]
        return initial

    def get_form(self, form_class=None):
        """
        Checks from querystring data that the edit form is actually being saved,
        otherwise removes the 'data' and 'files' kwargs from form initialisation.
        """
        if form_class is None:
            form_class = self.get_form_class()
        kwargs = self.get_form_kwargs()
        if self.request.POST.get(
                'save', '') != '1' and self.request.POST.get('preview') != '1':
            kwargs['data'] = None
            kwargs['files'] = None
            kwargs['no_clean'] = True
        return form_class(self.request, self.article.current_revision,
                          **kwargs)

    def get_sidebar_form_classes(self):
        """Returns dictionary of form classes for the sidebar. If no form class is
        specified, puts None in dictionary. Keys in the dictionary are used
        to identify which form is being saved."""
        form_classes = {}
        for cnt, plugin in enumerate(self.sidebar_plugins):
            form_classes['form%d' % cnt] = (plugin,
                                            plugin.sidebar.get(
                                                'form_class', None))
        return form_classes

    def get(self, request, *args, **kwargs):
        # Generate sidebar forms
        self.sidebar_forms = []
        for form_id, (plugin,
                      Form) in list(self.get_sidebar_form_classes().items()):
            if Form:
                form = Form(self.article, self.request.user)
                setattr(form, 'form_id', form_id)
            else:
                form = None
            self.sidebar.append((plugin, form))
        return super(Edit, self).get(request, *args, **kwargs)

    def post(self, request, *args, **kwargs):
        # Generate sidebar forms
        self.sidebar_forms = []
        for form_id, (plugin,
                      Form) in list(self.get_sidebar_form_classes().items()):
            if Form:
                if form_id == self.request.GET.get('f', None):
                    form = Form(self.article,
                                self.request,
                                data=self.request.POST,
                                files=self.request.FILES)
                    if form.is_valid():
                        form.save()
                        usermessage = form.get_usermessage()
                        if usermessage:
                            messages.success(self.request, usermessage)
                        else:
                            messages.success(self.request,
                                             _('Your changes were saved.'))

                        title = form.cleaned_data['unsaved_article_title']
                        content = form.cleaned_data['unsaved_article_content']

                        if title != self.article.current_revision.title or content != self.article.current_revision.content:
                            request.session['unsaved_article_title_%d' %
                                            self.article.id] = title
                            request.session['unsaved_article_content_%d' %
                                            self.article.id] = content
                            messages.warning(
                                request,
                                _('Please note that your article text has not yet been saved!'
                                  ))

                        if self.urlpath:
                            return redirect('wiki:edit',
                                            path=self.urlpath.path)
                        return redirect('wiki:edit',
                                        article_id=self.article.id)

                else:
                    form = Form(self.article, self.request)
                setattr(form, 'form_id', form_id)
            else:
                form = None
            self.sidebar.append((plugin, form))
        return super(Edit, self).post(request, *args, **kwargs)

    def form_valid(self, form):
        """Create a new article revision when the edit form is valid
        (does not concern any sidebar forms!)."""
        revision = models.ArticleRevision()
        revision.inherit_predecessor(self.article)
        revision.title = form.cleaned_data['title']
        revision.content = form.cleaned_data['content']
        revision.user_message = form.cleaned_data['summary']
        revision.deleted = False
        revision.set_from_request(self.request)
        self.article.add_revision(revision)
        messages.success(
            self.request,
            _('A new revision of the article was successfully added.'))
        return self.get_success_url()

    def get_success_url(self):
        """Go to the article view page when the article has been saved"""
        if self.urlpath:
            return redirect("wiki:get", path=self.urlpath.path)
        return redirect('wiki:get', article_id=self.article.id)

    def get_context_data(self, **kwargs):
        # Needed for Django 1.9 because get_context_data is no longer called
        # with the form instance
        if 'form' not in kwargs:
            kwargs['form'] = self.get_form()
        kwargs['edit_form'] = kwargs['form']
        kwargs['editor'] = editors.getEditor()
        kwargs['selected_tab'] = 'edit'
        kwargs['sidebar'] = self.sidebar
        return super(Edit, self).get_context_data(**kwargs)
예제 #15
0
class Delete(FormView, ArticleMixin):

    form_class = forms.DeleteForm
    template_name = "wiki/delete.html"

    @method_decorator(
        get_article(can_write=True, not_locked=True, can_delete=True))
    def dispatch(self, request, article, *args, **kwargs):
        return self.dispatch1(request, article, *args, **kwargs)

    def dispatch1(self, request, article, *args, **kwargs):
        """Deleted view needs to access this method without a decorator,
        therefore it is separate."""
        urlpath = kwargs.get('urlpath', None)
        # Where to go after deletion...
        self.next = ""
        self.cannot_delete_root = False
        if urlpath and urlpath.parent:
            self.next = reverse('wiki:get',
                                kwargs={'path': urlpath.parent.path})
        elif urlpath:
            # We are a urlpath with no parent. This is the root
            self.cannot_delete_root = True
        else:
            # We have no urlpath. Get it if a urlpath exists
            for art_obj in article.articleforobject_set.filter(is_mptt=True):
                if art_obj.content_object.parent:
                    self.next = reverse(
                        'wiki:get',
                        kwargs={
                            'article_id':
                            art_obj.content_object.parent.article.id
                        })
                else:
                    self.cannot_delete_root = True

        return super(Delete, self).dispatch(request, article, *args, **kwargs)

    def get_initial(self):
        return {'revision': self.article.current_revision}

    def get_form(self, form_class=None):
        form = super(Delete, self).get_form(form_class=form_class)
        if self.article.can_moderate(self.request.user):
            form.fields['purge'].widget = forms.forms.CheckboxInput()
        return form

    def get_form_kwargs(self):
        kwargs = FormView.get_form_kwargs(self)
        kwargs['article'] = self.article
        kwargs['has_children'] = bool(self.children_slice)
        return kwargs

    def form_valid(self, form):
        cd = form.cleaned_data

        purge = cd['purge']

        # If we are purging, only moderators can delete articles with children
        cannot_delete_children = False
        can_moderate = self.article.can_moderate(self.request.user)
        if purge and self.children_slice and not can_moderate:
            cannot_delete_children = True

        if self.cannot_delete_root or cannot_delete_children:
            messages.error(
                self.request,
                _('This article cannot be deleted because it has children or is a root article.'
                  ))
            return redirect('wiki:get', article_id=self.article.id)

        if can_moderate and purge:
            # First, remove children
            if self.urlpath:
                self.urlpath.delete_subtree()
            self.article.delete()
            messages.success(
                self.request,
                _('This article together with all its contents are now completely gone! Thanks!'
                  ))
        else:
            revision = models.ArticleRevision()
            revision.inherit_predecessor(self.article)
            revision.set_from_request(self.request)
            revision.deleted = True
            self.article.add_revision(revision)
            messages.success(
                self.request,
                _('The article "%s" is now marked as deleted! Thanks for keeping the site free from unwanted material!'
                  ) % revision.title)
        return self.get_success_url()

    def get_success_url(self):
        return redirect(self.next)

    def get_context_data(self, **kwargs):
        cannot_delete_children = False
        if self.children_slice and not self.article.can_moderate(
                self.request.user):
            cannot_delete_children = True

        # Needed since Django 1.9 because get_context_data is no longer called
        # with the form instance
        if 'form' not in kwargs:
            kwargs['form'] = self.get_form()
        kwargs['delete_form'] = kwargs.pop('form', None)
        kwargs['cannot_delete_root'] = self.cannot_delete_root
        kwargs['delete_children'] = self.children_slice[:20]
        kwargs['delete_children_more'] = len(self.children_slice) > 20
        kwargs['cannot_delete_children'] = cannot_delete_children
        return super(Delete, self).get_context_data(**kwargs)
예제 #16
0
class AttachmentView(ArticleMixin, FormView):

    form_class = forms.AttachmentForm
    template_name = "wiki/plugins/attachments/index.html"

    @method_decorator(get_article(can_read=True))
    def dispatch(self, request, article, *args, **kwargs):
        if article.can_moderate(request.user):
            self.attachments = models.Attachment.objects.filter(
                articles=article, current_revision__deleted=False
            ).exclude(
                current_revision__file=None
            ).order_by('original_filename')

            self.form_class = forms.AttachmentArchiveForm
        else:
            self.attachments = models.Attachment.objects.active().filter(
                articles=article)

        # Fixing some weird transaction issue caused by adding commit_manually
        # to form_valid
        return super(
            AttachmentView,
            self).dispatch(
            request,
            article,
            *args,
            **kwargs)

    def form_valid(self, form):

        if (self.request.user.is_anonymous() and not settings.ANONYMOUS or
                not self.article.can_write(self.request.user) or
                self.article.current_revision.locked):
            return response_forbidden(self.request, self.article, self.urlpath)

        attachment_revision = form.save()
        if isinstance(attachment_revision, list):
            messages.success(
                self.request, _('Successfully added: %s') %
                (", ".join(
                    [ar.get_filename() for ar in attachment_revision])))
        else:
            messages.success(
                self.request,
                _('%s was successfully added.') %
                attachment_revision.get_filename())
        self.article.clear_cache()

        return redirect(
            "wiki:attachments_index",
            path=self.urlpath.path,
            article_id=self.article.id)

    def get_form_kwargs(self):
        kwargs = super(AttachmentView, self).get_form_kwargs()
        kwargs['article'] = self.article
        kwargs['request'] = self.request
        return kwargs

    def get_context_data(self, **kwargs):
        kwargs['attachments'] = self.attachments
        kwargs['deleted_attachments'] = models.Attachment.objects.filter(
            articles=self.article,
            current_revision__deleted=True)
        kwargs['search_form'] = forms.SearchForm()
        kwargs['selected_tab'] = 'attachments'
        kwargs['anonymous_disallowed'] = self.request.user.is_anonymous(
        ) and not settings.ANONYMOUS
        return super(AttachmentView, self).get_context_data(**kwargs)
예제 #17
0
class AttachmentReplaceView(ArticleMixin, FormView):

    form_class = forms.AttachmentForm
    template_name = "wiki/plugins/attachments/replace.html"

    @method_decorator(get_article(can_write=True, not_locked=True))
    def dispatch(self, request, article, attachment_id, *args, **kwargs):
        if request.user.is_anonymous() and not settings.ANONYMOUS:
            return response_forbidden(
                request,
                article,
                kwargs.get(
                    'urlpath',
                    None))
        if article.can_moderate(request.user):
            self.attachment = get_object_or_404(
                models.Attachment,
                id=attachment_id,
                articles=article)
            self.can_moderate = True
        else:
            self.attachment = get_object_or_404(
                models.Attachment.objects.active(),
                id=attachment_id,
                articles=article)
            self.can_moderate = False
        return super(
            AttachmentReplaceView,
            self).dispatch(
            request,
            article,
            *args,
            **kwargs)

    def get_form_class(self):
        if self.can_moderate:
            return forms.AttachmentReplaceForm
        else:
            return forms.AttachmentForm

    def form_valid(self, form):

        try:
            attachment_revision = form.save(commit=True)
            attachment_revision.set_from_request(self.request)
            attachment_revision.previous_revision = self.attachment.current_revision
            attachment_revision.save()
            self.attachment.current_revision = attachment_revision
            self.attachment.save()
            messages.success(
                self.request,
                _('%s uploaded and replaces old attachment.') %
                attachment_revision.get_filename())
            self.article.clear_cache()
        except models.IllegalFileExtension as e:
            messages.error(
                self.request,
                _('Your file could not be saved: %s') %
                e)
            return redirect(
                "wiki:attachments_replace",
                attachment_id=self.attachment.id,
                path=self.urlpath.path,
                article_id=self.article.id)

        if self.can_moderate:
            if form.cleaned_data['replace']:
                # form has no cleaned_data field unless self.can_moderate is True
                try:
                    most_recent_revision = self.attachment.attachmentrevision_set.exclude(
                        id=attachment_revision.id,
                        created__lte=attachment_revision.created).latest()
                    most_recent_revision.delete()
                except ObjectDoesNotExist:
                    msg = "{attachment} does not contain any revisions.".format(\
                        attachment=str(self.attachment.original_filename))
                    messages.error(self.request, msg)

        return redirect(
            "wiki:attachments_index",
            path=self.urlpath.path,
            article_id=self.article.id)

    def get_form(self, form_class=None):
        form = super(AttachmentReplaceView, self).get_form(form_class=form_class)
        form.fields['file'].help_text = _(
            'Your new file will automatically be renamed to match the file already present. Files with different extensions are not allowed.')
        return form

    def get_form_kwargs(self):
        kwargs = super(AttachmentReplaceView, self).get_form_kwargs()
        kwargs['article'] = self.article
        kwargs['request'] = self.request
        kwargs['attachment'] = self.attachment
        return kwargs

    def get_initial(self, **kwargs):
        return {'description': self.attachment.current_revision.description}

    def get_context_data(self, **kwargs):
        kwargs['attachment'] = self.attachment
        kwargs['selected_tab'] = 'attachments'
        return super(AttachmentReplaceView, self).get_context_data(**kwargs)
예제 #18
0
class MergeView(View):
    preview = False
    template_name = "wiki/preview_inline.html"
    template_error_name = "wiki/error.html"
    urlpath = None

    @method_decorator(get_article(can_write=True))
    def dispatch(self, request, article, revision_id, *args, **kwargs):
        return super().dispatch(request, article, revision_id, *args, **kwargs)

    def get(self, request, article, revision_id, *args, **kwargs):
        revision = get_object_or_404(models.ArticleRevision,
                                     article=article,
                                     id=revision_id)

        current_text = article.current_revision.content if article.current_revision else ""
        new_text = revision.content

        content = simple_merge(current_text, new_text)

        # Save new revision
        if not self.preview:
            old_revision = article.current_revision

            if revision.deleted:
                c = {
                    'error_msg': _('You cannot merge with a deleted revision'),
                    'article': article,
                    'urlpath': self.urlpath
                }
                return render(request, self.template_error_name, context=c)

            new_revision = models.ArticleRevision()
            new_revision.inherit_predecessor(article)
            new_revision.deleted = False
            new_revision.locked = False
            new_revision.title = article.current_revision.title
            new_revision.content = content
            new_revision.automatic_log = (
                _('Merge between revision #%(r1)d and revision #%(r2)d') % {
                    'r1': revision.revision_number,
                    'r2': old_revision.revision_number
                })
            article.add_revision(new_revision, save=True)

            old_revision.simpleplugin_set.all().update(
                article_revision=new_revision)
            revision.simpleplugin_set.all().update(
                article_revision=new_revision)

            messages.success(
                request,
                _('A new revision was created: Merge between revision #%(r1)d and revision #%(r2)d'
                  ) % {
                      'r1': revision.revision_number,
                      'r2': old_revision.revision_number
                  })
            if self.urlpath:
                return redirect('wiki:edit', path=self.urlpath.path)
            else:
                return redirect('wiki:edit', article_id=article.id)

        c = {
            'article': article,
            'title': article.current_revision.title,
            'revision': None,
            'merge1': revision,
            'merge2': article.current_revision,
            'merge': True,
            'content': content
        }
        return render(request, self.template_name, c)
예제 #19
0
class Deleted(Delete):
    """Tell a user that an article has been deleted. If user has permissions,
    let user restore and possibly purge the deleted article and children."""

    template_name = "wiki/deleted.html"
    form_class = forms.DeleteForm

    @method_decorator(get_article(can_read=True, deleted_contents=True))
    def dispatch(self, request, article, *args, **kwargs):

        self.urlpath = kwargs.get("urlpath", None)
        self.article = article

        if self.urlpath:
            deleted_ancestor = self.urlpath.first_deleted_ancestor()
            if deleted_ancestor is None:
                # No one is deleted!
                return redirect("wiki:get", path=self.urlpath.path)
            elif deleted_ancestor != self.urlpath:
                # An ancestor was deleted, so redirect to that deleted page
                return redirect("wiki:deleted", path=deleted_ancestor.path)

        else:
            if not article.current_revision.deleted:
                return redirect("wiki:get", article_id=article.id)

        # Restore
        if request.GET.get("restore", False):
            can_restore = not article.current_revision.locked and article.can_delete(
                request.user)
            can_restore = can_restore or article.can_moderate(request.user)

            if can_restore:
                revision = models.ArticleRevision()
                revision.inherit_predecessor(self.article)
                revision.set_from_request(request)
                revision.deleted = False
                revision.automatic_log = _("Restoring article")
                self.article.add_revision(revision)
                messages.success(
                    request,
                    _('The article "%s" and its children are now restored.') %
                    revision.title,
                )
                if self.urlpath:
                    return redirect("wiki:get", path=self.urlpath.path)
                else:
                    return redirect("wiki:get", article_id=article.id)

        return super().dispatch1(request, article, *args, **kwargs)

    def get_initial(self):
        return {
            "revision": self.article.current_revision,
            "purge": True,
        }

    def get_context_data(self, **kwargs):
        kwargs["purge_form"] = self.get_form()
        kwargs["form"] = kwargs["purge_form"]
        return super().get_context_data(**kwargs)
예제 #20
0
class Create(FormView, ArticleMixin):
    form_class = forms.CreateForm
    template_name = "wiki/create.html"

    @method_decorator(get_article(can_write=True, can_create=True))
    def dispatch(self, request, article, *args, **kwargs):
        return super().dispatch(request, article, *args, **kwargs)

    def get_form(self, form_class=None):
        """
        Returns an instance of the form to be used in this view.
        """
        if form_class is None:
            form_class = self.get_form_class()
        kwargs = self.get_form_kwargs()
        initial = kwargs.get("initial", {})
        initial["slug"] = self.request.GET.get("slug", None)
        kwargs["initial"] = initial
        form = form_class(self.request, self.urlpath, **kwargs)
        form.fields["slug"].widget = forms.TextInputPrepend(
            prepend="/" + self.urlpath.path,
            attrs={
                # Make patterns force lowercase if we are case insensitive to bless the user with a
                # bit of strictness, anyways
                "pattern":
                "[a-z0-9_-]+"
                if not settings.URL_CASE_SENSITIVE else "[a-zA-Z0-9_-]+",
                "title":
                "Lowercase letters, numbers, hyphens and underscores"
                if not settings.URL_CASE_SENSITIVE else
                "Letters, numbers, hyphens and underscores",
            },
        )
        return form

    def form_valid(self, form):
        try:
            self.newpath = models.URLPath._create_urlpath_from_request(
                self.request,
                self.article,
                self.urlpath,
                form.cleaned_data["slug"],
                form.cleaned_data["title"],
                form.cleaned_data["content"],
                form.cleaned_data["summary"],
            )
            messages.success(
                self.request,
                _("New article '%s' created.") %
                self.newpath.article.current_revision.title,
            )
        # TODO: Handle individual exceptions better and give good feedback.
        except Exception as e:
            log.exception("Exception creating article.")
            if self.request.user.is_superuser:
                messages.error(
                    self.request,
                    _("There was an error creating this article: %s") % str(e),
                )
            else:
                messages.error(self.request,
                               _("There was an error creating this article."))
            return redirect("wiki:get", "")

        return self.get_success_url()

    def get_success_url(self):
        return redirect("wiki:get", self.newpath.path)

    def get_context_data(self, **kwargs):
        c = ArticleMixin.get_context_data(self, **kwargs)
        c["form"] = self.get_form()
        c["parent_urlpath"] = self.urlpath
        c["parent_article"] = self.article
        c["create_form"] = c.pop("form", None)
        c["editor"] = editors.getEditor()
        return c
예제 #21
0
class AttachmentReplaceView(ArticleMixin, FormView):

    form_class = forms.AttachmentForm
    template_name = "wiki/plugins/attachments/replace.html"

    @method_decorator(get_article(can_write=True, not_locked=True))
    def dispatch(self, request, article, attachment_id, *args, **kwargs):
        if request.user.is_anonymous() and not settings.ANONYMOUS:
            return response_forbidden(request, article,
                                      kwargs.get('urlpath', None))
        if article.can_moderate(request.user):
            self.attachment = get_object_or_404(models.Attachment,
                                                id=attachment_id,
                                                articles=article)
            self.can_moderate = True
        else:
            self.attachment = get_object_or_404(
                models.Attachment.objects.active(),
                id=attachment_id,
                articles=article)
            self.can_moderate = False
        return super(AttachmentReplaceView,
                     self).dispatch(request, article, *args, **kwargs)

    def get_form_class(self):
        if self.can_moderate:
            return forms.AttachmentReplaceForm
        else:
            return forms.AttachmentForm

    def form_valid(self, form):

        try:
            attachment_revision = form.save(commit=True)
            attachment_revision.set_from_request(self.request)
            attachment_revision.previous_revision = self.attachment.current_revision
            attachment_revision.save()
            self.attachment.current_revision = attachment_revision
            self.attachment.save()
            messages.success(
                self.request,
                _(u'%s uploaded and replaces old attachment.') %
                attachment_revision.get_filename())
        except models.IllegalFileExtension, e:
            messages.error(self.request,
                           _(u'Your file could not be saved: %s') % e)
            return redirect("wiki:attachments_replace",
                            attachment_id=self.attachment.id,
                            path=self.urlpath.path,
                            article_id=self.article.id)

        if self.can_moderate:
            older_revisions = self.attachment.attachmentrevision_set.exclude(
                id=attachment_revision.id,
                created__lte=attachment_revision.created,
            )
            # Because of signalling, the files are automatically removed...
            older_revisions.delete()

        return redirect("wiki:attachments_index",
                        path=self.urlpath.path,
                        article_id=self.article.id)
예제 #22
0
class Create(FormView, ArticleMixin):

    form_class = forms.CreateForm
    template_name = "wiki/create.html"

    @method_decorator(get_article(can_write=True, can_create=True))
    def dispatch(self, request, article, *args, **kwargs):

        return super(Create, self).dispatch(request, article, *args, **kwargs)

    def get_form(self, form_class):
        """
        Returns an instance of the form to be used in this view.
        """
        kwargs = self.get_form_kwargs()
        initial = kwargs.get('initial', {})
        initial['slug'] = self.request.GET.get('slug', None)
        kwargs['initial'] = initial
        form = form_class(self.request, self.urlpath, **kwargs)
        form.fields['slug'].widget = forms.TextInputPrepend(
            prepend='/' + self.urlpath.path,
            attrs={
                # Make patterns force lowercase if we are case insensitive to bless the user with a
                # bit of strictness, anyways
                'pattern':
                '[a-z0-9_]+'
                if not settings.URL_CASE_SENSITIVE else '[a-zA-Z0-9_]+',
                'title':
                'Lowercase letters, numbers, and underscores'
                if not settings.URL_CASE_SENSITIVE else
                'Letters, numbers, and underscores',
            })
        return form

    def form_valid(self, form):
        user = None
        ip_address = None
        if not self.request.user.is_anonymous():
            user = self.request.user
            if settings.LOG_IPS_USERS:
                ip_address = self.request.META.get('REMOTE_ADDR', None)
        elif settings.LOG_IPS_ANONYMOUS:
            ip_address = self.request.META.get('REMOTE_ADDR', None)

        try:
            self.newpath = models.URLPath.create_article(
                self.urlpath,
                form.cleaned_data['slug'],
                title=form.cleaned_data['title'],
                content=form.cleaned_data['content'],
                user_message=form.cleaned_data['summary'],
                user=user,
                ip_address=ip_address,
                article_kwargs={
                    'owner': user,
                    'group': self.article.group,
                    'group_read': self.article.group_read,
                    'group_write': self.article.group_write,
                    'other_read': self.article.other_read,
                    'other_write': self.article.other_write,
                })
            messages.success(
                self.request,
                _("New article '%s' created.") %
                self.newpath.article.current_revision.title)
            transaction.commit()
        # TODO: Handle individual exceptions better and give good feedback.
        except Exception as e:
            log.exception("Exception creating article.")
            transaction.rollback()
            if self.request.user.is_superuser:
                messages.error(
                    self.request,
                    _("There was an error creating this article: %s") % str(e))
            else:
                messages.error(self.request,
                               _("There was an error creating this article."))
            return redirect('wiki:get', '')

        url = self.get_success_url()
        return url

    def get_success_url(self):
        return redirect('wiki:get', self.newpath.path)

    def get_context_data(self, **kwargs):
        c = ArticleMixin.get_context_data(self, **kwargs)
        c['parent_urlpath'] = self.urlpath
        c['parent_article'] = self.article
        c['create_form'] = kwargs.pop('form', None)
        c['editor'] = editors.getEditor()
        return c
예제 #23
0
class MergeView(View):
    preview = False
    template_name = "wiki/preview_inline.html"
    template_error_name = "wiki/error.html"
    urlpath = None

    @method_decorator(get_article(can_write=True))
    def dispatch(self, request, article, revision_id, *args, **kwargs):
        return super().dispatch(request, article, revision_id, *args, **kwargs)

    def get(self, request, article, revision_id, *args, **kwargs):
        revision = get_object_or_404(models.ArticleRevision,
                                     article=article,
                                     id=revision_id)

        current_text = (article.current_revision.content
                        if article.current_revision else "")
        new_text = revision.content

        content = simple_merge(current_text, new_text)

        # Save new revision
        if not self.preview:
            old_revision = article.current_revision

            if revision.deleted:
                c = {
                    "error_msg": _("You cannot merge with a deleted revision"),
                    "article": article,
                    "urlpath": self.urlpath,
                }
                return render(request, self.template_error_name, context=c)

            new_revision = models.ArticleRevision()
            new_revision.inherit_predecessor(article)
            new_revision.deleted = False
            new_revision.locked = False
            new_revision.title = article.current_revision.title
            new_revision.content = content
            new_revision.automatic_log = _(
                "Merge between revision #%(r1)d and revision #%(r2)d") % {
                    "r1": revision.revision_number,
                    "r2": old_revision.revision_number
                }
            article.add_revision(new_revision, save=True)

            old_revision.simpleplugin_set.all().update(
                article_revision=new_revision)
            revision.simpleplugin_set.all().update(
                article_revision=new_revision)

            messages.success(
                request,
                _("A new revision was created: Merge between revision #%(r1)d and revision #%(r2)d"
                  ) % {
                      "r1": revision.revision_number,
                      "r2": old_revision.revision_number
                  },
            )
            if self.urlpath:
                return redirect("wiki:edit", path=self.urlpath.path)
            else:
                return redirect("wiki:edit", article_id=article.id)

        c = {
            "article": article,
            "title": article.current_revision.title,
            "revision": None,
            "merge1": revision,
            "merge2": article.current_revision,
            "merge": True,
            "content": content,
        }
        return render(request, self.template_name, c)
예제 #24
0
class Deleted(Delete):
    """Tell a user that an article has been deleted. If user has permissions,
    let user restore and possibly purge the deleted article and children."""

    template_name = "wiki/deleted.html"
    form_class = forms.DeleteForm

    @method_decorator(get_article(can_read=True, deleted_contents=True))
    def dispatch(self, request, article, *args, **kwargs):

        self.urlpath = kwargs.get('urlpath', None)
        self.article = article

        if self.urlpath:
            deleted_ancestor = self.urlpath.first_deleted_ancestor()
            if deleted_ancestor is None:
                # No one is deleted!
                return redirect('wiki:get', path=self.urlpath.path)
            elif deleted_ancestor != self.urlpath:
                # An ancestor was deleted, so redirect to that deleted page
                return redirect('wiki:deleted', path=deleted_ancestor.path)

        else:
            if not article.current_revision.deleted:
                return redirect('wiki:get', article_id=article.id)

        # Restore
        if request.GET.get('restore', False):
            can_restore = not article.current_revision.locked and article.can_delete(
                request.user)
            can_restore = can_restore or article.can_moderate(request.user)

            if can_restore:
                revision = models.ArticleRevision()
                revision.inherit_predecessor(self.article)
                revision.set_from_request(request)
                revision.deleted = False
                revision.automatic_log = _('Restoring article')
                self.article.add_revision(revision)
                messages.success(
                    request,
                    _('The article "%s" and its children are now restored.') %
                    revision.title)
                if self.urlpath:
                    return redirect('wiki:get', path=self.urlpath.path)
                else:
                    return redirect('wiki:get', article_id=article.id)

        return super(Deleted, self).dispatch1(request, article, *args,
                                              **kwargs)

    def get_initial(self):
        return {'revision': self.article.current_revision, 'purge': True}

    def get_context_data(self, **kwargs):
        # Needed since Django 1.9 because get_context_data is no longer called
        # with the form instance
        if 'form' not in kwargs:
            kwargs['form'] = self.get_form()
        kwargs['purge_form'] = kwargs.pop('form', None)
        return super(Delete, self).get_context_data(**kwargs)
예제 #25
0
class Move(ArticleMixin, FormView):

    form_class = forms.MoveForm
    template_name = "wiki/move.html"

    @method_decorator(login_required)
    @method_decorator(get_article(can_write=True, not_locked=True))
    def dispatch(self, request, article, *args, **kwargs):
        return super(Move, self).dispatch(request, article, *args, **kwargs)

    def get_initial(self):
        initial = FormView.get_initial(self)
        return initial

    def get_form(self, form_class=None):
        if form_class is None:
            form_class = self.get_form_class()
        kwargs = self.get_form_kwargs()
        return form_class(**kwargs)

    def get_context_data(self, **kwargs):
        if 'form' not in kwargs:
            kwargs['form'] = self.get_form()
        kwargs['root_path'] = models.URLPath.root()

        return super(Move, self).get_context_data(**kwargs)

    @atomic
    @transaction_commit_on_success
    def form_valid(self, form):
        if not self.urlpath.parent:
            messages.error(
                self.request,
                _('This article cannot be moved because it is a root article.')
            )
            return redirect('wiki:get', article_id=self.article.id)

        dest_path = get_object_or_404(models.URLPath,
                                      pk=form.cleaned_data['destination'])
        tmp_path = dest_path

        while tmp_path.parent:
            if tmp_path == self.urlpath:
                messages.error(
                    self.request,
                    _('This article cannot be moved to a child of itself.'))
                return redirect('wiki:move', article_id=self.article.id)
            tmp_path = tmp_path.parent

        # Clear cache to update article lists (Old links)
        for ancestor in self.article.ancestor_objects():
            ancestor.article.clear_cache()

        # Save the old path for later
        old_path = self.urlpath.path

        self.urlpath.parent = dest_path
        self.urlpath.slug = form.cleaned_data['slug']
        self.urlpath.save()

        # Reload url path form database
        self.urlpath = models.URLPath.objects.get(pk=self.urlpath.pk)

        # Use a copy of ourself (to avoid cache) and update article links again
        for ancestor in models.Article.objects.get(
                pk=self.article.pk).ancestor_objects():
            ancestor.article.clear_cache()

        # Create a redirect page for every moved article
        # /old-slug
        # /old-slug/child
        # /old-slug/child/grand-child
        if form.cleaned_data['redirect']:

            # NB! Includes self!
            descendants = list(
                self.urlpath.get_descendants(
                    include_self=True).order_by("level"))

            root_len = len(descendants[0].path)

            for descendant in descendants:
                # Without this descendant.get_ancestors() and as a result
                # descendant.path is wrong after the first create_article() due
                # to path caching
                descendant.refresh_from_db()
                dst_path = descendant.path
                src_path = urljoin(old_path, dst_path[root_len:])
                src_len = len(src_path)
                pos = src_path.rfind("/", 0, src_len - 1)
                slug = src_path[pos + 1:src_len - 1]
                parent_urlpath = models.URLPath.get_by_path(
                    src_path[0:max(pos, 0)])

                link = "[wiki:/{path}](wiki:/{path})".format(path=dst_path)
                urlpath_new = models.URLPath._create_urlpath_from_request(
                    self.request,
                    self.article,
                    parent_urlpath,
                    slug,
                    _("Moved: {title}").format(title=descendant.article),
                    _("Article moved to {link}").format(link=link),
                    _("Created redirect (auto)"),
                )
                urlpath_new.moved_to = descendant
                urlpath_new.save()

            messages.success(
                self.request,
                _("Article successfully moved! Created {n} redirects.").format(
                    n=len(descendants)))

        else:
            messages.success(self.request, _('Article successfully moved!'))
        return redirect("wiki:get", path=self.urlpath.path)
예제 #26
0
class CategoryView(ArticleMixin, FormView):
    ''' This view manages the creation of new categories '''

    form_class = forms.ArticleCategoryForm
    template_name = "category_detail.html"

    @method_decorator(
        get_article(can_read=True, can_create=True), )
    def dispatch(self, request, article, *args, **kwargs):
        categories = Category.objects.filter(slug="maincat")

        return super(CategoryView, self).dispatch(request, article, *args,
                                                  **kwargs)

    def get_form_kwargs(self, **kwargs):
        kwargs = super(CategoryView, self).get_form_kwargs(**kwargs)
        #kwargs['article'] = self.article
        #kwargs['request'] = self.request
        return kwargs

    # Processing of category creation form goes here, modify the category creation process below
    def form_valid(self, form):
        clean_data = form.cleaned_data
        print(clean_data)
        slug = clean_data['slug']
        title = clean_data['name']
        content = clean_data['description']

        # creates an article for the category and then associates them by having equaling titles and slugs

        self.landing_article_urlpath = URLPath.create_article(
            URLPath.root(),
            slug,
            title=title,
            content=content,
            user_message=" ",
            user=self.request.user,
            article_kwargs={
                'owner': self.request.user,
                'group': self.article.group,
                'group_read': self.article.group_read,
                'group_write': self.article.group_write,
                'other_read': self.article.other_read,
                'other_write': self.article.other_write,
            })
        landing_article = Article.objects.get(
            urlpath=self.landing_article_urlpath)
        form.instance.article = landing_article
        form.save()
        category = Category.objects.get(slug=slug)
        return redirect("wiki:get",
                        path=self.landing_article_urlpath.path,
                        article_id=self.article.id)

    def get_form(self):
        form = super(CategoryView,
                     self).get_form(form_class=forms.ArticleCategoryForm)
        return form

    # Insert form and category list into context for retrieval in template

    def get_context_data(self, **kwargs):
        kwargs['categories'] = Category.objects.all()
        kwargs['form'] = self.get_form()
        kwargs = super(CategoryView, self).get_context_data(**kwargs)
        kwargs['article'] = self.article
        return kwargs
예제 #27
0
class Create(FormView, ArticleMixin):

    form_class = forms.CreateForm
    template_name = "wiki/create.html"

    @method_decorator(get_article(can_write=True, can_create=True))
    def dispatch(self, request, article, *args, **kwargs):

        return super(Create, self).dispatch(request, article, *args, **kwargs)

    def get_form(self, form_class=None):
        """
        Returns an instance of the form to be used in this view.
        """
        if form_class is None:
            form_class = self.get_form_class()
        kwargs = self.get_form_kwargs()
        initial = kwargs.get('initial', {})
        initial['slug'] = self.request.GET.get('slug', None)
        kwargs['initial'] = initial
        form = form_class(self.request, self.urlpath, **kwargs)
        form.fields['slug'].widget = forms.TextInputPrepend(
            prepend='/' + self.urlpath.path,
            attrs={
                # Make patterns force lowercase if we are case insensitive to bless the user with a
                # bit of strictness, anyways
                'pattern':
                '[a-z0-9_-]+'
                if not settings.URL_CASE_SENSITIVE else '[a-zA-Z0-9_-]+',
                'title':
                'Lowercase letters, numbers, hyphens and underscores'
                if not settings.URL_CASE_SENSITIVE else
                'Letters, numbers, hyphens and underscores',
            })
        return form

    def form_valid(self, form):
        try:
            self.newpath = models.URLPath._create_urlpath_from_request(
                self.request, self.article, self.urlpath,
                form.cleaned_data['slug'], form.cleaned_data['title'],
                form.cleaned_data['content'], form.cleaned_data['summary'])
            messages.success(
                self.request,
                _("New article '%s' created.") %
                self.newpath.article.current_revision.title)
        # TODO: Handle individual exceptions better and give good feedback.
        except Exception as e:
            log.exception("Exception creating article.")
            if self.request.user.is_superuser:
                messages.error(
                    self.request,
                    _("There was an error creating this article: %s") % str(e))
            else:
                messages.error(self.request,
                               _("There was an error creating this article."))
            return redirect('wiki:get', '')

        url = self.get_success_url()
        return url

    def get_success_url(self):
        return redirect('wiki:get', self.newpath.path)

    def get_context_data(self, **kwargs):
        c = ArticleMixin.get_context_data(self, **kwargs)
        # Needed since Django 1.9 because get_context_data is no longer called
        # with the form instance
        if 'form' not in c:
            c['form'] = self.get_form()
        c['parent_urlpath'] = self.urlpath
        c['parent_article'] = self.article
        c['create_form'] = c.pop('form', None)
        c['editor'] = editors.getEditor()
        return c
예제 #28
0
class AttachmentDeleteView(ArticleMixin, FormView):

    form_class = forms.DeleteForm
    template_name = "wiki/plugins/attachments/delete.html"

    @method_decorator(get_article(can_write=True, not_locked=True))
    def dispatch(self, request, article, attachment_id, *args, **kwargs):
        self.attachment = get_object_or_404(
            models.Attachment,
            id=attachment_id,
            articles=article)
        if not self.attachment.can_delete(request.user):
            return response_forbidden(
                request,
                article,
                kwargs.get(
                    'urlpath',
                    None))
        return super(
            AttachmentDeleteView,
            self).dispatch(
            request,
            article,
            *args,
            **kwargs)

    def form_valid(self, form):

        if self.attachment.article == self.article:
            revision = models.AttachmentRevision()
            revision.attachment = self.attachment
            revision.set_from_request(self.request)
            revision.deleted = True
            revision.file = self.attachment.current_revision.file if self.attachment.current_revision else None
            revision.description = self.attachment.current_revision.description if self.attachment.current_revision else ""
            revision.save()
            self.attachment.current_revision = revision
            self.attachment.save()
            self.article.clear_cache()
            messages.info(
                self.request,
                _('The file %s was deleted.') %
                self.attachment.original_filename)
        else:
            self.attachment.articles.remove(self.article)
            messages.info(
                self.request,
                _('This article is no longer related to the file %s.') %
                self.attachment.original_filename)
        self.article.clear_cache()
        return redirect(
            "wiki:get",
            path=self.urlpath.path,
            article_id=self.article.id)

    def get_context_data(self, **kwargs):
        kwargs['attachment'] = self.attachment
        kwargs['selected_tab'] = 'attachments'
        if 'form' not in kwargs:
            kwargs['form'] = self.get_form()
        return super(AttachmentDeleteView, self).get_context_data(**kwargs)
예제 #29
0
class Settings(ArticleMixin, TemplateView):

    permission_form_class = forms.PermissionsForm
    template_name = "wiki/settings.html"

    @method_decorator(login_required)
    @method_decorator(get_article(can_read=True))
    def dispatch(self, request, article, *args, **kwargs):
        return super(Settings, self).dispatch(request, article, *args,
                                              **kwargs)

    def get_form_classes(self, ):
        """
        Return all settings forms that can be filled in
        """
        settings_forms = []
        if permissions.can_change_permissions(self.article, self.request.user):
            settings_forms.append(self.permission_form_class)
        plugin_forms = [F for F in plugin_registry.get_settings_forms()]
        plugin_forms.sort(key=lambda form: form.settings_order)
        settings_forms += plugin_forms
        for i in range(len(settings_forms)):
            # TODO: Do not set an attribute on a form class - this
            # could be mixed up with a different instance
            # Use strategy from Edit view...
            setattr(settings_forms[i], 'action', 'form%d' % i)

        return settings_forms

    def post(self, *args, **kwargs):
        self.forms = []
        for Form in self.get_form_classes():
            if Form.action == self.request.GET.get('f', None):
                form = Form(self.article, self.request, self.request.POST)
                if form.is_valid():
                    form.save()
                    usermessage = form.get_usermessage()
                    if usermessage:
                        messages.success(self.request, usermessage)
                    if self.urlpath:
                        return redirect('wiki:settings',
                                        path=self.urlpath.path)
                    return redirect('wiki:settings',
                                    article_id=self.article.id)
            else:
                form = Form(self.article, self.request)
            self.forms.append(form)
        return super(Settings, self).get(*args, **kwargs)

    def get(self, *args, **kwargs):
        self.forms = []

        # There is a bug where articles fetched with select_related have bad boolean field https://code.djangoproject.com/ticket/15040
        # We fetch a fresh new article for this reason
        new_article = models.Article.objects.get(id=self.article.id)

        for Form in self.get_form_classes():
            self.forms.append(Form(new_article, self.request))

        return super(Settings, self).get(*args, **kwargs)

    def get_success_url(self):
        if self.urlpath:
            return redirect('wiki:settings', path=self.urlpath.path)
        return redirect('wiki:settings', article_id=self.article.id)

    def get_context_data(self, **kwargs):
        kwargs['selected_tab'] = 'settings'
        kwargs['forms'] = self.forms
        return super(Settings, self).get_context_data(**kwargs)
예제 #30
0
class Create(FormView, ArticleMixin):

    form_class = forms.CreateForm
    template_name = "wiki/create.html"

    @method_decorator(get_article(can_write=True, can_create=True))
    def dispatch(self, request, article, *args, **kwargs):

        return super(Create, self).dispatch(request, article, *args, **kwargs)

    def get_form(self, form_class):
        """
        Returns an instance of the form to be used in this view.
        """
        kwargs = self.get_form_kwargs()
        initial = kwargs.get('initial', {})
        initial['slug'] = self.request.GET.get('slug', None)
        kwargs['initial'] = initial
        form = form_class(self.request, self.urlpath, **kwargs)
        form.fields['slug'].widget = forms.TextInputPrepend(prepend='/' +
                                                            self.urlpath.path)
        return form

    def form_valid(self, form):
        user = None
        ip_address = None
        if not self.request.user.is_anonymous():
            user = self.request.user
            if settings.LOG_IPS_USERS:
                ip_address = self.request.META.get('REMOTE_ADDR', None)
        elif settings.LOG_IPS_ANONYMOUS:
            ip_address = self.request.META.get('REMOTE_ADDR', None)

        try:
            self.newpath = models.URLPath.create_article(
                self.urlpath,
                form.cleaned_data['slug'],
                title=form.cleaned_data['title'],
                content=form.cleaned_data['content'],
                user_message=form.cleaned_data['summary'],
                user=user,
                ip_address=ip_address,
                article_kwargs={
                    'owner': user,
                    'group': self.article.group,
                    'group_read': self.article.group_read,
                    'group_write': self.article.group_write,
                    'other_read': self.article.other_read,
                    'other_write': self.article.other_write,
                })
            messages.success(
                self.request,
                _(u"New article '%s' created.") %
                self.newpath.article.current_revision.title)
        except Exception, e:
            log.exception("Exception creating article.")
            if self.request.user.is_superuser:
                messages.error(
                    self.request,
                    _(u"There was an error creating this article: %s") %
                    str(e))
            else:
                messages.error(self.request,
                               _(u"There was an error creating this article."))
            return redirect('wiki:get', '')

        url = self.get_success_url()
        return url