Blob Blame Raw
#-*- coding: utf-8 -*-

"""
 (c) 2014 - Copyright Red Hat Inc

 Authors:
   Pierre-Yves Chibon <pingou@pingoured.fr>

"""

import flask
import os
from math import ceil

import pygit2
from sqlalchemy.exc import SQLAlchemyError
from pygments import highlight
from pygments.lexers import guess_lexer
from pygments.lexers.text import DiffLexer
from pygments.formatters import HtmlFormatter

import progit.exceptions
import progit.lib
import progit.forms
from progit import (APP, SESSION, LOG, __get_file_in_tree, cla_required,
                    generate_gitolite_acls, generate_gitolite_key,
                    generate_authorized_key_file, markdown_filter)


def chunks(item_list, chunks_size):
    """ Yield successive n-sized chunks from item_list.
    """
    for i in xrange(0, len(item_list), chunks_size):
        yield item_list[i: i + chunks_size]


### Application


@APP.route('/')
def index():
    """ Front page of the application.
    """
    page = flask.request.args.get('page', 1)
    try:
        page = int(page)
    except ValueError:
        page = 1

    limit = APP.config['ITEM_PER_PAGE']
    start = limit * (page - 1)

    repos = progit.lib.list_projects(
        SESSION,
        fork=False,
        start=start,
        limit=limit)
    num_repos = progit.lib.list_projects(
        SESSION,
        fork=False,
        count=True)

    total_page = int(ceil(num_repos / float(limit)))

    repopage = None
    forkpage = None
    user_repos = None
    user_forks = None
    total_page_repos = None
    total_page_forks = None
    repos_obj = None
    forks_obj = None
    username = None
    user_repos_length = None
    user_forks_length = None

    if flask.g.fas_user:
        username = flask.g.fas_user.username

        repopage = flask.request.args.get('repopage', 1)
        try:
            repopage = int(repopage)
        except ValueError:
            repopage = 1

        forkpage = flask.request.args.get('forkpage', 1)
        try:
            forkpage = int(forkpage)
        except ValueError:
            forkpage = 1

        repo_start = limit * (repopage - 1)
        fork_start = limit * (forkpage - 1)

        user_repos = progit.lib.list_projects(
            SESSION,
            username=username,
            fork=False,
            start=repo_start,
            limit=limit)
        user_repos_length = progit.lib.list_projects(
            SESSION,
            username=username,
            fork=False,
            count=True)

        user_forks = progit.lib.list_projects(
            SESSION,
            username=username,
            fork=True,
            start=fork_start,
            limit=limit)
        user_forks_length = progit.lib.list_projects(
            SESSION,
            username=username,
            fork=True,
            count=True)

        total_page_repos = int(ceil(user_repos_length / float(limit)))
        total_page_forks = int(ceil(user_forks_length / float(limit)))

        repos_obj = [
            pygit2.Repository(
                os.path.join(APP.config['GIT_FOLDER'], repo.path))
            for repo in user_repos]

        forks_obj = [
            pygit2.Repository(
                os.path.join(APP.config['FORK_FOLDER'], repo.path))
            for repo in user_forks]

    return flask.render_template(
        'index.html',
        repos=repos,
        total_page=total_page,
        page=page,
        username=username,
        repopage=repopage,
        forkpage=forkpage,
        user_repos=user_repos,
        user_forks=user_forks,
        total_page_repos=total_page_repos,
        total_page_forks=total_page_forks,
        repos_obj=repos_obj,
        forks_obj=forks_obj,
        user_repos_length=user_repos_length,
        user_forks_length=user_forks_length,
        repos_length=num_repos,
    )


@APP.route('/users/')
def view_users():
    """ Present the list of users.
    """
    page = flask.request.args.get('page', 1)
    try:
        page = int(page)
    except ValueError:
        page = 1

    users = progit.lib.search_user(SESSION)

    limit = APP.config['ITEM_PER_PAGE']
    start = limit * (page - 1)
    end = limit * page
    users_length = len(users)
    users = users[start:end]

    total_page = int(ceil(users_length / float(limit)))

    return flask.render_template(
        'user_list.html',
        users=users,
        users_length=users_length,
        total_page=total_page,
        page=page,
    )


@APP.route('/user/<username>')
def view_user(username):
    """ Front page of a specific user.
    """

    repopage = flask.request.args.get('repopage', 1)
    try:
        repopage = int(repopage)
    except ValueError:
        repopage = 1

    forkpage = flask.request.args.get('forkpage', 1)
    try:
        forkpage = int(forkpage)
    except ValueError:
        forkpage = 1

    limit = APP.config['ITEM_PER_PAGE']
    repo_start = limit * (repopage - 1)
    fork_start = limit * (forkpage - 1)

    repos = progit.lib.list_projects(
        SESSION,
        username=username,
        fork=False,
        start=repo_start,
        limit=limit)
    repos_length = progit.lib.list_projects(
        SESSION,
        username=username,
        fork=False,
        count=True)

    forks = progit.lib.list_projects(
        SESSION,
        username=username,
        fork=True,
        start=fork_start,
        limit=limit)
    forks_length = progit.lib.list_projects(
        SESSION,
        username=username,
        fork=True,
        count=True)

    total_page_repos = int(ceil(repos_length / float(limit)))
    total_page_forks = int(ceil(forks_length / float(limit)))

    repos_obj = [
        pygit2.Repository(
            os.path.join(APP.config['GIT_FOLDER'], repo.path))
        for repo in repos]

    forks_obj = [
        pygit2.Repository(
            os.path.join(APP.config['FORK_FOLDER'], repo.path))
        for repo in forks]

    return flask.render_template(
        'user_info.html',
        username=username,
        repos=repos,
        repos_obj=repos_obj,
        total_page_repos=total_page_repos,
        forks=forks,
        forks_obj=forks_obj,
        total_page_forks=total_page_forks,
        repopage=repopage,
        forkpage=forkpage,
        repos_length=repos_length,
        forks_length=forks_length,
    )


@APP.route('/new/', methods=('GET', 'POST'))
@cla_required
def new_project():
    """ Form to create a new project.
    """
    form = progit.forms.ProjectForm()
    if form.validate_on_submit():
        name = form.name.data
        description = form.description.data

        try:
            message = progit.lib.new_project(
                SESSION,
                name=name,
                description=description,
                user=flask.g.fas_user.username,
                gitfolder=APP.config['GIT_FOLDER'],
                docfolder=APP.config['DOCS_FOLDER'],
                ticketfolder=APP.config['TICKETS_FOLDER']
            )
            SESSION.commit()
            generate_gitolite_acls()
            flask.flash(message)
            return flask.redirect(flask.url_for('view_repo', repo=name))
        except progit.exceptions.ProgitException, err:
            flask.flash(str(err), 'error')
        except SQLAlchemyError, err:  # pragma: no cover
            SESSION.rollback()
            flask.flash(str(err), 'error')

    return flask.render_template(
        'new_project.html',
        form=form,
    )


@APP.route('/settings/', methods=('GET', 'POST'))
@cla_required
def user_settings():
    """ Update the user settings.
    """
    user = progit.lib.search_user(
        SESSION, username=flask.g.fas_user.username)

    form = progit.forms.UserSettingsForm()
    if form.validate_on_submit():
        ssh_key = form.ssh_key.data

        try:
            message = progit.lib.update_user_ssh(
                SESSION,
                user=user,
                ssh_key=ssh_key,
            )
            if message != 'Nothing to update':
                generate_gitolite_key(user.user, ssh_key)
                generate_authorized_key_file()
            SESSION.commit()
            flask.flash(message)
            return flask.redirect(
                flask.url_for('view_user', username=user.user))
        except SQLAlchemyError, err:  # pragma: no cover
            SESSION.rollback()
            flask.flash(str(err), 'error')
    elif flask.request.method == 'GET':
        form.ssh_key.data = user.public_ssh_key

    return flask.render_template(
        'user_settings.html',
        user=user,
        form=form,
    )


@APP.route('/markdown/', methods=['POST'])
@cla_required
def markdown_preview():
    """ Return the provided markdown text in html.

    The text has to be provided via the parameter 'content' of a POST query.
    """
    return progit.markdown_filter(flask.request.form['content'])