Merge lp:~widelands-dev/widelands-website/bug-1399461_error_on_renaming_article into lp:widelands-website

Proposed by kaputtnik
Status: Merged
Merged at revision: 447
Proposed branch: lp:~widelands-dev/widelands-website/bug-1399461_error_on_renaming_article
Merge into: lp:widelands-website
Diff against target: 402 lines (+188/-44)
10 files modified
templates/admin/wiki/article/change_form.html (+9/-0)
templates/wiki/backlinks.html (+38/-0)
templates/wiki/edit.html (+4/-4)
templates/wiki/view.html (+9/-0)
wiki/admin.py (+5/-5)
wiki/forms.py (+24/-8)
wiki/migrations/0002_auto_20161218_1056.py (+19/-0)
wiki/models.py (+2/-2)
wiki/urls.py (+3/-0)
wiki/views.py (+75/-25)
To merge this branch: bzr merge lp:~widelands-dev/widelands-website/bug-1399461_error_on_renaming_article
Reviewer Review Type Date Requested Status
SirVer code Approve
Review via email: mp+314033@code.launchpad.net

Commit message

Prevent double names of wiki articles. Add a 'What links here' page.

Description of the change

This fixes bug 1399461 'Renaming an article triggers an error, if article exists' by making the name of an article a unique value on database level. Also prevents reverting an article if the reverting implies renaming and the name to which the article wants to be renamed exists in the meantime. An example (which shows also some other difficulties), imagine some month/years left between the steps:

1. Article "A_1" was created
2. Article "B_1" was created
3. "A_1" get renamed to "A" -> All old links called "A_1" redirects then to article "A"
4. "B_1" get renamed to "A_1" -> All old links called "A_1" open now article "A_1" (not "A" anymore)
5. "A" wants to be reverted to a revision where its name was "A_1" -> This is now prevented, because "A_1" already exists (got renamed from "B_1")

I wanted to prevent step 4 (renaming an article to a name where a redirect exists) but i couldn't fiddle this out. In general i think redirects are not really a good thing at all, because it may lead into many redirects after some time. So i implemented a 'backlinks' page ('What links here'). This page shows following information:

1. All articles which have links to the current name of this article
2. All articles which have links which points to (one of) the old name(s) of this article (redirects)
3. If this article is not linked at all, show a message with a request to link it somewhere

The 2. point has also a request to change the links in all listed articles to point to the current name. Generally speaking: Please remove the redirects
Point 3. has a disadvantage: If an article is only linked over the main menu, it shows also the message to link this article somewhere. Not the best, but i have no idea how to fix this in a convenient manner.

Changes to admin page of wiki:
1. Add a link to show all changesets of this article

If this branch get deployed, one has to run './manage.py migrate' to apply the changes.

To post a comment you must log in.
459. By kaputtnik

removed useless validation error

Revision history for this message
SirVer (sirver) wrote :

> In general i think redirects are not really a good thing at all, because it may lead into many redirects after some time.

While I agree here, they are also sorta required: if some external site links to a site in our Wiki, we want this link to stay valid forever ideally. So we have to track renames (or completely forbid them) and forward to the new page.

About the (internal) redirects: Is it not in our power to fix all internal links that linked to the old page into links that link to the new page? I mean, we can just make a new revision for each page algorithmically that just does the renames. No user interaction is needed.

> If an article is only linked over the main menu, it shows also the message to link this article somewhere.

Could be handled with a custom Django template tag like "WikiLink" that behaves like inter WikiLinking. Not sure if that is really necessary though.

Revision history for this message
kaputtnik (franku) wrote :

> > In general i think redirects are not really a good thing at all, because it
> may lead into many redirects after some time.
>
> While I agree here, they are also sorta required: if some external site links
> to a site in our Wiki, we want this link to stay valid forever ideally. So we
> have to track renames (or completely forbid them) and forward to the new page.

Forbid renaming isn't a good thing also. If one wants to put the content of an article under a new name, he has to create then a new article and copy and paste the content from the old article to the new one. So all changesets are gone and reverting to the previous situation is not possible anymore.

What should we do with following situation? An existing example:

1. https://wl.widelands.org/wiki/Description/
2. https://wl.widelands.org/wiki/GameHelp/

2. is a redirect to 1. But it is currently possible to create a new article GameHelp:

https://wl.widelands.org/wiki/edit/GameHelp/

When saving this new article, all old redirects are gone, respectively all Links to GameHelp open then the new article. Should creating of articles prevented if a redirect exists? On the long run this would mean the available amount of article names shrinks, because some articles reserve two (or more) names.

> About the (internal) redirects: Is it not in our power to fix all internal
> links that linked to the old page into links that link to the new page? I
> mean, we can just make a new revision for each page algorithmically that just
> does the renames. No user interaction is needed.

If we want redirects to stay forever, this isn't needed, isn't it? And reverting to a previous revision put then the old links in again. But we may need such a functionality also for bug 1595294 "Get rid of wikiwordification".

This is all a bit complicated to me... because our redirects are some kind of "soft-redirects": To determine a redirect the code looks just for the requested name in all changesets. If it is found the corresponding article get opened and the String "(redirected from ...)" is shown. There is no real 'redirect-object' and i have trouble to abstract the redirects. I think other wikis handle redirects in another way: If a renaming is done a new article with the old name is created and the content is the redirect with a special syntax. So there are two existing articles (the article it self, and the redirect to it), whereas we have only one.

See e.g.: https://www.mediawiki.org/wiki/Help:Moving_a_page

460. By kaputtnik

removed request for removing redirects

461. By kaputtnik

wording

Revision history for this message
SirVer (sirver) wrote :

> Should creating of articles prevented if a redirect exists?

Yes, I think this is acceptable. We create maybe 10 articles per year, it will be a while till we run out of names, even including redirects.

> If we want redirects to stay forever, this isn't needed, isn't it?

While that is true, it might still be nice to fix all references we have internally to have consistency.

> There is no real 'redirect-object' and i have trouble to abstract the redirects.

One solution would be to have a separate table that holds only the existing redirects. That table is queried first whenever a article is requested and if a match is found, the redirect is evaluated.

Revision history for this message
kaputtnik (franku) wrote :

> > Should creating of articles prevented if a redirect exists?
>
> Yes, I think this is acceptable. We create maybe 10 articles per year, it will
> be a while till we run out of names, even including redirects.

Ok, then i try to prevent it in this branch :-)

>
> > If we want redirects to stay forever, this isn't needed, isn't it?
>
> While that is true, it might still be nice to fix all references we have
> internally to have consistency.

I think this would be better to manage if we have the other bug fixed and we have also a consistent syntax for internal wiki links.

> > There is no real 'redirect-object' and i have trouble to abstract the
> redirects.
>
> One solution would be to have a separate table that holds only the existing
> redirects. That table is queried first whenever a article is requested and if
> a match is found, the redirect is evaluated.

I have to think about it. But i guess this would be also better to do it in another branch, because this one is only to prevent the renaming to a name an existing article, or a redirect, has.

462. By kaputtnik

added check if an artile name is reserved to not break old links

463. By kaputtnik

trying to edit a redirect opens now the actual article; reworked title check for the form

464. By kaputtnik

Added a hint for check on database level

Revision history for this message
kaputtnik (franku) wrote :

Puhh... hopefully i get it now. Giving the example of

1. https://wl.widelands.org/wiki/Description/
2. https://wl.widelands.org/wiki/GameHelp/ #redirect to 1.

- Trying to open /wiki/edit/GameHelp opens now 'Description' for editing.

Trying to change the title is handled as follows:

For existing articles those circumstances are prevented and a message is shown in the form:
- If the title is in a changeset (so redirects and old links will not break)
- If the title already exists as normal article (handled in wiki/forms.py)

For new articles:
- If one opens /wiki/edit/foo and immediately wants to rename it to 'bar' without saving first, the previous checks are also done. There is one difference: If 'bar' exists as normal article, django checks this on database level, a message is then also shown in the form.

I think this is ready but want to make a last test in the next days. A question:
I am unsure about a nested 'try: ... except:' clause. Is this good coding practice? See:

http://bazaar.launchpad.net/~widelands-dev/widelands-website/bug-1399461_error_on_renaming_article/view/head:/wiki/views.py#L262

Revision history for this message
SirVer (sirver) wrote :

Solution sounds good to me, but I did not test it.

> I am unsure about a nested 'try: ... except:' clause. Is this good coding practice? See:

Yes, that seems fine. I would not know how to code this in another fashion.

Revision history for this message
SirVer (sirver) :
review: Approve (code)
465. By kaputtnik

small fix in html file

Revision history for this message
kaputtnik (franku) wrote :

Thanks for the review :-)

Let's wait for Gun if she complains against my english pronouncing :-)

466. By kaputtnik

reworked the check for emmidiately changing the title for new articles, again

467. By kaputtnik

use our default color for errormessages

Revision history for this message
kaputtnik (franku) wrote :

Found a failure... tomorrow i want to merge this on the alpha site, so anybody can take a look at it and test.

Revision history for this message
kaputtnik (franku) wrote :

Merged but not committed on alpha, migrated the changes related to the database over there. For testing one has to start the alpha site.

Revision history for this message
SirVer (sirver) wrote :

I am unsure about the last comment. Is that a request for testing help? If so, I'd suggest you lanuch and leave the alpha site running.

Revision history for this message
kaputtnik (franku) wrote :

I have interpreted the statement:

> ... , but did not test it

as you would like to test. I think on the alpha site this is easier. The alpha site is running now.

Maybe i have one thing of the changes to explain further: To show the Changesets for an Article one has to open an article in the admin page and on the top right there is now a link called "Changesets".

Once you told me the alpha site should not run for a longer time, so i shut it down every time i had finished my tests. May we could clarify this on IRC?

Revision history for this message
GunChleoc (gunchleoc) wrote :

Linguistic proofreading done.

468. By kaputtnik

wording

Revision history for this message
kaputtnik (franku) wrote :

Thanks a lot :-)

469. By kaputtnik

reactivated preview

Revision history for this message
kaputtnik (franku) wrote :

This is merged and deployed now on the productive website.

Alpha is offline again.

Revision history for this message
SirVer (sirver) wrote :

Sorry for holding this off :(. I wanted to test this indeed, but I did not get around to it.

> Once you told me the alpha site should not run for a longer time, so i shut it down every time i had finished my tests. May we could clarify this on IRC?

As long as necessary, as short as possible. If it is online for a significant percentage of the year, it will be found by search engines leading to confusing (and mostly insignificant) links in search results. Search is our main influx of users, so this would be suboptimal. A few days at a time if there is something to test is probably not hurting us though. That was my entire thought process.

Revision history for this message
kaputtnik (franku) wrote :

> Sorry for holding this off :(

Sorry that i am such impatient in this case... but i think this branch does not hurt if it is productive. There are no writes to Database or to the storage, so the worst thing that could happen is a not catched server error (we had for a long time nor such errors :-D ). I just wanted to close this thing and work on stuff where this branch would be a help for.

Thanks for the clarification related to alpha :-)

I have seen that you are ill and hopefully you get well soon...

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== added directory 'templates/admin'
2=== added directory 'templates/admin/wiki'
3=== added directory 'templates/admin/wiki/article'
4=== added file 'templates/admin/wiki/article/change_form.html'
5--- templates/admin/wiki/article/change_form.html 1970-01-01 00:00:00 +0000
6+++ templates/admin/wiki/article/change_form.html 2017-01-18 20:19:31 +0000
7@@ -0,0 +1,9 @@
8+{% extends "admin/change_form.html" %}
9+{% load i18n admin_urls %}
10+
11+{% block object-tools-items %}
12+ <li>
13+ <a href="/admin/wiki/changeset/?article__title={{ original.title }}" class="historylink">{% trans "Changesets" %}</a>
14+ </li>
15+ {% if has_absolute_url %}<li><a href="{{ absolute_url }}" class="viewsitelink">{% trans "View on site" %}</a></li>{% endif %}
16+{% endblock %}
17
18=== added file 'templates/wiki/backlinks.html'
19--- templates/wiki/backlinks.html 1970-01-01 00:00:00 +0000
20+++ templates/wiki/backlinks.html 2017-01-18 20:19:31 +0000
21@@ -0,0 +1,38 @@
22+{% extends 'wiki/base.html' %}
23+{% load wiki_extras %}
24+{% load i18n %}
25+{% block title %}
26+{{ name }} - Backlinks - {{block.super}}
27+{% endblock %}
28+
29+{% block content %}
30+<div class="posRight small">
31+ <a class="invertedColor" href="{% url 'wiki_article' name %}">Back to article</a>
32+</div>
33+<h1>{% trans "Backlinks of " %} {{ name }}</h1>
34+<div class="blogEntry">
35+ {% if found_links or found_old_links %}
36+ {% if found_links %}
37+ <h3>The following pages have link(s) which point to this article:</h3>
38+ <ul>
39+ {% for article in found_links %}
40+ <li><a href="{% url 'wiki_article' article.title %}">{{ article.title }}</a></li>
41+ {% endfor %}
42+ </ul>
43+ {% endif %}
44+ {% if found_old_links %}
45+ <h3>The following articles have links which point to one of the old name(s) of this article (redirects):</h3>
46+ <ul>
47+ {% for article in found_old_links %}
48+ <li><a href="{% url 'wiki_article' article.title %}">{{ article.title }}</a>
49+ (has at least one link to: "{{ article.old_title }}")</li>
50+ {% endfor %}
51+ </ul>
52+ {% endif %}
53+ {% else %}
54+ <p><span class="errormessage">Every Wikipage must be linked from at least one another page.</span>
55+ Please link it <img src="/wlmedia/img/smileys/face-smile.png" alt="face-smile.png"> See <a href="/wiki/WikiSyntax/#links">Wiki Syntax</a> for help.</p></p>
56+ {% endif %}
57+</div>
58+{% endblock %}
59+
60
61=== modified file 'templates/wiki/edit.html'
62--- templates/wiki/edit.html 2016-11-26 20:55:21 +0000
63+++ templates/wiki/edit.html 2017-01-18 20:19:31 +0000
64@@ -60,17 +60,17 @@
65 <!-- Title -->
66 <tr>
67 <th><label for="id_title">{% trans "Title" %}:</label></th>
68- <td>{{ form.title.errors }}{{ form.title }}</td>
69+ <td class="errormessage">{{ form.title.errors }}{{ form.title }}</td>
70 </tr>
71 <!-- Content -->
72 <tr><th colspan="2"><label for="id_content">{% trans "Content" %}:</label></th></tr>
73- <tr><td colspan="2" >{{ form.content.errors }}{{ form.content }}</td></tr>
74+ <tr><td colspan="2" class="errormessage">{{ form.content.errors }}{{ form.content }}</td></tr>
75 <!-- Summary -->
76 <tr><th colspan="2"><label for="id_summary">{% trans "Page Summary" %}:</label></th></tr>
77- <tr><td colspan="2" >{{ form.summary.errors }}{{ form.summary }}</td></tr>
78+ <tr><td colspan="2" class="errormessage">{{ form.summary.errors }}{{ form.summary }}</td></tr>
79 <!-- Comment -->
80 <tr><th colspan=2><label for="id_comment">{% trans "Comment for this revision" %}:</label></th></tr>
81- <tr><td colspan=2 >{{ form.comment.errors }}{{ form.comment }}</td></tr>
82+ <tr><td colspan=2 class="errormessage">{{ form.comment.errors }}{{ form.comment }}</td></tr>
83 </table>
84 <!-- Markup as hidden element -->
85 <input type="hidden" name="markup" value="mrk" />
86
87=== modified file 'templates/wiki/view.html'
88--- templates/wiki/view.html 2016-04-26 16:10:04 +0000
89+++ templates/wiki/view.html 2017-01-18 20:19:31 +0000
90@@ -18,6 +18,8 @@
91 <a class="invertedColor" href="{% url 'wiki_edit' article.title %}">{% trans "Edit this article" %}</a>
92 |
93 <a class="invertedColor" href="{% url 'wiki_article_history' article.title %}">{% trans "Editing history" %}</a>
94+ |
95+ <a class="invertedColor" href="{% url 'backlinks' article.title %}">{% trans "Backlinks" %}</a>
96 {% if can_observe %}
97 |
98 {% if is_observing %}
99@@ -29,6 +31,13 @@
100 {% endif %}
101 </div>
102 <h1>{{ article.title }}</h1>
103+
104+ {% if messages %}
105+ {% for message in messages %}
106+ <p class="errormessage">{{ message }}</p>
107+ {% endfor %}
108+ {% endif %}
109+
110 <div class="blogEntry">
111 {% if not article.id %}
112 <p>
113
114=== modified file 'wiki/admin.py'
115--- wiki/admin.py 2016-11-22 22:17:23 +0000
116+++ wiki/admin.py 2017-01-18 20:19:31 +0000
117@@ -15,7 +15,7 @@
118
119 class ArticleAdmin(admin.ModelAdmin):
120 search_fields = ['title']
121- list_display = ('title', 'markup', 'created_at', 'last_update',)
122+ list_display = ('title', 'creator', 'last_update',)
123 list_filter = ('title',)
124 ordering = ['-last_update']
125 fieldsets = (
126@@ -32,11 +32,11 @@
127
128
129 class ChangeSetAdmin(admin.ModelAdmin):
130- search_fields = ['article__title']
131- list_display = ('article', 'revision', 'old_title', 'old_markup',
132- 'editor', 'editor_ip', 'reverted', 'modified',
133+ search_fields = ['old_title']
134+ list_display = ('article', 'old_title', 'old_markup',
135+ 'editor', 'reverted', 'modified',
136 'comment')
137- list_filter = ('old_title', 'content_diff')
138+ list_filter = ('article__title',)
139 ordering = ('-modified',)
140 fieldsets = (
141 ('Article', {'fields': ('article',)}),
142
143=== modified file 'wiki/forms.py'
144--- wiki/forms.py 2016-12-13 18:28:51 +0000
145+++ wiki/forms.py 2017-01-18 20:19:31 +0000
146@@ -2,11 +2,11 @@
147 import re
148
149 from django import forms
150-from django.forms import widgets
151 from django.contrib.contenttypes.models import ContentType
152 from django.utils.translation import ugettext_lazy as _
153
154 from wiki.models import Article
155+from wiki.models import ChangeSet
156 from wiki.templatetags.wiki_extras import WIKI_WORD_RE
157
158 wikiword_pattern = re.compile('^' + WIKI_WORD_RE + '$')
159@@ -34,11 +34,31 @@
160 'group', 'created_at', 'last_update')
161
162 def clean_title(self):
163- """Page title must be a WikiWord."""
164+ """Check for some errors regarding the title:
165+
166+ 1. Check for bad characters
167+ 2. Check for already used titles
168+
169+ Immediately trying to change the title of a new article to an existing title
170+ is handled on the database level.
171+
172+ """
173+
174 title = self.cleaned_data['title']
175 if not wikiword_pattern.match(title):
176- raise forms.ValidationError(_('Must be a WikiWord.'))
177-
178+ raise forms.ValidationError(
179+ _('Only alphanumeric characters, blank spaces and the underscore are allowed in a title.'))
180+
181+ # 'self.initial' contains the prefilled values of the form
182+ pre_title = self.initial.get('title', None)
183+ if pre_title != title or not pre_title:
184+ # Check if the new name has been used already
185+ cs = ChangeSet.objects.filter(old_title=title)
186+ if cs:
187+ raise forms.ValidationError(
188+ _('The title %(title)s is already in use, maybe an other article used to have this name.'), params={'title': title},)
189+
190+ # title not changed, no errors
191 return title
192
193 def clean(self):
194@@ -52,10 +72,6 @@
195 kw['object_id'] = self.cleaned_data['object_id']
196 except KeyError:
197 pass # some error in this fields
198- else:
199- if Article.objects.filter(**kw).count():
200- raise forms.ValidationError(
201- _('An article with this title already exists.'))
202
203 return self.cleaned_data
204
205
206=== added file 'wiki/migrations/0002_auto_20161218_1056.py'
207--- wiki/migrations/0002_auto_20161218_1056.py 1970-01-01 00:00:00 +0000
208+++ wiki/migrations/0002_auto_20161218_1056.py 2017-01-18 20:19:31 +0000
209@@ -0,0 +1,19 @@
210+# -*- coding: utf-8 -*-
211+from __future__ import unicode_literals
212+
213+from django.db import models, migrations
214+
215+
216+class Migration(migrations.Migration):
217+
218+ dependencies = [
219+ ('wiki', '0001_initial'),
220+ ]
221+
222+ operations = [
223+ migrations.AlterField(
224+ model_name='article',
225+ name='title',
226+ field=models.CharField(unique=True, max_length=50, verbose_name='Title'),
227+ ),
228+ ]
229
230=== modified file 'wiki/models.py'
231--- wiki/models.py 2016-12-13 18:28:51 +0000
232+++ wiki/models.py 2017-01-18 20:19:31 +0000
233@@ -48,8 +48,8 @@
234
235
236 class Article(models.Model):
237- """A wiki page."""
238- title = models.CharField(_(u"Title"), max_length=50)
239+ """A wiki page reflecting the actual revision."""
240+ title = models.CharField(_(u"Title"), max_length=50, unique=True)
241 content = models.TextField(_(u"Content"))
242 summary = models.CharField(_(u"Summary"), max_length=150,
243 null=True, blank=True)
244
245=== modified file 'wiki/urls.py'
246--- wiki/urls.py 2016-12-13 18:28:51 +0000
247+++ wiki/urls.py 2017-01-18 20:19:31 +0000
248@@ -56,4 +56,7 @@
249
250 url(r'^history/(?P<title>' + WIKI_URL_RE + r')/revert/$', views.revert_to_revision,
251 name='wiki_revert_to_revision'),
252+
253+ url(r'^backlinks/(?P<title>' + WIKI_URL_RE + r')/$', views.backlinks,
254+ name='backlinks'),
255 ]
256
257=== modified file 'wiki/views.py'
258--- wiki/views.py 2016-12-13 18:28:51 +0000
259+++ wiki/views.py 2017-01-18 20:19:31 +0000
260@@ -10,7 +10,7 @@
261 HttpResponseNotAllowed, HttpResponse, HttpResponseForbidden)
262 from django.shortcuts import get_object_or_404, render_to_response, redirect
263 from django.contrib.contenttypes.models import ContentType
264-
265+from django.contrib import messages
266 from wiki.forms import ArticleForm
267 from wiki.models import Article, ChangeSet, dmp
268
269@@ -19,6 +19,7 @@
270 from mainpage.templatetags.wl_markdown import do_wl_markdown
271
272 from wl_utils import get_real_ip
273+import re
274
275 # Settings
276 # lock duration in minutes
277@@ -260,29 +261,26 @@
278 return HttpResponseForbidden()
279
280 try:
281+ # Try to fetch an existing article
282 article = article_qs.get(**article_args)
283 except ArticleClass.DoesNotExist:
284- article = None
285+ # No article found, maybe we have a redirect
286+ try:
287+ cs = ChangeSet.objects.filter(old_title=title)[0]
288+ article = article_qs.get(title=cs.article)
289+ except IndexError:
290+ # No Article found and no redirect found
291+ article = None
292
293 if request.method == 'POST':
294
295 form = ArticleFormClass(request.POST, instance=article)
296-
297+
298 form.cache_old_content()
299 if form.is_valid():
300
301- # NOCOMM Franku: This has never worked as i know and is IMHO
302- # useless. This code works with django 1.8 but misses some code
303- # in template. See
304- # https://docs.djangoproject.com/en/1.8/ref/contrib/messages/#module-django.contrib.messages
305-
306 if request.user.is_authenticated():
307 form.editor = request.user
308- # if article is None:
309- # user_message = u"Your article was created successfully."
310- # else:
311- # user_message = u"Your article was edited successfully."
312- # messages.success(request, user_message)
313
314 if ((article is None) and (group_slug is not None)):
315 form.group = group
316@@ -478,18 +476,23 @@
317
318 article = get_object_or_404(article_qs, **article_args)
319
320- if request.user.is_authenticated():
321- article.revert_to(revision, get_real_ip(request), request.user)
322- else:
323- article.revert_to(revision, get_real_ip(request))
324-
325- # NOCOMM Franku: This has never worked as i know and is IMHO
326- # useless. If we want this it has to be fixed for django 1.8
327- # See comment in edit_article()
328- # if request.user.is_authenticated():
329- # request.user.message_set.create(
330- # message=u"The article was reverted successfully.")
331-
332+
333+ # Check whether there is another Article with the same name to which this article
334+ # wants to be reverted to. If so: prevent it and show a message.
335+ old_title = article.changeset_set.filter(
336+ revision=revision+1).get().old_title
337+ try:
338+ art = Article.objects.exclude(pk=article.pk).get(title=old_title)
339+ except Article.DoesNotExist:
340+ # No existing article found -> reverting possible
341+ if request.user.is_authenticated():
342+ article.revert_to(revision, get_real_ip(request), request.user)
343+ else:
344+ article.revert_to(revision, get_real_ip(request))
345+ return redirect(article)
346+ # An article with this name exists
347+ messages.error(
348+ request, 'Reverting not possible because an article with name \'%s\' already exists' % old_title)
349 return redirect(article)
350
351 return HttpResponseNotAllowed(['POST'])
352@@ -622,3 +625,50 @@
353 dmp.diff_cleanupSemantic(diffs)
354
355 return HttpResponse(dmp.diff_prettyHtml(diffs), content_type='text/html')
356+
357+
358+def backlinks(request, title):
359+ """Simple text search for links in other wiki articles pointing to the
360+ current article.
361+
362+ If we convert WikiWords to markdown wikilinks syntax, this view
363+ should be changed to use '[[title]]' for searching.
364+
365+ """
366+
367+ # Find old title(s) of this article
368+ this_article = Article.objects.get(title=title)
369+ changesets = this_article.changeset_set.all()
370+ old_titles = []
371+ for cs in changesets:
372+ if cs.old_title and cs.old_title != title and cs.old_title not in old_titles:
373+ old_titles.append(cs.old_title)
374+
375+ # Differentiate between WikiWords and other
376+ m = re.match(r"(!?)(\b[A-Z][a-z]+[A-Z]\w+\b)", title)
377+ if m:
378+ # title is a 'WikiWord' -> This catches also 'MingW' but we have no such title
379+ search_title = re.compile(r"%s" % title)
380+ else:
381+ # Others must be written like links: '[Wiki Page](/wiki/Wiki Page)'
382+ search_title = re.compile(r"\/%s\)" % title)
383+
384+ # Search for current and previous titles
385+ found_old_links = []
386+ found_links = []
387+ articles_all = Article.objects.all().exclude(title=title)
388+ for article in articles_all:
389+ match = search_title.search(article.content)
390+ if match:
391+ found_links.append({'title': article.title})
392+
393+ for old_title in old_titles:
394+ if old_title in article.content:
395+ found_old_links.append({'old_title': old_title, 'title': article.title })
396+
397+ context = {'found_links': found_links,
398+ 'found_old_links': found_old_links,
399+ 'name': title}
400+ return render_to_response('wiki/backlinks.html',
401+ context,
402+ context_instance=RequestContext(request))

Subscribers

People subscribed via source and target branches