~widelands-dev/widelands-website/django_staticfiles

« back to all changes in this revision

Viewing changes to wiki/models.py

  • Committer: Holger Rapp
  • Date: 2016-08-08 10:06:42 UTC
  • mto: This revision was merged to the branch mainline in revision 419.
  • Revision ID: sirver@gmx.de-20160808100642-z62vwqitxoyl5fh4
Added the apt-get update script I run every 30 days.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
from datetime import datetime
2
 
from django.urls import reverse
 
2
from django.core.urlresolvers import reverse
3
3
 
4
4
# Google Diff Match Patch library
5
5
# http://code.google.com/p/google-diff-match-patch
14
14
 
15
15
from tagging.fields import TagField
16
16
from tagging.models import Tag
 
17
 
 
18
import settings
 
19
if settings.USE_SPHINX:
 
20
    from djangosphinx.models import SphinxSearch
 
21
 
17
22
from wlimages.models import Image
18
23
 
19
24
try:
25
30
# We dont need to create a new one everytime
26
31
dmp = diff_match_patch()
27
32
 
28
 
 
29
33
def diff(txt1, txt2):
30
34
    """Create a 'diff' from txt1 to txt2."""
31
35
    patch = dmp.patch_make(txt1, txt2)
43
47
 
44
48
 
45
49
class Article(models.Model):
46
 
    """A wiki page reflecting the actual revision."""
47
 
    title = models.CharField(_(u"Title"), max_length=50, unique=True)
 
50
    """ A wiki page.
 
51
    """
 
52
    title = models.CharField(_(u"Title"), max_length=50)
48
53
    content = models.TextField(_(u"Content"))
49
54
    summary = models.CharField(_(u"Summary"), max_length=150,
50
55
                               null=True, blank=True)
53
58
                              null=True, blank=True)
54
59
    creator = models.ForeignKey(User, verbose_name=_('Article Creator'),
55
60
                                null=True)
 
61
    creator_ip = models.GenericIPAddressField(_("IP Address of the Article Creator"),
 
62
                                       blank=True, null=True)
56
63
    created_at = models.DateTimeField(default=datetime.now)
57
64
    last_update = models.DateTimeField(blank=True, null=True)
58
65
 
64
71
 
65
72
    tags = TagField()
66
73
 
 
74
    # Django sphinx 
 
75
    if settings.USE_SPHINX:
 
76
        search = SphinxSearch(
 
77
            weights = {
 
78
                'title': 100,
 
79
                'summary': 80,
 
80
                'content': 50,
 
81
                }
 
82
            )
 
83
 
67
84
    class Meta:
68
85
        verbose_name = _(u'Article')
69
86
        verbose_name_plural = _(u'Articles')
70
 
        app_label = 'wiki'
71
 
        default_permissions = ('change', 'add',)
72
 
        ordering = ['title']
 
87
        app_label = 'wiki'
73
88
 
74
89
    def get_absolute_url(self):
75
90
        if self.group is None:
86
101
                reverted=False).order_by('-revision')[0]
87
102
        except IndexError:
88
103
            return ChangeSet.objects.none()
89
 
 
 
104
    
90
105
    def all_images(self):
91
106
        return self.images.all()
92
107
 
93
108
    def new_revision(self, old_content, old_title, old_markup,
94
 
                     comment, editor):
95
 
        """Create a new ChangeSet with the old content."""
 
109
                     comment, editor_ip, editor):
 
110
        '''Create a new ChangeSet with the old content.'''
96
111
 
97
112
        content_diff = diff(self.content, old_content)
98
113
 
99
114
        cs = ChangeSet.objects.create(
100
115
            article=self,
101
116
            comment=comment,
 
117
            editor_ip=editor_ip,
102
118
            editor=editor,
103
119
            old_title=old_title,
104
120
            old_markup=old_markup,
106
122
 
107
123
        return cs
108
124
 
109
 
    def revert_to(self, revision, editor=None):
110
 
        """Revert the article to a previuos state, by revision number."""
 
125
    def revert_to(self, revision, editor_ip, editor=None):
 
126
        """ Revert the article to a previuos state, by revision number.
 
127
        """
111
128
        changeset = self.changeset_set.get(revision=revision)
112
 
        changeset.reapply(editor)
 
129
        changeset.reapply(editor_ip, editor)
113
130
 
114
131
    def compare(self, from_revision, to_revision):
115
 
        """Compares to revisions of this article."""
 
132
        """ Compares to revisions of this article.
 
133
        """
116
134
        changeset = self.changeset_set.get(revision=to_revision)
117
135
        return changeset.compare_to(from_revision)
118
136
 
 
137
 
119
138
    def __unicode__(self):
120
139
        return self.title
121
140
 
122
141
 
 
142
 
123
143
class ChangeSetManager(models.Manager):
124
144
 
125
145
    def all_later(self, revision):
126
 
        """Return all changes later to the given revision.
127
 
 
 
146
        """ Return all changes later to the given revision.
128
147
        Util when we want to revert to the given revision.
129
 
 
130
148
        """
131
149
        return self.filter(revision__gt=int(revision))
132
150
 
133
151
 
 
152
class NonRevertedChangeSetManager(ChangeSetManager):
 
153
 
 
154
    def get_default_queryset(self):
 
155
        super(PublishedBookManager, self).get_queryset().filter(
 
156
            reverted=False)
 
157
 
 
158
 
134
159
class ChangeSet(models.Model):
135
160
    """A report of an older version of some Article."""
136
161
 
137
162
    article = models.ForeignKey(Article, verbose_name=_(u"Article"))
138
163
 
139
 
    # Editor identification -- logged
 
164
    # Editor identification -- logged or anonymous
140
165
    editor = models.ForeignKey(User, verbose_name=_(u'Editor'),
141
166
                               null=True)
 
167
    editor_ip = models.GenericIPAddressField(_(u"IP Address of the Editor"))
142
168
 
143
169
    # Revision number, starting from 1
144
170
    revision = models.IntegerField(_(u"Revision Number"))
155
181
    reverted = models.BooleanField(_(u"Reverted Revision"), default=False)
156
182
 
157
183
    objects = ChangeSetManager()
 
184
    non_reverted_objects = NonRevertedChangeSetManager()
158
185
 
159
186
    class Meta:
160
187
        verbose_name = _(u'Change set')
161
188
        verbose_name_plural = _(u'Change sets')
162
 
        get_latest_by = 'modified'
 
189
        get_latest_by  = 'modified'
163
190
        ordering = ('-revision',)
164
 
        app_label = 'wiki'
 
191
        app_label = 'wiki'
165
192
 
166
193
    def __unicode__(self):
167
194
        return u'#%s' % self.revision
168
195
 
 
196
    @models.permalink
169
197
    def get_absolute_url(self):
170
198
        if self.article.group is None:
171
 
            return reverse('wiki_changeset', kwargs={
172
 
                'title': self.article.title,
173
 
                'revision': self.revision
174
 
            })
175
 
        return reverse('wiki_changeset', kwargs={
176
 
            'group_slug': self.article.group.slug,
177
 
            'title': self.article.title,
178
 
            'revision': self.revision,
179
 
        })
 
199
            return ('wiki_changeset', (),
 
200
                    {'title': self.article.title,
 
201
                     'revision': self.revision})
 
202
        return ('wiki_changeset', (),
 
203
                {'group_slug': self.article.group.slug,
 
204
                 'title': self.article.title,
 
205
                 'revision': self.revision})
 
206
 
180
207
 
181
208
    def is_anonymous_change(self):
182
209
        return self.editor is None
183
210
 
184
 
    def reapply(self, editor):
185
 
        """Return the Article to this revision."""
 
211
    def reapply(self, editor_ip, editor):
 
212
        """ Return the Article to this revision.
 
213
        """
186
214
 
187
215
        # XXX Would be better to exclude reverted revisions
188
216
        #     and revisions previous/next to reverted ones
213
241
        article.new_revision(
214
242
            old_content=old_content, old_title=old_title,
215
243
            old_markup=old_markup,
216
 
            comment='Reverted to revision #%s' % self.revision,
217
 
            editor=editor
218
 
            )
 
244
            comment="Reverted to revision #%s" % self.revision,
 
245
            editor_ip=editor_ip, editor=editor)
219
246
 
220
247
        self.save()
221
248
 
222
249
        if None not in (notification, self.editor):
223
 
            notification.send([self.editor], 'wiki_revision_reverted',
 
250
            notification.send([self.editor], "wiki_revision_reverted",
224
251
                              {'revision': self, 'article': self.article})
225
252
 
226
253
    def save(self, *args, **kwargs):
227
 
        """Saves the article with a new revision."""
 
254
        """ Saves the article with a new revision.
 
255
        """
228
256
        if self.id is None:
229
257
            try:
230
258
                self.revision = ChangeSet.objects.filter(
231
259
                    article=self.article).latest().revision + 1
232
260
            except self.DoesNotExist:
233
261
                self.revision = 1
234
 
 
235
262
        super(ChangeSet, self).save(*args, **kwargs)
236
263
 
 
264
    def display_diff(self):
 
265
        ''' Returns a HTML representation of the diff.
 
266
        '''
 
267
 
 
268
        # well, it *will* be the old content
 
269
        old_content = self.article.content
 
270
 
 
271
        # newer non-reverted revisions of this article, starting from this
 
272
        newer_changesets = ChangeSet.non_reverted_objects.filter(
 
273
            article=self.article,
 
274
            revision__gte=self.revision)
 
275
 
 
276
        # apply all patches to get the content of this revision
 
277
        for i, changeset in enumerate(newer_changesets):
 
278
            patches = dmp.patch_fromText(changeset.content_diff)
 
279
            if len(newer_changesets) == i+1:
 
280
                # we need to compare with the next revision after the change
 
281
                next_rev_content = old_content
 
282
            old_content = dmp.patch_apply(patches, old_content)[0]
 
283
 
 
284
        diffs = dmp.diff_main(old_content, next_rev_content)
 
285
        dmp.diff_cleanupSemantic(diffs)
 
286
        return dmp.diff_prettyHtml(diffs)
 
287
 
237
288
    def get_content(self):
238
 
        """Returns the content of this revision."""
 
289
        """ Returns the content of this revision.
 
290
        """
239
291
        content = self.article.content
240
 
        newer_changesets = ChangeSet.objects.filter(
241
 
            article=self.article, revision__gt=self.revision).order_by('-revision')
 
292
        newer_changesets = ChangeSet.objects.filter(article=self.article, revision__gt=self.revision).order_by('-revision')
242
293
        for changeset in newer_changesets:
243
294
            patches = dmp.patch_fromText(changeset.content_diff)
244
295
            content = dmp.patch_apply(patches, content)[0]
245
296
        return content
246
 
 
 
297
        
247
298
    def compare_to(self, revision_from):
248
299
        other_content = u""
249
300
        if revision_from > 0:
250
 
            other_content = ChangeSet.objects.filter(
251
 
                article=self.article, revision__lte=revision_from).order_by('-revision')[0].get_content()
 
301
            other_content = ChangeSet.objects.filter(article=self.article, revision__lte=revision_from).order_by("-revision")[0].get_content()
252
302
        diffs = dmp.diff_main(other_content, self.get_content())
253
303
        dmp.diff_cleanupSemantic(diffs)
254
304
        return dmp.diff_prettyHtml(diffs)
 
305
 
 
306
if notification is not None:
 
307
    signals.post_save.connect(notification.handle_observations, sender=Article)