Commits

Anonymous committed e51443b

completly refactored Paste model to optimize revisions & such things.
In the same time fix some bugs.

New version of friendsnippets is now incompatible with previous release.
A migration script need to be done.

Comments (0)

Files changed (10)

friendpaste/_design/paste/by_id/map.js

-function(doc) { 
-    if (doc.type == "snippet") { 
-        emit([doc._id, 0], doc); 
-    } else if (doc.type == "revision") { 
-        emit([doc.parent, 1, doc.updated], doc); 
-    }
+function (doc) { 
+    if (doc.itemType == "paste") {
+        emit(doc.pasteid, doc);  
+    }  
 }

friendpaste/_design/paste/by_revid/map.js

+function (doc) {
+    if (doc.itemType == "paste" || doc.itemType == "revision")
+        emit(doc.revid, doc);
+}

friendpaste/_design/paste/revisions/map.js

 function(doc) { 
-    if (doc.type == "revision") { 
-        emit([doc.parent,doc.updated], doc); 
-    } 
-    if (doc.type == "snippet") { 
-        emit([doc._id,doc.updated], doc); 
+    if (doc.itemType == "revision") {
+        emit(doc.parent, doc);
     }
 }

friendpaste/_design/paste/with_revisions/map.js

+function (doc) {
+    if (doc.itemType == "paste") {
+        emit([doc.pasteid, 0], doc);
+    } else if (doc.itemType == "revision") {
+        emit([doc.pasteid, 1], doc);
+    }
+}

friendpaste/models.py

 from friendpaste.utils import local, make_hash, short
 from friendpaste.utils.diff import unified_diff, diff_blocks
 
-class FoundRev(Exception):
-    """ exception raised when a revision is found """
+__all__ = ['Paste']
+
+class PasteExist(Exception):
+    """ exception raised when paste is found """
     
-class Snippet(Document):
-    title=TextField()
-    type=TextField(default='snippet')
-    parent=TextField(default='')
+class ArrayField(Field):
+    _to_python = list
+
+def _genid():
+    charset = 'abcdefghjkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789'
+    from random import choice
+    return ''.join([choice(charset) for i in range(8)])
+    
+class Paste(Document):
+    pasteid = TextField(default='')
+    title = TextField()
+    parent = TextField(default='')
+    previous  = TextField(default='')
     revid = TextField()
-    snippet=TextField()
-    language=TextField()
-    created=DateTimeField()
-    updated=DateTimeField()
-
-    def _genid(self):
-        charset = 'abcdefghjkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789'
-        from random import choice
-        return ''.join([choice(charset) for i in range(8)])
+    content = TextField(default='')
+    language = TextField(default='text')
+    changes = ArrayField(default=[])
+    nb_revision = IntegerField(default=0)
+    created = DateTimeField()
+    updated = DateTimeField()
+    
+    itemType = TextField(default='paste')
 
     def store(self, db):
         """
-        override store procedure to generate small id
+        override store procedure to generate pasteid
+        if not provided and manage revisions
         """
         self.updated = datetime.utcnow()
-        if getattr(self._data, 'id', None) is None:
+        if self.id is None:
             self.created = datetime.utcnow()
-            node = make_hash(self.snippet, self.title, self.language,'')
+            node = make_hash(self.content, self.title, self.language,'')
             self.revid = short(node)
-            stored=False
-            docid=None
-            while 1:
-                id = self._genid()
-                try:
-                    docid=db.resource.put(content=self._data, path='/%s/' % str(id))['id']
-                except:
-                    continue
-                if docid is not None:
-                    break
+            if not self.pasteid:
+                while 1:
+                    pasteid = _genid()
+                    if not self.is_exist(db, pasteid):
+                        self.pasteid = pasteid
+                        break
+                                       
+            docid = db.create(self._data)
             self._data = db.get(docid)
         else:
-            old_data = db.get(self._data.id)
+            old_data = db.get(self.id)
             self.created = datetime.utcnow()
-            old_hash = make_hash(old_data['snippet'],old_data['title'],old_data['language'], '')
-            new_hash = make_hash(self.snippet,self.title,self.language, '')
+            old_hash = make_hash(old_data['content'],old_data['title'],old_data['language'], '')
+            new_hash = make_hash(self.content,self.title,self.language, '')
             if old_hash != new_hash:
-                #no need to save changes if there isn't
-                old_data['type']='revision'
-                old_data['parent']=self._data.id
-                db.create(old_data)
+                del old_data['_id']
+                del old_data['_rev']
 
+                old_data['parent'] = self.id
+                old_data['itemType'] = 'revision'  
+                _previous = db.create(old_data)
+                
                 # get new revid
-                node = make_hash(self.snippet,self.title,self.language, old_data['revid'])
+                node = make_hash(self.content,self.title,self.language, old_data['revid'])
                 self.revid = short(node)
+                
+                # increment revision number
+                self.nb_revision = int(old_data['nb_revision']) + 1
+                
+                # save previous revision id, could be usefull
+                self.previous = _previous
+                
+                # get changes 
+                changes = diff_blocks(old_data['content'].splitlines(),
+                    self.content.splitlines(), 3, 8, 1, 0, 1)
+                _changes = []
+                for row in changes:
+                    for change in row:
+                        _changes.append(change)
+                self.changes = _changes
             
                 # save changes
-                db[self._data.id] = self._data
+                db[self.id] = self._data
         
         return self
         
-    def get_revision(cls, db, snippetid, revid):
-        revision = db.view('_view/paste/by_id', key=[str(snippetid), str(revid)])
-        data = revision.value
-        data['_id'] = r.value['parent']
-        return cls.wrap(data)
-    get_revision = classmethod(get_revision)
+    def get_paste(cls, db, pasteid):
+        rows = cls.view(db, '_view/paste/by_id', key=pasteid)
+        lrows = list(iter(rows))
+        if lrows:
+            return lrows[0]
+        return None
+    get_paste = classmethod(get_paste)
     
-    def get_revisions(cls, db, snippetid):
-        results = cls.view(db, '_view/paste/by_id', startkey=[str(snippetid)], endkey=[str(snippetid),10])
-        revisions = list(iter(results))
+    def is_exist(cls, db, pasteid):
+        paste = cls.get_paste(db, pasteid)
+        if paste is not None:
+            return True
+        return False
+    is_exist = classmethod(is_exist)
+    
+    def revision(self, db, revid):
+        if not self.id:
+            return None
+        rows = self.view(db, '_view/paste/by_revid', key=revid)
+        rows = list(iter(rows))
+        if rows:
+            return rows[0]
+        return None
+    
+    def revisions(self, db):
+        if not self.id or not self.previous:
+            return []  
+        rows = self.view(db, '_view/paste/revisions', key=self.id)
+        revisions = list(iter(rows))
         if revisions:
             revisions.sort(lambda a,b: cmp(a.updated, b.updated))
             revisions.reverse()
-        return revisions
-    get_revisions = classmethod(get_revisions)
+        return revisions   
         
-    def get_changeset(cls, db, snippetid, rev=None):
-        diff_to = ""
-        diff_from = ""
-        old_rev=rev
-        after = False
+    def get_changeset(self, db):
+        previous = Paste.load(db, self.previous)
+        unidiff = '--- Revision %s\n+++ Revision %s\n' % (previous.revid, self.revid) + \
+                '\n'.join(unified_diff (previous.content.splitlines(), self.content.splitlines(), 3))
+        tabular = diff_blocks(previous.content.splitlines(), self.content.splitlines(), 3, 8, 1, 0, 1)
+        return unidiff, tabular, previous
         
-        all_revisions = cls.get_revisions(db, snippetid)
-        if not all_revisions:
-            raise ResourceNotFound
-            
-        snippet = all_revisions[0]
-        if snippet.revid == rev:
-            diff_to = snippet.snippet
-            after = True
-
-        revisions = all_revisions[1:]
-        if revisions:  
-            try:
-                for r in revisions:
-                    if not after and r.revid==rev:
-                        if not diff_to:
-                            diff_to = r.snippet
-                        after=True
-                    elif after:
-                        diff_from = r.snippet
-                        old_rev=r.revid
-                        raise FoundRev
-            except FoundRev:
-                pass
-
-        unidiff = '--- Revision %s\n+++ Revision %s\n' % (old_rev, rev) + \
-                '\n'.join(unified_diff (diff_from.splitlines(), diff_to.splitlines(), 3))
-        tabular = diff_blocks(diff_from.splitlines(), diff_to.splitlines(), 3)
-        return snippet, rev, old_rev, unidiff, tabular
-    get_changeset = classmethod(get_changeset)
-        
-    def get_with_revisions(cls, db, snippetid, rev):
-        all_revisions = cls.get_revisions(db, snippetid)
-        if not all_revisions:
-            raise ResourceNotFound
-        
-        i = 0
-        if rev is not None:
-            for r in all_revisions:
-                if r.revid == rev:
-                    snippet = r
-                    snippet['_id'] = snippet.parent
-                    break
-                i = i + 1
-        else:
-            snippet = all_revisions[0]
-        print rev
-        
-        return snippet, all_revisions[i:]
-    get_with_revisions = classmethod(get_with_revisions)
+    def with_revisions(cls, db, pasteid, revid):
+        rows = cls.view(db, '_view/paste/with_revisions', startkey=[pasteid,0])
+        print rows
+        results = list(iter(rows))
+        print results
+        if results:
+            results.sort(lambda a,b: cmp(a.updated, b.updated))
+            results.reverse()
+            i = 0
+            if revid:
+                for paste in results:
+                    if paste.revid == revid:
+                        break
+                    i = i + 1
+            try:            
+                return results[i], results[i+1:]
+                print i
+            except IndexError:
+                try:
+                    return result[i], []
+                except IndexError:
+                    pass
+        return None, None
+    with_revisions = classmethod(with_revisions)

friendpaste/template.py

 template_env = Environment(loader=FileSystemLoader(settings.TEMPLATES_PATH))
 template_env.charset = 'utf-8'
 
-ALL_COLORSHEME = list(get_all_styles())
+DIFF_CHANGES = {
+    'mod': 'Changed',
+    'add': 'Added',
+    'del': 'Removed',
+    'ins': 'Inserted'
+}
 _context_processors = []
 
 
+def pretty_type(value):
+    return DIFF_CHANGES.get(value, '')
+template_env.filters['pretty_type'] = pretty_type
+
 def url_for(endpoint, _external=False, **values):
     return local.url_adapter.build(endpoint, values, force_external=_external)
 template_env.globals['url_for'] = url_for

friendpaste/utils/__init__.py

 from datetime import datetime, timedelta, time, tzinfo
 from time import strptime, localtime, struct_time
 from gettext import gettext, ngettext
-import thread, threading
+import os
+import sys
+from glob import glob
+
+
 # compatibility with python 2.4
 try:
     from hashlib import sha1 as _sha
     _sha = sha.new
 
 from werkzeug import Local, LocalManager
+from friendpaste import settings
 
 _hex = binascii.hexlify
 local = Local()

friendpaste/views.py

 import os.path
 import time
 
+from jinja2.filters import do_truncate, do_striptags, escape
 from wtforms import Form, TextField, TextAreaField, SelectField, ValidationError, \
         validators
 from pygments.lexers import get_all_lexers, get_lexer_for_filename
 import friendpaste.settings as settings
 from friendpaste.feeds import RssFeed, RssFeedEntry 
 from friendpaste.http import FPResponse, send_json
-from friendpaste.models import Snippet
-from friendpaste.template import render_response, highlighter
+from friendpaste.models import Paste
+from friendpaste.template import render_response, highlighter, pretty_type
 from friendpaste.utils import local, local_manager, datetimestr_topython, strptime
 
 
             except:
                 language = 'text'
         try:
-            s = Snippet(
+            s = Paste(
                     title=d.get('title', ""),
-                    snippet=d.get('snippet'),
+                    content=d.get('snippet'),
                     language=language
             )
             s.store(local.db)
 
         return send_json({
             'ok': True,
-            'id': s.id,
+            'id': s.pasteid,
             'revid': s.revid,
-            'url': '%s/%s' % (settings.SITE_URI, s.id)
+            'url': '%s/%s' % (settings.SITE_URI, s.pasteid)
         })
 
     form = PasteForm(request.form, prefix='paste')
     if request.method=='POST' and form.validate():
-        s = Snippet(title=form.data['title'], snippet=form.data['snippet'], language=form.data['language'])
+        s = Paste(title=form.data['title'], content=form.data['snippet'], language=form.data['language'])
         s.store(local.db)
-        print "id created : %s" % s.id
-        return redirect ('/%s' % s.id)
+        print "id created : %s" % s.pasteid
+        return redirect ('/%s' % s.pasteid)
 
     return render_response('paste/index.html', form=form)
 
 def edit_snippet(request, id):
-    s = Snippet.load(local.db, id)
+    s = Paste.load(local.db, id)
     if not s:
         raise NotFound
     form = PasteForm(request.form, prefix='paste', **{
         'title': s.title,
-        'snippet': s.snippet,
+        'snippet': s.content,
         'language': str(s.language)
     })
 
     if request.method=='POST' or request.method=='PUT' and form.validate():
         old_revid = s.revid
         s.title=form.data['title']
-        s.snippet = form.data['snippet']
+        s.content = form.data['snippet']
         s.language = form.data['language']
         s.store(local.db)
         if s.revid == old_revid:
-            return redirect ('/%s?msg=%s' % (s.id, url_quote("No changes detected.")))           
-        return redirect ('/%s' % s.id)
+            return redirect ('/%s?msg=%s' % (s.pasteid, url_quote("No changes detected.")))           
+        return redirect ('/%s' % s.pasteid)
     return render_response('paste/edit.html', form=form, snippet=s) 
 
 def view_snippet(request, id):
     mimetypes = request.accept_mimetypes
+    s = Paste.get_paste(local.db, id)
+    if s is None:
+        raise NotFound
     if 'application/json' in mimetypes and request.method=='PUT':
-        try:
-            s = Snippet.load(local.db, id)
-        except:
-            raise NotFound
-        if not s:
-            raise NotFound
-        d=json.loads(request.data)
+        d = json.loads(request.data)
         lang=request.values.get("lang", None)
         language=d.get('language', 'text')
         if lang == "ext":
         old_revid = s.revid
         try:
             s.title=d.get('title')
-            s.snippet = d.get('snippet')
+            s.content = d.get('snippet')
             s.language = language
             s.store(local.db)
         except:
             return send_json({'ok': False, 'reason': 'no changes detected'})
         return send_json({
             'ok': True,
-            'id': s.id,
+            'id': s.pasteid,
             'revid': s.revid,
             'url': '%s/%s' % (settings.SITE_URI, s.id)
         })
 
-    rev = request.values.get('rev', None)
-    if rev is None:
-        try:
-            s = Snippet.load(local.db, id)
-        except:
-            raise NotFound
-    else:
-        s, revisions = Snippet.get_with_revisions(local.db, id, rev)
-
-    if not s:
-        raise NotFound
-
+    revid = request.values.get('rev', None)
+    if revid is not None and revid != s.revid:
+        s = s.revision(local.db, revid)
+        
+        
     if 'application/json' in mimetypes:
+        if s is None:
+            return send_json({'ok': false})
         if request.method == 'GET':
-            if s is None:
-                return send_json({'ok': False})
             snippet_hash = {
-                'id': s.id,
+                'id': s.pasteid,
                 'revid': s.revid,
                 'title': s.title,
-                'snippet': s.snippet,
+                'snippet': s.content,
                 'language': str(s.language)
             }
             return send_json(snippet_hash)
+            
+    if s is None:
+        raise NotFound
     
     form = PasteForm(request.form, prefix='paste', **{
         'title': s.title,
-        'snippet': s.snippet,
+        'snippet': s.content,
         'language': str(s.language)
     })
 
-    # get theme
-    theme = request.cookies.get('theme', 'default')
-    return render_response('paste/view.html', snippet=s, form=form, rev=rev)
-
-
+    return render_response('paste/view.html', snippet=s, form=form, rev=revid)
 
 def view_rss(request, id):
-    try:
-        snippet, revisions = Snippet.get_with_revisions(local.db, id, request.values.get('rev'))
-    except:
+    snippet, revisions = Paste.with_revisions(local.db, id, request.values.get('rev'))
+    if snippet is None:
         raise NotFound
         
     feed = RssFeed(
-        title="Revisions to %s on Friendpaste" % (snippet.title and snippet.title or "snippet #%s" % s.id),
+        title="Revisions to %s on Friendpaste" % (snippet.title and snippet.title or "snippet #%s" % snippet.pasteid),
         description = '',
-        link = "%s/%s" % (settings.SITE_URI, s.id)
+        link = "%s/%s" % (settings.SITE_URI, snippet.pasteid)
     
     )
  
+    revisions = [snippet] + revisions
     for revision in revisions:
+        description = ""
+        if not revision.previous:
+            description = "Created"
+        else:
+            for change in revision.changes:
+                if change['type'] != "unmod":
+                    description = "%s " % pretty_type(change['type']) 
+                    description += "\n".join(change['changed']['lines'])
+                description = do_truncate(do_striptags(description), 60)
+                description = description.replace("\n", "<br />")
+                    
         feed.add_entry(RssFeedEntry(
-            title="%s revision %s" % (revision.value['title'], revision.value['revid']),
-            link= "%s/%s?rev=%s" % (settings.SITE_URI, id, revision.value['revid']),
-            description="",
+            title="%s revision %s" % (revision.title, revision.revid),
+            link= "%s/%s?rev=%s" % (settings.SITE_URI, id, revision.revid),
+            description=description,
             **{ 
-                'published': datetimestr_topython(revision.value['created']),
-                'updated': datetimestr_topython(revision.value['updated'])
+                'published': datetimestr_topython(revision.created),
+                'updated': datetimestr_topython(revision.updated)
             }
         ))
      
     return feed.get_response()
 
 def view_revisions(request, id):
-    snippet = None
-    revisions = None
-    snippet, revisions = Snippet.get_with_revisions(local.db, id, request.values.get('rev'))
-    try:
-        snippet, revisions = Snippet.get_with_revisions(local.db, id, request.values.get('rev'))
-    except:
-        pass
+    snippet, revisions = Paste.with_revisions(local.db, id, request.values.get('rev'))
      
     if 'application/json' in request.accept_mimetypes:
-        if revisions is None <= 0:
-            return send_json([])
-        _revisions = []
-        for rev in revisions:
-            _revisions.append(rev._data)
-        return send_json(_revisions)
+        if revisions and revisions is not None:      
+            return send_json([rev._data for rev in revisions])
+        return send_json([])
 
     if snippet is None:
         raise NotFound
     return render_response('paste/revisions.html', snippet=snippet, revisions=revisions)
 
 def view_rawsnippet(request, id, rev):
-    try:
-        snippet, revisions = Snippet.get_with_revisions(local.db, id, rev)
-    except:
+    snippet = Paste.load(local.db, id)
+    if not s:
         raise NotFound
-    response = FPResponse(snippet.snippet)
+    response = FPResponse(snippet.content)
     response.headers['content-type'] = 'text/plain'
     return response
 
 def view_original(request, id, rev):
-    try:
-        snippet, revisions = Snippet.get_with_revisions(local.db, id, rev)
-    except:
+    snippet = Paste.load(local.db, id)
+    if not s:
         raise NotFound
           
     from pygments import lexers
     lexer = lexers.get_lexer_by_name(snippet.language)
-    response = FPResponse(snippet.snippet)
+    response = FPResponse(snippet.content)
     response.headers['content-type'] = lexer.mimetypes[0]
     if lexer.filenames and len(lexer.filenames)>0:
         response.headers['content-disposition'] =  "filename=%s%s" % (
-            snippet.id, lexer.filenames[0][1:])
+            snippet.pasteid, lexer.filenames[0][1:])
     else:
         response.headers['content-disposition'] =  "filename=%s.txt" % snippet.id
     return response
 
 
 def view_changeset(request, id):
-    snippet, rev, old_rev, unidiff, tabular = Snippet.get_changeset(local.db, id, rev=request.values.get('rev'))
+    snippet = Paste.get_paste(local.db, id)
+    revid = request.values.get('rev', None)
+    if revid is not None and revid != snippet.revid:
+        snippet = snippet.revision(local.db, revid)
+    
+    unidiff, tabular, previous = snippet.get_changeset(local.db)
     mimetypes = request.accept_mimetypes
     if 'application/json' in mimetypes:
         return send_json({
             'id': id, 
-            'rev': startrev,
+            'rev': snippet.revid,
             'changeset': unidiff
         })
 
         response.headers['content-type'] = 'text/plain'
         return response
 
-    theme = request.cookies.get('theme', 'default')
     return render_response('paste/diff.html', unidiff=unidiff, difft=tabular,
-            snippet=snippet, rev=rev, old_rev=old_rev)
+            snippet=snippet, rev=snippet.revid, old_rev=previous.revid)
 
 def get_all_languages(request):
     lexers = get_all_lexers()
             data = json.loads(request.data)
         except ValueError:
             return send_json({'ok': False})
-            
-        print data
+        
         for attrname, value in data.items():
             request.session[attrname] = value
         

templates/paste/diff.html

 {% extends "base.html" %}
 
-{% block title %}{{ snippet['_id'] }} changes{% endblock %}
+{% block title %}{{ snippet.pasteid }} changes{% endblock %}
 {% block head %}
 <link rel="stylesheet" href="/static/css/{{theme }}.css" type="text/css" />
 {% endblock %}
 
 {% block content %}
 <div id="snippet">
-    <h2><a href="/{{ snippet['_id'] }}">{{ snippet['_id'] }}</a> changes</h2>
+    <h2><a href="/{{ snippet.pasteid }}">{{ snippet.pasteid }}</a> changes</h2>
     <div id="info">
         {{ snippet['updated']|datetimeformat }} 
         <table>
-            <tr><th>Changeset</th><td><a href="/{{ snippet['_id'] }}?rev={{ rev }}">{{ rev }}</a> (b)</td></tr>
-            <tr><th>Parent</th><td><a href="/{{ snippet['_id'] }}?rev={{ old_rev }}">{{ old_rev }}</a> (a)</td></tr>
+            <tr><th>Changeset</th><td><a href="/{{ snippet.pasteid }}?rev={{ rev }}">{{ rev }}</a> (b)</td></tr>
+            <tr><th>Parent</th><td><a href="/{{ snippet.pasteid }}?rev={{ old_rev }}">{{ old_rev }}</a> (a)</td></tr>
         </table>
     </div>
     <div id="actions">            
         <input type="submit" value="Back to the paste..." />
     </form>
 </div>
-<p id="dl"><strong>Download in other format:</strong><br /><a href="/{{ snippet['_id'] }}/changeset?rev={{ rev }}&amp;format=raw">Unified diff</a></p>
+<p id="dl"><strong>Download in other format:</strong><br /><a href="/{{ snippet.pasteid }}/changeset?rev={{ rev }}&amp;format=raw">Unified diff</a></p>
 <script type="text/javascript">
     Friendpaste.init();
     Diff.init();

templates/paste/view.html

 {% block title %}{% if snippet.title %}{{ snippet.title }}{% else %}Paste #{{ snippet.id }}{% endif %} {% endblock %}
 
 {% block head %}
-<link rel="alternate" href="/{{ snippet.id }}/rss" type="application/rss+xml" class="rss" title="RSS Feed" />
+<link rel="alternate" href="/{{ snippet.pasteid }}/rss" type="application/rss+xml" class="rss" title="RSS Feed" />
 
 <link rel="stylesheet" href="/static/css/{{theme }}.css" type="text/css" title="syntax_theme" />
 
 <script type="text/javascript">
-    snippet_id = "{{ snippet.id }}";
+    snippet_id = "{{ snippet.pasteid }}";
     {% if rev %}revid = "{{ snippet.revid }}";{% endif %}
 </script>
 {% endblock %}
 {% block content %}
 <div id="snippet">
 
-    <h2><a href="/{{ snippet.id }}" class="root">{{ snippet.id }}</a>&nbsp;/&nbsp;{% if snippet.title %}{{ snippet.title }}{% else %}No title{% endif %}</h2>
+    <h2><a href="/{{ snippet.pasteid }}" class="root">{{ snippet.pasteid }}</a>&nbsp;/&nbsp;{% if snippet.title %}{{ snippet.title }}{% else %}No title{% endif %}</h2>
     <div>
         
     </div>
     <div id="info">
-        <p>Revision <a href="/{{ snippet.id }}?rev={{ snippet.revid }}">{{ snippet.revid }}</a> ({{ snippet.updated|timesince }}) - <a href="{{ url_for('paste/changeset', id=snippet.id, rev=snippet.revid) }}">Diff</a>
+        <p>Revision <a href="/{{ snippet.pasteid }}?rev={{ snippet.revid }}">{{ snippet.revid }}</a> ({{ snippet.updated|timesince }}) - <a href="{{ url_for('paste/changeset', id=snippet.pasteid, rev=snippet.revid) }}">Diff</a>
         </p>
         <p class="lsnippet">Link to this snippet : <a href="/{{ snippet.id }}">http://friendpaste.com/{{ snippet.id  }}</a></p>
     </div>
         </div>
 
         <div class="highlight">
-            {{ snippet.snippet|highlight(snippet.language) }}
+            {{ snippet.content|highlight(snippet.language) }}
         </div>
         <div id="bottoma">
             <ul>
 </form>
 
 <div id="revisions" class="hidden">
-    <h2><a href="/{{ snippet.id }}" class="root">{{ snippet.id }}</a>&nbsp;/&nbsp;{% if snippet.title %}{{ snippet.title }}{% else %}No title{% endif %}</h2>
+    <h2><a href="/{{ snippet.pasteid }}" class="root">{{ snippet.paseid }}</a>&nbsp;/&nbsp;{% if snippet.title %}{{ snippet.title }}{% else %}No title{% endif %}</h2>
     <p>last change {{ snippet.updated|datetimeformat }} (UTC)</p>
     <h3>Older revisions</h3>
     <table class="revisionstable">