nautilebleu / django_hg

django_hg allows managing (create, authenticate, clone/push/pull…) Mercurial repositories throught django.

Clone this repository (size: 144.8 KB): HTTPS / SSH
$ hg clone http://bitbucket.org/nautilebleu/django_hg/
commit 14: 8932d6989fe4
parent 13: 16b135a6298d
branch: admin
Replace long if/elif dispatch in views.py/cmds by a __getattribute__
Goulwen Reboux / nautilebleu
9 months ago
django_hg / views.py
r14:8932d6989fe4 243 loc 7.1 KB embed / history / annotate / raw /
# coding=utf-8
import os.path
from datetime import datetime
from math import ceil

from django.http import HttpResponse, HttpResponseRedirect, Http404
from django.shortcuts import render_to_response, get_object_or_404
from django.contrib.auth import authenticate, login
from django.core.urlresolvers import reverse
from django.conf import settings as global_settings
import settings

from mercurial.error import RepoError

from django_hg.models import HgContext, HgRepository
from core.settings import MEDIA_URL

def __get_repo(request, name, rev):
    """
    this private function get the repository object from the database and
    returns the context view of the repository
    """
    repo = get_object_or_404(HgRepository, name=name)
    # Check that the user is allowed to view it
    if repo.anonymous_access == False:
        can_access = False
        for m in repo.members() :
            if request.user.id == m.user_id:
                can_access = True
                break
        if can_access == False :
            #redirect to an unauthorized page
            return HttpResponseRedirect(reverse('signin'))
    try:
        repo.set_context(HgContext(repo, rev))
    except RepoError  :
        raise Http404

    return repo

def changeset(request, name, rev):
    """
    display the file history
    ``name``
        the name of the repository
    ``rev``
        the revision in the changesets history
    """
    repo = __get_repo(request, name, rev)

    ctx = repo.get_context().repository[rev]
    files = []
    for f in ctx.files():
        fc = ctx[f]
        files.append({'name': f, 'size': len(fc.data()) })

    return render_to_response('django_hg/changeset.html', {
        'ctx' : {"user": ctx.user(),
                "description": ctx.description(),
                "date": ctx.date(),
                "hash": ctx,
                "rev": rev,
                "files_count": len(ctx.files())
               },
        'files': files,
        'MEDIA_URL': MEDIA_URL,
        'repo' : repo,
        'rev' : rev,
        'user' : request.user
    })



def changesets(request, name):
    """
    display the changesets history of a repository
    ``name``
        the name of the repository
    """
    repo = __get_repo(request, name, 'tip')

    max = repo.get_context().rev-1
    page = int(request.GET.get('page', 1))
    # forbid a page to be greater than the max or to be lower than one
    if page > max/global_settings.DJANGO_HG_PAGER_ITEMS:
        page = max/global_settings.DJANGO_HG_PAGER_ITEMS+1
    elif page < 1:
        page = 1

    start = max-(page-1)*global_settings.DJANGO_HG_PAGER_ITEMS
    end = max-(page)*global_settings.DJANGO_HG_PAGER_ITEMS

    changelog = []
    c = start
    while c > end:
        ctx = repo.get_context().repository[c]
        # we pass a tuple instead of the object because it's really, really
        # faster (from 12500 to 48 ms with the django repository ! )
        changelog.append({"user": ctx.user(),
                         "description": ctx.description(),
                         "date": ctx.date(),
                         "files_count": len(ctx.files()),
                         "hash": ctx,
                         "rev": c,
                        })
        c = c-1
        if c < 0:
            break

    return render_to_response('django_hg/changesets.html', {
        'changelog': changelog,
        'end': end > 0 and end+1 or 1,
        'items_per_page': global_settings.DJANGO_HG_PAGER_ITEMS,
        'max': max,
        'MEDIA_URL': global_settings.MEDIA_URL,
        'page': page,
        'repo': repo,
        'start': start,
        'user': request.user,
    })




def commands(request, name):
    """
    handles the commands sended by an hg client (clone, pull, push)
    ``name``
        the name of the repository
    """
    from mercurial import hg, ui
    from mercurial.hgweb.request import wsgirequest
    from mercurial.hgweb import protocol
    cmds  = ['between', 'branches', 'capabilities', 'changegroupsubset', 'heads']

    repo = __get_repo(request, name, 'tip')
    req = wsgirequest(request.META, None)
    r = hg.repository(ui.ui(),
                      repo.repo_path)

    if request.GET.get('cmd') in cmds:
        resp = protocol.__getattribute__(request.GET.get('cmd'))(r, req)

    return HttpResponse(resp, protocol.HGTYPE)

def filelog(request, name, rev, file):
    """
    display the file history
    ``name``
        the name of the repository
    ``file``
        the file for which we want the history
    """

    repo = __get_repo(request, name, 'tip')
    ctx = repo.get_context().repository[rev]
    fctx = ctx.filectx(file)
    filelog = []

    for fl in fctx.filelog():
        l = fctx.filectx(fl)
        filelog.append({
            'user': l.user(),
            'date': l.date(),
            'description': l.description(),
            'branch': l.branch(),
        })
    filelog.reverse()

    return render_to_response('django_hg/filelog.html', {
        'file': file,
        'filelog': filelog,
        'MEDIA_URL': global_settings.MEDIA_URL,
        'path': os.path.dirname(file),
        'referer': 'changesets', #request.META['HTTP_REFERER'],
        'repo': repo,
        'rev': rev,
        'user': request.user,
    })

def list(request):
    """
    display a paginated list of repositories. If the user is authenticated, the
    contains both public and private repositories. If not, the list contains
    only public repositories

    """
    page = int(request.GET.get('page', 1))
    if page <= 0 :
        page = 1
    max = HgRepository.objects.count_for_user(request.user, 1)
    if ceil(float(max)/float(settings.DJANGO_HG_PAGER_ITEMS))<page:
        page = int(ceil(float(max)/float(settings.DJANGO_HG_PAGER_ITEMS)))
    start = (page-1)*settings.DJANGO_HG_PAGER_ITEMS
    end = page*settings.DJANGO_HG_PAGER_ITEMS
    if end > max:
        end = max

    repositories = []
    if (max > 0):
        q = HgRepository.objects.get_for_user(request.user, 1)[start:end]
        for repo in q:
            try:
                repo.set_context(HgContext(repo, 'tip'))
                repositories.append(repo)
            except:
                pass

    return render_to_response('django_hg/list.html', {
        'end': end,
        'items_per_page': settings.DJANGO_HG_PAGER_ITEMS,
        'MEDIA_URL': settings.MEDIA_URL,
        'repositories': repositories,
        'page': page,
        'start': start+1,
        'max': int(max),
        'user': request.user,
    })



def detail(request, name, rev, path=''):
    """
    display a repository
    ``name``
        the name of the given repository
    ``rev``
        the revision of the repository. By default, it's equal to ``tip``
    ``path``
        optional. A valid path within the repository. If not given, the root of
        the repository is returned
    """
    repo = __get_repo(request, name, rev)
    files = repo.get_context().get_tree(path)

    return render_to_response('django_hg/detail.html', {
        'files': files,
        'MEDIA_URL': global_settings.MEDIA_URL,
        'path': path,
        'repo': repo,
        'rev': rev,
        'user': request.user
    })