Blame pagure/lib/__init__.py

Pierre-Yves Chibon 33b534
# -*- coding: utf-8 -*-
Pierre-Yves Chibon 1e2e25
Pierre-Yves Chibon 1e2e25
"""
Pierre-Yves Chibon 341785
 (c) 2014-2016 - Copyright Red Hat Inc
Pierre-Yves Chibon 1e2e25
Pierre-Yves Chibon 1e2e25
 Authors:
Pierre-Yves Chibon 1e2e25
   Pierre-Yves Chibon <pingou@pingoured.fr></pingou@pingoured.fr>
Pierre-Yves Chibon 1e2e25
Pierre-Yves Chibon 1e2e25
"""
Pierre-Yves Chibon 1e2e25
Pierre-Yves Chibon 22a554
# pylint: disable=too-many-branches
Pierre-Yves Chibon 22a554
# pylint: disable=too-many-arguments
Pierre-Yves Chibon 22a554
# pylint: disable=too-many-locals
Pierre-Yves Chibon 22a554
# pylint: disable=too-many-statements
Pierre-Yves Chibon 22a554
# pylint: disable=too-many-lines
Pierre-Yves Chibon c3b072
Pierre-Yves Chibon c3b072
Pierre-Yves Chibon 72a8e7
try:
Pierre-Yves Chibon 72a8e7
    import simplejson as json
Pierre-Yves Chibon 72a8e7
except ImportError:
Pierre-Yves Chibon 72a8e7
    import json
Pierre-Yves Chibon 1e2e25
Pierre-Yves Chibon 9af5a0
import datetime
Pierre-Yves Chibon 2d9881
import markdown
Pierre-Yves Chibon d8110b
import os
Pierre-Yves Chibon d133cd
import shutil
Pierre-Yves Chibon d133cd
import tempfile
Patrick Uiterwijk 073828
import subprocess
Pierre-Yves Chibon f1e2a9
import urlparse
Pierre-Yves Chibon 9cb884
import uuid
Pierre-Yves Chibon d8110b
Pierre-Yves Chibon 3916b5
import bleach
Pierre-Yves Chibon 2e464a
import redis
Pierre-Yves Chibon bbbc71
import six
Pierre-Yves Chibon 1e2e25
import sqlalchemy
Pierre-Yves Chibon 42693f
import sqlalchemy.schema
Pierre-Yves Chibon 42693f
from sqlalchemy import func
Ryan Lerch 636f6a
from sqlalchemy import asc
Pierre-Yves Chibon ed38ee
from sqlalchemy.orm import aliased
Pierre-Yves Chibon 1e2e25
from sqlalchemy.orm import sessionmaker
Pierre-Yves Chibon 1e2e25
from sqlalchemy.orm import scoped_session
Pierre-Yves Chibon 1e2e25
Pierre-Yves Chibon d8110b
import pygit2
Pierre-Yves Chibon d8110b
Pierre-Yves Chibon fe5017
import pagure.exceptions
Pierre-Yves Chibon fe5017
import pagure.lib.git
Pierre-Yves Chibon 4fd1f7
import pagure.lib.login
Pierre-Yves Chibon fe5017
import pagure.lib.notify
Pierre-Yves Chibon afcf11
import pagure.lib.plugins
Pierre-Yves Chibon 814bc8
import pagure.pfmarkdown
Pierre-Yves Chibon fe5017
from pagure.lib import model
Pierre-Yves Chibon 1e2e25
Pierre-Yves Chibon 1e2e25
Pierre-Yves Chibon 2e464a
REDIS = None
Pierre-Yves Chibon 587ba8
PAGURE_CI = None
Pierre-Yves Chibon 2e464a
Pierre-Yves Chibon b13b92
Pierre-Yves Chibon d1e053
def set_redis(host, port, dbname):
Pierre-Yves Chibon 2e464a
    """ Set the redis connection with the specified information. """
Pierre-Yves Chibon 2e464a
    global REDIS
Pierre-Yves Chibon d1e053
    pool = redis.ConnectionPool(host=host, port=port, db=dbname)
Pierre-Yves Chibon 2e464a
    REDIS = redis.StrictRedis(connection_pool=pool)
Pierre-Yves Chibon 2e464a
Pierre-Yves Chibon b13b92
Pierre-Yves Chibon 587ba8
def set_pagure_ci(services):
Pierre-Yves Chibon 587ba8
    """ Set the list of CI services supported by this pagure instance. """
Pierre-Yves Chibon 70cf75
    global PAGURE_CI
Pierre-Yves Chibon 587ba8
    PAGURE_CI = services
Pierre-Yves Chibon 587ba8
Pierre-Yves Chibon 2e464a
Pierre-Yves Chibon 6aa385
def get_user(session, key):
Pierre-Yves Chibon 60bea3
    """ Searches for a user in the database for a given username or email.
Pierre-Yves Chibon 60bea3
    """
Pierre-Yves Chibon 60bea3
    user_obj = search_user(session, username=key)
Pierre-Yves Chibon 60bea3
    if not user_obj:
Pierre-Yves Chibon 60bea3
        user_obj = search_user(session, email=key)
Pierre-Yves Chibon 60bea3
Pierre-Yves Chibon 60bea3
    if not user_obj:
Pierre-Yves Chibon fe5017
        raise pagure.exceptions.PagureException(
Pierre-Yves Chibon 60bea3
            'No user "%s" found' % key
Pierre-Yves Chibon 60bea3
        )
Pierre-Yves Chibon 60bea3
Pierre-Yves Chibon 60bea3
    return user_obj
Pierre-Yves Chibon 60bea3
Pierre-Yves Chibon 60bea3
Pierre-Yves Chibon 1e2e25
def create_session(db_url, debug=False, pool_recycle=3600):
Pierre-Yves Chibon 695ef6
    ''' Create the Session object to use to query the database.
Pierre-Yves Chibon 1e2e25
Pierre-Yves Chibon 1e2e25
    :arg db_url: URL used to connect to the database. The URL contains
Pierre-Yves Chibon 1e2e25
    information with regards to the database engine, the host to connect
Pierre-Yves Chibon 1e2e25
    to, the user and password and the database name.
Pierre-Yves Chibon 1e2e25
      ie: <engine>://<user>:<password>@<host>/<dbname></dbname></host></password></user></engine>
Pierre-Yves Chibon 1e2e25
    :kwarg debug: a boolean specifying wether we should have the verbose
Pierre-Yves Chibon 1e2e25
        output of sqlalchemy or not.
Pierre-Yves Chibon 1e2e25
    :return a Session that can be used to query the database.
Pierre-Yves Chibon 1e2e25
Pierre-Yves Chibon 695ef6
    '''
Ryan Lerch 6741dd
    if db_url.startswith('sqlite'):
Ryan Lerch cd0b04
        engine = sqlalchemy.create_engine(
Ryan Lerch cd0b04
            db_url, echo=debug, pool_recycle=pool_recycle)
Ryan Lerch cd0b04
    else:
Ryan Lerch cd0b04
        engine = sqlalchemy.create_engine(
Ryan Lerch cd0b04
            db_url, echo=debug, pool_recycle=pool_recycle,
Ryan Lerch cd0b04
            client_encoding='utf8')
Pierre-Yves Chibon 1e2e25
    scopedsession = scoped_session(sessionmaker(bind=engine))
Pierre-Yves Chibon 1dbdfe
    model.BASE.metadata.bind = scopedsession
Pierre-Yves Chibon 1e2e25
    return scopedsession
Pierre-Yves Chibon 1e2e25
Pierre-Yves Chibon 1e2e25
Pierre-Yves Chibon 42693f
def get_next_id(session, projectid):
Pierre-Yves Chibon 42693f
    """ Returns the next identifier of a project ticket or pull-request
Pierre-Yves Chibon 42693f
    based on the identifier already in the database.
Pierre-Yves Chibon 42693f
    """
Pierre-Yves Chibon b8c7ae
    query1 = session.query(
Pierre-Yves Chibon 7909ea
        func.max(model.Issue.id)
Pierre-Yves Chibon 42693f
    ).filter(
Pierre-Yves Chibon 42693f
        model.Issue.project_id == projectid
Pierre-Yves Chibon 42693f
    )
Pierre-Yves Chibon 42693f
Pierre-Yves Chibon b8c7ae
    query2 = session.query(
Pierre-Yves Chibon 7909ea
        func.max(model.PullRequest.id)
Pierre-Yves Chibon 42693f
    ).filter(
Pierre-Yves Chibon 42693f
        model.PullRequest.project_id == projectid
Pierre-Yves Chibon 42693f
    )
Pierre-Yves Chibon 42693f
Pierre-Yves Chibon b8c7ae
    nid = max([el[0] for el in query1.union(query2).all()]) or 0
Pierre-Yves Chibon 42693f
Pierre-Yves Chibon 7909ea
    return nid + 1
Pierre-Yves Chibon 42693f
Pierre-Yves Chibon 42693f
Pierre-Yves Chibon de2a45
def search_user(session, username=None, email=None, token=None, pattern=None):
Pierre-Yves Chibon de2a45
    ''' Searches the database for the user or users matching the given
Pierre-Yves Chibon de2a45
    criterias.
Pierre-Yves Chibon de2a45
Pierre-Yves Chibon de2a45
    :arg session: the session to use to connect to the database.
Pierre-Yves Chibon de2a45
    :kwarg username: the username of the user to look for.
Pierre-Yves Chibon de2a45
    :type username: string or None
Pierre-Yves Chibon de2a45
    :kwarg email: the email or one of the email of the user to look for
Pierre-Yves Chibon de2a45
    :type email: string or None
Pierre-Yves Chibon de2a45
    :kwarg token: the token of the user to look for
Pierre-Yves Chibon de2a45
    :type token: string or None
Pierre-Yves Chibon de2a45
    :kwarg pattern: a pattern to search the users with.
Pierre-Yves Chibon de2a45
    :type pattern: string or None
Pierre-Yves Chibon de2a45
    :return: A single User object if any of username, email or token is
Pierre-Yves Chibon de2a45
        specified, a list of User objects otherwise.
Pierre-Yves Chibon de2a45
    :rtype: User or [User]
Pierre-Yves Chibon 34cbca
Pierre-Yves Chibon 34cbca
    '''
Pierre-Yves Chibon 4cbbea
    query = session.query(
Pierre-Yves Chibon 556d85
        model.User
Pierre-Yves Chibon 692bf9
    ).order_by(
Pierre-Yves Chibon 692bf9
        model.User.user
Pierre-Yves Chibon 4cbbea
    )
Pierre-Yves Chibon 4cbbea
Pierre-Yves Chibon de2a45
    if username is not None:
Pierre-Yves Chibon de2a45
        query = query.filter(
Pierre-Yves Chibon de2a45
            model.User.user == username
Pierre-Yves Chibon de2a45
        )
Pierre-Yves Chibon de2a45
Pierre-Yves Chibon de2a45
    if email is not None:
Pierre-Yves Chibon de2a45
        query = query.filter(
Pierre-Yves Chibon de2a45
            model.UserEmail.user_id == model.User.id
Pierre-Yves Chibon de2a45
        ).filter(
Pierre-Yves Chibon de2a45
            model.UserEmail.email == email
Pierre-Yves Chibon de2a45
        )
Pierre-Yves Chibon de2a45
Pierre-Yves Chibon de2a45
    if token is not None:
Pierre-Yves Chibon de2a45
        query = query.filter(
Pierre-Yves Chibon de2a45
            model.User.token == token
Pierre-Yves Chibon de2a45
        )
Pierre-Yves Chibon de2a45
Pierre-Yves Chibon 4cbbea
    if pattern:
Pierre-Yves Chibon 4cbbea
        pattern = pattern.replace('*', '%')
Pierre-Yves Chibon 4cbbea
        query = query.filter(
Pierre-Yves Chibon 4cbbea
            model.User.user.like(pattern)
Pierre-Yves Chibon 4cbbea
        )
Pierre-Yves Chibon 4cbbea
Pierre-Yves Chibon de2a45
    if any([username, email, token]):
Pierre-Yves Chibon de2a45
        output = query.first()
Pierre-Yves Chibon de2a45
    else:
Pierre-Yves Chibon de2a45
        output = query.all()
Pierre-Yves Chibon de2a45
Pierre-Yves Chibon de2a45
    return output
Pierre-Yves Chibon 556d85
Pierre-Yves Chibon f365ae
Patrick Uiterwijk 073828
def is_valid_ssh_key(key):
Patrick Uiterwijk 073828
    key = key.strip()
Patrick Uiterwijk 073828
    if not key:
Patrick Uiterwijk 073828
        return None
Patrick Uiterwijk cf336e
    with tempfile.TemporaryFile() as f:
Pierre-Yves Chibon 695680
        f.write(key.encode('utf-8'))
Patrick Uiterwijk cf336e
        f.seek(0)
Patrick Uiterwijk cf336e
        proc = subprocess.Popen(['/usr/bin/ssh-keygen', '-l', '-f',
Patrick Uiterwijk cf336e
                                 '/dev/stdin'],
Patrick Uiterwijk cf336e
                                stdin=f,
Patrick Uiterwijk cf336e
                                stdout=subprocess.PIPE,
Patrick Uiterwijk cf336e
                                stderr=subprocess.PIPE)
Patrick Uiterwijk cf336e
    proc.communicate()
Patrick Uiterwijk 073828
    return proc.returncode == 0
Patrick Uiterwijk 073828
Patrick Uiterwijk 073828
Patrick Uiterwijk f8d590
def are_valid_ssh_keys(keys):
Patrick Uiterwijk f8d590
    return all([is_valid_ssh_key(key) is not False
Patrick Uiterwijk f8d590
                for key in keys.split('\n')])
Patrick Uiterwijk f8d590
Patrick Uiterwijk f8d590
Patrick Uiterwijk 0e5f4a
def create_user_ssh_keys_on_disk(user, gitolite_keydir):
Pierre-Yves Chibon d1e053
    ''' Create the ssh keys for the user on the specific folder.
Pierre-Yves Chibon d1e053
Pierre-Yves Chibon d1e053
    This is the method allowing to have multiple ssh keys per user.
Pierre-Yves Chibon d1e053
    '''
Patrick Uiterwijk 0e5f4a
    if gitolite_keydir:
Patrick Uiterwijk 0e5f4a
        # First remove any old keyfiles for the user
Patrick Uiterwijk 0e5f4a
        # Assumption: we populated the keydir. This means that files
Patrick Uiterwijk 0e5f4a
        #  will be in 0/<username>.pub, ..., and not in any deeper</username>
Patrick Uiterwijk 0e5f4a
        #  directory structures. Also, this means that if a user
Patrick Uiterwijk 0e5f4a
        #  had 5 lines, they will be up to at most keys_4/<username>.pub,</username>
Patrick Uiterwijk 0e5f4a
        #  meaning that if a user is not in keys_/<username>.pub, with</username>
Patrick Uiterwijk 0e5f4a
        #  i being any integer, the user is most certainly not in
Patrick Uiterwijk 0e5f4a
        #  keys_<i+1>/<username>.pub.</username></i+1>
Patrick Uiterwijk 0e5f4a
        i = 0
Patrick Uiterwijk 0e5f4a
        keyline_file = os.path.join(gitolite_keydir,
Patrick Uiterwijk 0e5f4a
                                    'keys_%i' % i,
Patrick Uiterwijk 0e5f4a
                                    '%s.pub' % user.user)
Patrick Uiterwijk 0e5f4a
        while os.path.exists(keyline_file):
Pierre-Yves Chibon 11f8ab
            os.unlink(keyline_file)
Patrick Uiterwijk 0e5f4a
            i += 1
Patrick Uiterwijk 0e5f4a
            keyline_file = os.path.join(gitolite_keydir,
Patrick Uiterwijk 0e5f4a
                                        'keys_%i' % i,
Patrick Uiterwijk 0e5f4a
                                        '%s.pub' % user.user)
Patrick Uiterwijk 0e5f4a
Patrick Uiterwijk 0e5f4a
        # Now let's create new keyfiles for the user
Patrick Uiterwijk 0e5f4a
        keys = user.public_ssh_key.split('\n')
Patrick Uiterwijk 0e5f4a
        for i in range(len(keys)):
Pierre-Yves Chibon 57803d
            if not keys[i]:
Pierre-Yves Chibon 57803d
                continue
Patrick Uiterwijk 073828
            if not is_valid_ssh_key(keys[i]):
Patrick Uiterwijk 073828
                continue
Patrick Uiterwijk 0e5f4a
            keyline_dir = os.path.join(gitolite_keydir, 'keys_%i' % i)
Patrick Uiterwijk 0e5f4a
            if not os.path.exists(keyline_dir):
Patrick Uiterwijk 0e5f4a
                os.mkdir(keyline_dir)
Patrick Uiterwijk 0e5f4a
            keyfile = os.path.join(keyline_dir, '%s.pub' % user.user)
Patrick Uiterwijk 0e5f4a
            with open(keyfile, 'w') as stream:
Patrick Uiterwijk 0e5f4a
                stream.write(keys[i].strip().encode('UTF-8'))
Pierre-Yves Chibon 556d85
Pierre-Yves Chibon f365ae
Pierre-Yves Chibon 27fdde
def add_issue_comment(session, issue, comment, user, ticketfolder,
Pierre-Yves Chibon 63d32c
                      notify=True, date_created=None, notification=False):
Pierre-Yves Chibon 03c11f
    ''' Add a comment to an issue. '''
Pierre-Yves Chibon 6aa385
    user_obj = get_user(session, user)
Pierre-Yves Chibon e1372f
Pierre-Yves Chibon 00c3f0
    issue_comment = model.IssueComment(
Pierre-Yves Chibon cc99df
        issue_uid=issue.uid,
Pierre-Yves Chibon 359db9
        comment=comment,
Pierre-Yves Chibon e1372f
        user_id=user_obj.id,
Clement Verna f45e89
        date_created=date_created,
Pierre-Yves Chibon 63d32c
        notification=notification,
Pierre-Yves Chibon 359db9
    )
Pierre-Yves Chibon 00c3f0
    session.add(issue_comment)
Pierre-Yves Chibon db8de8
    # Make sure we won't have SQLAlchemy error before we continue
Pierre-Yves Chibon 44a755
    session.commit()
Pierre-Yves Chibon 359db9
Pierre-Yves Chibon fe5017
    pagure.lib.git.update_git(
Pierre-Yves Chibon f7d56f
        issue, repo=issue.project, repofolder=ticketfolder)
Pierre-Yves Chibon a34835
Pierre-Yves Chibon 27fdde
    if notify:
Pierre-Yves Chibon fe5017
        pagure.lib.notify.notify_new_comment(issue_comment, user=user_obj)
Pierre-Yves Chibon 4b55b4
Pierre-Yves Chibon 399b0f
    if not issue.private:
Pierre-Yves Chibon c898e5
        pagure.lib.notify.log(
Pierre-Yves Chibon c898e5
            issue.project,
Pierre-Yves Chibon c898e5
            topic='issue.comment.added',
Pierre-Yves Chibon c898e5
            msg=dict(
Pierre-Yves Chibon 972598
                issue=issue.to_json(public=True),
Pierre-Yves Chibon 972598
                project=issue.project.to_json(public=True),
Pierre-Yves Chibon 399b0f
                agent=user_obj.username,
Pierre-Yves Chibon 482d84
            ),
Pierre-Yves Chibon 2e464a
            redis=REDIS,
Pierre-Yves Chibon 0ce3a2
        )
Pierre-Yves Chibon 0ce3a2
Pierre-Yves Chibon 2e464a
    if REDIS:
Pierre-Yves Chibon b7e379
        if issue.private:
Pierre-Yves Chibon 8e41fb
            REDIS.publish('pagure.%s' % issue.uid, json.dumps({
Pierre-Yves Chibon 0d9165
                'issue': 'private',
Pierre-Yves Chibon 0d9165
                'comment_id': issue_comment.id,
Pierre-Yves Chibon 0d9165
            }))
Pierre-Yves Chibon b7e379
        else:
Pierre-Yves Chibon 8e41fb
            REDIS.publish('pagure.%s' % issue.uid, json.dumps({
Pierre-Yves Chibon 59df71
                'comment_id': issue_comment.id,
Pierre-Yves Chibon 0110a9
                'issue_id': issue.id,
Pierre-Yves Chibon e1f29a
                'project': issue.project.fullname,
Pierre-Yves Chibon b7e379
                'comment_added': text2markdown(issue_comment.comment),
Pierre-Yves Chibon b7e379
                'comment_user': issue_comment.user.user,
Pierre-Yves Chibon 0ee9f8
                'avatar_url': avatar_url_from_openid(
Pierre-Yves Chibon 0ee9f8
                    issue_comment.user.default_email, size=16),
Pierre-Yves Chibon b7e379
                'comment_date': issue_comment.date_created.strftime(
Pierre-Yves Chibon c1c354
                    '%Y-%m-%d %H:%M:%S'),
Pierre-Yves Chibon 63d32c
                'notification': notification,
Pierre-Yves Chibon b7e379
            }))
Pierre-Yves Chibon 72a8e7
Pierre-Yves Chibon 359db9
    return 'Comment added'
Pierre-Yves Chibon 359db9
Pierre-Yves Chibon 359db9
Pierre-Yves Chibon 2e464a
def add_tag_obj(session, obj, tags, user, ticketfolder):
Pierre-Yves Chibon 931b1d
    ''' Add a tag to an object (either an issue or a project). '''
Pierre-Yves Chibon 6aa385
    user_obj = get_user(session, user)
Pierre-Yves Chibon aafc66
Pierre-Yves Chibon e1b51e
    if isinstance(tags, basestring):
Pierre-Yves Chibon e1b51e
        tags = [tags]
Pierre-Yves Chibon e1b51e
Pierre-Yves Chibon e1b51e
    added_tags = []
Pierre-Yves Chibon 931b1d
    for objtag in tags:
Pierre-Yves Chibon 931b1d
        objtag = objtag.strip()
Pierre-Yves Chibon e1b51e
        known = False
Pierre-Yves Chibon 931b1d
        for tagobj in obj.tags:
Pierre-Yves Chibon 931b1d
            if tagobj.tag == objtag:
Pierre-Yves Chibon e1b51e
                known = True
Pierre-Yves Chibon e1b51e
Pierre-Yves Chibon e1b51e
        if known:
Pierre-Yves Chibon e1b51e
            continue
Pierre-Yves Chibon e1b51e
Pierre-Yves Chibon 931b1d
        tagobj = get_tag(session, objtag)
Pierre-Yves Chibon e1b51e
        if not tagobj:
Pierre-Yves Chibon 931b1d
            tagobj = model.Tag(tag=objtag)
Pierre-Yves Chibon e1b51e
            session.add(tagobj)
Pierre-Yves Chibon e1b51e
            session.flush()
Pierre-Yves Chibon e1b51e
Pierre-Yves Chibon b0ba8a
        if isinstance(obj, model.Issue):
Pierre-Yves Chibon 931b1d
            dbobjtag = model.TagIssue(
Pierre-Yves Chibon 292bbc
                issue_uid=obj.uid,
Pierre-Yves Chibon 931b1d
                tag=tagobj.tag,
Pierre-Yves Chibon 931b1d
            )
Pierre-Yves Chibon b0ba8a
        if isinstance(obj, model.Project):
Pierre-Yves Chibon 931b1d
            dbobjtag = model.TagProject(
Pierre-Yves Chibon 931b1d
                project_id=obj.id,
Pierre-Yves Chibon 931b1d
                tag=tagobj.tag,
Pierre-Yves Chibon 931b1d
            )
Pierre-Yves Chibon 931b1d
Pierre-Yves Chibon 931b1d
        session.add(dbobjtag)
Pierre-Yves Chibon db8de8
        # Make sure we won't have SQLAlchemy error before we continue
Pierre-Yves Chibon 12bd3d
        session.flush()
Pierre-Yves Chibon e1b51e
        added_tags.append(tagobj.tag)
Pierre-Yves Chibon aafc66
Pierre-Yves Chibon b0ba8a
    if isinstance(obj, model.Issue):
Pierre-Yves Chibon 931b1d
        pagure.lib.git.update_git(
Pierre-Yves Chibon 292bbc
            obj, repo=obj.project, repofolder=ticketfolder)
Pierre-Yves Chibon aafc66
Pierre-Yves Chibon 292bbc
        if not obj.private:
Pierre-Yves Chibon 931b1d
            pagure.lib.notify.log(
Pierre-Yves Chibon 292bbc
                obj.project,
Pierre-Yves Chibon 931b1d
                topic='issue.tag.added',
Pierre-Yves Chibon 931b1d
                msg=dict(
Pierre-Yves Chibon 292bbc
                    issue=obj.to_json(public=True),
Pierre-Yves Chibon 292bbc
                    project=obj.project.to_json(public=True),
Pierre-Yves Chibon 931b1d
                    tags=added_tags,
Pierre-Yves Chibon 931b1d
                    agent=user_obj.username,
Pierre-Yves Chibon 482d84
                ),
Pierre-Yves Chibon 2e464a
                redis=REDIS,
Pierre-Yves Chibon 51719b
            )
Pierre-Yves Chibon 0ce3a2
Pierre-Yves Chibon 482d84
        # Send notification for the event-source server
Pierre-Yves Chibon 2e464a
        if REDIS:
Pierre-Yves Chibon 8e41fb
            REDIS.publish('pagure.%s' % obj.uid, json.dumps(
Pierre-Yves Chibon 8e41fb
                {'added_tags': added_tags}))
Pierre-Yves Chibon 26753b
Pierre-Yves Chibon e1b51e
    if added_tags:
Pierre-Yves Chibon e1b51e
        return 'Tag added: %s' % ', '.join(added_tags)
Pierre-Yves Chibon e1b51e
    else:
Pierre-Yves Chibon e1b51e
        return 'Nothing to add'
Pierre-Yves Chibon aafc66
Pierre-Yves Chibon aafc66
Clement Verna b46f3d
def add_issue_assignee(session, issue, assignee, user, ticketfolder,
Clement Verna b46f3d
                       notify=True):
Pierre-Yves Chibon cdaaf3
    ''' Add an assignee to an issue, in other words, assigned an issue. '''
Pierre-Yves Chibon 6aa385
    user_obj = get_user(session, user)
Pierre-Yves Chibon 153903
Pierre-Yves Chibon b53eb8
    if assignee is None and issue.assignee is not None:
Pierre-Yves Chibon e39d28
        issue.assignee_id = None
Pierre-Yves Chibon e39d28
        session.add(issue)
Pierre-Yves Chibon e39d28
        session.commit()
Pierre-Yves Chibon fe5017
        pagure.lib.git.update_git(
Pierre-Yves Chibon 2da35f
            issue, repo=issue.project, repofolder=ticketfolder)
Pierre-Yves Chibon e39d28
Clement Verna b46f3d
        if notify:
Clement Verna b46f3d
            pagure.lib.notify.notify_assigned_issue(issue, None, user_obj)
Clement Verna ef0ab2
Clement Verna ef0ab2
        if not issue.private:
Clement Verna ef0ab2
            pagure.lib.notify.log(
Clement Verna ef0ab2
                issue.project,
Clement Verna ef0ab2
                topic='issue.assigned.reset',
Clement Verna ef0ab2
                msg=dict(
Clement Verna ef0ab2
                    issue=issue.to_json(public=True),
Clement Verna ef0ab2
                    project=issue.project.to_json(public=True),
Clement Verna ef0ab2
                    agent=user_obj.username,
Clement Verna ef0ab2
                ),
Clement Verna ef0ab2
                redis=REDIS,
Clement Verna ef0ab2
            )
Clement Verna ef0ab2
Clement Verna ef0ab2
        # Send notification for the event-source server
Clement Verna ef0ab2
        if REDIS:
Clement Verna ef0ab2
            REDIS.publish('pagure.%s' % issue.uid, json.dumps(
Clement Verna ef0ab2
                {'unassigned': '-'}))
Clement Verna ef0ab2
Clement Verna ef0ab2
        return 'Assignee reset'
Pierre-Yves Chibon b53eb8
    elif assignee is None and issue.assignee is None:
Pierre-Yves Chibon 25a5fe
        return
Pierre-Yves Chibon e39d28
Pierre-Yves Chibon cdaaf3
    # Validate the assignee
Pierre-Yves Chibon 6aa385
    assignee_obj = get_user(session, assignee)
Pierre-Yves Chibon cdaaf3
Pierre-Yves Chibon 153903
    if issue.assignee_id != assignee_obj.id:
Pierre-Yves Chibon 153903
        issue.assignee_id = assignee_obj.id
Pierre-Yves Chibon cdaaf3
        session.add(issue)
Pierre-Yves Chibon cdaaf3
        session.flush()
Pierre-Yves Chibon fe5017
        pagure.lib.git.update_git(
Pierre-Yves Chibon 2da35f
            issue, repo=issue.project, repofolder=ticketfolder)
Clement Verna ef0ab2
        if notify:
Clement Verna ef0ab2
            pagure.lib.notify.notify_assigned_issue(
Clement Verna ef0ab2
                issue, assignee_obj, user_obj)
Pierre-Yves Chibon ff30f1
Pierre-Yves Chibon 006a5d
        if not issue.private:
Pierre-Yves Chibon c898e5
            pagure.lib.notify.log(
Pierre-Yves Chibon c898e5
                issue.project,
Pierre-Yves Chibon c898e5
                topic='issue.assigned.added',
Pierre-Yves Chibon c898e5
                msg=dict(
Pierre-Yves Chibon 972598
                    issue=issue.to_json(public=True),
Pierre-Yves Chibon 972598
                    project=issue.project.to_json(public=True),
Pierre-Yves Chibon 006a5d
                    agent=user_obj.username,
Pierre-Yves Chibon 482d84
                ),
Pierre-Yves Chibon 2e464a
                redis=REDIS,
Pierre-Yves Chibon 0ce3a2
            )
Pierre-Yves Chibon 0ce3a2
Pierre-Yves Chibon 482d84
        # Send notification for the event-source server
Pierre-Yves Chibon 2e464a
        if REDIS:
Pierre-Yves Chibon 8e41fb
            REDIS.publish('pagure.%s' % issue.uid, json.dumps(
Pierre-Yves Chibon ca0907
                {'assigned': assignee_obj.to_json(public=True)}))
Pierre-Yves Chibon ca0907
Pierre-Yves Chibon cdaaf3
        return 'Issue assigned'
Pierre-Yves Chibon cdaaf3
Pierre-Yves Chibon 723e4a
Pierre-Yves Chibon b1fc61
def add_pull_request_assignee(
Pierre-Yves Chibon 2e464a
        session, request, assignee, user, requestfolder):
Pierre-Yves Chibon 4c8e72
    ''' Add an assignee to a request, in other words, assigned an issue. '''
Pierre-Yves Chibon 6aa385
    get_user(session, assignee)
Pierre-Yves Chibon 6aa385
    user_obj = get_user(session, user)
Pierre-Yves Chibon 4c8e72
Pierre-Yves Chibon 4c8e72
    if assignee is None and request.assignee is not None:
Pierre-Yves Chibon 4c8e72
        request.assignee_id = None
Pierre-Yves Chibon 4c8e72
        session.add(request)
Pierre-Yves Chibon 4c8e72
        session.commit()
Pierre-Yves Chibon 4c8e72
        pagure.lib.git.update_git(
Pierre-Yves Chibon 4c8e72
            request, repo=request.project, repofolder=requestfolder)
Pierre-Yves Chibon 4c8e72
Pierre-Yves Chibon 4c8e72
        pagure.lib.notify.notify_assigned_request(request, None, user_obj)
Pierre-Yves Chibon c898e5
        pagure.lib.notify.log(
Pierre-Yves Chibon c898e5
            request.project,
Pierre-Yves Chibon c898e5
            topic='request.assigned.reset',
Pierre-Yves Chibon c898e5
            msg=dict(
Pierre-Yves Chibon 972598
                request=request.to_json(public=True),
Pierre-Yves Chibon 972598
                project=request.project.to_json(public=True),
Pierre-Yves Chibon 4c8e72
                agent=user_obj.username,
Pierre-Yves Chibon 482d84
            ),
Pierre-Yves Chibon 2e464a
            redis=REDIS,
Pierre-Yves Chibon 4c8e72
        )
Pierre-Yves Chibon 4c8e72
Pierre-Yves Chibon 4c8e72
        return 'Request reset'
Pierre-Yves Chibon 4c8e72
    elif assignee is None and request.assignee is None:
Pierre-Yves Chibon 4c8e72
        return
Pierre-Yves Chibon 4c8e72
Pierre-Yves Chibon 4c8e72
    # Validate the assignee
Pierre-Yves Chibon 6aa385
    assignee_obj = get_user(session, assignee)
Pierre-Yves Chibon 4c8e72
Pierre-Yves Chibon 4c8e72
    if request.assignee_id != assignee_obj.id:
Pierre-Yves Chibon 4c8e72
        request.assignee_id = assignee_obj.id
Pierre-Yves Chibon 4c8e72
        session.add(request)
Pierre-Yves Chibon 4c8e72
        session.flush()
Pierre-Yves Chibon 4c8e72
        pagure.lib.git.update_git(
Pierre-Yves Chibon 4c8e72
            request, repo=request.project, repofolder=requestfolder)
Pierre-Yves Chibon 4c8e72
Pierre-Yves Chibon 4c8e72
        pagure.lib.notify.notify_assigned_request(
Pierre-Yves Chibon 4c8e72
            request, assignee_obj, user_obj)
Pierre-Yves Chibon 4c8e72
Pierre-Yves Chibon c898e5
        pagure.lib.notify.log(
Pierre-Yves Chibon c898e5
            request.project,
Pierre-Yves Chibon c898e5
            topic='request.assigned.added',
Pierre-Yves Chibon c898e5
            msg=dict(
Pierre-Yves Chibon 972598
                request=request.to_json(public=True),
Pierre-Yves Chibon 972598
                project=request.project.to_json(public=True),
Pierre-Yves Chibon 4c8e72
                agent=user_obj.username,
Pierre-Yves Chibon 482d84
            ),
Pierre-Yves Chibon 2e464a
            redis=REDIS,
Pierre-Yves Chibon 4c8e72
        )
Pierre-Yves Chibon 4c8e72
Pierre-Yves Chibon 4c8e72
        return 'Request assigned'
Pierre-Yves Chibon cdaaf3
Pierre-Yves Chibon 723e4a
Pierre-Yves Chibon 85ee44
def add_issue_dependency(
Pierre-Yves Chibon 2e464a
        session, issue, issue_blocked, user, ticketfolder):
Pierre-Yves Chibon e523bf
    ''' Add a dependency between two issues. '''
Pierre-Yves Chibon 6aa385
    user_obj = get_user(session, user)
Pierre-Yves Chibon ad1385
Pierre-Yves Chibon ed19c4
    if issue.uid == issue_blocked.uid:
Pierre-Yves Chibon fe5017
        raise pagure.exceptions.PagureException(
Pierre-Yves Chibon ed19c4
            'An issue cannot depend on itself'
Pierre-Yves Chibon ed19c4
        )
Pierre-Yves Chibon ed19c4
Pierre-Yves Chibon ad1385
    if issue_blocked not in issue.children:
Pierre-Yves Chibon ad1385
        i2i = model.IssueToIssue(
Pierre-Yves Chibon ad1385
            parent_issue_id=issue_blocked.uid,
Pierre-Yves Chibon ad1385
            child_issue_id=issue.uid
Pierre-Yves Chibon ad1385
        )
Pierre-Yves Chibon ad1385
        session.add(i2i)
Pierre-Yves Chibon db8de8
        # Make sure we won't have SQLAlchemy error before we continue
Pierre-Yves Chibon ad1385
        session.flush()
Pierre-Yves Chibon fe5017
        pagure.lib.git.update_git(
Pierre-Yves Chibon 2da35f
            issue,
Pierre-Yves Chibon 2da35f
            repo=issue.project,
Pierre-Yves Chibon 2da35f
            repofolder=ticketfolder)
Pierre-Yves Chibon fe5017
        pagure.lib.git.update_git(
Pierre-Yves Chibon ad1385
            issue_blocked,
Pierre-Yves Chibon ad1385
            repo=issue_blocked.project,
Pierre-Yves Chibon 2da35f
            repofolder=ticketfolder)
Pierre-Yves Chibon ad1385
Pierre-Yves Chibon fe5017
        #pagure.lib.notify.notify_assigned_issue(issue, user_obj)
Pierre-Yves Chibon fe5017
        #pagure.lib.notify.notify_assigned_issue(issue_blocked, user_obj)
Pierre-Yves Chibon ad1385
Pierre-Yves Chibon 09dfdc
        if not issue.private:
Pierre-Yves Chibon c898e5
            pagure.lib.notify.log(
Pierre-Yves Chibon c898e5
                issue.project,
Pierre-Yves Chibon c898e5
                topic='issue.dependency.added',
Pierre-Yves Chibon c898e5
                msg=dict(
Pierre-Yves Chibon 972598
                    issue=issue.to_json(public=True),
Pierre-Yves Chibon 972598
                    project=issue.project.to_json(public=True),
Pierre-Yves Chibon f66b1e
                    added_dependency=issue_blocked.id,
Pierre-Yves Chibon 09dfdc
                    agent=user_obj.username,
Pierre-Yves Chibon 482d84
                ),
Pierre-Yves Chibon 2e464a
                redis=REDIS,
Pierre-Yves Chibon 0ce3a2
            )
Pierre-Yves Chibon 0ce3a2
Pierre-Yves Chibon 482d84
        # Send notification for the event-source server
Pierre-Yves Chibon 2e464a
        if REDIS:
Pierre-Yves Chibon 8e41fb
            REDIS.publish('pagure.%s' % issue.uid, json.dumps({
Pierre-Yves Chibon 85ee44
                'added_dependency': issue_blocked.id,
Pierre-Yves Chibon 85ee44
                'issue_uid': issue.uid,
Pierre-Yves Chibon 85ee44
                'type': 'children',
Pierre-Yves Chibon 85ee44
            }))
Pierre-Yves Chibon 8e41fb
            REDIS.publish('pagure.%s' % issue_blocked.uid, json.dumps({
Pierre-Yves Chibon 85ee44
                'added_dependency': issue.id,
Pierre-Yves Chibon 85ee44
                'issue_uid': issue_blocked.uid,
Pierre-Yves Chibon 85ee44
                'type': 'parent',
Pierre-Yves Chibon 85ee44
            }))
Pierre-Yves Chibon 85ee44
Pierre-Yves Chibon 7e765d
        return 'Dependency added'
Pierre-Yves Chibon ad1385
Pierre-Yves Chibon ad1385
Pierre-Yves Chibon 85ee44
def remove_issue_dependency(
Pierre-Yves Chibon 2e464a
        session, issue, issue_blocked, user, ticketfolder):
Pierre-Yves Chibon b49ea7
    ''' Remove a dependency between two issues. '''
Pierre-Yves Chibon 6aa385
    user_obj = get_user(session, user)
Pierre-Yves Chibon b49ea7
Pierre-Yves Chibon b49ea7
    if issue.uid == issue_blocked.uid:
Pierre-Yves Chibon fe5017
        raise pagure.exceptions.PagureException(
Pierre-Yves Chibon b49ea7
            'An issue cannot depend on itself'
Pierre-Yves Chibon b49ea7
        )
Pierre-Yves Chibon b49ea7
Pierre-Yves Chibon b49ea7
    if issue_blocked in issue.children:
Pierre-Yves Chibon b8c7ae
        child_del = []
Pierre-Yves Chibon b49ea7
        for child in issue.children:
Pierre-Yves Chibon b49ea7
            if child.uid == issue_blocked.uid:
Pierre-Yves Chibon b8c7ae
                child_del.append(child.id)
Pierre-Yves Chibon b49ea7
                issue.children.remove(child)
Pierre-Yves Chibon b49ea7
Pierre-Yves Chibon db8de8
        # Make sure we won't have SQLAlchemy error before we continue
Pierre-Yves Chibon b49ea7
        session.flush()
Pierre-Yves Chibon fe5017
        pagure.lib.git.update_git(
Pierre-Yves Chibon 2da35f
            issue,
Pierre-Yves Chibon 2da35f
            repo=issue.project,
Pierre-Yves Chibon 2da35f
            repofolder=ticketfolder)
Pierre-Yves Chibon fe5017
        pagure.lib.git.update_git(
Pierre-Yves Chibon b49ea7
            issue_blocked,
Pierre-Yves Chibon b49ea7
            repo=issue_blocked.project,
Pierre-Yves Chibon 2da35f
            repofolder=ticketfolder)
Pierre-Yves Chibon b49ea7
Pierre-Yves Chibon fe5017
        #pagure.lib.notify.notify_assigned_issue(issue, user_obj)
Pierre-Yves Chibon fe5017
        #pagure.lib.notify.notify_assigned_issue(issue_blocked, user_obj)
Pierre-Yves Chibon b49ea7
Pierre-Yves Chibon 09dfdc
        if not issue.private:
Pierre-Yves Chibon c898e5
            pagure.lib.notify.log(
Pierre-Yves Chibon c898e5
                issue.project,
Pierre-Yves Chibon c898e5
                topic='issue.dependency.removed',
Pierre-Yves Chibon c898e5
                msg=dict(
Pierre-Yves Chibon 972598
                    issue=issue.to_json(public=True),
Pierre-Yves Chibon 972598
                    project=issue.project.to_json(public=True),
Pierre-Yves Chibon b8c7ae
                    removed_dependency=child_del,
Pierre-Yves Chibon 09dfdc
                    agent=user_obj.username,
Pierre-Yves Chibon 482d84
                ),
Pierre-Yves Chibon 2e464a
                redis=REDIS,
Pierre-Yves Chibon 0ce3a2
            )
Pierre-Yves Chibon 0ce3a2
Pierre-Yves Chibon 482d84
        # Send notification for the event-source server
Pierre-Yves Chibon 2e464a
        if REDIS:
Pierre-Yves Chibon 8e41fb
            REDIS.publish('pagure.%s' % issue.uid, json.dumps({
Pierre-Yves Chibon 85ee44
                'removed_dependency': child_del,
Pierre-Yves Chibon 85ee44
                'issue_uid': issue.uid,
Pierre-Yves Chibon 85ee44
                'type': 'children',
Pierre-Yves Chibon 85ee44
            }))
Pierre-Yves Chibon 8e41fb
            REDIS.publish('pagure.%s' % issue_blocked.uid, json.dumps({
Pierre-Yves Chibon 85ee44
                'removed_dependency': issue.id,
Pierre-Yves Chibon 85ee44
                'issue_uid': issue_blocked.uid,
Pierre-Yves Chibon 85ee44
                'type': 'parent',
Pierre-Yves Chibon 85ee44
            }))
Pierre-Yves Chibon 85ee44
Pierre-Yves Chibon b49ea7
        return 'Dependency removed'
Pierre-Yves Chibon b49ea7
Pierre-Yves Chibon b49ea7
Pierre-Yves Chibon 2e464a
def remove_tags(session, project, tags, ticketfolder, user):
Pierre-Yves Chibon 83cba8
    ''' Removes the specified tag of a project. '''
Pierre-Yves Chibon 6aa385
    user_obj = get_user(session, user)
Pierre-Yves Chibon 83cba8
Pierre-Yves Chibon 83cba8
    if not isinstance(tags, list):
Pierre-Yves Chibon 83cba8
        tags = [tags]
Pierre-Yves Chibon 83cba8
Pierre-Yves Chibon 3b7b2b
    issues = search_issues(session, project, closed=False, tags=tags)
Pierre-Yves Chibon 3b7b2b
    issues.extend(search_issues(session, project, closed=True, tags=tags))
Pierre-Yves Chibon 83cba8
Pierre-Yves Chibon 83cba8
    msgs = []
Pierre-Yves Chibon ba0f71
    removed_tags = []
Pierre-Yves Chibon 83cba8
    if not issues:
Pierre-Yves Chibon fe5017
        raise pagure.exceptions.PagureException(
Pierre-Yves Chibon 782b9c
            'No issue found with the tags: %s' % ', '.join(tags))
Pierre-Yves Chibon 83cba8
    else:
Pierre-Yves Chibon 83cba8
        for issue in issues:
Pierre-Yves Chibon 782b9c
            for issue_tag in issue.tags:
Pierre-Yves Chibon 83cba8
                if issue_tag.tag in tags:
Pierre-Yves Chibon 83cba8
                    tag = issue_tag.tag
Pierre-Yves Chibon ba0f71
                    removed_tags.append(tag)
Pierre-Yves Chibon 83cba8
                    session.delete(issue_tag)
Pierre-Yves Chibon 83cba8
                    msgs.append('Removed tag: %s' % tag)
Pierre-Yves Chibon fe5017
            pagure.lib.git.update_git(
Pierre-Yves Chibon 2da35f
                issue, repo=issue.project, repofolder=ticketfolder)
Pierre-Yves Chibon b4ce96
Pierre-Yves Chibon c898e5
    pagure.lib.notify.log(
Pierre-Yves Chibon c898e5
        project,
Pierre-Yves Chibon c898e5
        topic='project.tag.removed',
Pierre-Yves Chibon c898e5
        msg=dict(
Pierre-Yves Chibon 972598
            project=project.to_json(public=True),
Pierre-Yves Chibon 0ce3a2
            tags=removed_tags,
Pierre-Yves Chibon 0ce3a2
            agent=user_obj.username,
Pierre-Yves Chibon 482d84
        ),
Pierre-Yves Chibon 2e464a
        redis=REDIS,
Pierre-Yves Chibon 0ce3a2
    )
Pierre-Yves Chibon 0ce3a2
Pierre-Yves Chibon 83cba8
    return msgs
Pierre-Yves Chibon 83cba8
Pierre-Yves Chibon 83cba8
Pierre-Yves Chibon 931b1d
def remove_tags_obj(
Pierre-Yves Chibon 2e464a
        session, obj, tags, ticketfolder, user):
Pierre-Yves Chibon 931b1d
    ''' Removes the specified tag(s) of a given object. '''
Pierre-Yves Chibon 6aa385
    user_obj = get_user(session, user)
Pierre-Yves Chibon b2497a
Pierre-Yves Chibon b2497a
    if isinstance(tags, basestring):
Pierre-Yves Chibon b2497a
        tags = [tags]
Pierre-Yves Chibon b2497a
Pierre-Yves Chibon 2d821e
    removed_tags = []
Pierre-Yves Chibon 931b1d
    for objtag in obj.tags:
Pierre-Yves Chibon 931b1d
        if objtag.tag in tags:
Pierre-Yves Chibon 931b1d
            tag = objtag.tag
Pierre-Yves Chibon 2d821e
            removed_tags.append(tag)
Pierre-Yves Chibon 931b1d
            session.delete(objtag)
Pierre-Yves Chibon b2497a
Pierre-Yves Chibon b0ba8a
    if isinstance(obj, model.Issue):
Pierre-Yves Chibon 931b1d
        pagure.lib.git.update_git(
Pierre-Yves Chibon 292bbc
            obj, repo=obj.project, repofolder=ticketfolder)
Pierre-Yves Chibon b2497a
Pierre-Yves Chibon 931b1d
        pagure.lib.notify.log(
Pierre-Yves Chibon 292bbc
            obj.project,
Pierre-Yves Chibon 931b1d
            topic='issue.tag.removed',
Pierre-Yves Chibon 931b1d
            msg=dict(
Pierre-Yves Chibon 292bbc
                issue=obj.to_json(public=True),
Pierre-Yves Chibon 292bbc
                project=obj.project.to_json(public=True),
Pierre-Yves Chibon 931b1d
                tags=removed_tags,
Pierre-Yves Chibon 931b1d
                agent=user_obj.username,
Pierre-Yves Chibon 482d84
            ),
Pierre-Yves Chibon 2e464a
            redis=REDIS,
Pierre-Yves Chibon 0ce3a2
        )
Pierre-Yves Chibon 0ce3a2
Pierre-Yves Chibon 482d84
        # Send notification for the event-source server
Pierre-Yves Chibon 2e464a
        if REDIS:
Pierre-Yves Chibon 8e41fb
            REDIS.publish('pagure.%s' % obj.uid, json.dumps(
Pierre-Yves Chibon 931b1d
                {'removed_tags': removed_tags}))
Pierre-Yves Chibon 9f629a
Pierre-Yves Chibon a152f2
    return 'Removed tag: %s' % ', '.join(removed_tags)
Pierre-Yves Chibon b2497a
Pierre-Yves Chibon b2497a
Pierre-Yves Chibon 2e464a
def edit_issue_tags(session, project, old_tag, new_tag, ticketfolder, user):
Pierre-Yves Chibon 9d0844
    ''' Removes the specified tag of a project. '''
Pierre-Yves Chibon 6aa385
    user_obj = get_user(session, user)
Pierre-Yves Chibon 9d0844
Pierre-Yves Chibon 58adfc
    if old_tag == new_tag:
Pierre-Yves Chibon fe5017
        raise pagure.exceptions.PagureException(
Pierre-Yves Chibon 58adfc
            'Old tag: "%s" is the same as new tag "%s", nothing to change'
Pierre-Yves Chibon 58adfc
            % (old_tag, new_tag))
Pierre-Yves Chibon 9d0844
Pierre-Yves Chibon 58adfc
    issues = search_issues(session, project, closed=False, tags=old_tag)
Pierre-Yves Chibon 58adfc
    issues.extend(search_issues(session, project, closed=True, tags=old_tag))
Pierre-Yves Chibon 9d0844
Pierre-Yves Chibon 9d0844
    msgs = []
Pierre-Yves Chibon 9d0844
    if not issues:
Pierre-Yves Chibon fe5017
        raise pagure.exceptions.PagureException(
Pierre-Yves Chibon 9d0844
            'No issue found with the tags: %s' % old_tag)
Pierre-Yves Chibon 9d0844
    else:
Pierre-Yves Chibon 9d0844
        tagobj = get_tag(session, new_tag)
Pierre-Yves Chibon 9d0844
        if not tagobj:
Pierre-Yves Chibon 9d0844
            tagobj = model.Tag(tag=new_tag)
Pierre-Yves Chibon 9d0844
            session.add(tagobj)
Pierre-Yves Chibon fb91fb
            session.flush()
Pierre-Yves Chibon 9d0844
Pierre-Yves Chibon fb91fb
        for issue in set(issues):
Pierre-Yves Chibon 333cb7
            add = True
Pierre-Yves Chibon 9d0844
            # Drop the old tag
Pierre-Yves Chibon 7d6d1f
            cnt = 0
Pierre-Yves Chibon 7d6d1f
            while cnt < len(issue.tags):
Pierre-Yves Chibon 7d6d1f
                issue_tag = issue.tags[cnt]
Pierre-Yves Chibon 58adfc
                if issue_tag.tag == old_tag:
Pierre-Yves Chibon fb91fb
                    issue.tags.remove(issue_tag)
Pierre-Yves Chibon 7d6d1f
                    cnt -= 1
Pierre-Yves Chibon fb91fb
                if issue_tag.tag == new_tag:
Pierre-Yves Chibon fb91fb
                    add = False
Pierre-Yves Chibon 7d6d1f
                cnt += 1
Pierre-Yves Chibon fb91fb
            session.flush()
Pierre-Yves Chibon 333cb7
Pierre-Yves Chibon fb91fb
            # Add the new one
Pierre-Yves Chibon 333cb7
            if add:
Pierre-Yves Chibon 333cb7
                issue_tag = model.TagIssue(
Pierre-Yves Chibon 58adfc
                    issue_uid=issue.uid,
Pierre-Yves Chibon fb91fb
                    tag=tagobj.tag
Pierre-Yves Chibon 333cb7
                )
Pierre-Yves Chibon 333cb7
                session.add(issue_tag)
Pierre-Yves Chibon fb91fb
                session.flush()
Pierre-Yves Chibon fb91fb
Pierre-Yves Chibon b8c7ae
            # Update the git version
Pierre-Yves Chibon b8c7ae
            pagure.lib.git.update_git(
Pierre-Yves Chibon b8c7ae
                issue, repo=issue.project, repofolder=ticketfolder)
Pierre-Yves Chibon b8c7ae
Pierre-Yves Chibon fb91fb
        msgs.append('Edited tag: %s to %s' % (old_tag, new_tag))
Pierre-Yves Chibon c898e5
        pagure.lib.notify.log(
Pierre-Yves Chibon c898e5
            project,
Pierre-Yves Chibon c898e5
            topic='project.tag.edited',
Pierre-Yves Chibon c898e5
            msg=dict(
Pierre-Yves Chibon 972598
                project=project.to_json(public=True),
Pierre-Yves Chibon fb91fb
                old_tag=old_tag,
Pierre-Yves Chibon fb91fb
                new_tag=new_tag,
Pierre-Yves Chibon fb91fb
                agent=user_obj.username,
Pierre-Yves Chibon 482d84
            ),
Pierre-Yves Chibon 2e464a
            redis=REDIS,
Pierre-Yves Chibon fb91fb
        )
Pierre-Yves Chibon 9d0844
Pierre-Yves Chibon 9d0844
    return msgs
Pierre-Yves Chibon 9d0844
Pierre-Yves Chibon 08c7a3
Pierre-Yves Chibon 2e464a
def add_user_to_project(session, project, new_user, user):
Pierre-Yves Chibon b9cb1e
    ''' Add a specified user to a specified project. '''
Pierre-Yves Chibon 6aa385
    new_user_obj = get_user(session, new_user)
Pierre-Yves Chibon 6aa385
    user_obj = get_user(session, user)
Pierre-Yves Chibon b9cb1e
Pierre-Yves Chibon 9ef892
    users = set([user.user for user in project.users])
Pierre-Yves Chibon 9ef892
    users.add(project.user.user)
Pierre-Yves Chibon 9ef892
    if new_user in users:
Pierre-Yves Chibon 9ef892
        raise pagure.exceptions.PagureException(
Pierre-Yves Chibon 9ef892
            'This user is already listed on this project.'
Pierre-Yves Chibon 9ef892
        )
Pierre-Yves Chibon 9ef892
Pierre-Yves Chibon b9cb1e
    project_user = model.ProjectUser(
Pierre-Yves Chibon b9cb1e
        project_id=project.id,
Pierre-Yves Chibon c900bd
        user_id=new_user_obj.id,
Pierre-Yves Chibon b9cb1e
    )
Pierre-Yves Chibon b9cb1e
    session.add(project_user)
Pierre-Yves Chibon db8de8
    # Make sure we won't have SQLAlchemy error before we continue
Pierre-Yves Chibon b9cb1e
    session.flush()
Pierre-Yves Chibon b9cb1e
Pierre-Yves Chibon c898e5
    pagure.lib.notify.log(
Pierre-Yves Chibon c898e5
        project,
Pierre-Yves Chibon c898e5
        topic='project.user.added',
Pierre-Yves Chibon c898e5
        msg=dict(
Pierre-Yves Chibon 972598
            project=project.to_json(public=True),
Pierre-Yves Chibon 0ce3a2
            new_user=new_user_obj.username,
Pierre-Yves Chibon 0ce3a2
            agent=user_obj.username,
Pierre-Yves Chibon 482d84
        ),
Pierre-Yves Chibon 2e464a
        redis=REDIS,
Pierre-Yves Chibon 0ce3a2
    )
Pierre-Yves Chibon 0ce3a2
Pierre-Yves Chibon c4933c
    return 'User added'
Pierre-Yves Chibon b9cb1e
Pierre-Yves Chibon a8a719
Pierre-Yves Chibon 754b1d
def add_group_to_project(
Pierre-Yves Chibon 754b1d
        session, project, new_group, user, create=False, is_admin=False):
Pierre-Yves Chibon 41ae55
    ''' Add a specified group to a specified project. '''
Pierre-Yves Chibon 8e5afe
    user_obj = search_user(session, username=user)
Pierre-Yves Chibon 8e5afe
    if not user_obj:
Pierre-Yves Chibon 8e5afe
        raise pagure.exceptions.PagureException(
Pierre-Yves Chibon 8e5afe
            'No user %s found.' % user
Pierre-Yves Chibon 8e5afe
        )
Pierre-Yves Chibon 8e5afe
Pierre-Yves Chibon 754b1d
    group_obj = search_groups(session, group_name=new_group)
Pierre-Yves Chibon 754b1d
Pierre-Yves Chibon 754b1d
    if not group_obj:
Pierre-Yves Chibon 754b1d
        if create:
Pierre-Yves Chibon 754b1d
            group_obj = pagure.lib.model.PagureGroup(
Pierre-Yves Chibon 754b1d
                group_name=new_group,
Pierre-Yves Chibon 754b1d
                group_type='user',
Pierre-Yves Chibon 754b1d
                user_id=user_obj.id,
Pierre-Yves Chibon 754b1d
            )
Pierre-Yves Chibon 754b1d
            session.add(group_obj)
Pierre-Yves Chibon 754b1d
            session.flush()
Pierre-Yves Chibon 754b1d
        else:
Pierre-Yves Chibon 754b1d
            raise pagure.exceptions.PagureException(
Pierre-Yves Chibon 754b1d
                'No group %s found.' % new_group
Pierre-Yves Chibon 754b1d
            )
Pierre-Yves Chibon 754b1d
Pierre-Yves Chibon 754b1d
    if user_obj not in project.users \
Pierre-Yves Chibon 754b1d
            and user_obj != project.user \
Pierre-Yves Chibon 754b1d
            and not is_admin:
Pierre-Yves Chibon 8e5afe
        raise pagure.exceptions.PagureException(
Pierre-Yves Chibon 8e5afe
            'You are not allowed to add a group of users to this project'
Pierre-Yves Chibon 8e5afe
        )
Pierre-Yves Chibon 8e5afe
Pierre-Yves Chibon 41ae55
    groups = set([group.group_name for group in project.groups])
Pierre-Yves Chibon 41ae55
    if new_group in groups:
Pierre-Yves Chibon 41ae55
        raise pagure.exceptions.PagureException(
Pierre-Yves Chibon 41ae55
            'This group is already associated to this project.'
Pierre-Yves Chibon 41ae55
        )
Pierre-Yves Chibon 41ae55
Pierre-Yves Chibon 41ae55
    project_group = model.ProjectGroup(
Pierre-Yves Chibon 41ae55
        project_id=project.id,
Pierre-Yves Chibon 41ae55
        group_id=group_obj.id,
Pierre-Yves Chibon 41ae55
    )
Pierre-Yves Chibon 41ae55
    session.add(project_group)
Pierre-Yves Chibon db8de8
    # Make sure we won't have SQLAlchemy error before we continue
Pierre-Yves Chibon 41ae55
    session.flush()
Pierre-Yves Chibon 41ae55
Pierre-Yves Chibon 41ae55
    pagure.lib.notify.log(
Pierre-Yves Chibon 41ae55
        project,
Pierre-Yves Chibon 41ae55
        topic='project.group.added',
Pierre-Yves Chibon 41ae55
        msg=dict(
Pierre-Yves Chibon 972598
            project=project.to_json(public=True),
Pierre-Yves Chibon 41ae55
            new_group=group_obj.group_name,
Pierre-Yves Chibon 41ae55
            agent=user,
Pierre-Yves Chibon 482d84
        ),
Pierre-Yves Chibon 2e464a
        redis=REDIS,
Pierre-Yves Chibon 41ae55
    )
Pierre-Yves Chibon 41ae55
Pierre-Yves Chibon 41ae55
    return 'Group added'
Pierre-Yves Chibon 41ae55
Pierre-Yves Chibon 41ae55
Pierre-Yves Chibon 4fa09b
def add_pull_request_comment(session, request, commit, tree_id, filename,
Pierre-Yves Chibon 4fa09b
                             row, comment, user, requestfolder,
Pierre-Yves Chibon 4fa09b
                             notify=True, notification=False):
Pierre-Yves Chibon 2c11b4
    ''' Add a comment to a pull-request. '''
Pierre-Yves Chibon 6aa385
    user_obj = get_user(session, user)
Pierre-Yves Chibon 2c11b4
Pierre-Yves Chibon 2c11b4
    pr_comment = model.PullRequestComment(
Pierre-Yves Chibon 446c3d
        pull_request_uid=request.uid,
Pierre-Yves Chibon 2c11b4
        commit_id=commit,
Pierre-Yves Chibon 4fa09b
        tree_id=tree_id,
Pierre-Yves Chibon 7df65e
        filename=filename,
Pierre-Yves Chibon 2c11b4
        line=row,
Pierre-Yves Chibon 2c11b4
        comment=comment,
Pierre-Yves Chibon 2c11b4
        user_id=user_obj.id,
Pierre-Yves Chibon 81cbe0
        notification=notification,
Pierre-Yves Chibon 2c11b4
    )
Pierre-Yves Chibon 2c11b4
    session.add(pr_comment)
Pierre-Yves Chibon db8de8
    # Make sure we won't have SQLAlchemy error before we continue
Pierre-Yves Chibon 2c11b4
    session.flush()
Pierre-Yves Chibon 2c11b4
Pierre-Yves Chibon fe5017
    pagure.lib.git.update_git(
Pierre-Yves Chibon a482cb
        request, repo=request.project, repofolder=requestfolder)
Pierre-Yves Chibon a1280f
Pierre-Yves Chibon 5f751f
    if notify:
Pierre-Yves Chibon 5f751f
        pagure.lib.notify.notify_pull_request_comment(pr_comment, user_obj)
Pierre-Yves Chibon 5f751f
Pierre-Yves Chibon 482d84
    # Send notification for the event-source server
Pierre-Yves Chibon 2e464a
    if REDIS:
Pierre-Yves Chibon 50f9a3
        comment_text = pr_comment.comment
Pierre-Yves Chibon 50f9a3
        if not notification:
Pierre-Yves Chibon 50f9a3
            comment_text = text2markdown(pr_comment.comment)
Pierre-Yves Chibon 50f9a3
Pierre-Yves Chibon 8e41fb
        REDIS.publish('pagure.%s' % request.uid, json.dumps({
Pierre-Yves Chibon 3d167a
            'request_id': request.id,
Pierre-Yves Chibon 50f9a3
            'comment_added': comment_text,
Pierre-Yves Chibon 62cec4
            'comment_user': pr_comment.user.user,
Pierre-Yves Chibon 3d167a
            'comment_id': pr_comment.id,
Pierre-Yves Chibon 0ee9f8
            'avatar_url': avatar_url_from_openid(
Pierre-Yves Chibon 0ee9f8
                pr_comment.user.default_email, size=16),
Pierre-Yves Chibon b13b92
            'comment_date': pr_comment.date_created.strftime(
Pierre-Yves Chibon b13b92
                '%Y-%m-%d %H:%M:%S'),
Pierre-Yves Chibon 62cec4
            'commit_id': commit,
Pierre-Yves Chibon 62cec4
            'filename': filename,
Pierre-Yves Chibon 62cec4
            'line': row,
Pierre-Yves Chibon 50f9a3
            'notification': notification,
Pierre-Yves Chibon 62cec4
        }))
Pierre-Yves Chibon 62cec4
Pierre-Yves Chibon b65483
        # Send notification to the CI server, if the comment added was a
Pierre-Yves Chibon b65483
        # notification and the PR is still open
Pierre-Yves Chibon b65483
        if notification and request.status == 'Open' \
Pierre-Yves Chibon b65483
                and request.project.ci_hook and PAGURE_CI:
Pierre-Yves Chibon b65483
            REDIS.publish('pagure.ci', json.dumps({
Pierre-Yves Chibon dcbd99
                'ci_type': request.project.ci_hook.ci_type,
Pierre-Yves Chibon b65483
                'pr': request.to_json(public=True, with_comments=False)
Pierre-Yves Chibon b65483
            }))
Pierre-Yves Chibon b65483
Pierre-Yves Chibon c898e5
    pagure.lib.notify.log(
Pierre-Yves Chibon c898e5
        request.project,
Pierre-Yves Chibon c898e5
        topic='pull-request.comment.added',
Pierre-Yves Chibon c898e5
        msg=dict(
Pierre-Yves Chibon 972598
            pullrequest=request.to_json(public=True),
Pierre-Yves Chibon 0ce3a2
            agent=user_obj.username,
Pierre-Yves Chibon 482d84
        ),
Pierre-Yves Chibon 2e464a
        redis=REDIS,
Pierre-Yves Chibon 0ce3a2
    )
Pierre-Yves Chibon 0ce3a2
Pierre-Yves Chibon 2c11b4
    return 'Comment added'
Pierre-Yves Chibon 2c11b4
Pierre-Yves Chibon 2c11b4
Pierre-Yves Chibon cb9dd7
def edit_comment(session, parent, comment, user,
Pierre-Yves Chibon 9fd2e5
                 updated_comment, folder):
Pierre-Yves Chibon cb9dd7
    ''' Edit a comment. '''
Pierre-Yves Chibon 6aa385
    user_obj = get_user(session, user)
farhaanbukhsh a04e02
    comment.comment = updated_comment
farhaanbukhsh a04e02
    comment.edited_on = datetime.datetime.utcnow()
farhaanbukhsh a04e02
    comment.editor = user_obj
farhaanbukhsh a04e02
farhaanbukhsh a04e02
    session.add(comment)
farhaanbukhsh a04e02
    # Make sure we won't have SQLAlchemy error before we continue
farhaanbukhsh a04e02
    session.flush()
farhaanbukhsh a04e02
farhaanbukhsh a04e02
    pagure.lib.git.update_git(
Pierre-Yves Chibon cb9dd7
        parent, repo=parent.project, repofolder=folder)
Pierre-Yves Chibon cb9dd7
Pierre-Yves Chibon 4a97e9
    topic = 'unknown'
Pierre-Yves Chibon 4a97e9
    key = 'unknown'
Pierre-Yves Chibon 4a97e9
    id_ = 'unknown'
Pierre-Yves Chibon cb9dd7
    if parent.isa == 'pull-request':
Pierre-Yves Chibon cb9dd7
        topic = 'pull-request.comment.edited'
Pierre-Yves Chibon cb9dd7
        key = 'pullrequest'
Pierre-Yves Chibon cb9dd7
        id_ = 'request_id'
Pierre-Yves Chibon 4a97e9
    elif parent.isa == 'issue':
Pierre-Yves Chibon 4a97e9
        topic = 'issue.comment.edited'
Pierre-Yves Chibon 4a97e9
        key = 'issue'
Pierre-Yves Chibon 4a97e9
        id_ = 'issue_id'
farhaanbukhsh a04e02
farhaanbukhsh a04e02
    pagure.lib.notify.log(
Pierre-Yves Chibon cb9dd7
        parent.project,
Pierre-Yves Chibon cb9dd7
        topic=topic,
Pierre-Yves Chibon cb9dd7
        msg={
Pierre-Yves Chibon 799766
            key: parent.to_json(public=True, with_comments=False),
Pierre-Yves Chibon 9d71a7
            'project': parent.project.to_json(public=True),
Pierre-Yves Chibon 799766
            'comment': comment.to_json(public=True),
Pierre-Yves Chibon cb9dd7
            'agent': user_obj.username,
Pierre-Yves Chibon 9fd2e5
        },
Pierre-Yves Chibon 9fd2e5
        redis=REDIS,
farhaanbukhsh a04e02
    )
farhaanbukhsh a04e02
Pierre-Yves Chibon 9fd2e5
    if REDIS:
Pierre-Yves Chibon 1fc23f
        if parent.isa == 'issue' and comment.parent.private:
Pierre-Yves Chibon 1fe5e5
            REDIS.publish('pagure.%s' % comment.parent.uid, json.dumps({
Pierre-Yves Chibon 798259
                'comment_updated': 'private',
Pierre-Yves Chibon 798259
                'comment_id': comment.id,
Pierre-Yves Chibon 798259
            }))
Pierre-Yves Chibon 798259
        else:
Pierre-Yves Chibon 798259
            REDIS.publish('pagure.%s' % parent.uid, json.dumps({
Pierre-Yves Chibon 798259
                id_: len(parent.comments),
Pierre-Yves Chibon 798259
                'comment_updated': text2markdown(comment.comment),
Pierre-Yves Chibon 798259
                'comment_id': comment.id,
Pierre-Yves Chibon 3d167a
                'parent_id': comment.parent.id,
Pierre-Yves Chibon 798259
                'comment_editor': user_obj.user,
Pierre-Yves Chibon 0ee9f8
                'avatar_url': avatar_url_from_openid(
Pierre-Yves Chibon 0ee9f8
                    comment.user.default_email, size=16),
Pierre-Yves Chibon b13b92
                'comment_date': comment.edited_on.strftime(
Pierre-Yves Chibon b13b92
                    '%Y-%m-%d %H:%M:%S'),
Pierre-Yves Chibon 798259
            }))
farhaanbukhsh a04e02
farhaanbukhsh a04e02
    return "Comment updated"
farhaanbukhsh a04e02
farhaanbukhsh a04e02
Pierre-Yves Chibon 393541
def add_pull_request_flag(session, request, username, percent, comment, url,
Pierre-Yves Chibon 2e464a
                          uid, user, requestfolder):
Pierre-Yves Chibon 393541
    ''' Add a flag to a pull-request. '''
Pierre-Yves Chibon 6aa385
    user_obj = get_user(session, user)
Pierre-Yves Chibon 393541
Pierre-Yves Chibon 032826
    action = 'added'
Pierre-Yves Chibon 032826
    pr_flag = get_pull_request_flag_by_uid(session, uid)
Pierre-Yves Chibon 032826
    if pr_flag:
Pierre-Yves Chibon 032826
        action = 'updated'
Pierre-Yves Chibon 032826
        pr_flag.comment = comment
Pierre-Yves Chibon 032826
        pr_flag.percent = percent
Pierre-Yves Chibon 032826
        pr_flag.url = url
Pierre-Yves Chibon 032826
    else:
Pierre-Yves Chibon 032826
        pr_flag = model.PullRequestFlag(
Pierre-Yves Chibon 032826
            pull_request_uid=request.uid,
Pierre-Yves Chibon 032826
            uid=uid or uuid.uuid4().hex,
Pierre-Yves Chibon 032826
            username=username,
Pierre-Yves Chibon 032826
            percent=percent,
Pierre-Yves Chibon 032826
            comment=comment,
Pierre-Yves Chibon 032826
            url=url,
Pierre-Yves Chibon 032826
            user_id=user_obj.id,
Pierre-Yves Chibon 032826
        )
Pierre-Yves Chibon 393541
    session.add(pr_flag)
Pierre-Yves Chibon db8de8
    # Make sure we won't have SQLAlchemy error before we continue
Pierre-Yves Chibon 393541
    session.flush()
Pierre-Yves Chibon 393541
Pierre-Yves Chibon 393541
    pagure.lib.git.update_git(
Pierre-Yves Chibon 393541
        request, repo=request.project, repofolder=requestfolder)
Pierre-Yves Chibon 393541
Pierre-Yves Chibon 393541
    pagure.lib.notify.log(
Pierre-Yves Chibon 393541
        request.project,
Pierre-Yves Chibon 032826
        topic='pull-request.flag.%s' % action,
Pierre-Yves Chibon 393541
        msg=dict(
Pierre-Yves Chibon 972598
            pullrequest=request.to_json(public=True),
Pierre-Yves Chibon 972598
            flag=pr_flag.to_json(public=True),
Pierre-Yves Chibon 393541
            agent=user_obj.username,
Pierre-Yves Chibon 482d84
        ),
Pierre-Yves Chibon 2e464a
        redis=REDIS,
Pierre-Yves Chibon 393541
    )
Pierre-Yves Chibon 393541
Pierre-Yves Chibon 032826
    return 'Flag %s' % action
Pierre-Yves Chibon 393541
Pierre-Yves Chibon 393541
Pierre-Yves Chibon cf78d3
def new_project(session, user, name, blacklist, allowed_prefix,
Pierre-Yves Chibon 11c405
                gitfolder, docfolder, ticketfolder, requestfolder,
Pierre-Yves Chibon 164a57
                description=None, url=None, avatar_email=None,
Pierre-Yves Chibon 74baff
                parent_id=None, add_readme=False, userobj=None,
Pierre-Yves Chibon d3b817
                prevent_40_chars=False, namespace=None):
Pierre-Yves Chibon d8110b
    ''' Create a new project based on the information provided.
Pierre-Yves Chibon d8110b
    '''
Pierre-Yves Chibon d3b817
    if name in blacklist or (
Pierre-Yves Chibon d3b817
            namespace and '%s/%s' % (namespace, name) in blacklist):
Pierre-Yves Chibon 29f5ac
        raise pagure.exceptions.RepoExistsException(
Pierre-Yves Chibon 29f5ac
            'No project "%s" are allowed to be created due to potential '
Pierre-Yves Chibon 29f5ac
            'conflicts in URLs with pagure itself' % name
Pierre-Yves Chibon 29f5ac
        )
Pierre-Yves Chibon 29f5ac
Pierre-Yves Chibon 6aa385
    user_obj = get_user(session, user)
Pierre-Yves Chibon cbe451
    allowed_prefix = allowed_prefix + [grp for grp in user_obj.groups]
Pierre-Yves Chibon cf78d3
Pierre-Yves Chibon d3b817
    if namespace and namespace not in allowed_prefix:
Pierre-Yves Chibon cf78d3
        raise pagure.exceptions.PagureException(
Pierre-Yves Chibon d3b817
            'The namespace of your project must be in the list of allowed '
Pierre-Yves Chibon d3b817
            'namespaces set by the admins of this pagure instance, or the '
Pierre-Yves Chibon d3b817
            'name of a group of which you are a member.'
Pierre-Yves Chibon cf78d3
        )
Pierre-Yves Chibon 74baff
Pierre-Yves Chibon d3b817
    if len(name) == 40 and prevent_40_chars:
Pierre-Yves Chibon 81d698
        # We must block project with a name <foo>/<bar> where the length</bar></foo>
Pierre-Yves Chibon 81d698
        # of <bar> is exactly 40 characters long as this would otherwise</bar>
Pierre-Yves Chibon 81d698
        # conflict with the old URL schema used for commit that was
Pierre-Yves Chibon 81d698
        # <foo>/<commit hash="">. To keep backward compatibility, we have an</commit></foo>
Pierre-Yves Chibon 81d698
        # endpoint redirecting <foo>/<commit hash=""> to <foo>/c/<commit hash=""></commit></foo></commit></foo>
Pierre-Yves Chibon 81d698
        # available as an option.
Pierre-Yves Chibon 18c7f9
        raise pagure.exceptions.PagureException(
Pierre-Yves Chibon 18c7f9
            'Your project name cannot have exactly 40 characters after '
Pierre-Yves Chibon 18c7f9
            'the `/`'
Pierre-Yves Chibon 18c7f9
        )
Pierre-Yves Chibon 18c7f9
Pierre-Yves Chibon 622d94
    path = name
Pierre-Yves Chibon 622d94
    if namespace:
Pierre-Yves Chibon 622d94
        path = '%s/%s' % (namespace, name)
Pierre-Yves Chibon 622d94
Pierre-Yves Chibon 622d94
    gitrepo = os.path.join(gitfolder, '%s.git' % path)
Pierre-Yves Chibon d8110b
    if os.path.exists(gitrepo):
Pierre-Yves Chibon fe5017
        raise pagure.exceptions.RepoExistsException(
Pierre-Yves Chibon 622d94
            'The project repo "%s" already exists' % path
Pierre-Yves Chibon d8110b
        )
Pierre-Yves Chibon d8110b
Pierre-Yves Chibon d8110b
    project = model.Project(
Pierre-Yves Chibon d8110b
        name=name,
Pierre-Yves Chibon d3b817
        namespace=namespace,
Pierre-Yves Chibon 608900
        description=description if description else None,
Pierre-Yves Chibon 3fe3ff
        url=url if url else None,
Pierre-Yves Chibon 3fe3ff
        avatar_email=avatar_email if avatar_email else None,
Pierre-Yves Chibon e1372f
        user_id=user_obj.id,
Pierre-Yves Chibon 1cc0de
        parent_id=parent_id,
Pierre-Yves Chibon 1cc0de
        hook_token=pagure.lib.login.id_generator(40)
Pierre-Yves Chibon d8110b
    )
Pierre-Yves Chibon d8110b
    session.add(project)
Pierre-Yves Chibon d8110b
    # Make sure we won't have SQLAlchemy error before we create the repo
Vivek Anand 5ba62d
    session.flush()
Pierre-Yves Chibon d8110b
Pierre-Yves Chibon afcf11
    # Add the readme file if it was asked
Ryan Lerch 743aca
    if not add_readme:
Ryan Lerch 743aca
        pygit2.init_repository(gitrepo, bare=True)
Ryan Lerch 743aca
    else:
Ryan Lerch 348bee
        temp_gitrepo_path = tempfile.mkdtemp(prefix='pagure-')
Ryan Lerch 743aca
        temp_gitrepo = pygit2.init_repository(temp_gitrepo_path, bare=False)
Vivek Anand 97c5c3
        author = userobj.fullname or userobj.user
Vivek Anand 97c5c3
        author_email = userobj.default_email
Vivek Anand 97c5c3
        if six.PY2:
Vivek Anand 97c5c3
            author = author.encode('utf-8')
Vivek Anand 97c5c3
            author_email = author_email.encode('utf-8')
Vivek Anand 97c5c3
        author = pygit2.Signature(author, author_email)
Pierre-Yves Chibon 1c9f01
        content = u"# %s\n\n%s" % (name, description)
Pierre-Yves Chibon f9f132
        readme_file = os.path.join(temp_gitrepo.workdir, "README.md")
Pierre-Yves Chibon f9f132
        with open(readme_file, 'wb') as stream:
Pierre-Yves Chibon d1e053
            stream.write(content.encode('utf-8'))
Ryan Lerch 743aca
        temp_gitrepo.index.add_all()
Ryan Lerch 743aca
        temp_gitrepo.index.write()
Ryan Lerch 743aca
        tree = temp_gitrepo.index.write_tree()
Pierre-Yves Chibon d1e053
        temp_gitrepo.create_commit(
Pierre-Yves Chibon f9f132
            'HEAD', author, author, 'Added the README', tree, [])
Ryan Lerch 743aca
        pygit2.clone_repository(temp_gitrepo_path, gitrepo, bare=True)
Ryan Lerch 743aca
        shutil.rmtree(temp_gitrepo_path)
Ryan Lerch 743aca
Pierre-Yves Chibon afcf11
    # Make the repo exportable via apache
Pierre-Yves Chibon 7546bb
    http_clone_file = os.path.join(gitrepo, 'git-daemon-export-ok')
Pierre-Yves Chibon 7546bb
    if not os.path.exists(http_clone_file):
Pierre-Yves Chibon 7546bb
        with open(http_clone_file, 'w') as stream:
Pierre-Yves Chibon 7546bb
            pass
Pierre-Yves Chibon d8110b
Pierre-Yves Chibon 18042a
    docrepo = os.path.join(docfolder, project.path)
Pierre-Yves Chibon 18042a
    if os.path.exists(docrepo):
Pierre-Yves Chibon 18042a
        shutil.rmtree(gitrepo)
Pierre-Yves Chibon fe5017
        raise pagure.exceptions.RepoExistsException(
Pierre-Yves Chibon ca47fa
            'The docs repo "%s" already exists' % project.path
Pierre-Yves Chibon 6160b6
        )
Pierre-Yves Chibon 18042a
    pygit2.init_repository(docrepo, bare=True)
Pierre-Yves Chibon 6160b6
Pierre-Yves Chibon 18042a
    ticketrepo = os.path.join(ticketfolder, project.path)
Pierre-Yves Chibon 18042a
    if os.path.exists(ticketrepo):
Pierre-Yves Chibon 18042a
        shutil.rmtree(gitrepo)
Pierre-Yves Chibon 18042a
        shutil.rmtree(docrepo)
Pierre-Yves Chibon fe5017
        raise pagure.exceptions.RepoExistsException(
Pierre-Yves Chibon 49b899
            'The tickets repo "%s" already exists' % project.path
Pierre-Yves Chibon 49b899
        )
Pierre-Yves Chibon f43a32
    pygit2.init_repository(
Pierre-Yves Chibon a0c6e1
        ticketrepo, bare=True,
Pierre-Yves Chibon a0c6e1
        mode=pygit2.C.GIT_REPOSITORY_INIT_SHARED_GROUP)
Pierre-Yves Chibon 49b899
Pierre-Yves Chibon 11c405
    requestrepo = os.path.join(requestfolder, project.path)
Pierre-Yves Chibon 11c405
    if os.path.exists(requestrepo):
Pierre-Yves Chibon 11c405
        shutil.rmtree(gitrepo)
Pierre-Yves Chibon 11c405
        shutil.rmtree(docrepo)
Pierre-Yves Chibon 11c405
        shutil.rmtree(ticketrepo)
Pierre-Yves Chibon fe5017
        raise pagure.exceptions.RepoExistsException(
Pierre-Yves Chibon 11c405
            'The requests repo "%s" already exists' % project.path
Pierre-Yves Chibon 11c405
        )
Pierre-Yves Chibon f43a32
    pygit2.init_repository(
Pierre-Yves Chibon a0c6e1
        requestrepo, bare=True,
Pierre-Yves Chibon a0c6e1
        mode=pygit2.C.GIT_REPOSITORY_INIT_SHARED_GROUP)
Pierre-Yves Chibon 11c405
Pierre-Yves Chibon afcf11
    # Install the default hook
Pierre-Yves Chibon afcf11
    plugin = pagure.lib.plugins.get_plugin('default')
Pierre-Yves Chibon afcf11
    dbobj = plugin.db_object()
Pierre-Yves Chibon afcf11
    dbobj.active = True
Pierre-Yves Chibon afcf11
    dbobj.project_id = project.id
Pierre-Yves Chibon afcf11
    session.add(dbobj)
Pierre-Yves Chibon afcf11
    session.flush()
Pierre-Yves Chibon afcf11
    plugin.set_up(project)
Pierre-Yves Chibon afcf11
    plugin.install(project, dbobj)
Pierre-Yves Chibon afcf11
vanzhiganov f88b67
    # create the project in the db
Vivek Anand 5ba62d
    session.commit()
Vivek Anand 5ba62d
Pierre-Yves Chibon c898e5
    pagure.lib.notify.log(
Pierre-Yves Chibon c898e5
        project,
Pierre-Yves Chibon c898e5
        topic='project.new',
Pierre-Yves Chibon c898e5
        msg=dict(
Pierre-Yves Chibon 972598
            project=project.to_json(public=True),
Pierre-Yves Chibon 0ce3a2
            agent=user_obj.username,
Pierre-Yves Chibon 482d84
        ),
Pierre-Yves Chibon 0ce3a2
    )
Pierre-Yves Chibon 0ce3a2
Pierre-Yves Chibon d8110b
    return 'Project "%s" created' % name
Mathieu Bridon eb729c
Pierre-Yves Chibon f74093
Pierre-Yves Chibon 60e0e5
def new_issue(session, repo, title, content, user, ticketfolder,
Pierre-Yves Chibon 23b63c
              issue_id=None, issue_uid=None, private=False, status=None,
Pierre-Yves Chibon 07bd83
              close_status=None, notify=True, date_created=None):
Pierre-Yves Chibon 33ff2c
    ''' Create a new issue for the specified repo. '''
Pierre-Yves Chibon 6aa385
    user_obj = get_user(session, user)
Pierre-Yves Chibon e1372f
Pierre-Yves Chibon 33ff2c
    issue = model.Issue(
Pierre-Yves Chibon 1d8ce3
        id=issue_id or get_next_id(session, repo.id),
Pierre-Yves Chibon 33ff2c
        project_id=repo.id,
Pierre-Yves Chibon 33ff2c
        title=title,
Pierre-Yves Chibon 33ff2c
        content=content,
Pierre-Yves Chibon e1372f
        user_id=user_obj.id,
Pierre-Yves Chibon 0be51b
        uid=issue_uid or uuid.uuid4().hex,
Pierre-Yves Chibon 60e0e5
        private=private,
Clement Verna f45e89
        date_created=date_created,
Pierre-Yves Chibon 33ff2c
    )
Pierre-Yves Chibon 0be51b
Pierre-Yves Chibon 0be51b
    if status is not None:
Pierre-Yves Chibon 0be51b
        issue.status = status
Pierre-Yves Chibon 07bd83
    if close_status is not None:
Pierre-Yves Chibon 07bd83
        issue.close_status = close_status
Pierre-Yves Chibon 0be51b
Pierre-Yves Chibon 33ff2c
    session.add(issue)
Pierre-Yves Chibon 057ee1
    # Make sure we won't have SQLAlchemy error before we create the issue
Pierre-Yves Chibon 33ff2c
    session.flush()
Pierre-Yves Chibon 33ff2c
Pierre-Yves Chibon fe5017
    pagure.lib.git.update_git(
Pierre-Yves Chibon f7d56f
        issue, repo=repo, repofolder=ticketfolder)
Pierre-Yves Chibon a34835
Pierre-Yves Chibon 27fdde
    if notify:
Pierre-Yves Chibon fe5017
        pagure.lib.notify.notify_new_issue(issue, user=user_obj)
Pierre-Yves Chibon 142bae
Pierre-Yves Chibon b38c20
    if not private:
Pierre-Yves Chibon c898e5
        pagure.lib.notify.log(
Pierre-Yves Chibon c898e5
            issue.project,
Pierre-Yves Chibon c898e5
            topic='issue.new',
Pierre-Yves Chibon c898e5
            msg=dict(
Pierre-Yves Chibon 972598
                issue=issue.to_json(public=True),
Pierre-Yves Chibon 972598
                project=issue.project.to_json(public=True),
Pierre-Yves Chibon b38c20
                agent=user_obj.username,
Pierre-Yves Chibon 482d84
            ),
Pierre-Yves Chibon 2e464a
            redis=REDIS,
Pierre-Yves Chibon 0ce3a2
        )
Pierre-Yves Chibon 0ce3a2
Pierre-Yves Chibon f1a75b
    return issue
Pierre-Yves Chibon 33ff2c
Pierre-Yves Chibon 33ff2c
Pierre-Yves Chibon 2e464a
def drop_issue(session, issue, user, ticketfolder):
Pierre-Yves Chibon 1714a1
    ''' Delete a specified issue. '''
Pierre-Yves Chibon 6aa385
    user_obj = get_user(session, user)
Pierre-Yves Chibon 1714a1
Pierre-Yves Chibon 1714a1
    private = issue.private
Pierre-Yves Chibon 1714a1
    session.delete(issue)
Pierre-Yves Chibon 1714a1
Pierre-Yves Chibon 1714a1
    # Make sure we won't have SQLAlchemy error before we create the issue
Pierre-Yves Chibon 1714a1
    session.flush()
Pierre-Yves Chibon 1714a1
Pierre-Yves Chibon 1714a1
    pagure.lib.git.clean_git(
Pierre-Yves Chibon 1714a1
        issue, repo=issue.project, repofolder=ticketfolder)
Pierre-Yves Chibon 1714a1
Pierre-Yves Chibon 1714a1
    if not private:
Pierre-Yves Chibon 1714a1
        pagure.lib.notify.log(
Pierre-Yves Chibon 1714a1
            issue.project,
Pierre-Yves Chibon 1714a1
            topic='issue.drop',
Pierre-Yves Chibon 1714a1
            msg=dict(
Pierre-Yves Chibon 972598
                issue=issue.to_json(public=True),
Pierre-Yves Chibon 972598
                project=issue.project.to_json(public=True),
Pierre-Yves Chibon 1714a1
                agent=user_obj.username,
Pierre-Yves Chibon 482d84
            ),
Pierre-Yves Chibon 2e464a
            redis=REDIS,
Pierre-Yves Chibon 1714a1
        )
Pierre-Yves Chibon 1714a1
Pierre-Yves Chibon 1714a1
    return issue
Pierre-Yves Chibon 1714a1
Pierre-Yves Chibon 1714a1
Pierre-Yves Chibon 09cda5
def new_pull_request(session, branch_from,
Pierre-Yves Chibon 851174
                     repo_to, branch_to, title, user,
Pierre-Yves Chibon 47947e
                     requestfolder, initial_comment=None,
Pierre-Yves Chibon 47947e
                     repo_from=None, remote_git=None,
Pierre-Yves Chibon 09cda5
                     requestuid=None, requestid=None,
Pierre-Yves Chibon 2e464a
                     status='Open', notify=True):
Pierre-Yves Chibon 472a61
    ''' Create a new pull request on the specified repo. '''
Pierre-Yves Chibon 09cda5
    if not repo_from and not remote_git:
Pierre-Yves Chibon 4ff493
        raise pagure.exceptions.PagureException(
Pierre-Yves Chibon 09cda5
            'Invalid input, you must specify either a local repo or a '
Pierre-Yves Chibon 09cda5
            'remote one')
Pierre-Yves Chibon 09cda5
Pierre-Yves Chibon 6aa385
    user_obj = get_user(session, user)
Pierre-Yves Chibon 7d23c0
Pierre-Yves Chibon 472a61
    request = model.PullRequest(
Pierre-Yves Chibon 851174
        id=requestid or get_next_id(session, repo_to.id),
Pierre-Yves Chibon 851174
        uid=requestuid or uuid.uuid4().hex,
Pierre-Yves Chibon aa5fb9
        project_id=repo_to.id,
Pierre-Yves Chibon 09cda5
        project_id_from=repo_from.id if repo_from else None,
Pierre-Yves Chibon 09cda5
        remote_git=remote_git if remote_git else None,
Pierre-Yves Chibon aa5fb9
        branch=branch_to,
Pierre-Yves Chibon aa5fb9
        branch_from=branch_from,
Pierre-Yves Chibon 472a61
        title=title,
Pierre-Yves Chibon 47947e
        initial_comment=initial_comment or None,
Pierre-Yves Chibon 7d23c0
        user_id=user_obj.id,
Pierre-Yves Chibon 851174
        status=status,
Pierre-Yves Chibon 472a61
    )
Pierre-Yves Chibon 472a61
    session.add(request)
Pierre-Yves Chibon 472a61
    # Make sure we won't have SQLAlchemy error before we create the request
Pierre-Yves Chibon 472a61
    session.flush()
Pierre-Yves Chibon 472a61
Pierre-Yves Chibon fe5017
    pagure.lib.git.update_git(
Pierre-Yves Chibon a482cb
        request, repo=request.project, repofolder=requestfolder)
Pierre-Yves Chibon a1280f
Pierre-Yves Chibon 27fdde
    if notify:
Pierre-Yves Chibon fe5017
        pagure.lib.notify.notify_new_pull_request(request)
Pierre-Yves Chibon e0589f
Pierre-Yves Chibon c898e5
    pagure.lib.notify.log(
Pierre-Yves Chibon c898e5
        request.project,
Pierre-Yves Chibon c898e5
        topic='pull-request.new',
Pierre-Yves Chibon c898e5
        msg=dict(
Pierre-Yves Chibon 972598
            pullrequest=request.to_json(public=True),
Pierre-Yves Chibon 0ce3a2
            agent=user_obj.username,
Pierre-Yves Chibon 482d84
        ),
Pierre-Yves Chibon 2e464a
        redis=REDIS,
Pierre-Yves Chibon 0ce3a2
    )
Pierre-Yves Chibon 0ce3a2
Pierre-Yves Chibon b65483
    # Send notification to the CI server
Pierre-Yves Chibon af2692
    if REDIS and request.project.ci_hook and PAGURE_CI:
Pierre-Yves Chibon b65483
        REDIS.publish('pagure.ci', json.dumps({
Pierre-Yves Chibon dcbd99
            'ci_type': request.project.ci_hook.ci_type,
Pierre-Yves Chibon b65483
            'pr': request.to_json(public=True, with_comments=False)
Pierre-Yves Chibon b65483
        }))
Pierre-Yves Chibon b65483
Pierre-Yves Chibon 573769
    return request
Pierre-Yves Chibon 472a61
Pierre-Yves Chibon 472a61
Pierre-Yves Chibon 5a326c
def edit_issue(session, issue, ticketfolder, user,
Pierre-Yves Chibon 05fc3c
               title=None, content=None, status=None, close_status=None,
Pierre-Yves Chibon 8a9c7e
               priority=None, milestone=None, private=False):
Pierre-Yves Chibon c71370
    ''' Edit the specified issue.
Pierre-Yves Chibon c71370
    '''
Pierre-Yves Chibon 6aa385
    user_obj = get_user(session, user)
Pierre-Yves Chibon 5a326c
Pierre-Yves Chibon 05fc3c
    if status != 'Open' and issue.parents:
Pierre-Yves Chibon 4713b8
        for parent in issue.parents:
Pierre-Yves Chibon 4713b8
            if parent.status == 'Open':
Pierre-Yves Chibon fe5017
                raise pagure.exceptions.PagureException(
Pierre-Yves Chibon 4713b8
                    'You cannot close a ticket that has ticket '
Pierre-Yves Chibon 4713b8
                    'depending that are still open.')
Pierre-Yves Chibon 4713b8
Pierre-Yves Chibon c71370
    edit = []
Pierre-Yves Chibon fb8b6c
    if title and title != issue.title:
Pierre-Yves Chibon c71370
        issue.title = title
Pierre-Yves Chibon c71370
        edit.append('title')
Pierre-Yves Chibon fb8b6c
    if content and content != issue.content:
Pierre-Yves Chibon c71370
        issue.content = content
Pierre-Yves Chibon c71370
        edit.append('content')
Pierre-Yves Chibon fb8b6c
    if status and status != issue.status:
Pierre-Yves Chibon 4d1cbe
        issue.status = status
Vivek Anand c25f97
        if status.lower() != 'open':
Vivek Anand c25f97
            issue.closed_at = datetime.datetime.utcnow()
Pierre-Yves Chibon 4d1cbe
        edit.append('status')
Pierre-Yves Chibon 05fc3c
    if close_status and close_status != issue.close_status:
Pierre-Yves Chibon 05fc3c
        issue.close_status = close_status
Pierre-Yves Chibon 05fc3c
        edit.append('close_status')
Pierre-Yves Chibon f8505e
    if priority:
Pierre-Yves Chibon f8505e
        try:
Pierre-Yves Chibon f8505e
            priority = int(priority)
Pierre-Yves Chibon f8505e
        except:
Pierre-Yves Chibon f8505e
            priority = None
Pierre-Yves Chibon f8505e
        if priority != issue.priority:
Pierre-Yves Chibon f8505e
            issue.priority = priority
Pierre-Yves Chibon f8505e
            edit.append('priority')
Pierre-Yves Chibon 3b17c8
    if private in [True, False] and private != issue.private:
Pierre-Yves Chibon 3b17c8
        issue.private = private
Pierre-Yves Chibon 3b17c8
        edit.append('private')
Pierre-Yves Chibon 8a9c7e
    if milestone != issue.milestone:
Pierre-Yves Chibon 8a9c7e
        issue.milestone = milestone
Pierre-Yves Chibon 8a9c7e
        edit.append('milestone')
Pierre-Yves Chibon c71370
Pierre-Yves Chibon fe5017
    pagure.lib.git.update_git(
Pierre-Yves Chibon 2da35f
        issue, repo=issue.project, repofolder=ticketfolder)
Pierre-Yves Chibon a34835
Pierre-Yves Chibon c077f3
    if 'status' in edit:
Pierre-Yves Chibon c077f3
        add_issue_comment(
Pierre-Yves Chibon c077f3
            session,
Pierre-Yves Chibon c077f3
            issue,
Pierre-Yves Chibon 976a0e
            comment='@%s changed the status to ``%s``' % (
Pierre-Yves Chibon 976a0e
                user_obj.username, status),
Pierre-Yves Chibon c077f3
            user=user,
Pierre-Yves Chibon c077f3
            ticketfolder=ticketfolder,
Pierre-Yves Chibon c077f3
            notify=False,
Pierre-Yves Chibon c077f3
            notification=True,
Pierre-Yves Chibon c077f3
        )
Pierre-Yves Chibon c077f3
Pierre-Yves Chibon be8acf
    if not issue.private and edit:
Pierre-Yves Chibon c898e5
        pagure.lib.notify.log(
Pierre-Yves Chibon c898e5
            issue.project,
Pierre-Yves Chibon c898e5
            topic='issue.edit',
Pierre-Yves Chibon c898e5
            msg=dict(
Pierre-Yves Chibon 972598
                issue=issue.to_json(public=True),
Pierre-Yves Chibon 972598
                project=issue.project.to_json(public=True),
Pierre-Yves Chibon a57ad3
                fields=edit,
Pierre-Yves Chibon a57ad3
                agent=user_obj.username,
Pierre-Yves Chibon 482d84
            ),
Pierre-Yves Chibon 2e464a
            redis=REDIS,
Pierre-Yves Chibon 0ce3a2
        )
Pierre-Yves Chibon 0ce3a2
Pierre-Yves Chibon 2e464a
    if REDIS and edit:
Pierre-Yves Chibon b7e379
        if issue.private:
Pierre-Yves Chibon 8e41fb
            REDIS.publish('pagure.%s' % issue.uid, json.dumps({
Pierre-Yves Chibon ff274a
                'issue': 'private',
Pierre-Yves Chibon ff274a
                'fields': edit,
Pierre-Yves Chibon ff274a
            }))
Pierre-Yves Chibon b7e379
        else:
Pierre-Yves Chibon 8e41fb
            REDIS.publish('pagure.%s' % issue.uid, json.dumps({
Pierre-Yves Chibon b7e379
                'fields': edit,
Pierre-Yves Chibon b7e379
                'issue': issue.to_json(public=True, with_comments=False),
Pierre-Yves Chibon b7e379
            }))
Pierre-Yves Chibon 68664f
Pierre-Yves Chibon cb9c01
    if edit:
Pierre-Yves Chibon c71370
        session.add(issue)
Pierre-Yves Chibon c71370
        session.flush()
Pierre-Yves Chibon 754e40
        return 'Successfully edited issue #%s' % issue.id
Pierre-Yves Chibon c71370
Pierre-Yves Chibon c71370
Pierre-Yves Chibon 2e464a
def update_project_settings(session, repo, settings, user):
Pierre-Yves Chibon b39aa4
    ''' Update the settings of a project. '''
Pierre-Yves Chibon 6aa385
    user_obj = get_user(session, user)
Pierre-Yves Chibon 997e82
Pierre-Yves Chibon b39aa4
    update = []
Pierre-Yves Chibon 385746
    new_settings = repo.settings
Pierre-Yves Chibon 385746
    for key in new_settings:
Pierre-Yves Chibon 385746
        if key in settings:
Pierre-Yves Chibon 385746
            if new_settings[key] != settings[key]:
Pierre-Yves Chibon 385746
                update.append(key)
Pierre-Yves Chibon 3ebdd9
                if key == 'Minimum_score_to_merge_pull-request':
Ricky Elrod 0bd55b
                    try:
Pierre-Yves Chibon 27549e
                        settings[key] = int(settings[key]) \
Pierre-Yves Chibon 27549e
                            if settings[key] else -1
Ricky Elrod 0bd55b
                    except ValueError:
Ricky Elrod 0bd55b
                        raise pagure.exceptions.PagureException(
Ricky Elrod 0bd55b
                            "Please enter a numeric value for the 'minimum "
Ricky Elrod 0bd55b
                            "score to merge pull request' field.")
Pierre-Yves Chibon 8e57b2
                elif key == 'Web-hooks':
Pierre-Yves Chibon 8e57b2
                    settings[key] = settings[key] or None
Pierre-Yves Chibon 385746
                new_settings[key] = settings[key]
Pierre-Yves Chibon 385746
        else:
Pierre-Yves Chibon 385746
            update.append(key)
Pierre-Yves Chibon 492752
            val = False
Pierre-Yves Chibon 492752
            if key == 'Web-hooks':
Pierre-Yves Chibon 492752
                val = None
Pierre-Yves Chibon 492752
            new_settings[key] = val
Pierre-Yves Chibon b39aa4
Pierre-Yves Chibon b39aa4
    if not update:
Pierre-Yves Chibon b39aa4
        return 'No settings to change'
Pierre-Yves Chibon b39aa4
    else:
Pierre-Yves Chibon 932d90
        repo.settings = new_settings
Pierre-Yves Chibon b39aa4
        session.add(repo)
Pierre-Yves Chibon b39aa4
        session.flush()
Pierre-Yves Chibon c898e5
        pagure.lib.notify.log(
Pierre-Yves Chibon c898e5
            repo,
Pierre-Yves Chibon c898e5
            topic='project.edit',
Pierre-Yves Chibon c898e5
            msg=dict(
Pierre-Yves Chibon 972598
                project=repo.to_json(public=True),
Pierre-Yves Chibon 0ce3a2
                fields=update,
Pierre-Yves Chibon 0ce3a2
                agent=user_obj.username,
Pierre-Yves Chibon 482d84
            ),
Pierre-Yves Chibon 2e464a
            redis=REDIS,
Pierre-Yves Chibon 0ce3a2
        )
Pierre-Yves Chibon 0ce3a2
Pierre-Yves Chibon 511a11
        return 'Edited successfully settings of repo: %s' % repo.fullname
Pierre-Yves Chibon b39aa4
Pierre-Yves Chibon b39aa4
Pierre-Yves Chibon b933a2
def update_user_settings(session, settings, user):
Pierre-Yves Chibon b933a2
    ''' Update the settings of a project. '''
Pierre-Yves Chibon b933a2
    user_obj = get_user(session, user)
Pierre-Yves Chibon b933a2
Pierre-Yves Chibon b933a2
    update = []
Pierre-Yves Chibon b933a2
    new_settings = user_obj.settings
Pierre-Yves Chibon b933a2
    for key in new_settings:
Pierre-Yves Chibon b933a2
        if key in settings:
Pierre-Yves Chibon b933a2
            if new_settings[key] != settings[key]:
Pierre-Yves Chibon b933a2
                update.append(key)
Pierre-Yves Chibon b933a2
                new_settings[key] = settings[key]
Pierre-Yves Chibon b933a2
        else:
Pierre-Yves Chibon b933a2
            update.append(key)
Pierre-Yves Chibon 711d5c
            new_settings[key] = False
Pierre-Yves Chibon b933a2
Pierre-Yves Chibon b933a2
    if not update:
Pierre-Yves Chibon b933a2
        return 'No settings to change'
Pierre-Yves Chibon b933a2
    else:
Pierre-Yves Chibon b933a2
        user_obj.settings = new_settings
Pierre-Yves Chibon b933a2
        session.add(user_obj)
Pierre-Yves Chibon b933a2
        session.flush()
Pierre-Yves Chibon b933a2
Pierre-Yves Chibon b933a2
        return 'Successfully edited your settings'
Pierre-Yves Chibon b933a2
Pierre-Yves Chibon b933a2
Pierre-Yves Chibon a33978
def fork_project(session, user, repo, gitfolder,
Pierre-Yves Chibon 4fcac8
                 docfolder, ticketfolder, requestfolder):
Pierre-Yves Chibon 652c2c
    ''' Fork a given project into the user's forks. '''
Pierre-Yves Chibon 4fcac8
    reponame = os.path.join(gitfolder, repo.path)
Pierre-Yves Chibon 4fcac8
    forkreponame = '%s.git' % os.path.join(
Pierre-Yves Chibon 4fcac8
        gitfolder, 'forks', user, repo.name)
Pierre-Yves Chibon 652c2c
Pierre-Yves Chibon 652c2c
    if os.path.exists(forkreponame):
Pierre-Yves Chibon fe5017
        raise pagure.exceptions.RepoExistsException(
Pierre-Yves Chibon 4fcac8
            'Repo "forks/%s/%s" already exists' % (user, repo.name))
Pierre-Yves Chibon 652c2c
Pierre-Yves Chibon 6aa385
    user_obj = get_user(session, user)
Pierre-Yves Chibon e1372f
Pierre-Yves Chibon 652c2c
    project = model.Project(
Pierre-Yves Chibon 652c2c
        name=repo.name,
Pierre-Yves Chibon 652c2c
        description=repo.description,
Pierre-Yves Chibon e1372f
        user_id=user_obj.id,
Pierre-Yves Chibon b0ebc2
        parent_id=repo.id,
farhaanbukhsh 778e69
        is_fork=True,
Pierre-Yves Chibon b0ebc2
        hook_token=pagure.lib.login.id_generator(40)
Pierre-Yves Chibon 652c2c
    )
Vivek Anand 591f1a
Pierre-Yves Chibon b13b92
    # disable issues, PRs in the fork by default
Vivek Anand 591f1a
    default_repo_settings = project.settings
Vivek Anand 591f1a
    default_repo_settings['issue_tracker'] = False
Vivek Anand 591f1a
    default_repo_settings['pull_requests'] = False
Vivek Anand 591f1a
    project.settings = default_repo_settings
Vivek Anand 591f1a
Pierre-Yves Chibon 652c2c
    session.add(project)
Pierre-Yves Chibon 652c2c
    # Make sure we won't have SQLAlchemy error before we create the repo
Pierre-Yves Chibon 652c2c
    session.flush()
Pierre-Yves Chibon 652c2c
Pierre-Yves Chibon aaf0c5
    frepo = pygit2.clone_repository(reponame, forkreponame, bare=True)
Pierre-Yves Chibon aaf0c5
    # Clone all the branches as well
Pierre-Yves Chibon e1497f
    for branch in frepo.listall_branches(pygit2.GIT_BRANCH_REMOTE):
Pierre-Yves Chibon f9f132
        branch_obj = frepo.lookup_branch(branch, pygit2.GIT_BRANCH_REMOTE)
Pierre-Yves Chibon f9f132
        name = branch_obj.branch_name.replace(
Pierre-Yves Chibon c36800
            branch_obj.remote_name, '', 1)[1:]
Pierre-Yves Chibon 36c1c9
        if name in frepo.listall_branches(pygit2.GIT_BRANCH_LOCAL):
Pierre-Yves Chibon 36c1c9
            continue
Pierre-Yves Chibon f9f132
        frepo.create_branch(name, frepo.get(branch_obj.target.hex))
Pierre-Yves Chibon 652c2c
Pierre-Yves Chibon 901806
    # Create the git-daemin-export-ok file on the clone
Pierre-Yves Chibon 901806
    http_clone_file = os.path.join(forkreponame, 'git-daemon-export-ok')
Pierre-Yves Chibon 901806
    if not os.path.exists(http_clone_file):
Pierre-Yves Chibon d1e053
        with open(http_clone_file, 'w'):
Pierre-Yves Chibon 901806
            pass
Pierre-Yves Chibon 901806
Pierre-Yves Chibon b09b48
    docrepo = os.path.join(docfolder, project.path)
Pierre-Yves Chibon b09b48
    if os.path.exists(docrepo):
Pierre-Yves Chibon b09b48
        shutil.rmtree(forkreponame)
Pierre-Yves Chibon fe5017
        raise pagure.exceptions.RepoExistsException(
Pierre-Yves Chibon 4b7a7d
            'The docs "%s" already exists' % project.path
Pierre-Yves Chibon 6160b6
        )
Pierre-Yves Chibon b09b48
    pygit2.init_repository(docrepo, bare=True)
Pierre-Yves Chibon a33978
Pierre-Yves Chibon b09b48
    ticketrepo = os.path.join(ticketfolder, project.path)
Pierre-Yves Chibon b09b48
    if os.path.exists(ticketrepo):
Pierre-Yves Chibon b09b48
        shutil.rmtree(forkreponame)
Pierre-Yves Chibon b09b48
        shutil.rmtree(docrepo)
Pierre-Yves Chibon fe5017
        raise pagure.exceptions.RepoExistsException(
Pierre-Yves Chibon a33978
            'The tickets repo "%s" already exists' % project.path
Pierre-Yves Chibon a33978
        )
Pierre-Yves Chibon f43a32
    pygit2.init_repository(
Pierre-Yves Chibon a0c6e1
        ticketrepo, bare=True,
Pierre-Yves Chibon a0c6e1
        mode=pygit2.C.GIT_REPOSITORY_INIT_SHARED_GROUP)
Pierre-Yves Chibon 6160b6
Pierre-Yves Chibon e74f1e
    requestrepo = os.path.join(requestfolder, project.path)
Pierre-Yves Chibon e74f1e
    if os.path.exists(requestrepo):
Pierre-Yves Chibon e74f1e
        shutil.rmtree(forkreponame)
Pierre-Yves Chibon e74f1e
        shutil.rmtree(docrepo)
Pierre-Yves Chibon e74f1e
        shutil.rmtree(ticketrepo)
Pierre-Yves Chibon fe5017
        raise pagure.exceptions.RepoExistsException(
Pierre-Yves Chibon e74f1e
            'The requests repo "%s" already exists' % project.path
Pierre-Yves Chibon e74f1e
        )
Pierre-Yves Chibon f43a32
    pygit2.init_repository(
Pierre-Yves Chibon a0c6e1
        requestrepo, bare=True,
Pierre-Yves Chibon a0c6e1
        mode=pygit2.C.GIT_REPOSITORY_INIT_SHARED_GROUP)
Pierre-Yves Chibon e74f1e
Pierre-Yves Chibon c898e5
    pagure.lib.notify.log(
Pierre-Yves Chibon c898e5
        project,
Pierre-Yves Chibon c898e5
        topic='project.forked',
Pierre-Yves Chibon c898e5
        msg=dict(
Pierre-Yves Chibon 972598
            project=project.to_json(public=True),
Pierre-Yves Chibon 0ce3a2
            agent=user_obj.username,
Pierre-Yves Chibon 482d84
        ),
Pierre-Yves Chibon 0ce3a2
    )
Pierre-Yves Chibon 0ce3a2
Pierre-Yves Chibon 652c2c
    return 'Repo "%s" cloned to "%s/%s"' % (repo.name, user, repo.name)
Pierre-Yves Chibon 652c2c
Pierre-Yves Chibon 652c2c
Pierre-Yves Chibon 7ece2d
def search_projects(
Pierre-Yves Chibon d3b817
        session, username=None,
Pierre-Yves Chibon d3b817
        fork=None, tags=None, namespace=None, pattern=None,
Ryan Lerch 770112
        start=None, limit=None, count=False, sort=None):
Pierre-Yves Chibon 695ef6
    '''List existing projects
Pierre-Yves Chibon 695ef6
    '''
Pierre-Yves Chibon 0b9290
    projects = session.query(
Pierre-Yves Chibon 394a13
        sqlalchemy.distinct(model.Project.id)
Pierre-Yves Chibon 0b9290
    )
Mathieu Bridon eb729c
Pierre-Yves Chibon ea0ee1
    if username is not None:
Pierre-Yves Chibon e1372f
        projects = projects.filter(
Pierre-Yves Chibon 394a13
            # User created the project
Pierre-Yves Chibon 394a13
            sqlalchemy.and_(
Pierre-Yves Chibon 394a13
                model.User.user == username,
Pierre-Yves Chibon 394a13
                model.User.id == model.Project.user_id,
Pierre-Yves Chibon 394a13
            )
Pierre-Yves Chibon 394a13
        )
Pierre-Yves Chibon f9f132
        sub_q2 = session.query(
Pierre-Yves Chibon 394a13
            model.Project.id
Pierre-Yves Chibon e1372f
        ).filter(
Pierre-Yves Chibon 394a13
            # User got commit right
Pierre-Yves Chibon 394a13
            sqlalchemy.and_(
Pierre-Yves Chibon 394a13
                model.User.user == username,
Pierre-Yves Chibon 394a13
                model.User.id == model.ProjectUser.user_id,
Pierre-Yves Chibon 394a13
                model.ProjectUser.project_id == model.Project.id
Pierre-Yves Chibon 394a13
            )
Pierre-Yves Chibon ea0ee1
        )
Pierre-Yves Chibon f9f132
        sub_q3 = session.query(
Pierre-Yves Chibon 394a13
            model.Project.id
Pierre-Yves Chibon 394a13
        ).filter(
Pierre-Yves Chibon 394a13
            # User created a group that has commit right
Pierre-Yves Chibon 394a13
            sqlalchemy.and_(
Pierre-Yves Chibon 394a13
                model.User.user == username,
Pierre-Yves Chibon 394a13
                model.PagureGroup.user_id == model.User.id,
Pierre-Yves Chibon 394a13
                model.PagureGroup.group_type == 'user',
Pierre-Yves Chibon 394a13
                model.PagureGroup.id == model.ProjectGroup.group_id,
Pierre-Yves Chibon 394a13
                model.Project.id == model.ProjectGroup.project_id,
Pierre-Yves Chibon 394a13
            )
Pierre-Yves Chibon 394a13
        )
Pierre-Yves Chibon f9f132
        sub_q4 = session.query(
Pierre-Yves Chibon 394a13
            model.Project.id
Pierre-Yves Chibon 394a13
        ).filter(
Pierre-Yves Chibon 394a13
            # User is part of a group that has commit right
Pierre-Yves Chibon 394a13
            sqlalchemy.and_(
Pierre-Yves Chibon 394a13
                model.User.user == username,
Pierre-Yves Chibon 394a13
                model.PagureUserGroup.user_id == model.User.id,
Pierre-Yves Chibon 394a13
                model.PagureUserGroup.group_id == model.PagureGroup.id,
Pierre-Yves Chibon 394a13
                model.PagureGroup.group_type == 'user',
Pierre-Yves Chibon 394a13
                model.PagureGroup.id == model.ProjectGroup.group_id,
Pierre-Yves Chibon 394a13
                model.Project.id == model.ProjectGroup.project_id,
Pierre-Yves Chibon 394a13
            )
Pierre-Yves Chibon 394a13
        )
Pierre-Yves Chibon 394a13
Pierre-Yves Chibon f9f132
        projects = projects.union(sub_q2).union(sub_q3).union(sub_q4)
Pierre-Yves Chibon ea0ee1
Pierre-Yves Chibon 7752a8
    if fork is not None:
Pierre-Yves Chibon 7752a8
        if fork is True:
Pierre-Yves Chibon 7752a8
            projects = projects.filter(
farhaanbukhsh 3e1439
                model.Project.is_fork == True
Pierre-Yves Chibon 7752a8
            )
Pierre-Yves Chibon 7752a8
        elif fork is False:
Pierre-Yves Chibon 2f8732
            projects = projects.filter(
farhaanbukhsh 3e1439
                model.Project.is_fork == False
Pierre-Yves Chibon 7752a8
            )
Pierre-Yves Chibon 7752a8
Pierre-Yves Chibon 1942c1
    if tags:
Pierre-Yves Chibon 995375
        if not isinstance(tags, (list, tuple)):
Pierre-Yves Chibon 995375
            tags = [tags]
Pierre-Yves Chibon 995375
Pierre-Yves Chibon 995375
        projects = projects.filter(
Pierre-Yves Chibon 995375
            model.Project.id == model.TagProject.project_id
Pierre-Yves Chibon 995375
        ).filter(
Pierre-Yves Chibon 995375
            model.TagProject.tag.in_(tags)
Pierre-Yves Chibon 995375
        )
Pierre-Yves Chibon 995375
Pierre-Yves Chibon 70be16
    if pattern:
Pierre-Yves Chibon 70be16
        pattern = pattern.replace('*', '%')
Pierre-Yves Chibon 2ccd5c
        if '%' in pattern:
Pierre-Yves Chibon 2ccd5c
            projects = projects.filter(
Pierre-Yves Chibon 2ccd5c
                model.Project.name.like(pattern)
Pierre-Yves Chibon 2ccd5c
            )
Pierre-Yves Chibon 2ccd5c
        else:
Pierre-Yves Chibon 2ccd5c
            projects = projects.filter(
Pierre-Yves Chibon 2ccd5c
                model.Project.name == pattern
Pierre-Yves Chibon 2ccd5c
            )
Pierre-Yves Chibon d3b817
Pierre-Yves Chibon d3b817
    if namespace:
Vivek Anand 0ba2b9
        projects = projects.filter(
Pierre-Yves Chibon d3b817
            model.Project.namespace == namespace
Pierre-Yves Chibon d3b817
        )
Pierre-Yves Chibon d3b817
Pierre-Yves Chibon f6ea15
    query = session.query(
Pierre-Yves Chibon f6ea15
        model.Project
Pierre-Yves Chibon f6ea15
    ).filter(
Pierre-Yves Chibon f6ea15
        model.Project.id.in_(projects.subquery())
Pierre-Yves Chibon f6ea15
    )
Pierre-Yves Chibon f6ea15
Pierre-Yves Chibon 60d820
    if sort == 'latest':
Pierre-Yves Chibon f6ea15
        query = query.order_by(
Pierre-Yves Chibon 60d820
            model.Project.date_created.desc()
Pierre-Yves Chibon f6ea15
        )
Pierre-Yves Chibon 60d820
    elif sort == 'oldest':
Pierre-Yves Chibon f6ea15
        query = query.order_by(
Pierre-Yves Chibon 60d820
            model.Project.date_created.asc()
Pierre-Yves Chibon 60d820
        )
Pierre-Yves Chibon 60d820
    else:
Pierre-Yves Chibon 60d820
        query = query.order_by(
Pierre-Yves Chibon 60d820
            asc(func.lower(model.Project.name))
Pierre-Yves Chibon f6ea15
        )
Pierre-Yves Chibon 394a13
Mathieu Bridon eb729c
    if start is not None:
Pierre-Yves Chibon 394a13
        query = query.offset(start)
Mathieu Bridon eb729c
Mathieu Bridon eb729c
    if limit is not None:
Pierre-Yves Chibon 394a13
        query = query.limit(limit)
Mathieu Bridon eb729c
Pierre-Yves Chibon f74093
    if count:
Pierre-Yves Chibon 394a13
        return query.count()
Pierre-Yves Chibon f74093
    else:
Pierre-Yves Chibon 394a13
        return query.all()
Mathieu Bridon eb729c
Mathieu Bridon 998605
Pierre-Yves Chibon d3b817
def get_project(session, name, user=None, namespace=None):
Pierre-Yves Chibon 695ef6
    '''Get a project from the database
Pierre-Yves Chibon 695ef6
    '''
Pierre-Yves Chibon 929595
    query = session.query(
Pierre-Yves Chibon f74093
        model.Project
Pierre-Yves Chibon 178d6f
    ).filter(
Pierre-Yves Chibon 178d6f
        model.Project.name == name
Pierre-Yves Chibon d3b817
    ).filter(
Pierre-Yves Chibon d3b817
        model.Project.namespace == namespace
Pierre-Yves Chibon 929595
    )
Pierre-Yves Chibon 1ac00b
Pierre-Yves Chibon 929595
    if user is not None:
Pierre-Yves Chibon 929595
        query = query.filter(
Pierre-Yves Chibon e1372f
            model.User.user == user
Pierre-Yves Chibon e1372f
        ).filter(
Pierre-Yves Chibon e1372f
            model.User.id == model.Project.user_id
Pierre-Yves Chibon 1ac00b
        ).filter(
farhaanbukhsh 3e1439
            model.Project.is_fork == True
Pierre-Yves Chibon 929595
        )
Pierre-Yves Chibon 1ac00b
    else:
Pierre-Yves Chibon 1ac00b
        query = query.filter(
farhaanbukhsh 3e1439
            model.Project.is_fork == False
Pierre-Yves Chibon 1ac00b
        )
Pierre-Yves Chibon 1ac00b
Pierre-Yves Chibon 929595
    return query.first()
Pierre-Yves Chibon 562d75
Pierre-Yves Chibon 5ffcae
def search_issues(
Pierre-Yves Chibon b585e1
        session, repo, issueid=None, issueuid=None, status=None,
Pierre-Yves Chibon b585e1
        closed=False, tags=None, assignee=None, author=None, private=None,
“AnjaliPardeshi” fa7e4c
        priority=None, milestones=None, count=False, offset=None,
Pierre-Yves Chibon b4970f
        limit=None, search_pattern=None, custom_search=None):
Pierre-Yves Chibon 5b2947
    ''' Retrieve one or more issues associated to a project with the given
Pierre-Yves Chibon 5b2947
    criterias.
Pierre-Yves Chibon b6df7d
Pierre-Yves Chibon b6df7d
    Watch out that the closed argument is incompatible with the status
Pierre-Yves Chibon b6df7d
    argument. The closed argument will return all the issues whose status
Pierre-Yves Chibon b6df7d
    is not 'Open', otherwise it will return the issues having the specified
Pierre-Yves Chibon b6df7d
    status.
Pierre-Yves Chibon bc60cc
    The `tags` argument can be used to filter the issues returned based on
Pierre-Yves Chibon bc60cc
    a certain tag.
Pierre-Yves Chibon 5b2947
    If the `issueid` argument is specified a single Issue object (or None)
Pierre-Yves Chibon 5b2947
    will be returned instead of a list of Issue objects.
Pierre-Yves Chibon 5b2947
Pierre-Yves Chibon 5b2947
    :arg session: the session to use to connect to the database.
Pierre-Yves Chibon 5b2947
    :arg repo: a Project object to which the issues should be associated
Pierre-Yves Chibon fe5017
    :type repo: pagure.lib.model.Project
Pierre-Yves Chibon 5b2947
    :kwarg issueid: the identifier of the issue to look for
Pierre-Yves Chibon 5b2947
    :type issueid: int or None
Pierre-Yves Chibon b585e1
    :kwarg issueuid: the unique identifier of the issue to look for
Pierre-Yves Chibon b585e1
    :type issueuid: str or None
Pierre-Yves Chibon 5b2947
    :kwarg status: the status of the issue to look for (incompatible with
Pierre-Yves Chibon 5b2947
        the `closed` argument).
Pierre-Yves Chibon 5b2947
    :type status: str or None
Pierre-Yves Chibon 5b2947
    :kwarg closed: a boolean indicating whether the issue to retrieve are
Pierre-Yves Chibon 5b2947
        closed or open (incompatible with the `status` argument).
Pierre-Yves Chibon 5b2947
    :type closed: bool or None
Pierre-Yves Chibon 5b2947
    :kwarg tags: a tag the issue(s) returned should be associated with
Pierre-Yves Chibon 5b2947
    :type tags: str or list(str) or None
Pierre-Yves Chibon 60bca7
    :kwarg assignee: the name of the user assigned to the issues to search
Pierre-Yves Chibon 60bca7
    :type assignee: str or None
Pierre-Yves Chibon 60bca7
    :kwarg author: the name of the user who created the issues to search
Pierre-Yves Chibon 60bca7
    :type author: str or None
Pierre-Yves Chibon 73a5b8
    :kwarg private: boolean or string to use to include or exclude private
Pierre-Yves Chibon 73a5b8
        tickets. Defaults to False.
Pierre-Yves Chibon 73a5b8
        If False: private tickets are excluded
Pierre-Yves Chibon 73a5b8
        If None: private tickets are included
Pierre-Yves Chibon 73a5b8
        If user name is specified: private tickets reported by that user
Pierre-Yves Chibon 73a5b8
        are included.
Pierre-Yves Chibon 73a5b8
    :type private: False, None or str
Pierre-Yves Chibon 8d019f
    :kwarg priority: the priority of the issues to search
Pierre-Yves Chibon 8d019f
    :type priority: int or None
Pierre-Yves Chibon 7e8958
    :kwarg milestones: a milestone the issue(s) returned should be
Pierre-Yves Chibon 7e8958
        associated with.
Pierre-Yves Chibon 7e8958
    :type milestones: str or list(str) or None
Pierre-Yves Chibon e69252
    :kwarg count: a boolean to specify if the method should return the list
Pierre-Yves Chibon e69252
        of Issues or just do a COUNT query.
Pierre-Yves Chibon e69252
    :type count: boolean
“AnjaliPardeshi” fa7e4c
    :kwarg search_pattern: a string to search in issues title
“AnjaliPardeshi” fa7e4c
    :type search_pattern: str or None
Pierre-Yves Chibon b4970f
    :kwarg custom_search: a dictionary of key/values to be used when
Pierre-Yves Chibon b4970f
        searching issues with a custom key constraint
Pierre-Yves Chibon b4970f
    :type custom_search: dict or None
Pierre-Yves Chibon 60bca7
Pierre-Yves Chibon 5b2947
    :return: A single Issue object if issueid is specified, a list of Project
Pierre-Yves Chibon 5b2947
        objects otherwise.
Pierre-Yves Chibon 5b2947
    :rtype: Project or [Project]
Pierre-Yves Chibon bc60cc
Pierre-Yves Chibon 562d75
    '''
Pierre-Yves Chibon 562d75
    query = session.query(
Pierre-Yves Chibon af678e
        sqlalchemy.distinct(model.Issue.uid)
Pierre-Yves Chibon 95f042
    ).filter(
Pierre-Yves Chibon 95f042
        model.Issue.project_id == repo.id
Pierre-Yves Chibon 562d75
    )
Pierre-Yves Chibon 562d75
Pierre-Yves Chibon 5b2947
    if issueid is not None:
Pierre-Yves Chibon 5b2947
        query = query.filter(
Pierre-Yves Chibon 5b2947
            model.Issue.id == issueid
Pierre-Yves Chibon 5b2947
        )
Pierre-Yves Chibon 5b2947
Pierre-Yves Chibon b585e1
    if issueuid is not None:
Pierre-Yves Chibon b585e1
        query = query.filter(
Pierre-Yves Chibon b585e1
            model.Issue.uid == issueuid
Pierre-Yves Chibon b585e1
        )
Pierre-Yves Chibon b585e1
Pierre-Yves Chibon a61250
    if status is not None:
Pierre-Yves Chibon 725259
        if status in ['Open', 'Closed']:
Pierre-Yves Chibon cfd95d
            query = query.filter(
Pierre-Yves Chibon cfd95d
                model.Issue.status == status
Pierre-Yves Chibon cfd95d
            )
Pierre-Yves Chibon cfd95d
        else:
Pierre-Yves Chibon cfd95d
            query = query.filter(
Pierre-Yves Chibon cfd95d
                model.Issue.close_status == status
Pierre-Yves Chibon cfd95d
            )
Pierre-Yves Chibon b6df7d
    if closed:
Pierre-Yves Chibon b6df7d
        query = query.filter(
Pierre-Yves Chibon b6df7d
            model.Issue.status != 'Open'
Pierre-Yves Chibon b6df7d
        )
Pierre-Yves Chibon 8d019f
    if priority:
Pierre-Yves Chibon 8d019f
        query = query.filter(
Pierre-Yves Chibon 8d019f
            model.Issue.priority == priority
Pierre-Yves Chibon 8d019f
        )
Pierre-Yves Chibon d01150
    if tags is not None and tags != []:
Pierre-Yves Chibon 5b2947
        if isinstance(tags, basestring):
Pierre-Yves Chibon 5b2947
            tags = [tags]
Pierre-Yves Chibon 6cd6a9
        notags = []
Pierre-Yves Chibon 6cd6a9
        ytags = []
Pierre-Yves Chibon 6cd6a9
        for tag in tags:
Pierre-Yves Chibon 6cd6a9
            if tag.startswith('!'):
Pierre-Yves Chibon 6cd6a9
                notags.append(tag[1:])
Pierre-Yves Chibon 6cd6a9
            else:
Pierre-Yves Chibon 6cd6a9
                ytags.append(tag)
Pierre-Yves Chibon 6cd6a9
Pierre-Yves Chibon 6cd6a9
        if ytags:
Pierre-Yves Chibon f9f132
            sub_q2 = session.query(
Pierre-Yves Chibon e79148
                sqlalchemy.distinct(model.Issue.uid)
Pierre-Yves Chibon e79148
            ).filter(
Pierre-Yves Chibon e79148
                model.Issue.project_id == repo.id
Pierre-Yves Chibon e79148
            ).filter(
Pierre-Yves Chibon 6cd6a9
                model.Issue.uid == model.TagIssue.issue_uid
Pierre-Yves Chibon 6cd6a9
            ).filter(
Pierre-Yves Chibon 6cd6a9
                model.TagIssue.tag.in_(ytags)
Pierre-Yves Chibon 6cd6a9
            )
Pierre-Yves Chibon 6cd6a9
        if notags:
Pierre-Yves Chibon f9f132
            sub_q3 = session.query(
Pierre-Yves Chibon e79148
                sqlalchemy.distinct(model.Issue.uid)
Pierre-Yves Chibon e79148
            ).filter(
Pierre-Yves Chibon e79148
                model.Issue.project_id == repo.id
Pierre-Yves Chibon 6cd6a9
            ).filter(
Pierre-Yves Chibon b53eb8
                model.Issue.uid == model.TagIssue.issue_uid
Pierre-Yves Chibon 6cd6a9
            ).filter(
Pierre-Yves Chibon b53eb8
                model.TagIssue.tag.in_(notags)
Pierre-Yves Chibon 6cd6a9
            )
Pierre-Yves Chibon e79148
        # Adjust the main query based on the parameters specified
Pierre-Yves Chibon e79148
        if ytags and not notags:
Pierre-Yves Chibon f9f132
            query = query.filter(model.Issue.uid.in_(sub_q2))
Pierre-Yves Chibon e79148
        elif not ytags and notags:
Pierre-Yves Chibon f9f132
            query = query.filter(~model.Issue.uid.in_(sub_q3))
Pierre-Yves Chibon e79148
        elif ytags and notags:
Pierre-Yves Chibon f9f132
            final_set = set(sub_q2.all()) - set(sub_q3.all())
Pierre-Yves Chibon e79148
            if final_set:
Pierre-Yves Chibon e79148
                query = query.filter(model.Issue.uid.in_(list(final_set)))
Pierre-Yves Chibon 5b2947
Pierre-Yves Chibon a10ca7
    if assignee is not None:
Pierre-Yves Chibon ba4b04
        if str(assignee).lower() not in ['false', '0', 'true', '1']:
Pierre-Yves Chibon ed38ee
            user2 = aliased(model.User)
Pierre-Yves Chibon 571a45
            if assignee.startswith('!'):
Pierre-Yves Chibon 571a45
                sub = session.query(
Pierre-Yves Chibon 571a45
                    model.Issue.uid
Pierre-Yves Chibon 571a45
                ).filter(
Pierre-Yves Chibon 571a45
                    model.Issue.assignee_id == user2.id
Pierre-Yves Chibon 571a45
                ).filter(
Pierre-Yves Chibon 571a45
                    user2.user == assignee[1:]
Pierre-Yves Chibon 571a45
                )
Pierre-Yves Chibon 571a45
Pierre-Yves Chibon 571a45
                query = query.filter(
Pierre-Yves Chibon 571a45
                    ~model.Issue.uid.in_(sub)
Pierre-Yves Chibon 571a45
                )
Pierre-Yves Chibon 571a45
            else:
Pierre-Yves Chibon 571a45
                query = query.filter(
Pierre-Yves Chibon 571a45
                    model.Issue.assignee_id == user2.id
Pierre-Yves Chibon 571a45
                ).filter(
Pierre-Yves Chibon 571a45
                    user2.user == assignee
Pierre-Yves Chibon 571a45
                )
Pierre-Yves Chibon ba4b04
        elif str(assignee).lower() in ['true', '1']:
Pierre-Yves Chibon ba4b04
            query = query.filter(
Pierre-Yves Chibon ba4b04
                model.Issue.assignee_id != None
Pierre-Yves Chibon ba4b04
            )
Pierre-Yves Chibon 685db8
        else:
Pierre-Yves Chibon 685db8
            query = query.filter(
Pierre-Yves Chibon 685db8
                model.Issue.assignee_id == None
Pierre-Yves Chibon 685db8
            )
Pierre-Yves Chibon 02e68a
    if author is not None:
Pierre-Yves Chibon 02e68a
        query = query.filter(
Pierre-Yves Chibon 7407c0
            model.Issue.user_id == model.User.id
Pierre-Yves Chibon 7407c0
        ).filter(
Pierre-Yves Chibon 7407c0
            model.User.user == author
Pierre-Yves Chibon 7407c0
        )
Pierre-Yves Chibon 4d1cbe
Pierre-Yves Chibon 73a5b8
    if private is False:
Pierre-Yves Chibon 73a5b8
        query = query.filter(
Pierre-Yves Chibon 73a5b8
            model.Issue.private == False
Pierre-Yves Chibon 73a5b8
        )
Pierre-Yves Chibon 73a5b8
    elif isinstance(private, basestring):
Pierre-Yves Chibon 1d9d7d
        user2 = aliased(model.User)
Pierre-Yves Chibon 73a5b8
        query = query.filter(
Pierre-Yves Chibon e93c34
            sqlalchemy.or_(
Pierre-Yves Chibon 73a5b8
                model.Issue.private == False,
Pierre-Yves Chibon e93c34
                sqlalchemy.and_(
Pierre-Yves Chibon 73a5b8
                    model.Issue.private == True,
Pierre-Yves Chibon 1d9d7d
                    model.Issue.user_id == user2.id,
Pierre-Yves Chibon 1d9d7d
                    user2.user == private,
Pierre-Yves Chibon 73a5b8
                )
Pierre-Yves Chibon 73a5b8
            )
Pierre-Yves Chibon 73a5b8
        )
Pierre-Yves Chibon 73a5b8
Pierre-Yves Chibon 7e8958
    if milestones is not None and milestones != []:
Pierre-Yves Chibon 7e8958
        if isinstance(milestones, basestring):
Pierre-Yves Chibon 7e8958
            milestones = [milestones]
Pierre-Yves Chibon 7e8958
Pierre-Yves Chibon 7e8958
        query = query.filter(
Pierre-Yves Chibon 7e8958
            model.Issue.milestone.in_(milestones)
Pierre-Yves Chibon 7e8958
        )
Pierre-Yves Chibon 7e8958
Pierre-Yves Chibon b4970f
    if custom_search:
Pierre-Yves Chibon b4970f
        constraints = []
Pierre-Yves Chibon b4970f
        for key in custom_search:
Pierre-Yves Chibon b4970f
            value = custom_search[key]
Pierre-Yves Chibon b4970f
            if '*' in value:
Pierre-Yves Chibon b4970f
                value = value.replace('*', '%')
Pierre-Yves Chibon b4970f
                constraints.append(
Pierre-Yves Chibon b4970f
                    sqlalchemy.and_(
Pierre-Yves Chibon b4970f
                        model.IssueKeys.name == key,
Pierre-Yves Chibon b4970f
                        model.IssueValues.value.ilike(value)
Pierre-Yves Chibon b4970f
                    )
Pierre-Yves Chibon b4970f
                )
Pierre-Yves Chibon b4970f
            else:
Pierre-Yves Chibon b4970f
                constraints.append(
Pierre-Yves Chibon b4970f
                    sqlalchemy.and_(
Pierre-Yves Chibon b4970f
                        model.IssueKeys.name == key,
Pierre-Yves Chibon b4970f
                        model.IssueValues.value == value
Pierre-Yves Chibon b4970f
                    )
Pierre-Yves Chibon b4970f
                )
Pierre-Yves Chibon b4970f
        if constraints:
Pierre-Yves Chibon b4970f
            query = query.filter(
Pierre-Yves Chibon b4970f
                model.Issue.uid == model.IssueValues.issue_uid
Pierre-Yves Chibon b4970f
            ).filter(
Pierre-Yves Chibon b4970f
                model.IssueValues.key_id == model.IssueKeys.id
Pierre-Yves Chibon b4970f
            )
Pierre-Yves Chibon b4970f
            query = query.filter(
Pierre-Yves Chibon b4970f
                sqlalchemy.or_(
Pierre-Yves Chibon b4970f
                    (const for const in constraints)
Pierre-Yves Chibon b4970f
                )
Pierre-Yves Chibon b4970f
            )
Pierre-Yves Chibon b4970f
Pierre-Yves Chibon 1d9d7d
    query = session.query(
Pierre-Yves Chibon 1d9d7d
        model.Issue
Pierre-Yves Chibon 1d9d7d
    ).filter(
Pierre-Yves Chibon af678e
        model.Issue.uid.in_(query.subquery())
Pierre-Yves Chibon af678e
    ).filter(
Pierre-Yves Chibon af678e
        model.Issue.project_id == repo.id
Pierre-Yves Chibon 1d9d7d
    )
Pierre-Yves Chibon 1d9d7d
“AnjaliPardeshi” fa7e4c
    if search_pattern is not None:
Pierre-Yves Chibon 130ecb
        query = query.filter(
“AnjaliPardeshi” fa7e4c
            model.Issue.title.like('%' + str(search_pattern) + '%')
“AnjaliPardeshi” fa7e4c
        )
“AnjaliPardeshi” fa7e4c
Pierre-Yves Chibon 5657d2
    query = query.order_by(
Pierre-Yves Chibon 5657d2
        model.Issue.date_created.desc()
Pierre-Yves Chibon 5657d2
    )
Anthony Lackey 78e2eb
Pierre-Yves Chibon b585e1
    if issueid is not None or issueuid is not None:
Pierre-Yves Chibon 5b2947
        output = query.first()
Pierre-Yves Chibon e69252
    elif count:
Pierre-Yves Chibon e69252
        output = query.count()
Pierre-Yves Chibon 5b2947
    else:
Pierre-Yves Chibon f7bee3
        if offset:
Pierre-Yves Chibon f7bee3
            query = query.offset(offset)
Pierre-Yves Chibon f7bee3
        if limit:
Pierre-Yves Chibon f7bee3
            query = query.limit(limit)
Pierre-Yves Chibon 5b2947
        output = query.all()
Pierre-Yves Chibon 562d75
Pierre-Yves Chibon 5b2947
    return output
Pierre-Yves Chibon 562d75
Pierre-Yves Chibon 35112d
Pierre-Yves Chibon 64b484
def get_tags_of_project(session, project, pattern=None):
Pierre-Yves Chibon 8efc30
    ''' Returns the list of tags associated with the issues of a project.
Pierre-Yves Chibon 8efc30
    '''
Pierre-Yves Chibon 8efc30
    query = session.query(
Pierre-Yves Chibon 8efc30
        model.Tag
Pierre-Yves Chibon 8efc30
    ).filter(
Pierre-Yves Chibon 8efc30
        model.Tag.tag == model.TagIssue.tag
Pierre-Yves Chibon 8efc30
    ).filter(
Pierre-Yves Chibon 4aca3b
        model.TagIssue.issue_uid == model.Issue.uid
Pierre-Yves Chibon 8efc30
    ).filter(
Pierre-Yves Chibon 8efc30
        model.Issue.project_id == project.id
Pierre-Yves Chibon 8efc30
    ).order_by(
Pierre-Yves Chibon 8efc30
        model.Tag.tag
Pierre-Yves Chibon 8efc30
    )
Pierre-Yves Chibon 8efc30
Pierre-Yves Chibon 64b484
    if pattern:
Pierre-Yves Chibon 64b484
        query = query.filter(
Pierre-Yves Chibon 64b484
            model.Tag.tag.ilike(pattern.replace('*', '%'))
Pierre-Yves Chibon 64b484
        )
Pierre-Yves Chibon 64b484
Pierre-Yves Chibon 8efc30
    return query.all()
Pierre-Yves Chibon 8efc30
Pierre-Yves Chibon 8efc30
Pierre-Yves Chibon 2e810e
def get_tag(session, tag):
Pierre-Yves Chibon 2e810e
    ''' Returns a Tag object for the given tag text.
Pierre-Yves Chibon 2e810e
    '''
Pierre-Yves Chibon 2e810e
    query = session.query(
Pierre-Yves Chibon 2e810e
        model.Tag
Pierre-Yves Chibon 2e810e
    ).filter(
Pierre-Yves Chibon 2e810e
        model.Tag.tag == tag
Pierre-Yves Chibon 2e810e
    )
Pierre-Yves Chibon 2e810e
Pierre-Yves Chibon 2e810e
    return query.first()
Pierre-Yves Chibon 2e810e
Pierre-Yves Chibon 35112d
Pierre-Yves Chibon 08dd17
def search_pull_requests(
Pierre-Yves Chibon a2002e
        session, requestid=None, project_id=None, project_id_from=None,
Pierre-Yves Chibon f7bee3
        status=None, author=None, assignee=None, count=False,
Pierre-Yves Chibon f7bee3
        offset=None, limit=None):
Pierre-Yves Chibon b0265c
    ''' Retrieve the specified issue
Pierre-Yves Chibon b0265c
    '''
Pierre-Yves Chibon 33e9fc
Pierre-Yves Chibon b0265c
    query = session.query(
Pierre-Yves Chibon 35a3e4
        model.PullRequest
Pierre-Yves Chibon 3a2a1c
    ).order_by(
Pierre-Yves Chibon f1f6ba
        model.PullRequest.id.desc()
Pierre-Yves Chibon b0265c
    )
Pierre-Yves Chibon b0265c
Pierre-Yves Chibon a2002e
    if requestid:
Pierre-Yves Chibon a2002e
        query = query.filter(
Pierre-Yves Chibon a2002e
            model.PullRequest.id == requestid
Pierre-Yves Chibon a2002e
        )
Pierre-Yves Chibon a2002e
Pierre-Yves Chibon b0265c
    if project_id:
Pierre-Yves Chibon b0265c
        query = query.filter(
Pierre-Yves Chibon b0265c
            model.PullRequest.project_id == project_id
Pierre-Yves Chibon b0265c
        )
Pierre-Yves Chibon b0265c
Pierre-Yves Chibon b0265c
    if project_id_from:
Pierre-Yves Chibon b0265c
        query = query.filter(
Pierre-Yves Chibon b0265c
            model.PullRequest.project_id_from == project_id_from
Pierre-Yves Chibon b0265c
        )
Pierre-Yves Chibon b0265c
Pierre-Yves Chibon b0265c
    if status is not None:
Pierre-Yves Chibon c0f8df
        if isinstance(status, bool):
Pierre-Yves Chibon c0f8df
            if status:
Pierre-Yves Chibon c0f8df
                query = query.filter(
Pierre-Yves Chibon c0f8df
                    model.PullRequest.status == 'Open'
Pierre-Yves Chibon c0f8df
                )
Pierre-Yves Chibon c0f8df
            else:
Pierre-Yves Chibon c0f8df
                query = query.filter(
Pierre-Yves Chibon c0f8df
                    model.PullRequest.status != 'Open'
Pierre-Yves Chibon c0f8df
                )
Pierre-Yves Chibon c0f8df
        else:
Pierre-Yves Chibon c0f8df
            query = query.filter(
Pierre-Yves Chibon c0f8df
                model.PullRequest.status == status
Pierre-Yves Chibon c0f8df
            )
Pierre-Yves Chibon b0265c
Pierre-Yves Chibon dcfb16
    if assignee is not None:
Pierre-Yves Chibon dcfb16
        if str(assignee).lower() not in ['false', '0', 'true', '1']:
Pierre-Yves Chibon dcfb16
            user2 = aliased(model.User)
Pierre-Yves Chibon dcfb16
            if assignee.startswith('!'):
Pierre-Yves Chibon dcfb16
                sub = session.query(
Pierre-Yves Chibon dcfb16
                    model.PullRequest.uid
Pierre-Yves Chibon dcfb16
                ).filter(
Pierre-Yves Chibon dcfb16
                    model.PullRequest.assignee_id == user2.id
Pierre-Yves Chibon dcfb16
                ).filter(
Pierre-Yves Chibon dcfb16
                    user2.user == assignee[1:]
Pierre-Yves Chibon dcfb16
                )
Pierre-Yves Chibon dcfb16
Pierre-Yves Chibon dcfb16
                query = query.filter(
Pierre-Yves Chibon dcfb16
                    ~model.PullRequest.uid.in_(sub)
Pierre-Yves Chibon dcfb16
                )
Pierre-Yves Chibon dcfb16
            else:
Pierre-Yves Chibon dcfb16
                query = query.filter(
Pierre-Yves Chibon dcfb16
                    model.PullRequest.assignee_id == user2.id
Pierre-Yves Chibon dcfb16
                ).filter(
Pierre-Yves Chibon dcfb16
                    user2.user == assignee
Pierre-Yves Chibon dcfb16
                )
Pierre-Yves Chibon dcfb16
        elif str(assignee).lower() in ['true', '1']:
Pierre-Yves Chibon dcfb16
            query = query.filter(
Pierre-Yves Chibon dcfb16
                model.PullRequest.assignee_id != None
Pierre-Yves Chibon dcfb16
            )
Pierre-Yves Chibon dcfb16
        else:
Pierre-Yves Chibon dcfb16
            query = query.filter(
Pierre-Yves Chibon dcfb16
                model.PullRequest.assignee_id == None
Pierre-Yves Chibon dcfb16
            )
Pierre-Yves Chibon dcfb16
Pierre-Yves Chibon dcfb16
    if author is not None:
Pierre-Yves Chibon dcfb16
        query = query.filter(
Pierre-Yves Chibon dcfb16
            model.PullRequest.user_id == model.User.id
Pierre-Yves Chibon dcfb16
        ).filter(
Pierre-Yves Chibon dcfb16
            model.User.user == author
Pierre-Yves Chibon dcfb16
        )
Pierre-Yves Chibon dcfb16
Pierre-Yves Chibon a2002e
    if requestid:
Pierre-Yves Chibon a2002e
        output = query.first()
Pierre-Yves Chibon 6f3845
    elif count:
Pierre-Yves Chibon 6f3845
        output = query.count()
Pierre-Yves Chibon a2002e
    else:
Pierre-Yves Chibon f7bee3
        if offset:
Pierre-Yves Chibon f7bee3
            query = query.offset(offset)
Pierre-Yves Chibon f7bee3
        if limit:
Pierre-Yves Chibon f7bee3
            query = query.limit(limit)
Pierre-Yves Chibon a2002e
        output = query.all()
Pierre-Yves Chibon 35112d
Pierre-Yves Chibon a2002e
    return output
Pierre-Yves Chibon 42a02c
Pierre-Yves Chibon 42a02c
Pierre-Yves Chibon 2e464a
def close_pull_request(session, request, user, requestfolder, merged=True):
Pierre-Yves Chibon 42a02c
    ''' Close the provided pull-request.
Pierre-Yves Chibon 42a02c
    '''
Pierre-Yves Chibon 6aa385
    user_obj = get_user(session, user)
Pierre-Yves Chibon 1e978e
Pierre-Yves Chibon f86685
    if merged is True:
Pierre-Yves Chibon f86685
        request.status = 'Merged'
Pierre-Yves Chibon f86685
    else:
Pierre-Yves Chibon f86685
        request.status = 'Closed'
Pierre-Yves Chibon 50644e
    request.closed_by_id = user_obj.id
Pierre-Yves Chibon e8692f
    request.closed_at = datetime.datetime.utcnow()
Pierre-Yves Chibon 42a02c
    session.add(request)
Pierre-Yves Chibon 42a02c
    session.flush()
Pierre-Yves Chibon 4d1cbe
Pierre-Yves Chibon b53eb8
    if merged is True:
Pierre-Yves Chibon 1e978e
        pagure.lib.notify.notify_merge_pull_request(request, user_obj)
Johan Cwiklinski 86d9c4
    else:
Pierre-Yves Chibon 1e978e
        pagure.lib.notify.notify_cancelled_pull_request(request, user_obj)
Pierre-Yves Chibon 5fdf85
Pierre-Yves Chibon fe5017
    pagure.lib.git.update_git(
Pierre-Yves Chibon a482cb
        request, repo=request.project, repofolder=requestfolder)
Pierre-Yves Chibon a1280f
Pierre-Yves Chibon 9af6f1
    pagure.lib.add_pull_request_comment(
Pierre-Yves Chibon 9af6f1
        session, request,
Pierre-Yves Chibon 0a0445
        commit=None, tree_id=None, filename=None, row=None,
Pierre-Yves Chibon 9af6f1
        comment='Pull-Request has been %s by %s' % (
Pierre-Yves Chibon 9af6f1
            request.status.lower(), user),
Pierre-Yves Chibon 9af6f1
        user=user,
Pierre-Yves Chibon 9af6f1
        requestfolder=requestfolder,
Pierre-Yves Chibon 9af6f1
        notify=False, notification=True
Pierre-Yves Chibon 9af6f1
    )
Pierre-Yves Chibon 9af6f1
Pierre-Yves Chibon c898e5
    pagure.lib.notify.log(
Pierre-Yves Chibon c898e5
        request.project,
Pierre-Yves Chibon c898e5
        topic='pull-request.closed',
Pierre-Yves Chibon c898e5
        msg=dict(
Pierre-Yves Chibon 972598
            pullrequest=request.to_json(public=True),
Pierre-Yves Chibon 0ce3a2
            merged=merged,
Pierre-Yves Chibon 0ce3a2
            agent=user_obj.username,
Pierre-Yves Chibon 482d84
        ),
Pierre-Yves Chibon 2e464a
        redis=REDIS,
Pierre-Yves Chibon 0ce3a2
    )
Pierre-Yves Chibon 0ce3a2
Pierre-Yves Chibon e1497f
Pierre-Yves Chibon 06785e
def reset_status_pull_request(session, project):
Pierre-Yves Chibon 06785e
    ''' Reset the status of all opened Pull-Requests of a project.
Pierre-Yves Chibon 06785e
    '''
Pierre-Yves Chibon 06785e
    requests = search_pull_requests(
Pierre-Yves Chibon 06785e
        session, project_id=project.id, status='Open')
Pierre-Yves Chibon 06785e
Pierre-Yves Chibon 06785e
    for request in requests:
Pierre-Yves Chibon 06785e
        request.merge_status = None
Pierre-Yves Chibon 06785e
        session.add(request)
Pierre-Yves Chibon 06785e
Pierre-Yves Chibon 06785e
    session.commit()
Pierre-Yves Chibon 06785e
Pierre-Yves Chibon 4d1cbe
Pierre-Yves Chibon 4d1cbe
def get_issue_statuses(session):
Pierre-Yves Chibon 4d1cbe
    ''' Return the complete list of status an issue can have.
Pierre-Yves Chibon 4d1cbe
    '''
Pierre-Yves Chibon 4d1cbe
    output = []
Pierre-Yves Chibon 4d1cbe
    statuses = session.query(model.StatusIssue).all()
Pierre-Yves Chibon 4d1cbe
    for status in statuses:
Pierre-Yves Chibon 4d1cbe
        output.append(status.status)
Pierre-Yves Chibon 4d1cbe
    return output
Pierre-Yves Chibon 7c47d2
Pierre-Yves Chibon 7c47d2
Pierre-Yves Chibon 4a2966
def get_issue_comment(session, issue_uid, comment_id):
Pierre-Yves Chibon 4a2966
    ''' Return a specific comment of a specified issue.
Pierre-Yves Chibon 4a2966
    '''
Pierre-Yves Chibon 4a2966
    query = session.query(
Pierre-Yves Chibon 4a2966
        model.IssueComment
Pierre-Yves Chibon 4a2966
    ).filter(
Pierre-Yves Chibon 4a2966
        model.IssueComment.issue_uid == issue_uid
Pierre-Yves Chibon 4a2966
    ).filter(
Pierre-Yves Chibon 4a2966
        model.IssueComment.id == comment_id
Pierre-Yves Chibon 4a2966
    )
Pierre-Yves Chibon 4a2966
Pierre-Yves Chibon 4a2966
    return query.first()
Pierre-Yves Chibon 4a2966
Pierre-Yves Chibon 1d9d7d
Pierre-Yves Chibon 83791f
def get_request_comment(session, request_uid, comment_id):
Pierre-Yves Chibon cb9dd7
    ''' Return a specific comment of a specified request.
Pierre-Yves Chibon 83791f
    '''
Pierre-Yves Chibon 83791f
    query = session.query(
Pierre-Yves Chibon 83791f
        model.PullRequestComment
Pierre-Yves Chibon 83791f
    ).filter(
Pierre-Yves Chibon 83791f
        model.PullRequestComment.pull_request_uid == request_uid
Pierre-Yves Chibon 83791f
    ).filter(
Pierre-Yves Chibon 83791f
        model.PullRequestComment.id == comment_id
Pierre-Yves Chibon 83791f
    )
Pierre-Yves Chibon 83791f
Pierre-Yves Chibon 83791f
    return query.first()
Pierre-Yves Chibon 83791f
Pierre-Yves Chibon 4a2966
Pierre-Yves Chibon bdd624
def get_issue_by_uid(session, issue_uid):
Pierre-Yves Chibon bdd624
    ''' Return the issue corresponding to the specified unique identifier.
Pierre-Yves Chibon bdd624
Pierre-Yves Chibon bdd624
    :arg session: the session to use to connect to the database.
Pierre-Yves Chibon bdd624
    :arg issue_uid: the unique identifier of an issue. This identifier is
Pierre-Yves Chibon fe5017
        unique accross all projects on this pagure instance and should be
Pierre-Yves Chibon fe5017
        unique accross multiple pagure instances as well
Pierre-Yves Chibon bdd624
    :type issue_uid: str or None
Pierre-Yves Chibon bdd624
Pierre-Yves Chibon bdd624
    :return: A single Issue object.
Pierre-Yves Chibon fe5017
    :rtype: pagure.lib.model.Issue
Pierre-Yves Chibon bdd624
Pierre-Yves Chibon bdd624
    '''
Pierre-Yves Chibon bdd624
    query = session.query(
Pierre-Yves Chibon bdd624
        model.Issue
Pierre-Yves Chibon bdd624
    ).filter(
Pierre-Yves Chibon bdd624
        model.Issue.uid == issue_uid
Pierre-Yves Chibon bdd624
    )
Pierre-Yves Chibon bdd624
    return query.first()
Pierre-Yves Chibon bdd624
Pierre-Yves Chibon bdd624
Pierre-Yves Chibon 9c5f7f
def get_request_by_uid(session, request_uid):
Pierre-Yves Chibon 9c5f7f
    ''' Return the request corresponding to the specified unique identifier.
Pierre-Yves Chibon 9c5f7f
Pierre-Yves Chibon 9c5f7f
    :arg session: the session to use to connect to the database.
Pierre-Yves Chibon 9c5f7f
    :arg request_uid: the unique identifier of a request. This identifier is
Pierre-Yves Chibon fe5017
        unique accross all projects on this pagure instance and should be
Pierre-Yves Chibon fe5017
        unique accross multiple pagure instances as well
Pierre-Yves Chibon 9c5f7f
    :type request_uid: str or None
Pierre-Yves Chibon 9c5f7f
Pierre-Yves Chibon 9c5f7f
    :return: A single Issue object.
Pierre-Yves Chibon fe5017
    :rtype: pagure.lib.model.PullRequest
Pierre-Yves Chibon 9c5f7f
Pierre-Yves Chibon 9c5f7f
    '''
Pierre-Yves Chibon 9c5f7f
    query = session.query(
Pierre-Yves Chibon 9c5f7f
        model.PullRequest
Pierre-Yves Chibon 9c5f7f
    ).filter(
Pierre-Yves Chibon 9c5f7f
        model.PullRequest.uid == request_uid
Pierre-Yves Chibon 9c5f7f
    )
Pierre-Yves Chibon 9c5f7f
    return query.first()
Pierre-Yves Chibon 9c5f7f
Pierre-Yves Chibon 9c5f7f
Pierre-Yves Chibon d236dc
def get_pull_request_flag_by_uid(session, flag_uid):
Pierre-Yves Chibon d236dc
    ''' Return the flag corresponding to the specified unique identifier.
Pierre-Yves Chibon d236dc
Pierre-Yves Chibon d236dc
    :arg session: the session to use to connect to the database.
Pierre-Yves Chibon d236dc
    :arg flag_uid: the unique identifier of a request. This identifier is
Pierre-Yves Chibon d236dc
        unique accross all flags on this pagure instance and should be
Pierre-Yves Chibon d236dc
        unique accross multiple pagure instances as well
Pierre-Yves Chibon d236dc
    :type request_uid: str or None
Pierre-Yves Chibon d236dc
Pierre-Yves Chibon d236dc
    :return: A single Issue object.
Pierre-Yves Chibon d236dc
    :rtype: pagure.lib.model.PullRequestFlag
Pierre-Yves Chibon d236dc
Pierre-Yves Chibon d236dc
    '''
Pierre-Yves Chibon d236dc
    query = session.query(
Pierre-Yves Chibon d236dc
        model.PullRequestFlag
Pierre-Yves Chibon d236dc
    ).filter(
Pierre-Yves Chibon d236dc
        model.PullRequestFlag.uid == flag_uid.strip() if flag_uid else None
Pierre-Yves Chibon d236dc
    )
Pierre-Yves Chibon d236dc
    return query.first()
Pierre-Yves Chibon d236dc
Pierre-Yves Chibon d236dc
Pierre-Yves Chibon b69b5c
def set_up_user(session, username, fullname, default_email,
Patrick Uiterwijk 0e5f4a
                emails=None, ssh_key=None, keydir=None):
Pierre-Yves Chibon c2aa0d
    ''' Set up a new user into the database or update its information. '''
Pierre-Yves Chibon f05535
    user = search_user(session, username=username)
Pierre-Yves Chibon c2aa0d
    if not user:
Pierre-Yves Chibon c2aa0d
        user = model.User(
Pierre-Yves Chibon c2aa0d
            user=username,
Pierre-Yves Chibon 71ee98
            fullname=fullname,
Pierre-Yves Chibon 96eb13
            default_email=default_email
Pierre-Yves Chibon 71ee98
        )
Pierre-Yves Chibon c2aa0d
        session.add(user)
Pierre-Yves Chibon c2aa0d
        session.flush()
Pierre-Yves Chibon c2aa0d
Pierre-Yves Chibon c2aa0d
    if user.fullname != fullname:
Pierre-Yves Chibon c2aa0d
        user.fullname = fullname
Pierre-Yves Chibon c2aa0d
        session.add(user)
Pierre-Yves Chibon c2aa0d
        session.flush()
Pierre-Yves Chibon c2aa0d
Pierre-Yves Chibon 96eb13
    if emails:
Pierre-Yves Chibon 96eb13
        emails = set(emails)
Pierre-Yves Chibon 96eb13
    else:
Pierre-Yves Chibon 96eb13
        emails = set()
Pierre-Yves Chibon 96eb13
    emails.add(default_email)
Pierre-Yves Chibon 96eb13
    for email in emails:
Pierre-Yves Chibon 96eb13
        add_email_to_user(session, user, email)
Pierre-Yves Chibon 5ccd12
Pierre-Yves Chibon b69b5c
    if ssh_key and not user.public_ssh_key:
Patrick Uiterwijk 0e5f4a
        update_user_ssh(session, user, ssh_key, keydir)
Pierre-Yves Chibon b69b5c
Pierre-Yves Chibon 5ccd12
    return user
Pierre-Yves Chibon 5ccd12
Pierre-Yves Chibon 5ccd12
Pierre-Yves Chibon 5ccd12
def add_email_to_user(session, user, user_email):
Pierre-Yves Chibon 5ccd12
    ''' Add the provided email to the specified user. '''
Pierre-Yves Chibon 8b2894
    emails = [email.email for email in user.emails]
Pierre-Yves Chibon 8b2894
    if user_email not in emails:
Pierre-Yves Chibon c2aa0d
        useremail = model.UserEmail(
Pierre-Yves Chibon c2aa0d
            user_id=user.id,
Pierre-Yves Chibon c2aa0d
            email=user_email)
Pierre-Yves Chibon c2aa0d
        session.add(useremail)
Pierre-Yves Chibon c2aa0d
        session.flush()
Pierre-Yves Chibon 8f25f2
Pierre-Yves Chibon 8f25f2
Patrick Uiterwijk 0e5f4a
def update_user_ssh(session, user, ssh_key, keydir):
Pierre-Yves Chibon 8f25f2
    ''' Set up a new user into the database or update its information. '''
Pierre-Yves Chibon 8f25f2
    if isinstance(user, basestring):
Pierre-Yves Chibon 6aa385
        user = get_user(session, user)
Pierre-Yves Chibon 8f25f2
Pierre-Yves Chibon eb310a
    user.public_ssh_key = ssh_key
Pierre-Yves Chibon eb310a
    if keydir and user.public_ssh_key:
Pierre-Yves Chibon eb310a
        create_user_ssh_keys_on_disk(user, keydir)
Patrick Uiterwijk 5c8d02
        pagure.lib.git.generate_gitolite_acls()
Pierre-Yves Chibon eb310a
    session.add(user)
Pierre-Yves Chibon eb310a
    session.flush()
Pierre-Yves Chibon f7d963
Pierre-Yves Chibon f7d963
Pierre-Yves Chibon 95245b
def avatar_url_from_openid(openid, size=64, default='retro', dns=False):
Pierre-Yves Chibon 95245b
    """
Pierre-Yves Chibon 95245b
    Our own implementation since fas doesn't support this nicely yet.
Pierre-Yves Chibon 95245b
    """
Pierre-Yves Chibon 95245b
Pierre-Yves Chibon 95245b
    if dns:  # pragma: no cover
Pierre-Yves Chibon 95245b
        # This makes an extra DNS SRV query, which can slow down our webapps.
Pierre-Yves Chibon 95245b
        # It is necessary for libravatar federation, though.
Pierre-Yves Chibon 95245b
        import libravatar
Pierre-Yves Chibon 95245b
        return libravatar.libravatar_url(
Pierre-Yves Chibon 95245b
            openid=openid,
Pierre-Yves Chibon 95245b
            size=size,
Pierre-Yves Chibon 95245b
            default=default,
Pierre-Yves Chibon 95245b
        )
Pierre-Yves Chibon 95245b
    else:
Pierre-Yves Chibon 7407c0
        import urllib
Pierre-Yves Chibon 7407c0
        import hashlib
Pierre-Yves Chibon 95245b
        query = urllib.urlencode({'s': size, 'd': default})
Pierre-Yves Chibon b8c7ae
        hashhex = hashlib.sha256(openid).hexdigest()
Pierre-Yves Chibon b8c7ae
        return "https://seccdn.libravatar.org/avatar/%s?%s" % (
Pierre-Yves Chibon b8c7ae
            hashhex, query)
Pierre-Yves Chibon 214a1e
Pierre-Yves Chibon 214a1e
Pierre-Yves Chibon 2e464a
def update_tags(session, obj, tags, username, ticketfolder):
Pierre-Yves Chibon 931b1d
    """ Update the tags of a specified object (adding or removing them).
Pierre-Yves Chibon 931b1d
    This object can be either an issue or a project.
Pierre-Yves Chibon 214a1e
Pierre-Yves Chibon 214a1e
    """
Pierre-Yves Chibon 214a1e
    if isinstance(tags, basestring):
Pierre-Yves Chibon 214a1e
        tags = [tags]
Pierre-Yves Chibon 214a1e
Pierre-Yves Chibon 931b1d
    toadd = set(tags) - set(obj.tags_text)
Pierre-Yves Chibon 931b1d
    torm = set(obj.tags_text) - set(tags)
Pierre-Yves Chibon 214a1e
    messages = []
Pierre-Yves Chibon 23368d
    if toadd:
Pierre-Yves Chibon 214a1e
        messages.append(
Pierre-Yves Chibon 931b1d
            add_tag_obj(
Pierre-Yves Chibon 214a1e
                session,
Pierre-Yves Chibon 931b1d
                obj=obj,
Pierre-Yves Chibon 23368d
                tags=toadd,
Pierre-Yves Chibon 214a1e
                user=username,
Pierre-Yves Chibon 214a1e
                ticketfolder=ticketfolder,
Pierre-Yves Chibon 214a1e
            )
Pierre-Yves Chibon 214a1e
        )
Pierre-Yves Chibon 214a1e
Pierre-Yves Chibon 214a1e
    if torm:
Pierre-Yves Chibon 23368d
        messages.append(
Pierre-Yves Chibon 931b1d
            remove_tags_obj(
Pierre-Yves Chibon 214a1e
                session,
Pierre-Yves Chibon 931b1d
                obj=obj,
Pierre-Yves Chibon 214a1e
                tags=torm,
Pierre-Yves Chibon e293ee
                user=username,
Pierre-Yves Chibon 214a1e
                ticketfolder=ticketfolder,
Pierre-Yves Chibon 214a1e
            )
Pierre-Yves Chibon 214a1e
        )
Pierre-Yves Chibon 214a1e
    session.commit()
Pierre-Yves Chibon 214a1e
Pierre-Yves Chibon 214a1e
    return messages
Pierre-Yves Chibon a86f36
Pierre-Yves Chibon a86f36
Pierre-Yves Chibon f49685
def update_dependency_issue(
Pierre-Yves Chibon 2e464a
        session, repo, issue, depends, username, ticketfolder):
Pierre-Yves Chibon a86f36
    """ Update the dependency of a specified issue (adding or removing them)
Pierre-Yves Chibon a86f36
Pierre-Yves Chibon a86f36
    """
Pierre-Yves Chibon a86f36
    if isinstance(depends, basestring):
Pierre-Yves Chibon a86f36
        depends = [depends]
Pierre-Yves Chibon a86f36
Pierre-Yves Chibon a86f36
    toadd = set(depends) - set(issue.depends_text)
Pierre-Yves Chibon a86f36
    torm = set(issue.depends_text) - set(depends)
Pierre-Yves Chibon a86f36
    messages = []
Pierre-Yves Chibon a86f36
Pierre-Yves Chibon a86f36
    # Add issue depending
Pierre-Yves Chibon a86f36
    for depend in toadd:
Pierre-Yves Chibon a86f36
        issue_depend = search_issues(session, repo, issueid=depend)
Pierre-Yves Chibon 2e498a
        if issue_depend is None:
Pierre-Yves Chibon a86f36
            continue
Pierre-Yves Chibon 2e498a
        if issue_depend.id in issue.depends_text:  # pragma: no cover
Pierre-Yves Chibon 2e498a
            # we should never be in this case but better safe than sorry...
Pierre-Yves Chibon a86f36
            continue
Pierre-Yves Chibon a86f36
Pierre-Yves Chibon a86f36
        messages.append(
Pierre-Yves Chibon a86f36
            add_issue_dependency(
Pierre-Yves Chibon a86f36
                session,
Pierre-Yves Chibon a86f36
                issue=issue_depend,
Pierre-Yves Chibon a86f36
                issue_blocked=issue,
Pierre-Yves Chibon a86f36
                user=username,
Pierre-Yves Chibon a86f36
                ticketfolder=ticketfolder,
Pierre-Yves Chibon a86f36
            )
Pierre-Yves Chibon a86f36
        )
Pierre-Yves Chibon a86f36
Pierre-Yves Chibon a86f36
    # Remove issue depending
Pierre-Yves Chibon a86f36
    for depend in torm:
Pierre-Yves Chibon a86f36
        issue_depend = search_issues(session, repo, issueid=depend)
Pierre-Yves Chibon 0fae14
        if issue_depend is None:  # pragma: no cover
Pierre-Yves Chibon 0fae14
            # We cannot test this as it would mean we managed to put in an
Pierre-Yves Chibon 0fae14
            # invalid ticket as dependency earlier
Pierre-Yves Chibon a86f36
            continue
Pierre-Yves Chibon 2e498a
        if issue_depend.id not in issue.depends_text:  # pragma: no cover
Pierre-Yves Chibon 2e498a
            # we should never be in this case but better safe than sorry...
Pierre-Yves Chibon a86f36
            continue
Pierre-Yves Chibon a86f36
Pierre-Yves Chibon a86f36
        messages.append(
Pierre-Yves Chibon a86f36
            remove_issue_dependency(
Pierre-Yves Chibon a86f36
                session,
Pierre-Yves Chibon a86f36
                issue=issue,
Pierre-Yves Chibon a86f36
                issue_blocked=issue_depend,
Pierre-Yves Chibon a86f36
                user=username,
Pierre-Yves Chibon a86f36
                ticketfolder=ticketfolder,
Pierre-Yves Chibon a86f36
            )
Pierre-Yves Chibon a86f36
        )
Pierre-Yves Chibon a86f36
Pierre-Yves Chibon a86f36
    session.commit()
Pierre-Yves Chibon a86f36
    return messages
Pierre-Yves Chibon a86f36
Pierre-Yves Chibon a86f36
Pierre-Yves Chibon f49685
def update_blocked_issue(
Pierre-Yves Chibon 2e464a
        session, repo, issue, blocks, username, ticketfolder):
Pierre-Yves Chibon a86f36
    """ Update the upstream dependency of a specified issue (adding or
Pierre-Yves Chibon a86f36
    removing them)
Pierre-Yves Chibon a86f36
Pierre-Yves Chibon a86f36
    """
Pierre-Yves Chibon a86f36
    if isinstance(blocks, basestring):
Pierre-Yves Chibon a86f36
        blocks = [blocks]
Pierre-Yves Chibon a86f36
Pierre-Yves Chibon a86f36
    toadd = set(blocks) - set(issue.blocks_text)
Pierre-Yves Chibon a86f36
    torm = set(issue.blocks_text) - set(blocks)
Pierre-Yves Chibon a86f36
    messages = []
Pierre-Yves Chibon a86f36
Pierre-Yves Chibon a86f36
    # Add issue blocked
Pierre-Yves Chibon a86f36
    for block in toadd:
Pierre-Yves Chibon a86f36
        issue_block = search_issues(session, repo, issueid=block)
Pierre-Yves Chibon a24b70
        if issue_block is None:
Pierre-Yves Chibon a86f36
            continue
Pierre-Yves Chibon a24b70
        if issue_block.id in issue.blocks_text:  # pragma: no cover
Pierre-Yves Chibon a24b70
            # we should never be in this case but better safe than sorry...
Pierre-Yves Chibon a86f36
            continue
Pierre-Yves Chibon a86f36
Pierre-Yves Chibon a86f36
        messages.append(
Pierre-Yves Chibon a86f36
            add_issue_dependency(
Pierre-Yves Chibon a86f36
                session,
Pierre-Yves Chibon a86f36
                issue=issue,
Pierre-Yves Chibon a86f36
                issue_blocked=issue_block,
Pierre-Yves Chibon a86f36
                user=username,
Pierre-Yves Chibon a86f36
                ticketfolder=ticketfolder,
Pierre-Yves Chibon a86f36
            )
Pierre-Yves Chibon a86f36
        )
Pierre-Yves Chibon a86f36
        session.commit()
Pierre-Yves Chibon a86f36
Pierre-Yves Chibon a86f36
    # Remove issue blocked
Pierre-Yves Chibon a86f36
    for block in torm:
Pierre-Yves Chibon a86f36
        issue_block = search_issues(session, repo, issueid=block)
Pierre-Yves Chibon a24b70
        if issue_block is None:  # pragma: no cover
Pierre-Yves Chibon a24b70
            # We cannot test this as it would mean we managed to put in an
Pierre-Yves Chibon a24b70
            # invalid ticket as dependency earlier
Pierre-Yves Chibon a86f36
            continue
Pierre-Yves Chibon a86f36
Pierre-Yves Chibon a24b70
        if issue_block.id not in issue.blocks_text:  # pragma: no cover
Pierre-Yves Chibon a24b70
            # we should never be in this case but better safe than sorry...
Pierre-Yves Chibon a86f36
            continue
Pierre-Yves Chibon a86f36
Pierre-Yves Chibon a86f36
        messages.append(
Pierre-Yves Chibon a86f36
            remove_issue_dependency(
Pierre-Yves Chibon a86f36
                session,
Pierre-Yves Chibon a86f36
                issue=issue_block,
Pierre-Yves Chibon a86f36
                issue_blocked=issue,
Pierre-Yves Chibon a86f36
                user=username,
Pierre-Yves Chibon a86f36
                ticketfolder=ticketfolder,
Pierre-Yves Chibon a86f36
            )
Pierre-Yves Chibon a86f36
        )
Pierre-Yves Chibon a86f36
Pierre-Yves Chibon a86f36
    session.commit()
Pierre-Yves Chibon a86f36
    return messages
Pierre-Yves Chibon 4fd1f7
Pierre-Yves Chibon 4fd1f7
Pierre-Yves Chibon 4fd1f7
def add_user_pending_email(session, userobj, email):
Pierre-Yves Chibon 4fd1f7
    ''' Add the provided user to the specified user.
Pierre-Yves Chibon 4fd1f7
    '''
Pierre-Yves Chibon 4fd1f7
    other_user = search_user(session, email=email)
Pierre-Yves Chibon 4fd1f7
    if other_user and other_user != userobj:
Pierre-Yves Chibon 4fd1f7
        raise pagure.exceptions.PagureException(
Pierre-Yves Chibon 4fd1f7
            'Someone else has already registered this email'
Pierre-Yves Chibon 4fd1f7
        )
Pierre-Yves Chibon 4fd1f7
Pierre-Yves Chibon 2a3a0e
    pending_email = search_pending_email(session, email=email)
Pierre-Yves Chibon 2a3a0e
    if pending_email:
Pierre-Yves Chibon 2a3a0e
        raise pagure.exceptions.PagureException(
Pierre-Yves Chibon 2a3a0e
            'This email is already pending confirmation'
Pierre-Yves Chibon 2a3a0e
        )
Pierre-Yves Chibon 2a3a0e
Pierre-Yves Chibon 4fd1f7
    tmpemail = pagure.lib.model.UserEmailPending(
Pierre-Yves Chibon 4fd1f7
        user_id=userobj.id,
Pierre-Yves Chibon 4fd1f7
        token=pagure.lib.login.id_generator(40),
Pierre-Yves Chibon 4fd1f7
        email=email
Pierre-Yves Chibon 4fd1f7
    )
Pierre-Yves Chibon 4fd1f7
    session.add(tmpemail)
Pierre-Yves Chibon 4fd1f7
    session.flush()
Pierre-Yves Chibon 4fd1f7
Pierre-Yves Chibon 4fd1f7
    pagure.lib.notify.notify_new_email(tmpemail, user=userobj)
Pierre-Yves Chibon ced619
Pierre-Yves Chibon ced619
Pierre-Yves Chibon 8bd0a9
def resend_pending_email(session, userobj, email):
Pierre-Yves Chibon 8bd0a9
    ''' Resend to the user the confirmation email for the provided email
Pierre-Yves Chibon 8bd0a9
    address.
Pierre-Yves Chibon 8bd0a9
    '''
Pierre-Yves Chibon 8bd0a9
    other_user = search_user(session, email=email)
Pierre-Yves Chibon 8bd0a9
    if other_user and other_user != userobj:
Pierre-Yves Chibon 8bd0a9
        raise pagure.exceptions.PagureException(
Pierre-Yves Chibon 323250
            'Someone else has already registered this email address'
Pierre-Yves Chibon 8bd0a9
        )
Pierre-Yves Chibon 8bd0a9
Pierre-Yves Chibon 8bd0a9
    pending_email = search_pending_email(session, email=email)
Pierre-Yves Chibon 8bd0a9
    if not pending_email:
Pierre-Yves Chibon 8bd0a9
        raise pagure.exceptions.PagureException(
Pierre-Yves Chibon 323250
            'This email address has already been confirmed'
Pierre-Yves Chibon 8bd0a9
        )
Pierre-Yves Chibon 8bd0a9
Pierre-Yves Chibon d1e053
    pending_email.token = pagure.lib.login.id_generator(40)
Pierre-Yves Chibon 8bd0a9
    session.add(pending_email)
Pierre-Yves Chibon 8bd0a9
    session.flush()
Pierre-Yves Chibon 8bd0a9
Pierre-Yves Chibon 8bd0a9
    pagure.lib.notify.notify_new_email(pending_email, user=userobj)
Pierre-Yves Chibon 8bd0a9
Pierre-Yves Chibon 8bd0a9
Pierre-Yves Chibon ced619
def search_pending_email(session, email=None, token=None):
Pierre-Yves Chibon ced619
    ''' Searches the database for the pending email matching the given
Pierre-Yves Chibon ced619
    criterias.
Pierre-Yves Chibon ced619
Pierre-Yves Chibon ced619
    :arg session: the session to use to connect to the database.
Pierre-Yves Chibon ced619
    :kwarg email: the email to look for
Pierre-Yves Chibon ced619
    :type email: string or None
Pierre-Yves Chibon ced619
    :kwarg token: the token of the pending email to look for
Pierre-Yves Chibon ced619
    :type token: string or None
Pierre-Yves Chibon ced619
    :return: A single UserEmailPending object
Pierre-Yves Chibon ced619
    :rtype: UserEmailPending
Pierre-Yves Chibon ced619
Pierre-Yves Chibon ced619
    '''
Pierre-Yves Chibon ced619
    query = session.query(
Pierre-Yves Chibon ced619
        model.UserEmailPending
Pierre-Yves Chibon ced619
    )
Pierre-Yves Chibon ced619
Pierre-Yves Chibon ced619
    if email is not None:
Pierre-Yves Chibon ced619
        query = query.filter(
Pierre-Yves Chibon ced619
            model.UserEmailPending.email == email
Pierre-Yves Chibon ced619
        )
Pierre-Yves Chibon ced619
Pierre-Yves Chibon ced619
    if token is not None:
Pierre-Yves Chibon ced619
        query = query.filter(
Pierre-Yves Chibon ced619
            model.UserEmailPending.token == token
Pierre-Yves Chibon ced619
        )
Pierre-Yves Chibon ced619
Pierre-Yves Chibon ced619
    output = query.first()
Pierre-Yves Chibon ced619
Pierre-Yves Chibon ced619
    return output
Pierre-Yves Chibon 623f37
Pierre-Yves Chibon 623f37
Pierre-Yves Chibon 623f37
def generate_hook_token(session):
Pierre-Yves Chibon 623f37
    ''' For each project in the database, re-generate a unique hook_token.
Pierre-Yves Chibon 623f37
Pierre-Yves Chibon 623f37
    '''
Pierre-Yves Chibon 623f37
Pierre-Yves Chibon 623f37
    for project in search_projects(session):
Pierre-Yves Chibon 623f37
        project.hook_token = pagure.lib.login.id_generator(40)
Pierre-Yves Chibon 623f37
        session.add(project)
Pierre-Yves Chibon 623f37
    session.commit()
Pierre-Yves Chibon 56fa2a
Pierre-Yves Chibon 56fa2a
Pierre-Yves Chibon c2a75b
def get_group_types(session, group_type=None):
Pierre-Yves Chibon 56fa2a
    ''' Return the list of type a group can have.
Pierre-Yves Chibon 56fa2a
Pierre-Yves Chibon 56fa2a
    '''
Pierre-Yves Chibon 56fa2a
    query = session.query(
Pierre-Yves Chibon 56fa2a
        model.PagureGroupType
Pierre-Yves Chibon 56fa2a
    ).order_by(
Pierre-Yves Chibon c2a75b
        model.PagureGroupType.group_type
Pierre-Yves Chibon 56fa2a
    )
Pierre-Yves Chibon 56fa2a
Pierre-Yves Chibon c2a75b
    if group_type:
Pierre-Yves Chibon 56fa2a
        query = query.filter(
Pierre-Yves Chibon c2a75b
            model.PagureGroupType.group_type == group_type
Pierre-Yves Chibon 56fa2a
        )
Pierre-Yves Chibon 56fa2a
Pierre-Yves Chibon 56fa2a
    return query.all()
Pierre-Yves Chibon 89b639
Pierre-Yves Chibon 89b639
Pierre-Yves Chibon c2a75b
def search_groups(session, pattern=None, group_name=None, group_type=None):
Pierre-Yves Chibon 89b639
    ''' Return the groups based on the criteria specified.
Pierre-Yves Chibon 89b639
Pierre-Yves Chibon 89b639
    '''
Pierre-Yves Chibon 89b639
    query = session.query(
Pierre-Yves Chibon 89b639
        model.PagureGroup
Pierre-Yves Chibon 89b639
    ).order_by(
Pierre-Yves Chibon c2a75b
        model.PagureGroup.group_type
Pierre-Yves Chibon 89b639
    )
Pierre-Yves Chibon 89b639
Pierre-Yves Chibon 89b639
    if pattern:
Pierre-Yves Chibon 89b639
        pattern = pattern.replace('*', '%')
Pierre-Yves Chibon 89b639
        query = query.filter(
Pierre-Yves Chibon 89b639
            model.PagureGroup.group_name.like(pattern)
Pierre-Yves Chibon 89b639
        )
Pierre-Yves Chibon 89b639
Pierre-Yves Chibon b4ec1c
    if group_name:
Pierre-Yves Chibon 89b639
        query = query.filter(
Pierre-Yves Chibon c2a75b
            model.PagureGroup.group_name == group_name
Pierre-Yves Chibon 89b639
        )
Pierre-Yves Chibon 89b639
Pierre-Yves Chibon c2a75b
    if group_type:
Pierre-Yves Chibon 89b639
        query = query.filter(
Pierre-Yves Chibon c2a75b
            model.PagureGroup.group_type == group_type
Pierre-Yves Chibon 89b639
        )
Pierre-Yves Chibon 89b639
Pierre-Yves Chibon c2a75b
    if group_name:
Pierre-Yves Chibon 89b639
        return query.first()
Pierre-Yves Chibon 89b639
    else:
Pierre-Yves Chibon 89b639
        return query.all()
Pierre-Yves Chibon 739196
Pierre-Yves Chibon 739196
Pierre-Yves Chibon bed068
def add_user_to_group(session, username, group, user, is_admin):
Pierre-Yves Chibon 759c87
    ''' Add the specified user to the given group.
Pierre-Yves Chibon 759c87
    '''
Pierre-Yves Chibon 82b9c8
    new_user = search_user(session, username=username)
Pierre-Yves Chibon 82b9c8
    if not new_user:
Pierre-Yves Chibon bed068
        raise pagure.exceptions.PagureException(
Pierre-Yves Chibon bed068
            'No user `%s` found' % username)
Pierre-Yves Chibon bed068
Pierre-Yves Chibon 60ba7f
    action_user = user
Pierre-Yves Chibon bed068
    user = search_user(session, username=user)
Pierre-Yves Chibon 60ba7f
    if not user:
Pierre-Yves Chibon 60ba7f
        raise pagure.exceptions.PagureException(
Pierre-Yves Chibon 60ba7f
            'No user `%s` found' % action_user)
Pierre-Yves Chibon 60ba7f
Pierre-Yves Chibon 2a7216
    if group.group_name not in user.groups and not is_admin\
Pierre-Yves Chibon 60ba7f
            and user.username != group.creator.username:
Pierre-Yves Chibon bed068
        raise pagure.exceptions.PagureException(
Pierre-Yves Chibon bed068
            'You are not allowed to add user to this group')
Pierre-Yves Chibon 82b9c8
Pierre-Yves Chibon 759c87
    for guser in group.users:
Pierre-Yves Chibon e660c6
        if guser.username == new_user.username:
Pierre-Yves Chibon 759c87
            return 'User `%s` already in the group, nothing to change.' % (
Pierre-Yves Chibon e660c6
                new_user.username)
Pierre-Yves Chibon 759c87
Pierre-Yves Chibon 759c87
    grp = model.PagureUserGroup(
Pierre-Yves Chibon 759c87
        group_id=group.id,
Pierre-Yves Chibon e660c6
        user_id=new_user.id
Pierre-Yves Chibon 759c87
    )
Pierre-Yves Chibon 759c87
    session.add(grp)
Pierre-Yves Chibon 759c87
    session.flush()
Pierre-Yves Chibon 60ba7f
    return 'User `%s` added to the group `%s`.' % (
Pierre-Yves Chibon 60ba7f
        new_user.username, group.group_name)
Pierre-Yves Chibon 759c87
Pierre-Yves Chibon 759c87
Pierre-Yves Chibon 42452c
def edit_group_info(
Pierre-Yves Chibon 42452c
        session, group, display_name, description, user, is_admin):
Pierre-Yves Chibon 42452c
    ''' Edit the information regarding a given group.
Pierre-Yves Chibon 42452c
    '''
Pierre-Yves Chibon 42452c
    action_user = user
Pierre-Yves Chibon 42452c
    user = search_user(session, username=user)
Pierre-Yves Chibon 42452c
    if not user:
Pierre-Yves Chibon 42452c
        raise pagure.exceptions.PagureException(
Pierre-Yves Chibon 42452c
            'No user `%s` found' % action_user)
Pierre-Yves Chibon 42452c
Pierre-Yves Chibon 42452c
    if group.group_name not in user.groups \
Pierre-Yves Chibon 42452c
            and not is_admin \
Pierre-Yves Chibon 42452c
            and user.username != group.creator.username:
Pierre-Yves Chibon 42452c
        raise pagure.exceptions.PagureException(
Pierre-Yves Chibon 42452c
            'You are not allowed to edit this group')
Pierre-Yves Chibon 42452c
Pierre-Yves Chibon 42452c
    edits = []
Pierre-Yves Chibon 42452c
    if display_name and display_name != group.display_name:
Pierre-Yves Chibon 42452c
        group.display_name = display_name
Pierre-Yves Chibon 42452c
        edits.append('display_name')
Pierre-Yves Chibon 42452c
    if description and description != group.description:
Pierre-Yves Chibon 42452c
        group.description = description
Pierre-Yves Chibon 42452c
        edits.append('description')
Pierre-Yves Chibon 42452c
Pierre-Yves Chibon 42452c
    session.add(group)
Pierre-Yves Chibon 42452c
    session.flush()
Pierre-Yves Chibon 42452c
Pierre-Yves Chibon 42452c
    msg = 'Nothing changed'
Pierre-Yves Chibon 42452c
    if edits:
Pierre-Yves Chibon 42452c
        pagure.lib.notify.log(
Pierre-Yves Chibon 42452c
            None,
Pierre-Yves Chibon 42452c
            topic='group.edit',
Pierre-Yves Chibon 42452c
            msg=dict(
Pierre-Yves Chibon 42452c
                group=group.to_json(public=True),
Pierre-Yves Chibon 42452c
                fields=edits,
Pierre-Yves Chibon 42452c
                agent=user.username,
Pierre-Yves Chibon 42452c
            ),
Pierre-Yves Chibon 42452c
            redis=REDIS,
Pierre-Yves Chibon 42452c
        )
Pierre-Yves Chibon 42452c
        msg = 'Group "%s" (%s) edited' % (
Pierre-Yves Chibon 42452c
            group.display_name, group.group_name)
Pierre-Yves Chibon 42452c
Pierre-Yves Chibon 42452c
    return msg
Pierre-Yves Chibon 42452c
Pierre-Yves Chibon 42452c
Pierre-Yves Chibon d7b5a0
def delete_user_of_group(session, username, groupname, user, is_admin,
Pierre-Yves Chibon d7b5a0
                         force=False):
Pierre-Yves Chibon bed068
    ''' Removes the specified user from the given group.
Pierre-Yves Chibon bed068
    '''
Pierre-Yves Chibon bed068
    group_obj = search_groups(session, group_name=groupname)
Pierre-Yves Chibon bed068
Pierre-Yves Chibon bed068
    if not group_obj:
Pierre-Yves Chibon bed068
        raise pagure.exceptions.PagureException(
Pierre-Yves Chibon bed068
            'No group `%s` found' % groupname)
Pierre-Yves Chibon bed068
Pierre-Yves Chibon bed068
    drop_user = search_user(session, username=username)
Pierre-Yves Chibon bed068
    if not drop_user:
Pierre-Yves Chibon bed068
        raise pagure.exceptions.PagureException(
Pierre-Yves Chibon bed068
            'No user `%s` found' % username)
Pierre-Yves Chibon bed068
Pierre-Yves Chibon 7780e4
    action_user = user
Pierre-Yves Chibon bed068
    user = search_user(session, username=user)
Pierre-Yves Chibon 7780e4
    if not user:
Pierre-Yves Chibon 7780e4
        raise pagure.exceptions.PagureException(
Pierre-Yves Chibon 7780e4
            'Could not find user %s' % action_user)
Pierre-Yves Chibon 7780e4
Pierre-Yves Chibon 2a7216
    if group_obj.group_name not in user.groups and not is_admin:
Pierre-Yves Chibon bed068
        raise pagure.exceptions.PagureException(
Pierre-Yves Chibon bed068
            'You are not allowed to remove user from this group')
Pierre-Yves Chibon bed068
Pierre-Yves Chibon d7b5a0
    if drop_user.username == group_obj.creator.username and not force:
Pierre-Yves Chibon bed068
        raise pagure.exceptions.PagureException(
Pierre-Yves Chibon bed068
            'The creator of a group cannot be removed')
Pierre-Yves Chibon bed068
Pierre-Yves Chibon bed068
    user_grp = get_user_group(session, drop_user.id, group_obj.id)
Pierre-Yves Chibon 7780e4
    if not user_grp:
Pierre-Yves Chibon 7780e4
        raise pagure.exceptions.PagureException(
Pierre-Yves Chibon 7780e4
            'User `%s` could not be found in the group `%s`' % (
Pierre-Yves Chibon 2a7216
                username, groupname))
Pierre-Yves Chibon 7780e4
Pierre-Yves Chibon bed068
    session.delete(user_grp)
Pierre-Yves Chibon bed068
    session.flush()
Pierre-Yves Chibon bed068
Pierre-Yves Chibon bed068
Pierre-Yves Chibon 4451bc
def add_group(
Pierre-Yves Chibon 4451bc
        session, group_name, display_name, description,
Pierre-Yves Chibon 4451bc
        group_type, user, is_admin, blacklist):
Pierre-Yves Chibon bed068
    ''' Creates a new group with the given information.
Pierre-Yves Chibon bed068
    '''
Pierre-Yves Chibon 250931
    if ' ' in group_name:
Pierre-Yves Chibon 250931
        raise pagure.exceptions.PagureException(
Pierre-Yves Chibon 250931
            'Spaces are not allowed in group names: %s' % group_name)
Pierre-Yves Chibon bed068
Pierre-Yves Chibon ca10fd
    if group_name in blacklist:
Pierre-Yves Chibon ca10fd
        raise pagure.exceptions.PagureException(
Pierre-Yves Chibon 165c3e
            'This group name has been blacklisted, '
Pierre-Yves Chibon 165c3e
            'please choose another one')
Pierre-Yves Chibon ca10fd
Pierre-Yves Chibon bed068
    group_types = ['user']
Pierre-Yves Chibon bed068
    if is_admin:
Pierre-Yves Chibon bed068
        group_types = [
Pierre-Yves Chibon bed068
            grp.group_type
Pierre-Yves Chibon bed068
            for grp in get_group_types(session)
Pierre-Yves Chibon bed068
        ]
Pierre-Yves Chibon bed068
Pierre-Yves Chibon bed068
    if not is_admin:
Pierre-Yves Chibon bed068
        group_type = 'user'
Pierre-Yves Chibon bed068
Pierre-Yves Chibon bed068
    if group_type not in group_types:
Pierre-Yves Chibon bed068
        raise pagure.exceptions.PagureException(
Pierre-Yves Chibon bed068
            'Invalide type for this group')
Pierre-Yves Chibon bed068
Pierre-Yves Chibon e509f7
    username = user
Pierre-Yves Chibon bed068
    user = search_user(session, username=user)
Pierre-Yves Chibon e509f7
    if not user:
Pierre-Yves Chibon e509f7
        raise pagure.exceptions.PagureException(
Pierre-Yves Chibon e509f7
            'Could not find user %s' % username)
Pierre-Yves Chibon bed068
Pierre-Yves Chibon 84ac61
    group = search_groups(session, group_name=group_name)
Pierre-Yves Chibon 84ac61
    if group:
Pierre-Yves Chibon 84ac61
        raise pagure.exceptions.PagureException(
Pierre-Yves Chibon 84ac61
            'There is already a group named %s' % group_name)
Pierre-Yves Chibon 84ac61
Pierre-Yves Chibon bed068
    grp = pagure.lib.model.PagureGroup(
Pierre-Yves Chibon bed068
        group_name=group_name,
Pierre-Yves Chibon 4451bc
        display_name=display_name,
Pierre-Yves Chibon 4451bc
        description=description,
Pierre-Yves Chibon bed068
        group_type=group_type,
Pierre-Yves Chibon bed068
        user_id=user.id,
Pierre-Yves Chibon bed068
    )
Pierre-Yves Chibon e509f7
    session.add(grp)
Pierre-Yves Chibon e509f7
    session.flush()
Pierre-Yves Chibon bed068
Pierre-Yves Chibon e509f7
    return add_user_to_group(
Pierre-Yves Chibon e509f7
        session, user.username, grp, user.username, is_admin)
Pierre-Yves Chibon bed068
Pierre-Yves Chibon bed068
Pierre-Yves Chibon 739196
def get_user_group(session, userid, groupid):
Pierre-Yves Chibon 739196
    ''' Return a specific user_group for the specified group and user
Pierre-Yves Chibon 739196
    identifiers.
Pierre-Yves Chibon 739196
Pierre-Yves Chibon 739196
    :arg session: the session with which to connect to the database.
Pierre-Yves Chibon 739196
Pierre-Yves Chibon 739196
    '''
Pierre-Yves Chibon 739196
    query = session.query(
Pierre-Yves Chibon 739196
        model.PagureUserGroup
Pierre-Yves Chibon 739196
    ).filter(
Pierre-Yves Chibon 739196
        model.PagureUserGroup.user_id == userid
Pierre-Yves Chibon 739196
    ).filter(
Pierre-Yves Chibon 739196
        model.PagureUserGroup.group_id == groupid
Pierre-Yves Chibon 739196
    )
Pierre-Yves Chibon 739196
Pierre-Yves Chibon 739196
    return query.first()
Pierre-Yves Chibon ade106
Pierre-Yves Chibon ade106
Pierre-Yves Chibon ade106
def is_group_member(session, user, groupname):
Pierre-Yves Chibon ade106
    """ Return whether the user is a member of the specified group. """
Pierre-Yves Chibon ade106
    if not user:
Pierre-Yves Chibon ade106
        return False
Pierre-Yves Chibon ade106
Pierre-Yves Chibon ade106
    user = search_user(session, username=user)
Pierre-Yves Chibon ade106
    if not user:
Pierre-Yves Chibon ade106
        return False
Pierre-Yves Chibon ade106
Pierre-Yves Chibon ade106
    return groupname in user.groups
Pierre-Yves Chibon 6e345c
Pierre-Yves Chibon 6e345c
Pierre-Yves Chibon 6e345c
def get_api_token(session, token_str):
Pierre-Yves Chibon 6e345c
    """ Return the Token object corresponding to the provided token string
Pierre-Yves Chibon 6e345c
    if there is any, returns None otherwise.
Pierre-Yves Chibon 6e345c
    """
Pierre-Yves Chibon 6e345c
    query = session.query(
Pierre-Yves Chibon 6e345c
        model.Token
Pierre-Yves Chibon 6e345c
    ).filter(
Pierre-Yves Chibon 6e345c
        model.Token.id == token_str
Pierre-Yves Chibon 6e345c
    )
Pierre-Yves Chibon 6e345c
Pierre-Yves Chibon 6e345c
    return query.first()
Pierre-Yves Chibon 112bd1
Pierre-Yves Chibon 112bd1
Pierre-Yves Chibon 112bd1
def get_acls(session):
Pierre-Yves Chibon 112bd1
    """ Returns all the possible ACLs a token can have according to the
Pierre-Yves Chibon 112bd1
    database.
Pierre-Yves Chibon 112bd1
    """
Pierre-Yves Chibon 112bd1
    query = session.query(
Pierre-Yves Chibon 112bd1
        model.ACL
Pierre-Yves Chibon 112bd1
    ).order_by(
Pierre-Yves Chibon 112bd1
        model.ACL.name
Pierre-Yves Chibon 112bd1
    )
Pierre-Yves Chibon 112bd1
Pierre-Yves Chibon 112bd1
    return query.all()
Pierre-Yves Chibon 0b80a3
Pierre-Yves Chibon 0b80a3
Pierre-Yves Chibon 0b80a3
def add_token_to_user(session, project, acls, username):
Pierre-Yves Chibon 0b80a3
    """ Create a new token for the specified user on the specified project
Pierre-Yves Chibon 0b80a3
    with the given ACLs.
Pierre-Yves Chibon 0b80a3
    """
Pierre-Yves Chibon 0b80a3
    acls_obj = session.query(
Pierre-Yves Chibon 0b80a3
        model.ACL
Pierre-Yves Chibon 0b80a3
    ).filter(
Pierre-Yves Chibon 0b80a3
        model.ACL.name.in_(acls)
Pierre-Yves Chibon 0b80a3
    ).all()
Pierre-Yves Chibon 0b80a3
Pierre-Yves Chibon 0b80a3
    user = search_user(session, username=username)
Pierre-Yves Chibon 0b80a3
Pierre-Yves Chibon 0b80a3
    token = pagure.lib.model.Token(
Pierre-Yves Chibon 0b80a3
        id=pagure.lib.login.id_generator(64),
Pierre-Yves Chibon 0b80a3
        user_id=user.id,
Pierre-Yves Chibon 0b80a3
        project_id=project.id,
Pierre-Yves Chibon 0b80a3
        expiration=datetime.datetime.utcnow() + datetime.timedelta(days=60)
Pierre-Yves Chibon 0b80a3
    )
Pierre-Yves Chibon 0b80a3
    session.add(token)
Pierre-Yves Chibon 0b80a3
    session.flush()
Pierre-Yves Chibon 0b80a3
Pierre-Yves Chibon 0b80a3
    for acl in acls_obj:
Pierre-Yves Chibon 0b80a3
        item = pagure.lib.model.TokenAcl(
Pierre-Yves Chibon 0b80a3
            token_id=token.id,
Pierre-Yves Chibon 0b80a3
            acl_id=acl.id,
Pierre-Yves Chibon 0b80a3
        )
Pierre-Yves Chibon 0b80a3
        session.add(item)
Pierre-Yves Chibon 0b80a3
Pierre-Yves Chibon 0b80a3
    session.commit()
Pierre-Yves Chibon 0b80a3
Pierre-Yves Chibon 0b80a3
    return 'Token created'
Pierre-Yves Chibon 2d9881
Pierre-Yves Chibon 300559
Pierre-Yves Chibon 814bc8
def text2markdown(text, extended=True):
Pierre-Yves Chibon 2d9881
    """ Simple text to html converter using the markdown library.
Pierre-Yves Chibon 2d9881
    """
Pierre-Yves Chibon f9f132
    md_processor = markdown.Markdown(safe_mode="escape")
Pierre-Yves Chibon 814bc8
    if extended:
Pierre-Yves Chibon 814bc8
        # Install our markdown modifications
Pierre-Yves Chibon f9f132
        md_processor = markdown.Markdown(extensions=['pagure.pfmarkdown'])
Pierre-Yves Chibon 814bc8
Pierre-Yves Chibon 2d9881
    if text:
Pierre-Yves Chibon 2d9881
        # Hack to allow blockquotes to be marked by ~~~
Pierre-Yves Chibon 2d9881
        ntext = []
Pierre-Yves Chibon 2d9881
        indent = False
Pierre-Yves Chibon 2d9881
        for line in text.split('\n'):
Pierre-Yves Chibon 2d9881
            if line.startswith('~~~'):
Pierre-Yves Chibon 2d9881
                indent = not indent
Pierre-Yves Chibon 2d9881
                continue
Pierre-Yves Chibon 2d9881
            if indent:
Pierre-Yves Chibon 2d9881
                line = '    %s' % line
Pierre-Yves Chibon 2d9881
            ntext.append(line)
Pierre-Yves Chibon f9f132
        return clean_input(md_processor.convert('\n'.join(ntext)))
Pierre-Yves Chibon 2d9881
Pierre-Yves Chibon 2d9881
    return ''
Pierre-Yves Chibon 3916b5
Pierre-Yves Chibon 300559
Pierre-Yves Chibon 300559
def filter_img_src(name, value):
Pierre-Yves Chibon 300559
    ''' Filter in img html tags images coming from a different domain. '''
Pierre-Yves Chibon 300559
    if name in ('alt', 'height', 'width', 'class'):
Pierre-Yves Chibon 300559
        return True
Pierre-Yves Chibon 300559
    if name == 'src':
Pierre-Yves Chibon f9f132
        parsed = urlparse.urlparse(value)
Pierre-Yves Chibon f9f132
        return (not parsed.netloc) or parsed.netloc == urlparse.urlparse(
Pierre-Yves Chibon 88a560
            pagure.APP.config['APP_URL']).netloc
Pierre-Yves Chibon 300559
    return False
Pierre-Yves Chibon 300559
Pierre-Yves Chibon 300559
Pierre-Yves Chibon faecff
def clean_input(text, ignore=None):
Pierre-Yves Chibon 3916b5
    """ For a given html text, escape everything we do not want to support
Pierre-Yves Chibon 3916b5
    to avoid potential security breach.
Pierre-Yves Chibon 3916b5
    """
Pierre-Yves Chibon faecff
    if ignore and not isinstance(ignore, (tuple, set, list)):
Pierre-Yves Chibon faecff
        ignore = [ignore]
Pierre-Yves Chibon faecff
Pierre-Yves Chibon 3916b5
    attrs = bleach.ALLOWED_ATTRIBUTES
Pierre-Yves Chibon b60425
    if not ignore or not 'img' in ignore:
Pierre-Yves Chibon faecff
        attrs['img'] = filter_img_src
Pierre-Yves Chibon faecff
Pierre-Yves Chibon faecff
    tags = bleach.ALLOWED_TAGS + [
Pierre-Yves Chibon 24584d
        'p', 'br', 'div', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6',
Pierre-Yves Chibon 24584d
        'table', 'td', 'tr', 'th',
Pierre-Yves Chibon a4a4c1
        'col', 'tbody', 'pre', 'img', 'hr', 'dl', 'dt', 'dd', 'span',
Clement Verna 506ac6
        'kbd', 'var', 'del',
Pierre-Yves Chibon faecff
    ]
Pierre-Yves Chibon faecff
    if ignore:
Pierre-Yves Chibon c52651
        for tag in ignore:
Pierre-Yves Chibon c52651
            if tag in tags:
Pierre-Yves Chibon c52651
                tags.remove(tag)
Pierre-Yves Chibon faecff
Pierre-Yves Chibon faecff
    return bleach.clean(text, tags=tags, attributes=attrs)
Pierre-Yves Chibon cf88d8
Pierre-Yves Chibon cf88d8
Pierre-Yves Chibon eae5cc
def could_be_text(text):
Pierre-Yves Chibon eae5cc
    """ Returns wether we think this chain of character could be text or not
Pierre-Yves Chibon cf88d8
    """
Pierre-Yves Chibon fe765e
    try:
Pierre-Yves Chibon b0235c
        text.decode('utf-8')
Pierre-Yves Chibon 97c77d
        return True
Pierre-Yves Chibon 7f81da
    except:
Pierre-Yves Chibon 7f81da
        return False
Pierre-Yves Chibon 573e63
Pierre-Yves Chibon 573e63
Pierre-Yves Chibon 573e63
def get_pull_request_of_user(session, username):
Pierre-Yves Chibon 573e63
    '''List the opened pull-requests of an user.
Pierre-Yves Chibon 573e63
    These pull-requests have either been opened by that user or against
Pierre-Yves Chibon 573e63
    projects that user has commit on.
Pierre-Yves Chibon 573e63
    '''
Pierre-Yves Chibon 573e63
    projects = session.query(
Pierre-Yves Chibon 573e63
        sqlalchemy.distinct(model.Project.id)
Pierre-Yves Chibon 573e63
    )
Pierre-Yves Chibon 573e63
Pierre-Yves Chibon 573e63
    projects = projects.filter(
Pierre-Yves Chibon 573e63
        # User created the project
Pierre-Yves Chibon 573e63
        sqlalchemy.and_(
Pierre-Yves Chibon 573e63
            model.User.user == username,
Pierre-Yves Chibon 573e63
            model.User.id == model.Project.user_id,
Pierre-Yves Chibon 573e63
        )
Pierre-Yves Chibon 573e63
    )
Pierre-Yves Chibon f9f132
    sub_q2 = session.query(
Pierre-Yves Chibon 573e63
        model.Project.id
Pierre-Yves Chibon 573e63
    ).filter(
Pierre-Yves Chibon 573e63
        # User got commit right
Pierre-Yves Chibon 573e63
        sqlalchemy.and_(
Pierre-Yves Chibon 573e63
            model.User.user == username,
Pierre-Yves Chibon 573e63
            model.User.id == model.ProjectUser.user_id,
Pierre-Yves Chibon 573e63
            model.ProjectUser.project_id == model.Project.id
Pierre-Yves Chibon 573e63
        )
Pierre-Yves Chibon 573e63
    )
Pierre-Yves Chibon f9f132
    sub_q3 = session.query(
Pierre-Yves Chibon 573e63
        model.Project.id
Pierre-Yves Chibon 573e63
    ).filter(
Pierre-Yves Chibon 573e63
        # User created a group that has commit right
Pierre-Yves Chibon 573e63
        sqlalchemy.and_(
Pierre-Yves Chibon 573e63
            model.User.user == username,
Pierre-Yves Chibon 573e63
            model.PagureGroup.user_id == model.User.id,
Pierre-Yves Chibon 573e63
            model.PagureGroup.group_type == 'user',
Pierre-Yves Chibon 573e63
            model.PagureGroup.id == model.ProjectGroup.group_id,
Pierre-Yves Chibon 573e63
            model.Project.id == model.ProjectGroup.project_id,
Pierre-Yves Chibon 573e63
        )
Pierre-Yves Chibon 573e63
    )
Pierre-Yves Chibon f9f132
    sub_q4 = session.query(
Pierre-Yves Chibon 573e63
        model.Project.id
Pierre-Yves Chibon 573e63
    ).filter(
Pierre-Yves Chibon 573e63
        # User is part of a group that has commit right
Pierre-Yves Chibon 573e63
        sqlalchemy.and_(
Pierre-Yves Chibon 573e63
            model.User.user == username,
Pierre-Yves Chibon 573e63
            model.PagureUserGroup.user_id == model.User.id,
Pierre-Yves Chibon 573e63
            model.PagureUserGroup.group_id == model.PagureGroup.id,
Pierre-Yves Chibon 573e63
            model.PagureGroup.group_type == 'user',
Pierre-Yves Chibon 573e63
            model.PagureGroup.id == model.ProjectGroup.group_id,
Pierre-Yves Chibon 573e63
            model.Project.id == model.ProjectGroup.project_id,
Pierre-Yves Chibon 573e63
        )
Pierre-Yves Chibon 573e63
    )
Pierre-Yves Chibon 573e63
Pierre-Yves Chibon f9f132
    projects = projects.union(sub_q2).union(sub_q3).union(sub_q4)
Pierre-Yves Chibon 573e63
Pierre-Yves Chibon 573e63
    query = session.query(
Pierre-Yves Chibon 573e63
        model.PullRequest
Pierre-Yves Chibon 573e63
    ).filter(
Pierre-Yves Chibon 573e63
        model.PullRequest.project_id.in_(projects.subquery())
Pierre-Yves Chibon 573e63
    ).order_by(
Pierre-Yves Chibon 573e63
        model.PullRequest.date_created.desc()
Pierre-Yves Chibon 573e63
    )
Pierre-Yves Chibon 573e63
Pierre-Yves Chibon 573e63
    return query.all()
Gaurav Kumar 00f2c8
Pierre-Yves Chibon b13b92
Gaurav Kumar 00f2c8
def update_watch_status(session, project, user, watch):
Gaurav Kumar 00f2c8
    ''' Update the user status for watching a project.
Gaurav Kumar 00f2c8
    '''
Pierre-Yves Chibon 6aa385
    user_obj = get_user(session, user)
Gaurav Kumar 00f2c8
Gaurav Kumar 00f2c8
    if not user_obj:
Gaurav Kumar 00f2c8
        raise pagure.exceptions.PagureException(
Gaurav Kumar 00f2c8
            'No user with username: %s' % user)
Gaurav Kumar 00f2c8
Gaurav Kumar 00f2c8
    watcher = session.query(
Gaurav Kumar 00f2c8
        model.Watcher
Gaurav Kumar 00f2c8
    ).filter(
Gaurav Kumar 00f2c8
        sqlalchemy.and_(
Gaurav Kumar 00f2c8
            model.Watcher.project_id == project.id,
Gaurav Kumar 00f2c8
            model.Watcher.user_id == user_obj.id,
Gaurav Kumar 00f2c8
        )
Gaurav Kumar 00f2c8
    ).first()
Gaurav Kumar 00f2c8
Gaurav Kumar 00f2c8
    if not watcher:
Gaurav Kumar 00f2c8
        watcher = model.Watcher(
Gaurav Kumar 00f2c8
            project_id=project.id,
Gaurav Kumar 00f2c8
            user_id=user_obj.id,
Gaurav Kumar 00f2c8
            watch=watch
Gaurav Kumar 00f2c8
        )
Gaurav Kumar 00f2c8
    else:
Gaurav Kumar 00f2c8
        watcher.watch = watch
Gaurav Kumar 00f2c8
Gaurav Kumar 00f2c8
    session.add(watcher)
Gaurav Kumar 00f2c8
    session.flush()
Gaurav Kumar 00f2c8
Gaurav Kumar 6cf178
    msg_success = 'You are now watching this repo.'
Gaurav Kumar 00f2c8
    if not int(watch):
Gaurav Kumar 00f2c8
        msg_success = 'You are no longer watching this repo.'
Gaurav Kumar 00f2c8
    return msg_success
Gaurav Kumar 604af6
Pierre-Yves Chibon 784502
Pierre-Yves Chibon 3b50fe
def is_watching(session, user, reponame, repouser=None, namespace=None):
Gaurav Kumar 604af6
    ''' Check user watching the project. '''
Gaurav Kumar 604af6
Gaurav Kumar 4e29d1
    if user is None:
Gaurav Kumar 4e29d1
        return False
Gaurav Kumar 4e29d1
Pierre-Yves Chibon 784502
    user_obj = search_user(session, username=user.username)
Gaurav Kumar 604af6
    if not user_obj:
Pierre-Yves Chibon 784502
        return False
Gaurav Kumar 604af6
Pierre-Yves Chibon c8160d
    query = session.query(
Gaurav Kumar 604af6
        model.Watcher
Gaurav Kumar 604af6
    ).filter(
Pierre-Yves Chibon c8160d
        model.Watcher.user_id == user_obj.id
Pierre-Yves Chibon c8160d
    ).filter(
Pierre-Yves Chibon c8160d
        model.Watcher.project_id == model.Project.id
Pierre-Yves Chibon c8160d
    ).filter(
Pierre-Yves Chibon c8160d
        model.Project.name == reponame
Pierre-Yves Chibon c8160d
    )
Pierre-Yves Chibon c8160d
Pierre-Yves Chibon c8160d
    if repouser is not None:
Pierre-Yves Chibon c8160d
        query = query.filter(
Pierre-Yves Chibon c8160d
            model.User.user == repouser
Pierre-Yves Chibon c8160d
        ).filter(
Pierre-Yves Chibon c8160d
            model.User.id == model.Project.user_id
Pierre-Yves Chibon c8160d
        ).filter(
farhaanbukhsh 3e1439
            model.Project.is_fork == True
Gaurav Kumar 604af6
        )
Pierre-Yves Chibon c8160d
    else:
Pierre-Yves Chibon c8160d
        query = query.filter(
farhaanbukhsh 3e1439
            model.Project.is_fork == False
Pierre-Yves Chibon c8160d
        )
Pierre-Yves Chibon c8160d
Pierre-Yves Chibon 3b50fe
    if namespace is not None:
Pierre-Yves Chibon 3b50fe
        query = query.filter(
Pierre-Yves Chibon 3b50fe
            model.Project.namespace == namespace
Pierre-Yves Chibon 3b50fe
        )
Pierre-Yves Chibon 3b50fe
Pierre-Yves Chibon c8160d
    watcher = query.first()
Gaurav Kumar 604af6
Gaurav Kumar 604af6
    if watcher:
Gaurav Kumar 604af6
        return watcher.watch
Pierre-Yves Chibon b65564
Pierre-Yves Chibon 3b50fe
    project = pagure.lib.get_project(
Pierre-Yves Chibon 3b50fe
        session, reponame, user=repouser, namespace=namespace)
Pierre-Yves Chibon b65564
    if not project:
Pierre-Yves Chibon b65564
        return False
Pierre-Yves Chibon b65564
Pierre-Yves Chibon 784502
    if user.username == project.user.username:
Gaurav Kumar 604af6
        return True
Gaurav Kumar 604af6
Gaurav Kumar 604af6
    for group in project.groups:
Gaurav Kumar cece6f
        for guser in group.users:
Pierre-Yves Chibon 784502
            if user.username == guser.username:
Pierre-Yves Chibon cc69f7
                return True
Gaurav Kumar 604af6
Pierre-Yves Chibon cc69f7
    return False
Vivek Anand 272efb
Vivek Anand 272efb
Vivek Anand 272efb
def user_watch_list(session, user):
Vivek Anand 272efb
    ''' Returns list of all the projects which the user is watching '''
Vivek Anand 272efb
Vivek Anand 272efb
    user_obj = search_user(session, username=user)
Vivek Anand 272efb
    if not user_obj:
Vivek Anand 272efb
        return []
Vivek Anand 272efb
Vivek Anand 272efb
    unwatched = session.query(
Vivek Anand 272efb
        model.Watcher
Vivek Anand 272efb
    ).filter(
Vivek Anand 272efb
        model.Watcher.user_id == user_obj.id
Vivek Anand 272efb
    ).filter(
Vivek Anand 272efb
        model.Watcher.watch == False
Vivek Anand 272efb
    )
Vivek Anand 272efb
Vivek Anand 272efb
    unwatched_list = []
Vivek Anand 272efb
    if unwatched:
Vivek Anand 272efb
        unwatched_list = [unwatch.project for unwatch in unwatched.all()]
Vivek Anand 272efb
Vivek Anand 272efb
    watched = session.query(
Vivek Anand 272efb
        model.Watcher
Vivek Anand 272efb
    ).filter(
Vivek Anand 272efb
        model.Watcher.user_id == user_obj.id
Vivek Anand 272efb
    ).filter(
Vivek Anand 272efb
        model.Watcher.watch == True
Vivek Anand 272efb
    )
Vivek Anand 272efb
Vivek Anand 272efb
    watched_list = []
Vivek Anand 272efb
    if watched:
Vivek Anand 272efb
        watched_list = [watch.project for watch in watched.all()]
Vivek Anand 272efb
Vivek Anand 272efb
    user_projects = search_projects(session, username=user_obj.user)
Vivek Anand 272efb
    watch = set(watched_list + user_projects)
Vivek Anand 272efb
Vivek Anand 272efb
    for project in user_projects:
Vivek Anand 272efb
        if project in unwatched_list:
Vivek Anand 272efb
            watch.remove(project)
Vivek Anand 272efb
Vivek Anand 272efb
    return sorted(list(watch), key=lambda proj: proj.name)
Pierre-Yves Chibon cd6615
Pierre-Yves Chibon cd6615
Pierre-Yves Chibon cd6615
def save_report(session, repo, name, url, username):
Pierre-Yves Chibon cd6615
    """ Save the report of issues based on the given URL of the project.
Pierre-Yves Chibon cd6615
    """
Pierre-Yves Chibon cd6615
    url_obj = urlparse.urlparse(url)
Pierre-Yves Chibon cd6615
    url = url_obj.geturl().replace(url_obj.query, '')
Pierre-Yves Chibon cd6615
    query = dict(urlparse.parse_qsl(url_obj.query))
Pierre-Yves Chibon cd6615
    reports = repo.reports
Pierre-Yves Chibon cd6615
    reports[name] = query
Pierre-Yves Chibon cd6615
    repo.reports = reports
Pierre-Yves Chibon cd6615
    session.add(repo)
Pierre-Yves Chibon cdb5d4
Pierre-Yves Chibon cdb5d4
Pierre-Yves Chibon cdb5d4
def set_custom_key_fields(session, project, fields, types):
Pierre-Yves Chibon cdb5d4
    """ Set or update the custom key fields of a project with the values
Pierre-Yves Chibon cdb5d4
    provided.
Pierre-Yves Chibon cdb5d4
    """
Pierre-Yves Chibon cdb5d4
Pierre-Yves Chibon cdb5d4
    current_keys = {}
Pierre-Yves Chibon cdb5d4
    for key in project.issue_keys:
Pierre-Yves Chibon cdb5d4
        current_keys[key.name] = key
Pierre-Yves Chibon cdb5d4
Pierre-Yves Chibon cdb5d4
    for idx, key in enumerate(fields):
Pierre-Yves Chibon cdb5d4
        if key in current_keys:
Pierre-Yves Chibon cdb5d4
            issuekey = current_keys[key]
Pierre-Yves Chibon 1fb905
            issuekey.key_type = types[idx]
Pierre-Yves Chibon cdb5d4
        else:
Pierre-Yves Chibon cdb5d4
            issuekey = model.IssueKeys(
Pierre-Yves Chibon cdb5d4
                project_id=project.id,
Pierre-Yves Chibon cdb5d4
                name=key,
Pierre-Yves Chibon 1fb905
                key_type=types[idx],
Pierre-Yves Chibon cdb5d4
            )
Pierre-Yves Chibon cdb5d4
        session.add(issuekey)
Pierre-Yves Chibon cdb5d4
Pierre-Yves Chibon d89f6b
    # Delete keys
Pierre-Yves Chibon d89f6b
    for key in current_keys:
Pierre-Yves Chibon d89f6b
        if key not in fields:
Pierre-Yves Chibon d89f6b
            session.delete(current_keys[key])
Pierre-Yves Chibon d89f6b
Pierre-Yves Chibon cdb5d4
    return 'List of custom fields updated'
Pierre-Yves Chibon cdb5d4
Pierre-Yves Chibon cdb5d4
Pierre-Yves Chibon cdb5d4
def set_custom_key_value(session, issue, key, value):
Pierre-Yves Chibon cdb5d4
    """ Set or update the value of the specified custom key.
Pierre-Yves Chibon cdb5d4
    """
Pierre-Yves Chibon cdb5d4
Pierre-Yves Chibon cdb5d4
    query = session.query(
Pierre-Yves Chibon cdb5d4
        model.IssueValues
Pierre-Yves Chibon cdb5d4
    ).filter(
Pierre-Yves Chibon 4371c1
        model.IssueValues.key_id == key.id
Pierre-Yves Chibon cdb5d4
    ).filter(
Pierre-Yves Chibon cdb5d4
        model.IssueValues.issue_uid == issue.uid
Pierre-Yves Chibon cdb5d4
    )
Pierre-Yves Chibon cdb5d4
Pierre-Yves Chibon cdb5d4
    current_field = query.first()
Pierre-Yves Chibon cdb5d4
    if current_field:
Pierre-Yves Chibon cdb5d4
        current_field.value = value
Pierre-Yves Chibon cdb5d4
    else:
Pierre-Yves Chibon cdb5d4
        current_field = model.IssueValues(
Pierre-Yves Chibon cdb5d4
            issue_uid=issue.uid,
Pierre-Yves Chibon cdb5d4
            key_id=key.id,
Pierre-Yves Chibon cdb5d4
            value=value,
Pierre-Yves Chibon cdb5d4
        )
Pierre-Yves Chibon cdb5d4
    session.add(current_field)
Pierre-Yves Chibon cdb5d4
Pierre-Yves Chibon cdb5d4
    return 'Custom key adjusted'