#3958 Move the code in pagure/lib/init into pagure/lib/query and fix a circular import
Merged 7 years ago by pingou. Opened 7 years ago by pingou.

@@ -15,7 +15,7 @@ 

  from alembic import op

  import sqlalchemy as sa

  

- from pagure.lib import is_valid_ssh_key

+ from pagure.lib.query import is_valid_ssh_key

  

  

  def upgrade():

file modified
+25 -24
@@ -17,7 +17,8 @@ 

  

  import pagure

  import tests

- from pagure.lib import create_session

+ import pagure.lib.model

+ import pagure.lib.query

  from pagure.lib.login import generate_hashed_value

  from pagure.lib.model import create_default_status

  from pagure.lib.repo import PagureRepo
@@ -44,7 +45,7 @@ 

          acls=_config.get('ACLS', {}),

          debug=True)

  

-     engine = create_engine('%s' % DB_URL, echo=True)

+     engine = pagure.lib.query.create_engine('%s' % DB_URL, echo=True)

  

      metadata = MetaData(engine)

      metadata.reflect(bind=engine)
@@ -290,7 +291,7 @@ 

  

      ######################################

      # pagure_user_group

-     group = pagure.lib.search_groups(session, pattern=None,

+     group = pagure.lib.query.search_groups(session, pattern=None,

                                       group_name="rel-eng", group_type=None)

      item = pagure.lib.model.PagureUserGroup(

          user_id=pingou.id,
@@ -299,7 +300,7 @@ 

      session.add(item)

      session.commit()

  

-     group = pagure.lib.search_groups(session, pattern=None,

+     group = pagure.lib.query.search_groups(session, pattern=None,

                                       group_name="admin", group_type=None)

  

      item = pagure.lib.model.PagureUserGroup(
@@ -309,7 +310,7 @@ 

      session.add(item)

      session.commit()

  

-     group = pagure.lib.search_groups(session, pattern=None,

+     group = pagure.lib.query.search_groups(session, pattern=None,

                                       group_name="group", group_type=None)

  

      item = pagure.lib.model.PagureUserGroup(
@@ -321,9 +322,9 @@ 

  

      ######################################

      # projects_groups

-     group = pagure.lib.search_groups(session, pattern=None,

+     group = pagure.lib.query.search_groups(session, pattern=None,

                                       group_name="rel-eng", group_type=None)

-     repo = pagure.lib.get_authorized_project(session, 'test')

+     repo = pagure.lib.query.get_authorized_project(session, 'test')

      item = pagure.lib.model.ProjectGroup(

          project_id=repo.id,

          group_id=group.id,
@@ -332,9 +333,9 @@ 

      session.add(item)

      session.commit()

  

-     group = pagure.lib.search_groups(session, pattern=None,

+     group = pagure.lib.query.search_groups(session, pattern=None,

                                       group_name="admin", group_type=None)

-     repo = pagure.lib.get_authorized_project(session, 'test2')

+     repo = pagure.lib.query.get_authorized_project(session, 'test2')

      item = pagure.lib.model.ProjectGroup(

          project_id=repo.id,

          group_id=group.id,
@@ -345,9 +346,9 @@ 

  

      ######################################

      # pull_requests

-     repo = pagure.lib.get_authorized_project(session, 'test')

-     forked_repo = pagure.lib.get_authorized_project(session, 'test')

-     req = pagure.lib.new_pull_request(

+     repo = pagure.lib.query.get_authorized_project(session, 'test')

+     forked_repo = pagure.lib.query.get_authorized_project(session, 'test')

+     req = pagure.lib.query.new_pull_request(

          session=session,

          repo_from=forked_repo,

          branch_from='master',
@@ -364,7 +365,7 @@ 

  

      ######################################

      # user_projects

-     repo = pagure.lib.get_authorized_project(session, 'test')

+     repo = pagure.lib.query.get_authorized_project(session, 'test')

      item = pagure.lib.model.ProjectUser(

          project_id=repo.id,

          user_id=foo.id,
@@ -373,7 +374,7 @@ 

      session.add(item)

      session.commit()

  

-     repo = pagure.lib.get_authorized_project(session, 'test2')

+     repo = pagure.lib.query.get_authorized_project(session, 'test2')

      item = pagure.lib.model.ProjectUser(

          project_id=repo.id,

          user_id=you.id,
@@ -394,16 +395,16 @@ 

  

      ######################################

      # issue_to_issue

-     repo = pagure.lib.get_authorized_project(session, 'test')

-     all_issues = pagure.lib.search_issues(session, repo)

-     pagure.lib.add_issue_dependency(session, all_issues[0],

+     repo = pagure.lib.query.get_authorized_project(session, 'test')

+     all_issues = pagure.lib.query.search_issues(session, repo)

+     pagure.lib.query.add_issue_dependency(session, all_issues[0],

                                      all_issues[1], 'pingou')

  

      ######################################

      # pull_request_comments

-     user = pagure.lib.search_user(session, username='pingou')

+     user = pagure.lib.query.search_user(session, username='pingou')

      # only 1 pull request available atm

-     pr = pagure.lib.get_pull_request_of_user(session, "pingou")[0]

+     pr = pagure.lib.query.get_pull_request_of_user(session, "pingou")[0]

      item = pagure.lib.model.PullRequestComment(

          pull_request_uid=pr.uid,

          user_id=user.id,
@@ -416,7 +417,7 @@ 

      ######################################

      # pull_request_flags

      # only 1 pull request available atm

-     pr = pagure.lib.get_pull_request_of_user(session, "pingou")[0]

+     pr = pagure.lib.query.get_pull_request_of_user(session, "pingou")[0]

      item = pagure.lib.model.PullRequestFlag(

          uid="random_pr_flag_uid",

          pull_request_uid=pr.uid,
@@ -432,8 +433,8 @@ 

  

      ######################################

      # tags_issues

-     repo = pagure.lib.get_authorized_project(session, 'test')

-     issues = pagure.lib.search_issues(session, repo)

+     repo = pagure.lib.query.get_authorized_project(session, 'test')

+     issues = pagure.lib.query.search_issues(session, repo)

      item = pagure.lib.model.TagIssue(

          issue_uid=issues[0].uid,

          tag='tag1',
@@ -473,8 +474,8 @@ 

      except:

          print('requests folder already deleted')

  

-     repo = pagure.lib.get_authorized_project(session, 'test')

-     result = pagure.lib.fork_project(session, 'foo', repo)

+     repo = pagure.lib.query.get_authorized_project(session, 'test')

+     result = pagure.lib.query.fork_project(session, 'foo', repo)

      if result == 'Repo "test" cloned to "foo/test"':

          session.commit()

  

file modified
+3 -2
@@ -8,7 +8,8 @@ 

  from sqlalchemy.exc import SQLAlchemyError

  

  import pagure.config

- import pagure.lib

+ import pagure.lib.query

+ import pagure.lib.notify

  import pagure.lib.model as model

  

  if 'PAGURE_CONFIG' not in os.environ \
@@ -28,7 +29,7 @@ 

      email_dates = [email_day.date() for email_day in \

              [current_time + timedelta(days=i) for i in day_diff_for_mail]]

  

-     session = pagure.lib.create_session(_config['DB_URL'])

+     session = pagure.lib.query.create_session(_config['DB_URL'])

      tokens = session.query(model.Token).all()

  

      for token in tokens:

@@ -40,7 +40,7 @@ 

  

  

  import pagure  # noqa: E402

- import pagure.lib  # noqa: E402

+ import pagure.lib.query  # noqa: E402

  from pagure.exceptions import PagureEvException  # noqa: E402

  

  SERVER = None
@@ -55,7 +55,8 @@ 

      global SESSION

      if SESSION is None:

          print(pagure.config.config['DB_URL'])

-         SESSION = pagure.lib.create_session(pagure.config.config['DB_URL'])

+         SESSION = pagure.lib.query.create_session(

+             pagure.config.config['DB_URL'])

  

      return SESSION

  
@@ -69,7 +70,7 @@ 

          raise PagureEvException("No issue tracker found for this project")

  

      session = _get_session()

-     issue = pagure.lib.search_issues(session, repo, issueid=objid)

+     issue = pagure.lib.query.search_issues(session, repo, issueid=objid)

  

      if issue is None or issue.project != repo:

          raise PagureEvException("Issue '%s' not found" % objid)
@@ -91,7 +92,7 @@ 

              "No pull-request tracker found for this project")

  

      session = _get_session()

-     request = pagure.lib.search_pull_requests(

+     request = pagure.lib.query.search_pull_requests(

          session, project_id=repo.id, requestid=objid)

  

      if request is None or request.project != repo:
@@ -164,7 +165,7 @@ 

      """

      (username, namespace, reponame, objtype, objid) = _parse_path(path)

      session = _get_session()

-     repo = pagure.lib.get_authorized_project(

+     repo = pagure.lib.query.get_authorized_project(

              session, reponame, user=username, namespace=namespace)

  

      if repo is None:

@@ -22,7 +22,7 @@ 

  from Milter.utils import parse_addr

  

  import pagure.config

- import pagure.lib

+ import pagure.lib.query

  

  

  if 'PAGURE_CONFIG' not in os.environ \
@@ -157,9 +157,9 @@ 

          # they are trying to forge their ID into someone else's

          salt = _config.get('SALT_EMAIL')

          from_email = clean_item(msg['From'])

-         session = pagure.lib.create_session(_config['DB_URL'])

+         session = pagure.lib.query.create_session(_config['DB_URL'])

          try:

-             user = pagure.lib.get_user(session, from_email)

+             user = pagure.lib.query.get_user(session, from_email)

          except:

              self.log(

                  "Could not find an user in the DB associated with %s" %

file modified
+6 -6
@@ -30,7 +30,7 @@ 

  API = flask.Blueprint("api_ns", __name__, url_prefix="/api/0")

  

  

- import pagure.lib  # noqa: E402

+ import pagure.lib.query  # noqa: E402

  import pagure.lib.tasks  # noqa: E402

  from pagure.config import config as pagure_config  # noqa: E402

  from pagure.doc_utils import load_doc, modify_rst, modify_html  # noqa: E402
@@ -123,7 +123,7 @@ 

  

  def get_authorized_api_project(session, repo, user=None, namespace=None):

      """ Helper function to get an authorized_project with optional lock. """

-     repo = pagure.lib.get_authorized_project(

+     repo = pagure.lib.query.get_authorized_project(

          flask.g.session, repo, user=user, namespace=namespace

      )

      flask.g.repo = repo
@@ -153,7 +153,7 @@ 

  

      token_auth = False

      if token_str:

-         token = pagure.lib.get_api_token(flask.g.session, token_str)

+         token = pagure.lib.query.get_api_token(flask.g.session, token_str)

          if token and not token.expired:

              flask.g.authenticated = True

              if acls and set(token.acls_list).intersection(set(acls)):
@@ -389,7 +389,7 @@ 

      if pattern is not None and not pattern.endswith("*"):

          pattern += "*"

  

-     users = pagure.lib.search_user(flask.g.session, pattern=pattern)

+     users = pagure.lib.query.search_user(flask.g.session, pattern=pattern)

  

      return flask.jsonify(

          {
@@ -399,7 +399,7 @@ 

                  {

                      "username": usr.username,

                      "name": usr.fullname,

-                     "image": pagure.lib.avatar_url_from_email(

+                     "image": pagure.lib.query.avatar_url_from_email(

                          usr.default_email, size=16

                      ),

                  }
@@ -516,7 +516,7 @@ 

          jsonout.status_code = 404

          return jsonout

  

-     tags = pagure.lib.get_tags_of_project(

+     tags = pagure.lib.query.get_tags_of_project(

          flask.g.session, project_obj, pattern=pattern

      )

  

file modified
+2 -2
@@ -19,7 +19,7 @@ 

  

  import pagure

  import pagure.exceptions

- import pagure.lib

+ import pagure.lib.query

  import pagure.lib.lib_ci as lib_ci

  from pagure.api import API, APIERROR, api_method

  
@@ -59,7 +59,7 @@ 

  

      """

  

-     project = pagure.lib._get_project(

+     project = pagure.lib.query._get_project(

          flask.g.session, repo, user=username, namespace=namespace

      )

      flask.g.repo_locked = True

file modified
+22 -22
@@ -18,7 +18,7 @@ 

  

  import pagure

  import pagure.exceptions

- import pagure.lib

+ import pagure.lib.query

  import pagure.lib.tasks

  from pagure.api import (

      API,
@@ -165,7 +165,7 @@ 

      status_text = ("%s" % status).lower()

      requests = []

      if status_text in ["0", "false", "closed"]:

-         requests = pagure.lib.search_pull_requests(

+         requests = pagure.lib.query.search_pull_requests(

              flask.g.session,

              project_id=repo.id,

              status=False,
@@ -174,7 +174,7 @@ 

          )

  

      elif status_text == "all":

-         requests = pagure.lib.search_pull_requests(

+         requests = pagure.lib.query.search_pull_requests(

              flask.g.session,

              project_id=repo.id,

              status=None,
@@ -183,7 +183,7 @@ 

          )

  

      else:

-         requests = pagure.lib.search_pull_requests(

+         requests = pagure.lib.query.search_pull_requests(

              flask.g.session,

              project_id=repo.id,

              assignee=assignee,
@@ -194,7 +194,7 @@ 

      page = get_page()

      per_page = get_per_page()

  

-     pagination_metadata = pagure.lib.get_pagination_metadata(

+     pagination_metadata = pagure.lib.query.get_pagination_metadata(

          flask.request, page, per_page, len(requests)

      )

      start = (page - 1) * per_page
@@ -280,7 +280,7 @@ 

          }

  

      """

-     request = pagure.lib.get_request_by_uid(flask.g.session, uid)

+     request = pagure.lib.query.get_request_by_uid(flask.g.session, uid)

      if not request:

          raise pagure.exceptions.APIError(404, error_code=APIERROR.ENOREQ)

  
@@ -390,7 +390,7 @@ 

              404, error_code=APIERROR.EPULLREQUESTSDISABLED

          )

  

-     request = pagure.lib.search_pull_requests(

+     request = pagure.lib.query.search_pull_requests(

          flask.g.session, project_id=repo.id, requestid=requestid

      )

  
@@ -467,7 +467,7 @@ 

      if flask.g.token.project and repo != flask.g.token.project:

          raise pagure.exceptions.APIError(401, error_code=APIERROR.EINVALIDTOK)

  

-     request = pagure.lib.search_pull_requests(

+     request = pagure.lib.query.search_pull_requests(

          flask.g.session, project_id=repo.id, requestid=requestid

      )

  
@@ -562,7 +562,7 @@ 

      if repo != flask.g.token.project:

          raise pagure.exceptions.APIError(401, error_code=APIERROR.EINVALIDTOK)

  

-     request = pagure.lib.search_pull_requests(

+     request = pagure.lib.query.search_pull_requests(

          flask.g.session, project_id=repo.id, requestid=requestid

      )

  
@@ -573,7 +573,7 @@ 

          raise pagure.exceptions.APIError(403, error_code=APIERROR.ENOPRCLOSE)

  

      try:

-         pagure.lib.close_pull_request(

+         pagure.lib.query.close_pull_request(

              flask.g.session, request, flask.g.fas_user.username, merged=False

          )

          flask.g.session.commit()
@@ -674,7 +674,7 @@ 

      if flask.g.token.project and repo != flask.g.token.project:

          raise pagure.exceptions.APIError(401, error_code=APIERROR.EINVALIDTOK)

  

-     request = pagure.lib.search_pull_requests(

+     request = pagure.lib.query.search_pull_requests(

          flask.g.session, project_id=repo.id, requestid=requestid

      )

  
@@ -690,7 +690,7 @@ 

          row = form.row.data or None

          try:

              # New comment

-             message = pagure.lib.add_pull_request_comment(

+             message = pagure.lib.query.add_pull_request_comment(

                  flask.g.session,

                  request=request,

                  commit=commit,
@@ -863,7 +863,7 @@ 

      if flask.g.token.project and repo != flask.g.token.project:

          raise pagure.exceptions.APIError(401, error_code=APIERROR.EINVALIDTOK)

  

-     request = pagure.lib.search_pull_requests(

+     request = pagure.lib.query.search_pull_requests(

          flask.g.session, project_id=repo.id, requestid=requestid

      )

  
@@ -893,7 +893,7 @@ 

                  )

          try:

              # New Flag

-             message, uid = pagure.lib.add_pull_request_flag(

+             message, uid = pagure.lib.query.add_pull_request_flag(

                  flask.g.session,

                  request=request,

                  username=username,
@@ -906,7 +906,7 @@ 

                  token=flask.g.token.id,

              )

              flask.g.session.commit()

-             pr_flag = pagure.lib.get_pull_request_flag_by_uid(

+             pr_flag = pagure.lib.query.get_pull_request_flag_by_uid(

                  flask.g.session, request, uid

              )

              output["message"] = message
@@ -926,7 +926,7 @@ 

              400, error_code=APIERROR.EINVALIDREQ, errors=form.errors

          )

  

-     output["avatar_url"] = pagure.lib.avatar_url_from_email(

+     output["avatar_url"] = pagure.lib.query.avatar_url_from_email(

          flask.g.fas_user.default_email, size=30

      )

  
@@ -1016,7 +1016,7 @@ 

      ) or not authenticated():

          raise pagure.exceptions.APIError(401, error_code=APIERROR.EINVALIDTOK)

  

-     request = pagure.lib.search_pull_requests(

+     request = pagure.lib.query.search_pull_requests(

          flask.g.session, project_id=repo.id, requestid=requestid

      )

  
@@ -1028,7 +1028,7 @@ 

          status = is_true(form.status.data)

          try:

              # Toggle subscribtion

-             message = pagure.lib.set_watch_obj(

+             message = pagure.lib.query.set_watch_obj(

                  flask.g.session,

                  user=flask.g.fas_user.username,

                  obj=request,
@@ -1036,10 +1036,10 @@ 

              )

              flask.g.session.commit()

              output["message"] = message

-             user_obj = pagure.lib.get_user(

+             user_obj = pagure.lib.query.get_user(

                  flask.g.session, flask.g.fas_user.username

              )

-             output["avatar_url"] = pagure.lib.avatar_url_from_email(

+             output["avatar_url"] = pagure.lib.query.avatar_url_from_email(

                  user_obj.default_email, size=30

              )

              output["user"] = flask.g.fas_user.username
@@ -1229,7 +1229,7 @@ 

          commit_stop = diff_commits[0].oid.hex

          commit_start = diff_commits[-1].oid.hex

  

-     request = pagure.lib.new_pull_request(

+     request = pagure.lib.query.new_pull_request(

          flask.g.session,

          repo_to=parent,

          branch_to=branch_to,
@@ -1325,7 +1325,7 @@ 

              404, error_code=APIERROR.EPULLREQUESTSDISABLED

          )

  

-     request = pagure.lib.search_pull_requests(

+     request = pagure.lib.query.search_pull_requests(

          flask.g.session, project_id=repo.id, requestid=requestid

      )

  

file modified
+5 -5
@@ -15,7 +15,7 @@ 

  

  import pagure

  import pagure.exceptions

- import pagure.lib

+ import pagure.lib.query

  from pagure.api import (

      API,

      APIERROR,
@@ -87,16 +87,16 @@ 

  

      page = get_page()

      per_page = get_per_page()

-     group_cnt = pagure.lib.search_groups(

+     group_cnt = pagure.lib.query.search_groups(

          flask.g.session, pattern=pattern, count=True

      )

-     pagination_metadata = pagure.lib.get_pagination_metadata(

+     pagination_metadata = pagure.lib.query.get_pagination_metadata(

          flask.request, page, per_page, group_cnt

      )

      query_start = (page - 1) * per_page

      query_limit = per_page

  

-     groups = pagure.lib.search_groups(

+     groups = pagure.lib.query.search_groups(

          flask.g.session, pattern=pattern, limit=query_limit, offset=query_start

      )

  
@@ -222,7 +222,7 @@ 

      elif acl:

          acl = [acl]

  

-     group = pagure.lib.search_groups(flask.g.session, group_name=group)

+     group = pagure.lib.query.search_groups(flask.g.session, group_name=group)

      if not group:

          raise pagure.exceptions.APIError(404, error_code=APIERROR.ENOGROUP)

  

file modified
+29 -27
@@ -18,7 +18,7 @@ 

  from sqlalchemy.exc import SQLAlchemyError

  

  import pagure.exceptions

- import pagure.lib

+ import pagure.lib.query

  from pagure.api import (

      API,

      api_method,
@@ -107,7 +107,7 @@ 

      :raises pagure.exceptions.APIError: when issues doesn't exists

      :return: issue

      """

-     issue = pagure.lib.search_issues(

+     issue = pagure.lib.query.search_issues(

          flask.g.session, repo, issueid=issueid, issueuid=issueuid

      )

  
@@ -275,7 +275,9 @@ 

      _check_issue_tracker(repo)

      _check_token(repo, project_token=False)

  

-     user_obj = pagure.lib.get_user(flask.g.session, flask.g.fas_user.username)

+     user_obj = pagure.lib.query.get_user(

+         flask.g.session, flask.g.fas_user.username

+     )

      if not user_obj:

          raise pagure.exceptions.APIError(404, error_code=APIERROR.ENOUSER)

  
@@ -298,7 +300,7 @@ 

          ]

  

          try:

-             issue = pagure.lib.new_issue(

+             issue = pagure.lib.query.new_issue(

                  flask.g.session,

                  repo=repo,

                  title=title,
@@ -314,7 +316,7 @@ 

              # If there is a file attached, attach it.

              filestream = flask.request.files.get("filestream")

              if filestream and "<!!image>" in issue.content:

-                 new_filename = pagure.lib.add_attachment(

+                 new_filename = pagure.lib.query.add_attachment(

                      repo=repo,

                      issue=issue,

                      attachmentfolder=pagure_config["ATTACHMENTS_FOLDER"],
@@ -588,8 +590,8 @@ 

      page = get_page()

      per_page = get_per_page()

      params["count"] = True

-     issue_cnt = pagure.lib.search_issues(**params)

-     pagination_metadata = pagure.lib.get_pagination_metadata(

+     issue_cnt = pagure.lib.query.search_issues(**params)

+     pagination_metadata = pagure.lib.query.get_pagination_metadata(

          flask.request, page, per_page, issue_cnt

      )

      query_start = (page - 1) * per_page
@@ -598,7 +600,7 @@ 

      params["count"] = False

      params["limit"] = query_limit

      params["offset"] = query_start

-     issues = pagure.lib.search_issues(**params)

+     issues = pagure.lib.query.search_issues(**params)

  

      jsonout = flask.jsonify(

          {
@@ -754,14 +756,14 @@ 

      issue = _get_issue(repo, issue_id, issueuid=issue_uid)

      _check_private_issue_access(issue)

  

-     comment = pagure.lib.get_issue_comment(

+     comment = pagure.lib.query.get_issue_comment(

          flask.g.session, issue.uid, commentid

      )

      if not comment:

          raise pagure.exceptions.APIError(404, error_code=APIERROR.ENOCOMMENT)

  

      output = comment.to_json(public=True)

-     output["avatar_url"] = pagure.lib.avatar_url_from_email(

+     output["avatar_url"] = pagure.lib.query.avatar_url_from_email(

          comment.user.default_email, size=16

      )

      output["comment_date"] = comment.date_created.strftime("%Y-%m-%d %H:%M:%S")
@@ -830,7 +832,7 @@ 

      open_access = repo.settings.get("open_metadata_access_to_all", False)

      _check_ticket_access(issue, assignee=True, open_access=open_access)

  

-     status = pagure.lib.get_issue_statuses(flask.g.session)

+     status = pagure.lib.query.get_issue_statuses(flask.g.session)

      form = pagure.forms.StatusForm(

          status=status, close_status=repo.close_status, csrf_enabled=False

      )
@@ -847,7 +849,7 @@ 

      if form.validate_on_submit():

          try:

              # Update status

-             message = pagure.lib.edit_issue(

+             message = pagure.lib.query.edit_issue(

                  flask.g.session,

                  issue=issue,

                  status=new_status,
@@ -861,7 +863,7 @@ 

                  output["message"] = "No changes"

  

              if message:

-                 pagure.lib.add_metadata_update_notif(

+                 pagure.lib.query.add_metadata_update_notif(

                      session=flask.g.session,

                      obj=issue,

                      messages=message,
@@ -953,7 +955,7 @@ 

          new_milestone = form.milestone.data or None

          try:

              # Update status

-             message = pagure.lib.edit_issue(

+             message = pagure.lib.query.edit_issue(

                  flask.g.session,

                  issue=issue,

                  milestone=new_milestone,
@@ -966,7 +968,7 @@ 

                  output["message"] = "No changes"

  

              if message:

-                 pagure.lib.add_metadata_update_notif(

+                 pagure.lib.query.add_metadata_update_notif(

                      session=flask.g.session,

                      obj=issue,

                      messages=message,
@@ -1049,7 +1051,7 @@ 

          comment = form.comment.data

          try:

              # New comment

-             message = pagure.lib.add_issue_comment(

+             message = pagure.lib.query.add_issue_comment(

                  flask.g.session,

                  issue=issue,

                  comment=comment,
@@ -1067,7 +1069,7 @@ 

              400, error_code=APIERROR.EINVALIDREQ, errors=form.errors

          )

  

-     output["avatar_url"] = pagure.lib.avatar_url_from_email(

+     output["avatar_url"] = pagure.lib.query.avatar_url_from_email(

          flask.g.fas_user.default_email, size=30

      )

  
@@ -1139,7 +1141,7 @@ 

          # Create our metadata comment object

          try:

              # New comment

-             message = pagure.lib.add_issue_assignee(

+             message = pagure.lib.query.add_issue_assignee(

                  flask.g.session,

                  issue=issue,

                  assignee=assignee,
@@ -1147,7 +1149,7 @@ 

              )

              flask.g.session.commit()

              if message:

-                 pagure.lib.add_metadata_update_notif(

+                 pagure.lib.query.add_metadata_update_notif(

                      session=flask.g.session,

                      obj=issue,

                      messages=message,
@@ -1236,7 +1238,7 @@ 

          status = is_true(form.status.data)

          try:

              # Toggle subscribtion

-             message = pagure.lib.set_watch_obj(

+             message = pagure.lib.query.set_watch_obj(

                  flask.g.session,

                  user=flask.g.fas_user.username,

                  obj=issue,
@@ -1244,10 +1246,10 @@ 

              )

              flask.g.session.commit()

              output["message"] = message

-             user_obj = pagure.lib.get_user(

+             user_obj = pagure.lib.query.get_user(

                  flask.g.session, flask.g.fas_user.username

              )

-             output["avatar_url"] = pagure.lib.avatar_url_from_email(

+             output["avatar_url"] = pagure.lib.query.avatar_url_from_email(

                  user_obj.default_email, size=30

              )

              output["user"] = flask.g.fas_user.username
@@ -1332,14 +1334,14 @@ 

      if value:

          _check_link_custom_field(key, value)

      try:

-         message = pagure.lib.set_custom_key_value(

+         message = pagure.lib.query.set_custom_key_value(

              flask.g.session, issue, key, value

          )

  

          flask.g.session.commit()

          if message:

              output["message"] = message

-             pagure.lib.add_metadata_update_notif(

+             pagure.lib.query.add_metadata_update_notif(

                  session=flask.g.session,

                  obj=issue,

                  messages=message,
@@ -1456,14 +1458,14 @@ 

          if value:

              _check_link_custom_field(key, value)

          try:

-             message = pagure.lib.set_custom_key_value(

+             message = pagure.lib.query.set_custom_key_value(

                  flask.g.session, issue, key, value

              )

  

              flask.g.session.commit()

              if message:

                  output["messages"].append({key.name: message})

-                 pagure.lib.add_metadata_update_notif(

+                 pagure.lib.query.add_metadata_update_notif(

                      session=flask.g.session,

                      obj=issue,

                      messages=message,
@@ -1527,6 +1529,6 @@ 

      repo = _get_repo(repo, username, namespace)

      _check_issue_tracker(repo)

  

-     stats = pagure.lib.issues_history_stats(flask.g.session, repo)

+     stats = pagure.lib.query.issues_history_stats(flask.g.session, repo)

      jsonout = flask.jsonify({"stats": stats})

      return jsonout

file modified
+32 -26
@@ -20,8 +20,8 @@ 

  import pagure

  import pagure.forms

  import pagure.exceptions

- import pagure.lib

  import pagure.lib.git

+ import pagure.lib.query

  import pagure.utils

  from pagure.api import (

      API,
@@ -158,7 +158,7 @@ 

  

      watching_users_to_watch_level = {}

      for implicit_watch_user in implicit_watch_users:

-         user_watch_level = pagure.lib.get_watch_level_on_repo(

+         user_watch_level = pagure.lib.query.get_watch_level_on_repo(

              flask.g.session, implicit_watch_user, repo

          )

          watching_users_to_watch_level[implicit_watch_user] = user_watch_level
@@ -170,9 +170,9 @@ 

          for group_name in group_names:

              if group_name not in watching_users_to_watch_level:

                  watching_users_to_watch_level[group_name] = set()

-             # By the logic in pagure.lib.get_watch_level_on_repo, group members

-             # only by default watch issues.  If they want to watch commits they

-             # have to explicitly subscribe.

+             # By the logic in pagure.lib.query.get_watch_level_on_repo, group

+             # members only by default watch issues.  If they want to watch

+             # commits they have to explicitly subscribe.

              watching_users_to_watch_level[group_name].add("issues")

  

      for key in watching_users_to_watch_level:
@@ -185,7 +185,7 @@ 

          if watcher.watch_issues or watcher.watch_commits:

              watching_users_to_watch_level[

                  watcher.user.username

-             ] = pagure.lib.get_watch_level_on_repo(

+             ] = pagure.lib.query.get_watch_level_on_repo(

                  flask.g.session, watcher.user.username, repo

              )

          else:
@@ -476,7 +476,7 @@ 

      if pagure.utils.authenticated() and username == flask.g.fas_user.username:

          private = flask.g.fas_user.username

  

-     project_count = pagure.lib.search_projects(

+     project_count = pagure.lib.query.search_projects(

          flask.g.session,

          username=username,

          fork=fork,
@@ -491,13 +491,13 @@ 

      # Pagination code inspired by Flask-SQLAlchemy

      page = get_page()

      per_page = get_per_page()

-     pagination_metadata = pagure.lib.get_pagination_metadata(

+     pagination_metadata = pagure.lib.query.get_pagination_metadata(

          flask.request, page, per_page, project_count

      )

      query_start = (page - 1) * per_page

      query_limit = per_page

  

-     projects = pagure.lib.search_projects(

+     projects = pagure.lib.query.search_projects(

          flask.g.session,

          username=username,

          fork=fork,
@@ -741,7 +741,7 @@ 

          }

  

      """  # noqa

-     user = pagure.lib.search_user(

+     user = pagure.lib.query.search_user(

          flask.g.session, username=flask.g.fas_user.username

      )

      output = {}
@@ -780,7 +780,7 @@ 

              ignore_existing_repos = False

  

          try:

-             task = pagure.lib.new_project(

+             task = pagure.lib.query.new_project(

                  flask.g.session,

                  name=name,

                  namespace=namespace,
@@ -805,7 +805,7 @@ 

  

              if get_request_data().get("wait", True):

                  result = task.get()

-                 project = pagure.lib._get_project(

+                 project = pagure.lib.query._get_project(

                      flask.g.session,

                      name=result["repo"],

                      namespace=result["namespace"],
@@ -956,16 +956,18 @@ 

              return flask.jsonify(project.to_json(public=False, api=True))

  

          try:

-             new_main_admin = pagure.lib.get_user(

+             new_main_admin = pagure.lib.query.get_user(

                  flask.g.session, args["main_admin"]

              )

          except pagure.exceptions.PagureException:

              raise pagure.exceptions.APIError(400, error_code=APIERROR.ENOUSER)

  

          old_main_admin = project.user.user

-         pagure.lib.set_project_owner(flask.g.session, project, new_main_admin)

+         pagure.lib.query.set_project_owner(

+             flask.g.session, project, new_main_admin

+         )

          if retain_access and flask.g.fas_user.username == old_main_admin:

-             pagure.lib.add_user_to_project(

+             pagure.lib.query.add_user_to_project(

                  flask.g.session,

                  project,

                  new_user=flask.g.fas_user.username,
@@ -1057,7 +1059,7 @@ 

              )

  

          try:

-             task = pagure.lib.fork_project(

+             task = pagure.lib.query.fork_project(

                  flask.g.session, user=flask.g.fas_user.username, repo=repo

              )

              flask.g.session.commit()
@@ -1347,7 +1349,9 @@ 

      except ValueError:

          raise pagure.exceptions.APIError(404, error_code=APIERROR.ENOCOMMIT)

  

-     flags = pagure.lib.get_commit_flag(flask.g.session, repo, commit_hash)

+     flags = pagure.lib.query.get_commit_flag(

+         flask.g.session, repo, commit_hash

+     )

      flags = [f.to_json(public=True) for f in flags]

      return flask.jsonify({"total_flags": len(flags), "flags": flags})

  
@@ -1496,7 +1500,7 @@ 

          status = form.status.data.strip()

          try:

              # New Flag

-             message, uid = pagure.lib.add_commit_flag(

+             message, uid = pagure.lib.query.add_commit_flag(

                  session=flask.g.session,

                  repo=repo,

                  commit_hash=commit_hash,
@@ -1510,7 +1514,7 @@ 

                  token=flask.g.token.id,

              )

              flask.g.session.commit()

-             c_flag = pagure.lib.get_commit_flag_by_uid(

+             c_flag = pagure.lib.query.get_commit_flag_by_uid(

                  flask.g.session, commit_hash, uid

              )

              output["message"] = message
@@ -1636,7 +1640,7 @@ 

          )

  

      try:

-         pagure.lib.get_user(flask.g.session, watcher)

+         pagure.lib.query.get_user(flask.g.session, watcher)

      except pagure.exceptions.PagureException:

          _log.debug(

              "api_update_project_watchers: Invalid user watching: %s", watcher
@@ -1646,7 +1650,7 @@ 

      watch_status = data.get("status")

  

      try:

-         msg = pagure.lib.update_watch_status(

+         msg = pagure.lib.query.update_watch_status(

              session=flask.g.session,

              project=project,

              user=watcher,
@@ -1807,14 +1811,16 @@ 

              )

  

          if user:

-             user_obj = pagure.lib.search_user(flask.g.session, username=user)

+             user_obj = pagure.lib.query.search_user(

+                 flask.g.session, username=user

+             )

              if not user_obj:

                  raise pagure.exceptions.APIError(

                      404, error_code=APIERROR.ENOUSER

                  )

  

          elif group:

-             group_obj = pagure.lib.search_groups(

+             group_obj = pagure.lib.query.search_groups(

                  flask.g.session, group_name=group

              )

              if not group_obj:
@@ -1831,7 +1837,7 @@ 

                  _log.info(

                      "Adding user %s to project: %s", user, project.fullname

                  )

-                 pagure.lib.add_user_to_project(

+                 pagure.lib.query.add_user_to_project(

                      session=flask.g.session,

                      project=project,

                      new_user=user,
@@ -1842,7 +1848,7 @@ 

                  _log.info(

                      "Adding group %s to project: %s", group, project.fullname

                  )

-                 pagure.lib.add_group_to_project(

+                 pagure.lib.query.add_group_to_project(

                      session=flask.g.session,

                      project=project,

                      new_group=group,
@@ -1859,7 +1865,7 @@ 

                      project.fullname,

                  )

                  try:

-                     pagure.lib.remove_user_of_project(

+                     pagure.lib.query.remove_user_of_project(

                          flask.g.session,

                          user_obj,

                          project,

file modified
+25 -25
@@ -19,7 +19,7 @@ 

  

  import pagure

  import pagure.exceptions

- import pagure.lib

+ import pagure.lib.query

  from pagure.api import API, api_method, APIERROR, get_page, get_per_page

  from pagure.utils import is_true

  
@@ -28,7 +28,7 @@ 

      """ Check user is valid or not

      """

      try:

-         return pagure.lib.get_user(flask.g.session, username)

+         return pagure.lib.query.get_user(flask.g.session, username)

      except pagure.exceptions.PagureException:

          raise pagure.exceptions.APIError(404, error_code=APIERROR.ENOUSER)

  
@@ -135,17 +135,17 @@ 

      except ValueError:

          forkpage = 1

  

-     repos_cnt = pagure.lib.search_projects(

+     repos_cnt = pagure.lib.query.search_projects(

          flask.g.session, username=username, fork=False, count=True

      )

  

-     pagination_metadata_repo = pagure.lib.get_pagination_metadata(

+     pagination_metadata_repo = pagure.lib.query.get_pagination_metadata(

          flask.request, repopage, per_page, repos_cnt, key_page="repopage"

      )

      repopage_start = (repopage - 1) * per_page

      repopage_limit = per_page

  

-     repos = pagure.lib.search_projects(

+     repos = pagure.lib.query.search_projects(

          flask.g.session,

          username=username,

          fork=False,
@@ -153,17 +153,17 @@ 

          limit=repopage_limit,

      )

  

-     forks_cnt = pagure.lib.search_projects(

+     forks_cnt = pagure.lib.query.search_projects(

          flask.g.session, username=username, fork=True, count=True

      )

  

-     pagination_metadata_fork = pagure.lib.get_pagination_metadata(

+     pagination_metadata_fork = pagure.lib.query.get_pagination_metadata(

          flask.request, forkpage, per_page, forks_cnt, key_page="forkpage"

      )

      forkpage_start = (forkpage - 1) * per_page

      forkpage_limit = per_page

  

-     forks = pagure.lib.search_projects(

+     forks = pagure.lib.query.search_projects(

          flask.g.session,

          username=username,

          fork=True,
@@ -436,10 +436,10 @@ 

          # Issues authored by this user

          params_created = params.copy()

          params_created.update({"author": username})

-         issues_created = pagure.lib.search_issues(**params_created)

+         issues_created = pagure.lib.query.search_issues(**params_created)

          params_created.update({"offset": None, "limit": None, "count": True})

-         issues_created_cnt = pagure.lib.search_issues(**params_created)

-         pagination_issues_created = pagure.lib.get_pagination_metadata(

+         issues_created_cnt = pagure.lib.query.search_issues(**params_created)

+         pagination_issues_created = pagure.lib.query.get_pagination_metadata(

              flask.request, page, per_page, issues_created_cnt

          )

  
@@ -451,10 +451,10 @@ 

          # Issues assigned to this user

          params_assigned = params.copy()

          params_assigned.update({"assignee": username})

-         issues_assigned = pagure.lib.search_issues(**params_assigned)

+         issues_assigned = pagure.lib.query.search_issues(**params_assigned)

          params_assigned.update({"offset": None, "limit": None, "count": True})

-         issues_assigned_cnt = pagure.lib.search_issues(**params_assigned)

-         pagination_issues_assigned = pagure.lib.get_pagination_metadata(

+         issues_assigned_cnt = pagure.lib.query.search_issues(**params_assigned)

+         pagination_issues_assigned = pagure.lib.query.get_pagination_metadata(

              flask.request, page, per_page, issues_assigned_cnt

          )

  
@@ -572,7 +572,7 @@ 

  

      user = _get_user(username=username)

  

-     stats = pagure.lib.get_yearly_stats_user(

+     stats = pagure.lib.query.get_yearly_stats_user(

          flask.g.session,

          user,

          datetime.datetime.utcnow().date() + datetime.timedelta(days=1),
@@ -689,7 +689,7 @@ 

  

      user = _get_user(username=username)

  

-     activities = pagure.lib.get_user_activity_day(

+     activities = pagure.lib.query.get_user_activity_day(

          flask.g.session, user, date, tz=tz

      )

      js_act = []
@@ -704,13 +704,13 @@ 

          for project in commits:

              if len(commits[project]) == 1:

                  tmp = dict(

-                     description_mk=pagure.lib.text2markdown(

+                     description_mk=pagure.lib.query.text2markdown(

                          six.text_type(commits[project][0])

                      )

                  )

              else:

                  tmp = dict(

-                     description_mk=pagure.lib.text2markdown(

+                     description_mk=pagure.lib.query.text2markdown(

                          "@%s pushed %s commits to %s"

                          % (username, len(commits[project]), project)

                      )
@@ -720,7 +720,7 @@ 

  

      for act in activities:

          activity = act.to_json(public=True)

-         activity["description_mk"] = pagure.lib.text2markdown(

+         activity["description_mk"] = pagure.lib.query.text2markdown(

              six.text_type(act)

          )

          js_act.append(activity)
@@ -937,14 +937,14 @@ 

      else:

          status = status.capitalize()

  

-     pullrequests_cnt = pagure.lib.get_pull_request_of_user(

+     pullrequests_cnt = pagure.lib.query.get_pull_request_of_user(

          flask.g.session, username=username, status=status, count=True

      )

-     pagination = pagure.lib.get_pagination_metadata(

+     pagination = pagure.lib.query.get_pagination_metadata(

          flask.request, page, per_page, pullrequests_cnt

      )

  

-     pullrequests = pagure.lib.get_pull_request_of_user(

+     pullrequests = pagure.lib.query.get_pull_request_of_user(

          flask.g.session,

          username=username,

          status=status,
@@ -1175,14 +1175,14 @@ 

      else:

          status = status.capitalize()

  

-     pullrequests_cnt = pagure.lib.get_pull_request_of_user(

+     pullrequests_cnt = pagure.lib.query.get_pull_request_of_user(

          flask.g.session, username=username, status=status, count=True

      )

-     pagination = pagure.lib.get_pagination_metadata(

+     pagination = pagure.lib.query.get_pagination_metadata(

          flask.request, page, per_page, pullrequests_cnt

      )

  

-     pullrequests = pagure.lib.get_pull_request_of_user(

+     pullrequests = pagure.lib.query.get_pull_request_of_user(

          flask.g.session,

          username=username,

          status=status,

file modified
+26 -22
@@ -29,14 +29,14 @@ 

  

  import pagure.config  # noqa: E402

  import pagure.exceptions  # noqa: E402

- import pagure.lib  # noqa: E402

  import pagure.lib.git  # noqa: E402

  import pagure.lib.tasks  # noqa: E402

+ import pagure.lib.query  # noqa: E402

  from pagure.flask_app import generate_user_key_files  # noqa: E402

  

  

  _config = pagure.config.reload_config()

- session = pagure.lib.create_session(_config["DB_URL"])

+ session = pagure.lib.query.create_session(_config["DB_URL"])

  _log = logging.getLogger(__name__)

  

  
@@ -469,7 +469,7 @@ 

      else:

          name = arg_project

  

-     return pagure.lib._get_project(

+     return pagure.lib.query._get_project(

          session, namespace=namespace, name=name, user=user

      )

  
@@ -508,7 +508,9 @@ 

  

      group_obj = None

      if args.group:

-         group_obj = pagure.lib.search_groups(session, group_name=args.group)

+         group_obj = pagure.lib.query.search_groups(

+             session, group_name=args.group

+         )

      _log.debug(

          "Calling helper: %s with arg: project=%s, group=%s",

          helper,
@@ -557,7 +559,7 @@ 

          "instance. You should only ever run this for a security issue"

      )

      if _ask_confirmation():

-         pagure.lib.generate_hook_token(session)

+         pagure.lib.query.generate_hook_token(session)

          print("Hook token all re-generated")

  

  
@@ -576,7 +578,7 @@ 

      acls = pagure.config.config["ADMIN_API_ACLS"]

      if args.all:

          acls = None

-     tokens = pagure.lib.search_token(

+     tokens = pagure.lib.query.search_token(

          session, acls, user=args.user, active=args.active, expired=args.expired

      )

  
@@ -594,7 +596,7 @@ 

      """

      _log.debug("token:          %s", args.token)

  

-     token = pagure.lib.search_token(session, acls=None, token=args.token)

+     token = pagure.lib.query.search_token(session, acls=None, token=args.token)

      if not token:

          raise pagure.exceptions.PagureException("No such admin token found")

  
@@ -613,7 +615,7 @@ 

      _log.debug("token:          %s", args.token)

  

      acls = pagure.config.config["ADMIN_API_ACLS"]

-     token = pagure.lib.search_token(session, acls, token=args.token)

+     token = pagure.lib.query.search_token(session, acls, token=args.token)

      if not token:

          raise pagure.exceptions.PagureException("No such admin token found")

  
@@ -640,7 +642,7 @@ 

      _log.debug("new date:       %s", args.date)

  

      acls = pagure.config.config["ADMIN_API_ACLS"]

-     token = pagure.lib.search_token(session, acls, token=args.token)

+     token = pagure.lib.query.search_token(session, acls, token=args.token)

      if not token:

          raise pagure.exceptions.PagureException("No such admin token found")

  
@@ -683,7 +685,7 @@ 

      """

      _log.debug("user:          %s", args.user)

      # Validate user first

-     pagure.lib.get_user(session, args.user)

+     pagure.lib.query.get_user(session, args.user)

  

      acls_list = pagure.config.config["ADMIN_API_ACLS"]

      for idx, acl in enumerate(acls_list):
@@ -700,7 +702,9 @@ 

  

      print("Do you want to create this API token?")

      if _ask_confirmation():

-         print(pagure.lib.add_token_to_user(session, None, acls, args.user))

+         print(

+             pagure.lib.query.add_token_to_user(session, None, acls, args.user)

+         )

  

  

  def do_get_watch_status(args):
@@ -712,7 +716,7 @@ 

      _log.debug("user:          %s", args.user)

      _log.debug("project:       %s", args.project)

      # Validate user

-     pagure.lib.get_user(session, args.user)

+     pagure.lib.query.get_user(session, args.user)

  

      # Get the project

      project = _get_project(args.project)
@@ -723,7 +727,7 @@ 

          )

  

      level = (

-         pagure.lib.get_watch_level_on_repo(

+         pagure.lib.query.get_watch_level_on_repo(

              session=session,

              user=args.user,

              repo=project.name,
@@ -755,7 +759,7 @@ 

      _log.debug("project:       %s", args.project)

  

      # Validate user

-     pagure.lib.get_user(session, args.user)

+     pagure.lib.query.get_user(session, args.user)

  

      # Ask the status if none were given

      if args.status is None:
@@ -784,7 +788,7 @@ 

          % (args.user, args.status, WATCH[args.status], args.project)

      )

  

-     pagure.lib.update_watch_status(

+     pagure.lib.query.update_watch_status(

          session=session, project=project, user=args.user, watch=args.status

      )

      session.commit()
@@ -802,7 +806,7 @@ 

      _log.debug("read-only:     %s", args.ro)

  

      # Validate user

-     pagure.lib.get_user(session, args.user)

+     pagure.lib.query.get_user(session, args.user)

  

      # Get the project

      project = _get_project(args.project, user=args.user)
@@ -825,7 +829,7 @@ 

              % (project.fullname, project.read_only)

          )

      else:

-         pagure.lib.update_read_only_mode(

+         pagure.lib.query.update_read_only_mode(

              session, project, read_only=(args.ro.lower() == "true")

          )

          session.commit()
@@ -848,7 +852,7 @@ 

      _log.debug("username:           %s", args.username)

  

      # Validate user

-     pagure.lib.get_user(session, args.username)

+     pagure.lib.query.get_user(session, args.username)

  

      if not args.username:

          raise pagure.exceptions.PagureException(
@@ -865,7 +869,7 @@ 

          if not _ask_confirmation():

              return

  

-     msg = pagure.lib.add_group(

+     msg = pagure.lib.query.add_group(

          session=session,

          group_name=args.group_name,

          display_name=args.display,
@@ -887,7 +891,7 @@ 

  

      """

  

-     msg = pagure.lib.search_groups(session=session)

+     msg = pagure.lib.query.search_groups(session=session)

      if msg:

          print("List of groups on this Pagure instance:")

          for group in msg:
@@ -922,7 +926,7 @@ 

          )

  

      # Validate user

-     user = pagure.lib.get_user(session, args.username)

+     user = pagure.lib.query.get_user(session, args.username)

  

      print(

          "The user `%s` will be blocked from all interaction with this "
@@ -1017,7 +1021,7 @@ 

  

          global session, _config

          _config = pagure.config.reload_config()

-         session = pagure.lib.create_session(_config["DB_URL"])

+         session = pagure.lib.query.create_session(_config["DB_URL"])

  

      logging.basicConfig()

      if args.debug:

file modified
+2 -2
@@ -20,7 +20,7 @@ 

  import textwrap

  

  from pagure.config import config as pagure_config

- import pagure.lib

+ import pagure.lib.query

  import pagure.lib.encoding_utils

  

  
@@ -106,7 +106,7 @@ 

          safe = True

          output = convert_doc(output, view_file_url)

      elif ext and ext in [".mk", ".md", ".markdown"]:

-         output = pagure.lib.text2markdown(output, readme=True)

+         output = pagure.lib.query.text2markdown(output, readme=True)

          safe = True

      elif not ext or (ext and ext in [".text", ".txt"]):

          safe = True

file modified
+3 -3
@@ -21,7 +21,7 @@ 

  import pagure.config

  import pagure.doc_utils

  import pagure.exceptions

- import pagure.lib

+ import pagure.lib.query

  import pagure.lib.mimetype

  import pagure.forms

  
@@ -31,7 +31,7 @@ 

  # set up FAS

  APP.config = pagure.config.reload_config()

  

- SESSION = pagure.lib.create_session(APP.config["DB_URL"])

+ SESSION = pagure.lib.query.create_session(APP.config["DB_URL"])

  

  if not APP.debug:

      APP.logger.addHandler(
@@ -153,7 +153,7 @@ 

      if "." in repo:

          namespace, repo = repo.split(".", 1)

  

-     repo = pagure.lib.get_authorized_project(

+     repo = pagure.lib.query.get_authorized_project(

          SESSION, repo, user=username, namespace=namespace

      )

  

file modified
+12 -12
@@ -22,8 +22,8 @@ 

  import pagure.doc_utils

  import pagure.exceptions

  import pagure.forms

- import pagure.lib

  import pagure.lib.git

+ import pagure.lib.query

  import pagure.login_forms

  import pagure.mail_logging

  import pagure.proxy
@@ -45,7 +45,7 @@ 

      or pagure_config["WEBHOOK"]

      or pagure_config.get("PAGURE_CI_SERVICES")

  ):

-     pagure.lib.set_redis(

+     pagure.lib.query.set_redis(

          host=pagure_config["REDIS_HOST"],

          port=pagure_config["REDIS_PORT"],

          dbname=pagure_config["REDIS_DB"],
@@ -53,7 +53,7 @@ 

  

  

  if pagure_config.get("PAGURE_CI_SERVICES"):

-     pagure.lib.set_pagure_ci(pagure_config["PAGURE_CI_SERVICES"])

+     pagure.lib.query.set_pagure_ci(pagure_config["PAGURE_CI_SERVICES"])

  

  

  def create_app(config=None):
@@ -173,9 +173,9 @@ 

      """

      gitolite_home = pagure_config.get("GITOLITE_HOME", None)

      if gitolite_home:

-         users = pagure.lib.search_user(flask.g.session)

+         users = pagure.lib.query.search_user(flask.g.session)

          for user in users:

-             pagure.lib.update_user_ssh(

+             pagure.lib.query.update_user_ssh(

                  flask.g.session,

                  user,

                  None,
@@ -229,7 +229,7 @@ 

      """ Prepare every request. """

      flask.session.permanent = True

      if not hasattr(flask.g, "session") or not flask.g.session:

-         flask.g.session = pagure.lib.create_session(

+         flask.g.session = pagure.lib.query.create_session(

              flask.current_app.config["DB_URL"]

          )

  
@@ -281,17 +281,17 @@ 

      # If there isn't a `repo` in the URL path, or if there is but the

      # endpoint called is part of the API, just don't do anything

      if repo:

-         flask.g.repo = pagure.lib.get_authorized_project(

+         flask.g.repo = pagure.lib.query.get_authorized_project(

              flask.g.session, repo, user=username, namespace=namespace

          )

          if flask.g.authenticated:

-             flask.g.repo_forked = pagure.lib.get_authorized_project(

+             flask.g.repo_forked = pagure.lib.query.get_authorized_project(

                  flask.g.session,

                  repo,

                  user=flask.g.fas_user.username,

                  namespace=namespace,

              )

-             flask.g.repo_starred = pagure.lib.has_starred(

+             flask.g.repo_starred = pagure.lib.query.has_starred(

                  flask.g.session, flask.g.repo, user=flask.g.fas_user.username

              )

  
@@ -323,7 +323,7 @@ 

  

          repouser = flask.g.repo.user.user if flask.g.repo.is_fork else None

          fas_user = flask.g.fas_user if pagure.utils.authenticated() else None

-         flask.g.repo_watch_levels = pagure.lib.get_watch_level_on_repo(

+         flask.g.repo_watch_levels = pagure.lib.query.get_watch_level_on_repo(

              flask.g.session,

              fas_user,

              flask.g.repo.name,
@@ -402,7 +402,7 @@ 

          if not pagure_config.get("ENABLE_GROUP_MNGT", False):

              groups = [

                  group.group_name

-                 for group in pagure.lib.search_groups(

+                 for group in pagure.lib.query.search_groups(

                      flask.g.session, group_type="user"

                  )

              ]
@@ -450,6 +450,6 @@ 

      """ Check if user exists or not

      """

      try:

-         return pagure.lib.get_user(flask.g.session, username)

+         return pagure.lib.query.get_user(flask.g.session, username)

      except pagure.exceptions.PagureException as e:

          flask.abort(404, "%s" % e)

file modified
+2 -2
@@ -28,7 +28,7 @@ 

  import six

  import wtforms

  

- import pagure.lib

+ import pagure.lib.query

  from pagure.config import config as pagure_config

  from pagure.utils import urlpattern, is_admin

  
@@ -122,7 +122,7 @@ 

  

  def ssh_key_validator(form, field):

      """ Form for ssh key validation """

-     if not pagure.lib.are_valid_ssh_keys(field.data):

+     if not pagure.lib.query.are_valid_ssh_keys(field.data):

          raise wtforms.ValidationError("Invalid SSH keys")

  

  

file modified
+6 -6
@@ -20,7 +20,7 @@ 

  

  from pagure.config import config as pagure_config

  from pagure.exceptions import FileNotFoundException

- import pagure.lib

+ import pagure.lib.query

  import pagure.lib.git

  from pagure.lib.git_auth import get_git_auth_helper

  from pagure.lib.plugins import get_enabled_plugins
@@ -165,7 +165,7 @@ 

              os.path.dirname(os.path.realpath(__file__)), "files"

          )

  

-         for repotype in pagure.lib.REPOTYPES:

+         for repotype in pagure.lib.query.REPOTYPES:

              repopath = project.repopath(repotype)

              if repopath is None:

                  continue
@@ -414,7 +414,7 @@ 

              # Determine if this is an actual hook, or if it's a remnant

              # from a hook that was installed before it was moved to the

              # runner system.

-             if os.path.realpath(hookfile) == pagure.lib.HOOK_DNE_TARGET:

+             if os.path.realpath(hookfile) == pagure.lib.query.HOOK_DNE_TARGET:

                  continue

  

              # Execute
@@ -469,7 +469,7 @@ 

          raise ValueError("Hook type %s not valid" % hooktype)

      changes = extract_changes(from_stdin=hooktype != "update")

  

-     session = pagure.lib.create_session(pagure_config["DB_URL"])

+     session = pagure.lib.query.create_session(pagure_config["DB_URL"])

      if not session:

          raise Exception("Unable to initialize db session")

  
@@ -477,7 +477,7 @@ 

      is_internal = os.environ.get("internal", False) == "yes"

      pull_request = None

      if "pull_request_uid" in os.environ:

-         pull_request = pagure.lib.get_request_by_uid(

+         pull_request = pagure.lib.query.get_request_by_uid(

              session, os.environ["pull_request_uid"]

          )

  
@@ -492,7 +492,7 @@ 

          repo,

      ) = pagure.lib.git.get_repo_info_from_path(gitdir)

  

-     project = pagure.lib._get_project(

+     project = pagure.lib.query._get_project(

          session, repo, user=username, namespace=namespace

      )

      if not project:

file modified
+3 -2
@@ -26,6 +26,7 @@ 

  

  import pagure.config

  import pagure.exceptions

+ import pagure.lib.query

  import pagure.lib.tasks

  import pagure.lib.tasks_services

  import pagure.utils
@@ -109,7 +110,7 @@ 

      for rev in revs:

          email = pagure.lib.git.get_author_email(rev, repodir)

          name = pagure.lib.git.get_author(rev, repodir)

-         author = pagure.lib.search_user(session, email=email) or name

+         author = pagure.lib.query.search_user(session, email=email) or name

          auths.add(author)

  

      authors = []
@@ -190,7 +191,7 @@ 

          and target_repo.settings.get("pull_requests", True)

      ):

          print()

-         prs = pagure.lib.search_pull_requests(

+         prs = pagure.lib.query.search_pull_requests(

              session,

              project_id_from=project.id,

              status="Open",

@@ -22,7 +22,7 @@ 

      sys.path.append(PYPATH)

  

  import pagure

- import pagure.lib

+ import pagure.lib.query

  from pagure.hooks import run_project_hooks, extract_changes

  from pagure.config import config as pagure_config

  
@@ -40,13 +40,13 @@ 

  

  changes = extract_changes(from_stdin=hooktype != "update")

  

- session = pagure.lib.create_session(pagure_config["DB_URL"])

+ session = pagure.lib.query.create_session(pagure_config["DB_URL"])

  if not session:

      raise Exception("Unable to initialize db session")

  

  gitdir = os.path.abspath(os.environ["GIT_DIR"])

  

- project = pagure.lib._get_project(

+ project = pagure.lib.query._get_project(

      session, project_name, project_user, project_namespace

  )

  if not project:
@@ -55,7 +55,7 @@ 

  

  pull_request = None

  if pruid:

-     pull_request = pagure.lib.get_request_by_uid(

+     pull_request = pagure.lib.query.get_request_by_uid(

          session, pruid

      )

  

file modified
+1 -1
@@ -21,7 +21,7 @@ 

  from sqlalchemy.orm import relation

  from sqlalchemy.orm import backref

  

- import pagure.lib

+ import pagure.lib.login

  from pagure.hooks import BaseHook, BaseRunner, RequiredIf

  from pagure.lib.model import BASE, Project

  

file modified
+6 -5
@@ -25,6 +25,7 @@ 

  from sqlalchemy.orm import backref

  

  import pagure.config

+ import pagure.lib.query

  import pagure.lib.git

  from pagure.hooks import BaseHook, BaseRunner

  from pagure.lib.model import BASE, Project
@@ -135,7 +136,7 @@ 

      )

  

      try:

-         pagure.lib.add_issue_comment(

+         pagure.lib.query.add_issue_comment(

              session, issue=issue, comment=comment, user=username

          )

          session.commit()
@@ -167,11 +168,11 @@ 

  

      try:

          if relation.isa == "issue":

-             pagure.lib.add_issue_comment(

+             pagure.lib.query.add_issue_comment(

                  session, issue=relation, comment=comment, user=username

              )

          elif relation.isa == "pull-request":

-             pagure.lib.add_pull_request_comment(

+             pagure.lib.query.add_pull_request_comment(

                  session,

                  request=relation,

                  commit=None,
@@ -190,7 +191,7 @@ 

  

      try:

          if relation.isa == "issue":

-             pagure.lib.edit_issue(

+             pagure.lib.query.edit_issue(

                  session,

                  relation,

                  user=username,
@@ -198,7 +199,7 @@ 

                  close_status="Fixed",

              )

          elif relation.isa == "pull-request":

-             pagure.lib.close_pull_request(

+             pagure.lib.query.close_pull_request(

                  session, relation, user=username, merged=True

              )

          session.commit()

@@ -21,6 +21,7 @@ 

  from sqlalchemy.orm import backref

  

  import pagure.lib.git

+ import pagure.lib.tasks_services

  from pagure.hooks import BaseHook, BaseRunner

  from pagure.lib.model import BASE, Project

  

@@ -23,7 +23,8 @@ 

  from sqlalchemy.orm import relation

  from sqlalchemy.orm import backref

  

- import pagure.lib

+ import pagure.lib.git

+ import pagure.lib.tasks_services

  from pagure.config import config as pagure_config

  from pagure.hooks import BaseHook, BaseRunner

  from pagure.lib.model import BASE, Project

@@ -21,6 +21,7 @@ 

  from sqlalchemy.orm import backref

  

  import pagure.config

+ import pagure.lib.git

  from pagure.hooks import BaseHook, BaseRunner

  from pagure.lib.model import BASE, Project

  

file modified
+21 -19
@@ -28,8 +28,8 @@ 

  import pagure  # noqa: E402

  import pagure.exceptions  # noqa: E402

  import pagure.forms  # noqa: E402

- import pagure.lib  # noqa: E402

  import pagure.lib.git  # noqa: E402

+ import pagure.lib.query  # noqa: E402

  import pagure.lib.tasks  # noqa: E402

  import pagure.utils  # noqa: E402

  import pagure.ui.fork  # noqa: E402
@@ -88,7 +88,7 @@ 

      """ Looks up an SSH key by search_key for keyhelper.py """

      search_key = flask.request.form["search_key"]

      username = flask.request.form.get("username")

-     key = pagure.lib.find_ssh_key(flask.g.session, search_key, username)

+     key = pagure.lib.query.find_ssh_key(flask.g.session, search_key, username)

  

      if not key:

          return flask.jsonify({"found": False})
@@ -127,7 +127,7 @@ 

      if repo is None:

          return flask.jsonify({"access": False})

  

-     project = pagure.lib.get_authorized_project(

+     project = pagure.lib.query.get_authorized_project(

          flask.g.session,

          repo,

          user=project_user,
@@ -169,7 +169,9 @@ 

      objid = pform.objid.data

      useremail = pform.useremail.data

  

-     request = pagure.lib.get_request_by_uid(flask.g.session, request_uid=objid)

+     request = pagure.lib.query.get_request_by_uid(

+         flask.g.session, request_uid=objid

+     )

  

      if not request:

          flask.abort(404, "Pull-request not found")
@@ -186,7 +188,7 @@ 

      comment = form.comment.data

  

      try:

-         message = pagure.lib.add_pull_request_comment(

+         message = pagure.lib.query.add_pull_request_comment(

              flask.g.session,

              request=request,

              commit=commit,
@@ -217,12 +219,12 @@ 

      objid = pform.objid.data

      useremail = pform.useremail.data

  

-     issue = pagure.lib.get_issue_by_uid(flask.g.session, issue_uid=objid)

+     issue = pagure.lib.query.get_issue_by_uid(flask.g.session, issue_uid=objid)

  

      if issue is None:

          flask.abort(404, "Issue not found")

  

-     user_obj = pagure.lib.search_user(flask.g.session, email=useremail)

+     user_obj = pagure.lib.query.search_user(flask.g.session, email=useremail)

      admin = False

      if user_obj:

          admin = user_obj.user == issue.project.user.user or (
@@ -247,7 +249,7 @@ 

      comment = form.comment.data

  

      try:

-         message = pagure.lib.add_issue_comment(

+         message = pagure.lib.query.add_issue_comment(

              flask.g.session,

              issue=issue,

              comment=comment,
@@ -281,7 +283,7 @@ 

  

      requestid = flask.request.form.get("requestid")

  

-     request = pagure.lib.get_request_by_uid(

+     request = pagure.lib.query.get_request_by_uid(

          flask.g.session, request_uid=requestid

      )

  
@@ -350,7 +352,7 @@ 

      args_namespace = flask.request.form.get("namespace", "").strip() or None

      args_user = flask.request.form.get("repouser", "").strip() or None

  

-     repo = pagure.lib.get_authorized_project(

+     repo = pagure.lib.query.get_authorized_project(

          flask.g.session,

          args_reponame,

          namespace=args_namespace,
@@ -420,7 +422,7 @@ 

          response.status_code = 400

          return response

  

-     repo = pagure.lib.get_authorized_project(

+     repo = pagure.lib.query.get_authorized_project(

          flask.g.session, repo, user=username, namespace=namespace

      )

  
@@ -481,7 +483,7 @@ 

          response.status_code = 400

          return response

  

-     repo = pagure.lib.get_authorized_project(

+     repo = pagure.lib.query.get_authorized_project(

          flask.g.session,

          flask.request.form.get("repo", "").strip() or None,

          user=flask.request.form.get("repouser", "").strip() or None,
@@ -588,7 +590,7 @@ 

          response.status_code = 400

          return response

  

-     repo = pagure.lib.get_authorized_project(

+     repo = pagure.lib.query.get_authorized_project(

          flask.g.session,

          flask.request.form.get("repo", "").strip() or None,

          namespace=flask.request.form.get("namespace", "").strip() or None,
@@ -662,7 +664,7 @@ 

          response.status_code = 400

          return response

  

-     repo = pagure.lib.get_authorized_project(

+     repo = pagure.lib.query.get_authorized_project(

          flask.g.session,

          flask.request.form.get("repo", "").strip() or None,

          namespace=flask.request.form.get("namespace", "").strip() or None,
@@ -706,7 +708,7 @@ 

          response.status_code = 400

          return response

  

-     repo = pagure.lib.get_authorized_project(

+     repo = pagure.lib.query.get_authorized_project(

          flask.g.session,

          flask.request.form.get("repo", "").strip() or None,

          namespace=flask.request.form.get("namespace", "").strip() or None,
@@ -767,7 +769,7 @@ 

          response.status_code = 400

          return response

  

-     repo = pagure.lib.get_authorized_project(

+     repo = pagure.lib.query.get_authorized_project(

          flask.g.session, repo, user=username, namespace=namespace

      )

  
@@ -784,19 +786,19 @@ 

      if allows_pr:

          family = [

              p.url_path

-             for p in pagure.lib.get_project_family(flask.g.session, repo)

+             for p in pagure.lib.query.get_project_family(flask.g.session, repo)

              if p.settings.get("pull_requests", True)

          ]

      elif allows_issues:

          family = [

              p.url_path

-             for p in pagure.lib.get_project_family(flask.g.session, repo)

+             for p in pagure.lib.query.get_project_family(flask.g.session, repo)

              if p.settings.get("issue_tracker", True)

          ]

      else:

          family = [

              p.url_path

-             for p in pagure.lib.get_project_family(flask.g.session, repo)

+             for p in pagure.lib.query.get_project_family(flask.g.session, repo)

          ]

  

      return flask.jsonify({"code": "OK", "family": family})

file modified
-5580
@@ -8,5583 +8,3 @@ 

     Farhaan Bukhsh <farhaan.bukhsh@gmail.com>

  

  """

- 

- from __future__ import unicode_literals

- 

- # pylint: disable=too-many-branches

- # pylint: disable=too-many-arguments

- # pylint: disable=too-many-locals

- # pylint: disable=too-many-statements

- # pylint: disable=too-many-lines

- 

- 

- try:

-     import simplejson as json

- except ImportError:  # pragma: no cover

-     import json

- 

- import datetime

- import fnmatch

- import functools

- import hashlib

- import logging

- import os

- import tempfile

- import subprocess

- import uuid

- import markdown

- import werkzeug

- from collections import Counter

- from math import ceil

- import copy

- 

- import bleach

- import redis

- import six

- import sqlalchemy

- import sqlalchemy.schema

- 

- from six.moves.urllib_parse import urlparse, urlencode, parse_qsl

- from sqlalchemy import func

- from sqlalchemy import asc, desc

- from sqlalchemy.orm import aliased

- from sqlalchemy.orm import sessionmaker

- from sqlalchemy.orm import scoped_session

- from flask import url_for

- 

- import pagure.exceptions

- import pagure.lib.git

- import pagure.lib.git_auth

- import pagure.lib.login

- import pagure.lib.notify

- import pagure.lib.plugins

- import pagure.pfmarkdown

- import pagure.utils

- from pagure.config import config as pagure_config

- from pagure.lib import model

- from pagure.lib import tasks

- from pagure.lib import tasks_services

- 

- 

- REDIS = None

- PAGURE_CI = None

- REPOTYPES = ("main", "docs", "tickets", "requests")

- _log = logging.getLogger(__name__)

- # The target for hooks migrated to the Runner system, to be able to detect

- # whether a hook was migrated without having to open and read the file

- HOOK_DNE_TARGET = "/does/not/exist"

- 

- 

- class Unspecified(object):

-     """ Custom None object used to indicate that the caller has not made

-     a choice for a particular argument.

-     """

- 

-     pass

- 

- 

- def set_redis(host, port, dbname):

-     """ Set the redis connection with the specified information. """

-     global REDIS

-     pool = redis.ConnectionPool(host=host, port=port, db=dbname)

-     REDIS = redis.StrictRedis(connection_pool=pool)

- 

- 

- def set_pagure_ci(services):

-     """ Set the list of CI services supported by this pagure instance. """

-     global PAGURE_CI

-     PAGURE_CI = services

- 

- 

- def get_user(session, key):

-     """ Searches for a user in the database for a given username or email.

-     """

-     user_obj = search_user(session, username=key)

-     if not user_obj:

-         user_obj = search_user(session, email=key)

- 

-     if not user_obj:

-         raise pagure.exceptions.PagureException('No user "%s" found' % key)

- 

-     return user_obj

- 

- 

- def get_user_by_id(session, userid):

-     """ Searches for a user in the database for a given username or email.

-     """

-     query = session.query(model.User).filter(model.User.id == userid)

- 

-     return query.first()

- 

- 

- SESSIONMAKER = None

- 

- 

- def create_session(db_url=None, debug=False, pool_recycle=3600):

-     """ Create the Session object to use to query the database.

- 

-     :arg db_url: URL used to connect to the database. The URL contains

-     information with regards to the database engine, the host to connect

-     to, the user and password and the database name.

-       ie: <engine>://<user>:<password>@<host>/<dbname>

-     :kwarg debug: a boolean specifying whether we should have the verbose

-         output of sqlalchemy or not.

-     :return a Session that can be used to query the database.

- 

-     """

-     global SESSIONMAKER

- 

-     if SESSIONMAKER is None or (

-         db_url and db_url != ("%s" % SESSIONMAKER.kw["bind"].engine.url)

-     ):

-         if db_url is None:

-             raise ValueError("First call to create_session needs db_url")

-         if db_url.startswith("postgres"):  # pragma: no cover

-             engine = sqlalchemy.create_engine(

-                 db_url,

-                 echo=debug,

-                 pool_recycle=pool_recycle,

-                 client_encoding="utf8",

-             )

-         else:  # pragma: no cover

-             engine = sqlalchemy.create_engine(

-                 db_url, echo=debug, pool_recycle=pool_recycle

-             )

- 

-         if db_url.startswith("sqlite:"):

-             # Ignore the warning about con_record

-             # pylint: disable=unused-argument

-             def _fk_pragma_on_connect(dbapi_con, _):  # pragma: no cover

-                 """ Tries to enforce referential constraints on sqlite. """

-                 dbapi_con.execute("pragma foreign_keys=ON")

- 

-             sqlalchemy.event.listen(engine, "connect", _fk_pragma_on_connect)

-         SESSIONMAKER = sessionmaker(bind=engine)

- 

-     scopedsession = scoped_session(SESSIONMAKER)

-     model.BASE.metadata.bind = scopedsession

-     return scopedsession

- 

- 

- def get_next_id(session, projectid):

-     """ Returns the next identifier of a project ticket or pull-request

-     based on the identifier already in the database.

-     """

-     query1 = session.query(func.max(model.Issue.id)).filter(

-         model.Issue.project_id == projectid

-     )

- 

-     query2 = session.query(func.max(model.PullRequest.id)).filter(

-         model.PullRequest.project_id == projectid

-     )

- 

-     ids = [el[0] for el in query1.union(query2).all() if el[0] is not None]

-     nid = 0

-     if ids:

-         nid = max(ids)

- 

-     return nid + 1

- 

- 

- def search_user(session, username=None, email=None, token=None, pattern=None):

-     """ Searches the database for the user or users matching the given

-     criterias.

- 

-     :arg session: the session to use to connect to the database.

-     :kwarg username: the username of the user to look for.

-     :type username: string or None

-     :kwarg email: the email or one of the email of the user to look for

-     :type email: string or None

-     :kwarg token: the token of the user to look for

-     :type token: string or None

-     :kwarg pattern: a pattern to search the users with.

-     :type pattern: string or None

-     :return: A single User object if any of username, email or token is

-         specified, a list of User objects otherwise.

-     :rtype: User or [User]

- 

-     """

-     query = session.query(model.User).order_by(model.User.user)

- 

-     if username is not None:

-         query = query.filter(model.User.user == username)

- 

-     if email is not None:

-         query = query.filter(model.UserEmail.user_id == model.User.id).filter(

-             model.UserEmail.email == email

-         )

- 

-     if token is not None:

-         query = query.filter(model.User.token == token)

- 

-     if pattern:

-         pattern = pattern.replace("*", "%")

-         query = query.filter(model.User.user.like(pattern))

- 

-     if any([username, email, token]):

-         output = query.first()

-     else:

-         output = query.all()

- 

-     return output

- 

- 

- def is_valid_ssh_key(key, fp_hash="SHA256"):

-     """ Validates the ssh key using ssh-keygen. """

-     key = key.strip()

-     if not key:

-         return None

-     with tempfile.TemporaryFile() as f:

-         f.write(key.encode("utf-8"))

-         f.seek(0)

-         cmd = ["/usr/bin/ssh-keygen", "-l", "-f", "/dev/stdin", "-E", fp_hash]

-         proc = subprocess.Popen(

-             cmd, stdin=f, stdout=subprocess.PIPE, stderr=subprocess.PIPE

-         )

-     stdout, stderr = proc.communicate()

-     if proc.returncode != 0:

-         return False

-     stdout = stdout.decode("utf-8")

- 

-     return stdout

- 

- 

- def are_valid_ssh_keys(keys):

-     """ Checks if all the ssh keys are valid or not. """

-     return all(

-         [is_valid_ssh_key(key) is not False for key in keys.split("\n")]

-     )

- 

- 

- def find_ssh_key(session, search_key, username):

-     """ Finds and returns SSHKey matching the requested search_key.

- 

-     Args:

-         session: database session

-         search_key (string): The SSH fingerprint we are requested to look up

-         username (string or None): If this is provided, the key is looked up

-             to belong to the requested user.

-     """

-     query = session.query(model.SSHKey).filter(

-         model.SSHKey.ssh_search_key == search_key

-     )

- 

-     if username:

-         userowner = (

-             session.query(model.User.id)

-             .filter(model.User.user == username)

-             .subquery()

-         )

-         query = query.filter(model.SSHKey.user_id == userowner)

- 

-     try:

-         return query.one()

-     except sqlalchemy.orm.exc.NoResultFound:

-         return None

- 

- 

- def create_deploykeys_ssh_keys_on_disk(project, gitolite_keydir):

-     """ Create the ssh keys for the projects' deploy keys on the key dir.

- 

-     This method does NOT support multiple ssh keys per deploy key.

-     """

-     if not gitolite_keydir:

-         # Nothing to do here, move right along

-         return

- 

-     # First remove deploykeys that no longer exist

-     keyfiles = [

-         "deploykey_%s_%s.pub"

-         % (werkzeug.secure_filename(project.fullname), key.id)

-         for key in project.deploykeys

-     ]

- 

-     project_key_dir = os.path.join(

-         gitolite_keydir, "deploykeys", project.fullname

-     )

-     if not os.path.exists(project_key_dir):

-         os.makedirs(project_key_dir)

- 

-     for keyfile in os.listdir(project_key_dir):

-         if keyfile not in keyfiles:

-             # This key is no longer in the project. Remove it.

-             os.remove(os.path.join(project_key_dir, keyfile))

- 

-     for deploykey in project.deploykeys:

-         # See the comment in lib/git.py:write_gitolite_acls about why this

-         # name for a file is sane and does not inject a new security risk.

-         keyfile = "deploykey_%s_%s.pub" % (

-             werkzeug.secure_filename(project.fullname),

-             deploykey.id,

-         )

-         if not os.path.exists(os.path.join(project_key_dir, keyfile)):

-             # We only take the very first key - deploykeys must be single keys

-             key = deploykey.public_ssh_key.split("\n")[0]

-             if not key:

-                 continue

-             if not is_valid_ssh_key(key):

-                 continue

-             with open(os.path.join(project_key_dir, keyfile), "w") as f:

-                 f.write(deploykey.public_ssh_key)

- 

- 

- def create_user_ssh_keys_on_disk(user, gitolite_keydir):

-     """ Create the ssh keys for the user on the specific folder.

- 

-     This is the method allowing to have multiple ssh keys per user.

-     """

-     if gitolite_keydir:

-         # First remove any old keyfiles for the user

-         # Assumption: we populated the keydir. This means that files

-         #  will be in 0/<username>.pub, ..., and not in any deeper

-         #  directory structures. Also, this means that if a user

-         #  had 5 lines, they will be up to at most keys_4/<username>.pub,

-         #  meaning that if a user is not in keys_<i>/<username>.pub, with

-         #  i being any integer, the user is most certainly not in

-         #  keys_<i+1>/<username>.pub.

-         i = 0

-         keyline_file = os.path.join(

-             gitolite_keydir, "keys_%i" % i, "%s.pub" % user.user

-         )

-         while os.path.exists(keyline_file):

-             os.unlink(keyline_file)

-             i += 1

-             keyline_file = os.path.join(

-                 gitolite_keydir, "keys_%i" % i, "%s.pub" % user.user

-             )

- 

-         if not user.sshkeys:

-             return

- 

-         # Now let's create new keyfiles for the user

-         i = 0

-         for key in user.sshkeys:

-             if not is_valid_ssh_key(key.public_ssh_key):

-                 continue

-             keyline_dir = os.path.join(gitolite_keydir, "keys_%i" % i)

-             if not os.path.exists(keyline_dir):

-                 os.mkdir(keyline_dir)

-             keyfile = os.path.join(keyline_dir, "%s.pub" % user.user)

-             with open(keyfile, "w") as stream:

-                 stream.write(key.public_ssh_key.strip())

-             i += 1

- 

- 

- def add_issue_comment(

-     session,

-     issue,

-     comment,

-     user,

-     notify=True,

-     date_created=None,

-     notification=False,

- ):

-     """ Add a comment to an issue. """

-     user_obj = get_user(session, user)

- 

-     issue_comment = model.IssueComment(

-         issue_uid=issue.uid,

-         comment=comment,

-         user_id=user_obj.id,

-         date_created=date_created,

-         notification=notification,

-     )

-     issue.last_updated = datetime.datetime.utcnow()

-     session.add(issue)

-     session.add(issue_comment)

-     # Make sure we won't have SQLAlchemy error before we continue

-     session.commit()

- 

-     pagure.lib.git.update_git(issue, repo=issue.project)

- 

-     if not notification:

-         log_action(session, "commented", issue, user_obj)

- 

-     if notify:

-         pagure.lib.notify.notify_new_comment(issue_comment, user=user_obj)

- 

-     if not issue.private:

-         pagure.lib.notify.log(

-             issue.project,

-             topic="issue.comment.added",

-             msg=dict(

-                 issue=issue.to_json(public=True),

-                 project=issue.project.to_json(public=True),

-                 agent=user_obj.username,

-             ),

-             redis=REDIS,

-         )

- 

-     # TODO: we should notify the SSE server even on update of the ticket

-     # via git push to the ticket repo (the only case where notify=False

-     # basically), but this causes problem with some of our markdown extension

-     # so until we figure this out, we won't do live-refresh

-     if REDIS and notify:

-         if issue.private:

-             REDIS.publish(

-                 "pagure.%s" % issue.uid,

-                 json.dumps(

-                     {"issue": "private", "comment_id": issue_comment.id}

-                 ),

-             )

-         else:

-             REDIS.publish(

-                 "pagure.%s" % issue.uid,

-                 json.dumps(

-                     {

-                         "comment_id": issue_comment.id,

-                         "issue_id": issue.id,

-                         "project": issue.project.fullname,

-                         "comment_added": text2markdown(issue_comment.comment),

-                         "comment_user": issue_comment.user.user,

-                         "avatar_url": avatar_url_from_email(

-                             issue_comment.user.default_email, size=16

-                         ),

-                         "comment_date": issue_comment.date_created.strftime(

-                             "%Y-%m-%d %H:%M:%S"

-                         ),

-                         "notification": notification,

-                     }

-                 ),

-             )

- 

-     return "Comment added"

- 

- 

- def add_tag_obj(session, obj, tags, user):

-     """ Add a tag to an object (either an issue or a project). """

-     user_obj = get_user(session, user)

- 

-     if isinstance(tags, six.string_types):

-         tags = [tags]

- 

-     added_tags = []

-     added_tags_color = []

-     for objtag in tags:

-         objtag = objtag.strip()

-         known = False

-         for tagobj in obj.tags:

-             if tagobj.tag == objtag:

-                 known = True

- 

-         if known:

-             continue

- 

-         if obj.isa == "project":

-             tagobj = get_tag(session, objtag)

-             if not tagobj:

-                 tagobj = model.Tag(tag=objtag)

- 

-                 session.add(tagobj)

-                 session.flush()

- 

-             dbobjtag = model.TagProject(project_id=obj.id, tag=tagobj.tag)

- 

-         else:

-             tagobj = get_colored_tag(session, objtag, obj.project.id)

-             if not tagobj:

-                 tagobj = model.TagColored(

-                     tag=objtag, project_id=obj.project.id

-                 )

-                 session.add(tagobj)

-                 session.flush()

- 

-             if obj.isa == "issue":

-                 dbobjtag = model.TagIssueColored(

-                     issue_uid=obj.uid, tag_id=tagobj.id

-                 )

-             else:

-                 dbobjtag = model.TagPullRequest(

-                     request_uid=obj.uid, tag_id=tagobj.id

-                 )

- 

-             added_tags_color.append(tagobj.tag_color)

- 

-         session.add(dbobjtag)

-         # Make sure we won't have SQLAlchemy error before we continue

-         session.flush()

-         added_tags.append(tagobj.tag)

- 

-     if isinstance(obj, model.Issue):

-         pagure.lib.git.update_git(obj, repo=obj.project)

- 

-         if not obj.private:

-             pagure.lib.notify.log(

-                 obj.project,

-                 topic="issue.tag.added",

-                 msg=dict(

-                     issue=obj.to_json(public=True),

-                     project=obj.project.to_json(public=True),

-                     tags=added_tags,

-                     agent=user_obj.username,

-                 ),

-                 redis=REDIS,

-             )

- 

-         # Send notification for the event-source server

-         if REDIS and not obj.project.private:

-             REDIS.publish(

-                 "pagure.%s" % obj.uid,

-                 json.dumps(

-                     {

-                         "added_tags": added_tags,

-                         "added_tags_color": added_tags_color,

-                     }

-                 ),

-             )

-     elif isinstance(obj, model.PullRequest):

-         pagure.lib.git.update_git(obj, repo=obj.project)

- 

-         if not obj.private:

-             pagure.lib.notify.log(

-                 obj.project,

-                 topic="pull-request.tag.added",

-                 msg=dict(

-                     pull_request=obj.to_json(public=True),

-                     project=obj.project.to_json(public=True),

-                     tags=added_tags,

-                     agent=user_obj.username,

-                 ),

-                 redis=REDIS,

-             )

- 

-         # Send notification for the event-source server

-         if REDIS and not obj.project.private:

-             REDIS.publish(

-                 "pagure.%s" % obj.uid,

-                 json.dumps(

-                     {

-                         "added_tags": added_tags,

-                         "added_tags_color": added_tags_color,

-                     }

-                 ),

-             )

- 

-     if added_tags:

-         return "%s tagged with: %s" % (

-             obj.isa.capitalize(),

-             ", ".join(added_tags),

-         )

-     else:

-         return "Nothing to add"

- 

- 

- def add_issue_assignee(session, issue, assignee, user, notify=True):

-     """ Add an assignee to an issue, in other words, assigned an issue. """

-     user_obj = get_user(session, user)

- 

-     old_assignee = issue.assignee

- 

-     if not assignee and issue.assignee is not None:

-         issue.assignee_id = None

-         issue.last_updated = datetime.datetime.utcnow()

-         session.add(issue)

-         session.commit()

-         pagure.lib.git.update_git(issue, repo=issue.project)

- 

-         if notify:

-             pagure.lib.notify.notify_assigned_issue(issue, None, user_obj)

- 

-         if not issue.private:

-             pagure.lib.notify.log(

-                 issue.project,

-                 topic="issue.assigned.reset",

-                 msg=dict(

-                     issue=issue.to_json(public=True),

-                     project=issue.project.to_json(public=True),

-                     agent=user_obj.username,

-                 ),

-                 redis=REDIS,

-             )

- 

-         # Send notification for the event-source server

-         if REDIS and not issue.project.private:

-             REDIS.publish(

-                 "pagure.%s" % issue.uid, json.dumps({"unassigned": "-"})

-             )

- 

-         return "Assignee reset"

-     elif not assignee and issue.assignee is None:

-         return

- 

-     old_assignee = issue.assignee

-     # Validate the assignee

-     assignee_obj = get_user(session, assignee)

- 

-     if issue.assignee_id != assignee_obj.id:

-         issue.assignee_id = assignee_obj.id

-         session.add(issue)

-         session.commit()

-         pagure.lib.git.update_git(issue, repo=issue.project)

- 

-         if notify:

-             pagure.lib.notify.notify_assigned_issue(

-                 issue, assignee_obj, user_obj

-             )

- 

-         if not issue.private:

-             pagure.lib.notify.log(

-                 issue.project,

-                 topic="issue.assigned.added",

-                 msg=dict(

-                     issue=issue.to_json(public=True),

-                     project=issue.project.to_json(public=True),

-                     agent=user_obj.username,

-                 ),

-                 redis=REDIS,

-             )

-         issue.last_updated = datetime.datetime.utcnow()

- 

-         # Send notification for the event-source server

-         if REDIS and not issue.project.private:

-             REDIS.publish(

-                 "pagure.%s" % issue.uid,

-                 json.dumps({"assigned": assignee_obj.to_json(public=True)}),

-             )

- 

-         output = "Issue assigned to %s" % assignee

-         if old_assignee:

-             output += " (was: %s)" % old_assignee.username

-         return output

- 

- 

- def add_pull_request_assignee(session, request, assignee, user):

-     """ Add an assignee to a request, in other words, assigned an issue. """

-     get_user(session, assignee)

-     user_obj = get_user(session, user)

- 

-     if assignee is None and request.assignee is not None:

-         request.assignee_id = None

-         request.last_updated = datetime.datetime.utcnow()

-         session.add(request)

-         session.commit()

-         pagure.lib.git.update_git(request, repo=request.project)

- 

-         pagure.lib.notify.notify_assigned_request(request, None, user_obj)

- 

-         pagure.lib.notify.log(

-             request.project,

-             topic="request.assigned.reset",

-             msg=dict(

-                 request=request.to_json(public=True),

-                 project=request.project.to_json(public=True),

-                 agent=user_obj.username,

-             ),

-             redis=REDIS,

-         )

- 

-         return "Request reset"

-     elif assignee is None and request.assignee is None:

-         return

- 

-     # Validate the assignee

-     assignee_obj = get_user(session, assignee)

- 

-     if request.assignee_id != assignee_obj.id:

-         request.assignee_id = assignee_obj.id

-         request.last_updated = datetime.datetime.utcnow()

-         session.add(request)

-         session.flush()

-         pagure.lib.git.update_git(request, repo=request.project)

- 

-         pagure.lib.notify.notify_assigned_request(

-             request, assignee_obj, user_obj

-         )

- 

-         pagure.lib.notify.log(

-             request.project,

-             topic="request.assigned.added",

-             msg=dict(

-                 request=request.to_json(public=True),

-                 project=request.project.to_json(public=True),

-                 agent=user_obj.username,

-             ),

-             redis=REDIS,

-         )

- 

-         return "Request assigned"

- 

- 

- def add_issue_dependency(session, issue, issue_blocked, user):

-     """ Add a dependency between two issues. """

-     user_obj = get_user(session, user)

- 

-     if issue.uid == issue_blocked.uid:

-         raise pagure.exceptions.PagureException(

-             "An issue cannot depend on itself"

-         )

- 

-     if issue_blocked not in issue.children:

-         i2i = model.IssueToIssue(

-             parent_issue_id=issue.uid, child_issue_id=issue_blocked.uid

-         )

-         session.add(i2i)

-         # Make sure we won't have SQLAlchemy error before we continue

-         session.flush()

-         pagure.lib.git.update_git(issue, repo=issue.project)

-         pagure.lib.git.update_git(issue_blocked, repo=issue_blocked.project)

- 

-         if not issue.private:

-             pagure.lib.notify.log(

-                 issue.project,

-                 topic="issue.dependency.added",

-                 msg=dict(

-                     issue=issue.to_json(public=True),

-                     project=issue.project.to_json(public=True),

-                     added_dependency=issue_blocked.id,

-                     agent=user_obj.username,

-                 ),

-                 redis=REDIS,

-             )

- 

-         # Send notification for the event-source server

-         if REDIS and not issue.project.private:

-             REDIS.publish(

-                 "pagure.%s" % issue.uid,

-                 json.dumps(

-                     {

-                         "added_dependency": issue_blocked.id,

-                         "issue_uid": issue.uid,

-                         "type": "children",

-                     }

-                 ),

-             )

-             REDIS.publish(

-                 "pagure.%s" % issue_blocked.uid,

-                 json.dumps(

-                     {

-                         "added_dependency": issue.id,

-                         "issue_uid": issue_blocked.uid,

-                         "type": "parent",

-                     }

-                 ),

-             )

- 

-         return "Issue marked as depending on: #%s" % issue_blocked.id

- 

- 

- def remove_issue_dependency(session, issue, issue_blocked, user):

-     """ Remove a dependency between two issues. """

-     user_obj = get_user(session, user)

- 

-     if issue.uid == issue_blocked.uid:

-         raise pagure.exceptions.PagureException(

-             "An issue cannot depend on itself"

-         )

- 

-     if issue_blocked in issue.parents:

-         parent_del = []

-         for parent in issue.parents:

-             if parent.uid == issue_blocked.uid:

-                 parent_del.append(parent.id)

-                 issue.parents.remove(parent)

- 

-         # Make sure we won't have SQLAlchemy error before we continue

-         session.flush()

-         pagure.lib.git.update_git(issue, repo=issue.project)

-         pagure.lib.git.update_git(issue_blocked, repo=issue_blocked.project)

- 

-         if not issue.private:

-             pagure.lib.notify.log(

-                 issue.project,

-                 topic="issue.dependency.removed",

-                 msg=dict(

-                     issue=issue.to_json(public=True),

-                     project=issue.project.to_json(public=True),

-                     removed_dependency=parent_del,

-                     agent=user_obj.username,

-                 ),

-                 redis=REDIS,

-             )

- 

-         # Send notification for the event-source server

-         if REDIS and not issue.project.private:

-             REDIS.publish(

-                 "pagure.%s" % issue.uid,

-                 json.dumps(

-                     {

-                         "removed_dependency": parent_del,

-                         "issue_uid": issue.uid,

-                         "type": "children",

-                     }

-                 ),

-             )

-             REDIS.publish(

-                 "pagure.%s" % issue_blocked.uid,

-                 json.dumps(

-                     {

-                         "removed_dependency": issue.id,

-                         "issue_uid": issue_blocked.uid,

-                         "type": "parent",

-                     }

-                 ),

-             )

- 

-         return "Issue **un**marked as depending on: #%s" % " #".join(

-             [("%s" % id) for id in parent_del]

-         )

- 

- 

- def remove_tags(session, project, tags, user):

-     """ Removes the specified tag of a project. """

-     user_obj = get_user(session, user)

- 

-     if not isinstance(tags, list):

-         tags = [tags]

- 

-     issues = search_issues(session, project, closed=False, tags=tags)

-     issues.extend(search_issues(session, project, closed=True, tags=tags))

- 

-     msgs = []

-     removed_tags = []

-     tag_found = False

-     for tag in tags:

-         tagobj = get_colored_tag(session, tag, project.id)

-         if tagobj:

-             tag_found = True

-             removed_tags.append(tag)

-             msgs.append("Tag: %s has been deleted" % tag)

-             session.delete(tagobj)

- 

-     if not tag_found:

-         raise pagure.exceptions.PagureException(

-             "Tags not found: %s" % ", ".join(tags)

-         )

- 

-     for issue in issues:

-         for issue_tag in issue.tags:

-             if issue_tag.tag in tags:

-                 tag = issue_tag.tag

-                 session.delete(issue_tag)

-         pagure.lib.git.update_git(issue, repo=issue.project)

- 

-     pagure.lib.notify.log(

-         project,

-         topic="project.tag.removed",

-         msg=dict(

-             project=project.to_json(public=True),

-             tags=removed_tags,

-             agent=user_obj.username,

-         ),

-         redis=REDIS,

-     )

- 

-     return msgs

- 

- 

- def remove_tags_obj(session, obj, tags, user):

-     """ Removes the specified tag(s) of a given object. """

-     user_obj = get_user(session, user)

- 

-     if isinstance(tags, six.string_types):

-         tags = [tags]

- 

-     removed_tags = []

-     if obj.isa == "project":

-         for objtag in obj.tags:

-             if objtag.tag in tags:

-                 tag = objtag.tag

-                 removed_tags.append(tag)

-                 session.delete(objtag)

-     elif obj.isa == "issue":

-         for objtag in obj.tags_issues_colored:

-             if objtag.tag.tag in tags:

-                 tag = objtag.tag.tag

-                 removed_tags.append(tag)

-                 session.delete(objtag)

-     elif obj.isa == "pull-request":

-         for objtag in obj.tags_pr_colored:

-             if objtag.tag.tag in tags:

-                 tag = objtag.tag.tag

-                 removed_tags.append(tag)

-                 session.delete(objtag)

- 

-     if isinstance(obj, model.Issue):

-         pagure.lib.git.update_git(obj, repo=obj.project)

- 

-         pagure.lib.notify.log(

-             obj.project,

-             topic="issue.tag.removed",

-             msg=dict(

-                 issue=obj.to_json(public=True),

-                 project=obj.project.to_json(public=True),

-                 tags=removed_tags,

-                 agent=user_obj.username,

-             ),

-             redis=REDIS,

-         )

- 

-         # Send notification for the event-source server

-         if REDIS and not obj.project.private:

-             REDIS.publish(

-                 "pagure.%s" % obj.uid,

-                 json.dumps({"removed_tags": removed_tags}),

-             )

-     elif isinstance(obj, model.PullRequest):

-         pagure.lib.git.update_git(obj, repo=obj.project)

- 

-         pagure.lib.notify.log(

-             obj.project,

-             topic="pull-request.tag.removed",

-             msg=dict(

-                 pull_request=obj.to_json(public=True),

-                 project=obj.project.to_json(public=True),

-                 tags=removed_tags,

-                 agent=user_obj.username,

-             ),

-             redis=REDIS,

-         )

- 

-         # Send notification for the event-source server

-         if REDIS and not obj.project.private:

-             REDIS.publish(

-                 "pagure.%s" % obj.uid,

-                 json.dumps({"removed_tags": removed_tags}),

-             )

- 

-     return "%s **un**tagged with: %s" % (

-         obj.isa.capitalize(),

-         ", ".join(removed_tags),

-     )

- 

- 

- def edit_issue_tags(

-     session,

-     project,

-     old_tag,

-     new_tag,

-     new_tag_description,

-     new_tag_color,

-     user,

- ):

-     """ Removes the specified tag of a project. """

-     user_obj = get_user(session, user)

-     old_tag_name = old_tag

- 

-     if not isinstance(old_tag, model.TagColored):

-         old_tag = get_colored_tag(session, old_tag_name, project.id)

- 

-     if not old_tag:

-         raise pagure.exceptions.PagureException(

-             'No tag "%s" found related to this project' % (old_tag_name)

-         )

- 

-     old_tag_name = old_tag.tag

-     old_tag_description = old_tag.tag_description

-     old_tag_color = old_tag.tag_color

- 

-     # check for change

-     no_change_in_tag = (

-         old_tag.tag == new_tag

-         and old_tag_description == new_tag_description

-         and old_tag_color == new_tag_color

-     )

-     if no_change_in_tag:

-         raise pagure.exceptions.PagureException(

-             'No change.  Old tag "%s(%s)[%s]" is the same as '

-             'new tag "%s(%s)[%s]"'

-             % (

-                 old_tag,

-                 old_tag_description,

-                 old_tag_color,

-                 new_tag,

-                 new_tag_description,

-                 new_tag_color,

-             )

-         )

-     elif old_tag.tag != new_tag:

-         # Check if new tag already exists

-         existing_tag = get_colored_tag(session, new_tag, project.id)

-         if existing_tag:

-             raise pagure.exceptions.PagureException(

-                 "Can not rename a tag to an existing tag name: %s" % new_tag

-             )

- 

-     session.query(model.TagColored).filter(

-         model.TagColored.tag == old_tag.tag

-     ).filter(model.TagColored.project_id == project.id).update(

-         {

-             model.TagColored.tag: new_tag,

-             model.TagColored.tag_description: new_tag_description,

-             model.TagColored.tag_color: new_tag_color,

-         }

-     )

- 

-     issues = (

-         session.query(model.Issue)

-         .filter(model.TagIssueColored.tag_id == old_tag.id)

-         .filter(model.TagIssueColored.issue_uid == model.Issue.uid)

-         .all()

-     )

-     for issue in issues:

-         # Update the git version

-         pagure.lib.git.update_git(issue, repo=issue.project)

- 

-     msgs = []

-     msgs.append(

-         "Edited tag: %s(%s)[%s] to %s(%s)[%s]"

-         % (

-             old_tag_name,

-             old_tag_description,

-             old_tag_color,

-             new_tag,

-             new_tag_description,

-             new_tag_color,

-         )

-     )

- 

-     pagure.lib.notify.log(

-         project,

-         topic="project.tag.edited",

-         msg=dict(

-             project=project.to_json(public=True),

-             old_tag=old_tag.tag,

-             old_tag_description=old_tag_description,

-             old_tag_color=old_tag_color,

-             new_tag=new_tag,

-             new_tag_description=new_tag_description,

-             new_tag_color=new_tag_color,

-             agent=user_obj.username,

-         ),

-         redis=REDIS,

-     )

- 

-     return msgs

- 

- 

- def add_sshkey_to_project_or_user(

-     session, ssh_key, pushaccess, creator, project=None, user=None

- ):

-     """ Add a deploy key to a specified project. """

-     if project is None and user is None:

-         raise ValueError(

-             "SSH Keys need to be added to either a project or a user"

-         )

-     if project is not None and user is not None:

-         raise ValueError("SSH Keys need to be assigned to at least one object")

- 

-     ssh_key = ssh_key.strip()

- 

-     if "\n" in ssh_key:

-         raise pagure.exceptions.PagureException("Please add single SSH keys.")

- 

-     ssh_short_key = is_valid_ssh_key(ssh_key)

-     if ssh_short_key in [None, False]:

-         raise pagure.exceptions.PagureException("SSH key invalid.")

- 

-     # We are sure that this only contains a single key, but ssh-keygen still

-     # returns a \n at the end

-     ssh_short_key = ssh_short_key.strip()

-     if "\n" in ssh_key:

-         raise pagure.exceptions.PagureException(

-             "SSH has misbehaved when analyzing the SSH key"

-         )

- 

-     # Make sure that this key is not an SSH key for another project or user.

-     # If we dupe keys, we can't really know who this is for.

-     ssh_search_key = ssh_short_key.split(" ")[1]

-     if (

-         session.query(model.SSHKey)

-         .filter(model.SSHKey.ssh_search_key == ssh_search_key)

-         .count()

-         != 0

-     ):

-         raise pagure.exceptions.PagureException("SSH key already exists.")

- 

-     new_key_obj = model.SSHKey(

-         pushaccess=pushaccess,

-         public_ssh_key=ssh_key,

-         ssh_short_key=ssh_short_key,

-         ssh_search_key=ssh_search_key,

-         creator_user_id=creator.id,

-     )

- 

-     if project:

-         new_key_obj.project = project

-     if user:

-         new_key_obj.user_id = user.id

- 

-     session.add(new_key_obj)

-     # Make sure we won't have SQLAlchemy error before we continue

-     session.flush()

- 

-     # We do not send any notifications on purpose

- 

-     return "SSH key added"

- 

- 

- def add_user_to_project(

-     session, project, new_user, user, access="admin", required_groups=None

- ):

-     """ Add a specified user to a specified project with a specified access

-     """

- 

-     new_user_obj = get_user(session, new_user)

- 

-     if required_groups and access != "ticket":

-         for key in required_groups:

-             if fnmatch.fnmatch(project.fullname, key):

-                 user_grps = set(new_user_obj.groups)

-                 req_grps = set(required_groups[key])

-                 if not user_grps.intersection(req_grps):

-                     raise pagure.exceptions.PagureException(

-                         "This user must be in one of the following groups "

-                         "to be allowed to be added to this project: %s"

-                         % ", ".join(req_grps)

-                     )

- 

-     user_obj = get_user(session, user)

- 

-     users = set(

-         [

-             user_.user

-             for user_ in project.get_project_users(access, combine=False)

-         ]

-     )

-     users.add(project.user.user)

- 

-     if new_user in users:

-         raise pagure.exceptions.PagureException(

-             "This user is already listed on this project with the same access"

-         )

- 

-     # user has some access on project, so update to new access

-     if new_user_obj in project.users:

-         access_obj = get_obj_access(session, project, new_user_obj)

-         access_obj.access = access

-         project.date_modified = datetime.datetime.utcnow()

-         update_read_only_mode(session, project, read_only=True)

-         session.add(access_obj)

-         session.add(project)

-         session.flush()

- 

-         pagure.lib.notify.log(

-             project,

-             topic="project.user.access.updated",

-             msg=dict(

-                 project=project.to_json(public=True),

-                 new_user=new_user_obj.username,

-                 new_access=access,

-                 agent=user_obj.username,

-             ),

-             redis=REDIS,

-         )

- 

-         return "User access updated"

- 

-     project_user = model.ProjectUser(

-         project_id=project.id, user_id=new_user_obj.id, access=access

-     )

-     project.date_modified = datetime.datetime.utcnow()

-     session.add(project_user)

-     # Mark the project as read only, celery will then unmark it

-     update_read_only_mode(session, project, read_only=True)

-     session.add(project)

-     # Make sure we won't have SQLAlchemy error before we continue

-     session.flush()

- 

-     pagure.lib.notify.log(

-         project,

-         topic="project.user.added",

-         msg=dict(

-             project=project.to_json(public=True),

-             new_user=new_user_obj.username,

-             access=access,

-             agent=user_obj.username,

-         ),

-         redis=REDIS,

-     )

- 

-     return "User added"

- 

- 

- def add_group_to_project(

-     session,

-     project,

-     new_group,

-     user,

-     access="admin",

-     create=False,

-     is_admin=False,

- ):

-     """ Add a specified group to a specified project with some access """

- 

-     user_obj = search_user(session, username=user)

-     if not user_obj:

-         raise pagure.exceptions.PagureException("No user %s found." % user)

- 

-     group_obj = search_groups(session, group_name=new_group)

- 

-     if not group_obj:

-         if create:

-             group_obj = pagure.lib.model.PagureGroup(

-                 group_name=new_group,

-                 display_name=new_group,

-                 group_type="user",

-                 user_id=user_obj.id,

-             )

-             session.add(group_obj)

-             session.flush()

-         else:

-             raise pagure.exceptions.PagureException(

-                 "No group %s found." % new_group

-             )

- 

-     if (

-         user_obj not in project.users

-         and user_obj != project.user

-         and not is_admin

-     ):

-         raise pagure.exceptions.PagureException(

-             "You are not allowed to add a group of users to this project"

-         )

- 

-     groups = set(

-         [

-             group.group_name

-             for group in project.get_project_groups(access, combine=False)

-         ]

-     )

- 

-     if new_group in groups:

-         raise pagure.exceptions.PagureException(

-             "This group already has this access on this project"

-         )

- 

-     # the group already has some access, update to new access

-     if group_obj in project.groups:

-         access_obj = get_obj_access(session, project, group_obj)

-         access_obj.access = access

-         session.add(access_obj)

-         project.date_modified = datetime.datetime.utcnow()

-         update_read_only_mode(session, project, read_only=True)

-         session.add(project)

-         session.flush()

- 

-         pagure.lib.notify.log(

-             project,

-             topic="project.group.access.updated",

-             msg=dict(

-                 project=project.to_json(public=True),

-                 new_group=group_obj.group_name,

-                 new_access=access,

-                 agent=user,

-             ),

-             redis=REDIS,

-         )

- 

-         return "Group access updated"

- 

-     project_group = model.ProjectGroup(

-         project_id=project.id, group_id=group_obj.id, access=access

-     )

-     session.add(project_group)

-     # Make sure we won't have SQLAlchemy error before we continue

-     project.date_modified = datetime.datetime.utcnow()

-     # Mark the project read_only, celery will then unmark it

-     update_read_only_mode(session, project, read_only=True)

-     session.add(project)

-     session.flush()

- 

-     pagure.lib.notify.log(

-         project,

-         topic="project.group.added",

-         msg=dict(

-             project=project.to_json(public=True),

-             new_group=group_obj.group_name,

-             access=access,

-             agent=user,

-         ),

-         redis=REDIS,

-     )

- 

-     return "Group added"

- 

- 

- def add_pull_request_comment(

-     session,

-     request,

-     commit,

-     tree_id,

-     filename,

-     row,

-     comment,

-     user,

-     notify=True,

-     notification=False,

-     trigger_ci=None,

- ):

-     """ Add a comment to a pull-request. """

-     user_obj = get_user(session, user)

- 

-     pr_comment = model.PullRequestComment(

-         pull_request_uid=request.uid,

-         commit_id=commit,

-         tree_id=tree_id,

-         filename=filename,

-         line=row,

-         comment=comment,

-         user_id=user_obj.id,

-         notification=notification,

-     )

-     session.add(pr_comment)

-     # Make sure we won't have SQLAlchemy error before we continue

-     session.flush()

- 

-     request.last_updated = datetime.datetime.utcnow()

- 

-     pagure.lib.git.update_git(request, repo=request.project)

- 

-     log_action(session, "commented", request, user_obj)

- 

-     if notify:

-         pagure.lib.notify.notify_pull_request_comment(pr_comment, user_obj)

- 

-     # Send notification for the event-source server

-     if REDIS and not request.project.private:

-         comment_text = text2markdown(pr_comment.comment)

- 

-         REDIS.publish(

-             "pagure.%s" % request.uid,

-             json.dumps(

-                 {

-                     "request_id": request.id,

-                     "comment_added": comment_text,

-                     "comment_user": pr_comment.user.user,

-                     "comment_id": pr_comment.id,

-                     "project": request.project.fullname,

-                     "avatar_url": avatar_url_from_email(

-                         pr_comment.user.default_email, size=16

-                     ),

-                     "comment_date": pr_comment.date_created.strftime(

-                         "%Y-%m-%d %H:%M:%S"

-                     ),

-                     "commit_id": commit,

-                     "filename": filename,

-                     "line": row,

-                     "notification": notification,

-                 }

-             ),

-         )

- 

-     # Send notification to the CI server, if the comment added was a

-     # notification and the PR is still open and project is not private

-     if (

-         notification

-         and request.status == "Open"

-         and pagure_config.get("PAGURE_CI_SERVICES")

-         and request.project.ci_hook

-         and request.project.ci_hook.active_pr

-         and not request.project.private

-     ):

-         tasks_services.trigger_ci_build.delay(

-             pr_uid=request.uid,

-             cause=request.id,

-             branch=request.branch_from,

-             ci_type=request.project.ci_hook.ci_type,

-         )

- 

-     pagure.lib.notify.log(

-         request.project,

-         topic="pull-request.comment.added",

-         msg=dict(

-             pullrequest=request.to_json(public=True), agent=user_obj.username

-         ),

-         redis=REDIS,

-     )

- 

-     if (

-         trigger_ci

-         and comment.strip().lower() in trigger_ci

-         and pagure_config.get("PAGURE_CI_SERVICES")

-         and request.project.ci_hook

-         and request.project.ci_hook.active_pr

-     ):

-         tasks_services.trigger_ci_build.delay(

-             pr_uid=request.uid,

-             cause=request.id,

-             branch=request.branch_from,

-             ci_type=request.project.ci_hook.ci_type,

-         )

- 

-     return "Comment added"

- 

- 

- def edit_comment(session, parent, comment, user, updated_comment):

-     """ Edit a comment. """

-     user_obj = get_user(session, user)

-     comment.comment = updated_comment

-     comment.edited_on = datetime.datetime.utcnow()

-     comment.editor = user_obj

-     parent.last_updated = comment.edited_on

- 

-     session.add(parent)

-     session.add(comment)

-     # Make sure we won't have SQLAlchemy error before we continue

-     session.flush()

- 

-     pagure.lib.git.update_git(parent, repo=parent.project)

- 

-     topic = "unknown"

-     key = "unknown"

-     id_ = "unknown"

-     private = False

-     if parent.isa == "pull-request":

-         topic = "pull-request.comment.edited"

-         key = "pullrequest"

-         id_ = "request_id"

-     elif parent.isa == "issue":

-         topic = "issue.comment.edited"

-         key = "issue"

-         id_ = "issue_id"

-         private = parent.private

- 

-     if not private:

-         pagure.lib.notify.log(

-             parent.project,

-             topic=topic,

-             msg={

-                 key: parent.to_json(public=True, with_comments=False),

-                 "project": parent.project.to_json(public=True),

-                 "comment": comment.to_json(public=True),

-                 "agent": user_obj.username,

-             },

-             redis=REDIS,

-         )

- 

-     if REDIS and not parent.project.private:

-         if private:

-             REDIS.publish(

-                 "pagure.%s" % comment.parent.uid,

-                 json.dumps(

-                     {"comment_updated": "private", "comment_id": comment.id}

-                 ),

-             )

-         else:

-             REDIS.publish(

-                 "pagure.%s" % parent.uid,

-                 json.dumps(

-                     {

-                         id_: len(parent.comments),

-                         "comment_updated": text2markdown(comment.comment),

-                         "comment_id": comment.id,

-                         "parent_id": comment.parent.id,

-                         "comment_editor": user_obj.user,

-                         "avatar_url": avatar_url_from_email(

-                             comment.user.default_email, size=16

-                         ),

-                         "comment_date": comment.edited_on.strftime(

-                             "%Y-%m-%d %H:%M:%S"

-                         ),

-                     }

-                 ),

-             )

- 

-     return "Comment updated"

- 

- 

- def add_pull_request_flag(

-     session, request, username, percent, comment, url, status, uid, user, token

- ):

-     """ Add a flag to a pull-request. """

-     user_obj = get_user(session, user)

- 

-     action = "added"

-     pr_flag = None

-     if uid:

-         pr_flag = get_pull_request_flag_by_uid(session, request, uid)

-     if pr_flag:

-         action = "updated"

-         pr_flag.comment = comment

-         pr_flag.status = status

-         pr_flag.percent = percent

-         pr_flag.url = url

-     else:

-         pr_flag = model.PullRequestFlag(

-             pull_request_uid=request.uid,

-             uid=uid or uuid.uuid4().hex,

-             username=username,

-             percent=percent,

-             comment=comment,

-             status=status,

-             url=url,

-             user_id=user_obj.id,

-             token_id=token,

-         )

-     session.add(pr_flag)

-     # Make sure we won't have SQLAlchemy error before we continue

-     session.flush()

- 

-     if request.project.settings.get("notify_on_pull-request_flag"):

-         pagure.lib.notify.notify_pull_request_flag(pr_flag, username)

- 

-     pagure.lib.git.update_git(request, repo=request.project)

- 

-     pagure.lib.notify.log(

-         request.project,

-         topic="pull-request.flag.%s" % action,

-         msg=dict(

-             pullrequest=request.to_json(public=True),

-             flag=pr_flag.to_json(public=True),

-             agent=user_obj.username,

-         ),

-         redis=REDIS,

-     )

- 

-     return ("Flag %s" % action, pr_flag.uid)

- 

- 

- def add_commit_flag(

-     session,

-     repo,

-     commit_hash,

-     username,

-     status,

-     percent,

-     comment,

-     url,

-     uid,

-     user,

-     token,

- ):

-     """ Add a flag to a add_commit_flag. """

-     user_obj = get_user(session, user)

- 

-     action = "added"

-     c_flag = get_commit_flag_by_uid(session, commit_hash, uid)

-     if c_flag:

-         action = "updated"

-         c_flag.comment = comment

-         c_flag.percent = percent

-         c_flag.status = status

-         c_flag.url = url

-     else:

-         c_flag = model.CommitFlag(

-             uid=uid or uuid.uuid4().hex,

-             project_id=repo.id,

-             commit_hash=commit_hash,

-             username=username,

-             status=status,

-             percent=percent,

-             comment=comment,

-             url=url,

-             user_id=user_obj.id,

-             token_id=token,

-         )

-     session.add(c_flag)

-     # Make sure we won't have SQLAlchemy error before we continue

-     session.flush()

- 

-     if repo.settings.get("notify_on_commit_flag"):

-         pagure.lib.notify.notify_commit_flag(c_flag, username)

- 

-     pagure.lib.notify.log(

-         repo,

-         topic="commit.flag.%s" % action,

-         msg=dict(

-             repo=repo.to_json(public=True),

-             flag=c_flag.to_json(public=True),

-             agent=user_obj.username,

-         ),

-         redis=REDIS,

-     )

- 

-     return ("Flag %s" % action, c_flag.uid)

- 

- 

- def get_commit_flag(session, project, commit_hash):

-     """ Return the commit flags corresponding to the specified git hash

-     (commitid) in the specified repository.

- 

-     :arg session: the session with which to connect to the database

-     :arg repo: the pagure.lib.model.Project object corresponding to the

-         project whose commit has been flagged

-     :arg commit_hash: the hash of the commit who has been flagged

-     :return: list of pagure.lib.model.CommitFlag objects or an empty list

- 

-     """

-     query = (

-         session.query(model.CommitFlag)

-         .filter(model.CommitFlag.project_id == project.id)

-         .filter(model.CommitFlag.commit_hash == commit_hash)

-     )

- 

-     return query.all()

- 

- 

- def new_project(

-     session,

-     user,

-     name,

-     blacklist,

-     allowed_prefix,

-     repospanner_region,

-     description=None,

-     url=None,

-     avatar_email=None,

-     parent_id=None,

-     add_readme=False,

-     userobj=None,

-     prevent_40_chars=False,

-     namespace=None,

-     user_ns=False,

-     ignore_existing_repo=False,

-     private=False,

- ):

-     """ Create a new project based on the information provided.

- 

-     Is an async operation, and returns task ID.

-     """

-     ns_name = name if not namespace else "%s/%s" % (namespace, name)

-     matched = any(map(functools.partial(fnmatch.fnmatch, ns_name), blacklist))

-     if matched:

-         raise pagure.exceptions.ProjectBlackListedException(

-             'No project "%s" are allowed to be created due to potential '

-             "conflicts in URLs with pagure itself" % ns_name

-         )

- 

-     user_obj = get_user(session, user)

-     allowed_prefix = allowed_prefix + [grp for grp in user_obj.groups]

-     if user_ns:

-         allowed_prefix.append(user)

-         if not namespace:

-             namespace = user

-     if private:

-         allowed_prefix.append(user)

-         namespace = user

- 

-     if namespace and namespace not in allowed_prefix:

-         raise pagure.exceptions.PagureException(

-             "The namespace of your project must be in the list of allowed "

-             "namespaces set by the admins of this pagure instance, or the "

-             "name of a group of which you are a member."

-         )

- 

-     if len(name) == 40 and prevent_40_chars:

-         # We must block project with a name <foo>/<bar> where the length

-         # of <bar> is exactly 40 characters long as this would otherwise

-         # conflict with the old URL schema used for commit that was

-         # <foo>/<commit hash>. To keep backward compatibility, we have an

-         # endpoint redirecting <foo>/<commit hash> to <foo>/c/<commit hash>

-         # available as an option.

-         raise pagure.exceptions.PagureException(

-             "Your project name cannot have exactly 40 characters after "

-             "the `/`"

-         )

- 

-     path = name

-     if namespace:

-         path = "%s/%s" % (namespace, name)

- 

-     # Repo exists in the DB

-     repo = _get_project(session, name, namespace=namespace)

-     # this is leaking private repos but we're leaking them anyway if we fail

-     # to add the requested repo later. Let's be less clear about why :)

-     if repo:

-         raise pagure.exceptions.RepoExistsException(

-             'It is not possible to create the repo "%s"' % (path)

-         )

- 

-     if repospanner_region == "none":

-         repospanner_region = None

-     elif repospanner_region is None:

-         repospanner_region = pagure_config["REPOSPANNER_NEW_REPO"]

- 

-     if (

-         repospanner_region

-         and repospanner_region not in pagure_config["REPOSPANNER_REGIONS"]

-     ):

-         raise Exception("repoSpanner region %s invalid" % repospanner_region)

- 

-     project = model.Project(

-         name=name,

-         namespace=namespace,

-         repospanner_region=repospanner_region,

-         description=description if description else None,

-         url=url if url else None,

-         avatar_email=avatar_email if avatar_email else None,

-         user_id=user_obj.id,

-         parent_id=parent_id,

-         private=private,

-         hook_token=pagure.lib.login.id_generator(40),

-     )

-     session.add(project)

-     # Flush so that a project ID is generated

-     session.flush()

-     for ltype in model.ProjectLock.lock_type.type.enums:

-         lock = model.ProjectLock(project_id=project.id, lock_type=ltype)

-         session.add(lock)

-     session.commit()

- 

-     # Register creation et al

-     log_action(session, "created", project, user_obj)

- 

-     pagure.lib.notify.log(

-         project,

-         topic="project.new",

-         msg=dict(

-             project=project.to_json(public=True), agent=user_obj.username

-         ),

-     )

- 

-     return tasks.create_project.delay(

-         user_obj.username, namespace, name, add_readme, ignore_existing_repo

-     )

- 

- 

- def new_issue(

-     session,

-     repo,

-     title,

-     content,

-     user,

-     issue_id=None,

-     issue_uid=None,

-     private=False,

-     status=None,

-     close_status=None,

-     notify=True,

-     date_created=None,

-     milestone=None,

-     priority=None,

-     assignee=None,

-     tags=None,

- ):

-     """ Create a new issue for the specified repo. """

-     user_obj = get_user(session, user)

- 

-     # Only store the priority if there is one in the project

-     priorities = repo.priorities or []

-     try:

-         priority = int(priority)

-     except (ValueError, TypeError):

-         priority = None

-     if (

-         priorities

-         and priority is not None

-         and ("%s" % priority) not in priorities

-     ):

-         raise pagure.exceptions.PagureException(

-             "You are trying to create an issue with a priority that does "

-             "not exist in the project."

-         )

- 

-     assignee_id = None

-     if assignee is not None:

-         assignee_id = get_user(session, assignee).id

- 

-     issue = model.Issue(

-         id=issue_id or get_next_id(session, repo.id),

-         project_id=repo.id,

-         title=title,

-         content=content,

-         priority=priority,

-         milestone=milestone,

-         assignee_id=assignee_id,

-         user_id=user_obj.id,

-         uid=issue_uid or uuid.uuid4().hex,

-         private=private,

-         date_created=date_created,

-     )

- 

-     if status is not None:

-         issue.status = status

-     if close_status is not None:

-         issue.close_status = close_status

-     issue.last_updated = datetime.datetime.utcnow()

- 

-     session.add(issue)

-     # Make sure we won't have SQLAlchemy error before we create the issue

-     session.flush()

- 

-     # Add the tags if any are specified

-     if tags is not None:

-         for lbl in tags:

-             tagobj = get_colored_tag(session, lbl, repo.id)

-             if not tagobj:

-                 tagobj = model.TagColored(tag=lbl, project_id=repo.id)

-                 session.add(tagobj)

-                 session.flush()

- 

-             dbobjtag = model.TagIssueColored(

-                 issue_uid=issue.uid, tag_id=tagobj.id

-             )

-             session.add(dbobjtag)

- 

-     session.commit()

- 

-     pagure.lib.git.update_git(issue, repo=repo)

- 

-     log_action(session, "created", issue, user_obj)

- 

-     if notify:

-         pagure.lib.notify.notify_new_issue(issue, user=user_obj)

- 

-     if not private:

-         pagure.lib.notify.log(

-             issue.project,

-             topic="issue.new",

-             msg=dict(

-                 issue=issue.to_json(public=True),

-                 project=issue.project.to_json(public=True),

-                 agent=user_obj.username,

-             ),

-             redis=REDIS,

-         )

- 

-     return issue

- 

- 

- def drop_issue(session, issue, user):

-     """ Delete a specified issue. """

-     user_obj = get_user(session, user)

- 

-     repotype = issue.repotype

-     uid = issue.uid

- 

-     private = issue.private

-     session.delete(issue)

- 

-     # Make sure we won't have SQLAlchemy error before we create the issue

-     session.flush()

- 

-     if not private:

-         pagure.lib.notify.log(

-             issue.project,

-             topic="issue.drop",

-             msg=dict(

-                 issue=issue.to_json(public=True),

-                 project=issue.project.to_json(public=True),

-                 agent=user_obj.username,

-             ),

-             redis=REDIS,

-         )

- 

-     session.commit()

- 

-     pagure.lib.git.clean_git(issue.project, repotype, uid)

- 

-     return issue

- 

- 

- def new_pull_request(

-     session,

-     branch_from,

-     repo_to,

-     branch_to,

-     title,

-     user,

-     initial_comment=None,

-     repo_from=None,

-     remote_git=None,

-     requestuid=None,

-     requestid=None,

-     status="Open",

-     notify=True,

-     commit_start=None,

-     commit_stop=None,

- ):

-     """ Create a new pull request on the specified repo. """

-     if not repo_from and not remote_git:

-         raise pagure.exceptions.PagureException(

-             "Invalid input, you must specify either a local repo or a "

-             "remote one"

-         )

- 

-     user_obj = get_user(session, user)

- 

-     request = model.PullRequest(

-         id=requestid or get_next_id(session, repo_to.id),

-         uid=requestuid or uuid.uuid4().hex,

-         project_id=repo_to.id,

-         project_id_from=repo_from.id if repo_from else None,

-         remote_git=remote_git if remote_git else None,

-         branch=branch_to,

-         branch_from=branch_from,

-         title=title,

-         initial_comment=initial_comment or None,

-         user_id=user_obj.id,

-         status=status,

-         commit_start=commit_start,

-         commit_stop=commit_stop,

-     )

-     request.last_updated = datetime.datetime.utcnow()

- 

-     session.add(request)

-     # Make sure we won't have SQLAlchemy error before we create the request

-     session.flush()

- 

-     pagure.lib.git.update_git(request, repo=request.project)

- 

-     pagure.lib.tasks.link_pr_to_ticket.delay(request.uid)

- 

-     log_action(session, "created", request, user_obj)

- 

-     if notify:

-         pagure.lib.notify.notify_new_pull_request(request)

- 

-     pagure.lib.notify.log(

-         request.project,

-         topic="pull-request.new",

-         msg=dict(

-             pullrequest=request.to_json(public=True), agent=user_obj.username

-         ),

-         redis=REDIS,

-     )

- 

-     # Send notification to the CI server

-     if (

-         pagure_config.get("PAGURE_CI_SERVICES")

-         and request.project.ci_hook

-         and request.project.ci_hook.active_pr

-         and not request.project.private

-     ):

-         tasks_services.trigger_ci_build.delay(

-             pr_uid=request.uid,

-             cause=request.id,

-             branch=request.branch_from,

-             ci_type=request.project.ci_hook.ci_type,

-         )

- 

-     # Create the ref from the start

-     tasks.sync_pull_ref.delay(

-         request.project.name,

-         request.project.namespace,

-         request.project.user.username if request.project.is_fork else None,

-         request.id,

-     )

- 

-     return request

- 

- 

- def new_tag(session, tag_name, tag_description, tag_color, project_id):

-     """ Return a new tag object """

-     tagobj = model.TagColored(

-         tag=tag_name,

-         tag_description=tag_description,

-         tag_color=tag_color,

-         project_id=project_id,

-     )

-     session.add(tagobj)

-     session.flush()

- 

-     return tagobj

- 

- 

- def edit_issue(

-     session,

-     issue,

-     user,

-     repo=None,

-     title=None,

-     content=None,

-     status=None,

-     close_status=Unspecified,

-     priority=Unspecified,

-     milestone=Unspecified,

-     private=None,

- ):

-     """ Edit the specified issue.

- 

-     :arg session: the session to use to connect to the database.

-     :arg issue: the pagure.lib.model.Issue object to edit.

-     :arg user: the username of the user editing the issue,

-     :kwarg repo: somehow this isn't used anywhere here...

-     :kwarg title: the new title of the issue if it's being changed

-     :kwarg content: the new content of the issue if it's being changed

-     :kwarg status: the new status of the issue if it's being changed

-     :kwarg close_status: the new close_status of the issue if it's being

-         changed

-     :kwarg priority: the new priority of the issue if it's being changed

-     :kwarg milestone: the new milestone of the issue if it's being changed

-     :kwarg private: the new private of the issue if it's being changed

- 

-     """

-     user_obj = get_user(session, user)

-     if status and status != "Open" and issue.parents:

-         for parent in issue.parents:

-             if parent.status == "Open":

-                 raise pagure.exceptions.PagureException(

-                     "You cannot close a ticket that has ticket "

-                     "depending that are still open."

-                 )

- 

-     edit = []

-     messages = []

-     if title and title != issue.title:

-         issue.title = title

-         edit.append("title")

-     if content and content != issue.content:

-         issue.content = content

-         edit.append("content")

-     if status and status != issue.status:

-         old_status = issue.status

-         issue.status = status

-         if status.lower() != "open":

-             issue.closed_at = datetime.datetime.utcnow()

-         elif issue.close_status:

-             issue.close_status = None

-             close_status = Unspecified

-             edit.append("close_status")

-         edit.append("status")

-         messages.append(

-             "Issue status updated to: %s (was: %s)" % (status, old_status)

-         )

-     if close_status != Unspecified and close_status != issue.close_status:

-         old_status = issue.close_status

-         issue.close_status = close_status

-         edit.append("close_status")

-         msg = "Issue close_status updated to: %s" % close_status

-         if old_status:

-             msg += " (was: %s)" % old_status

-         if issue.status.lower() == "open" and close_status:

-             issue.status = "Closed"

-             issue.closed_at = datetime.datetime.utcnow()

-             edit.append("status")

-         messages.append(msg)

-     if priority != Unspecified:

-         priorities = issue.project.priorities

-         try:

-             priority = int(priority)

-         except (ValueError, TypeError):

-             priority = None

- 

-         priority_string = "%s" % priority

-         if priority_string not in priorities:

-             priority = None

- 

-         if priority != issue.priority:

-             old_priority = issue.priority

-             issue.priority = priority

-             edit.append("priority")

-             msg = "Issue priority set to: %s" % (

-                 priorities[priority_string] if priority else None

-             )

-             if old_priority:

-                 msg += " (was: %s)" % priorities.get(

-                     "%s" % old_priority, old_priority

-                 )

-             messages.append(msg)

-     if private in [True, False] and private != issue.private:

-         old_private = issue.private

-         issue.private = private

-         edit.append("private")

-         msg = "Issue private status set to: %s" % private

-         if old_private:

-             msg += " (was: %s)" % old_private

-         messages.append(msg)

-     if milestone != Unspecified and milestone != issue.milestone:

-         old_milestone = issue.milestone

-         issue.milestone = milestone

-         edit.append("milestone")

-         msg = "Issue set to the milestone: %s" % milestone

-         if old_milestone:

-             msg += " (was: %s)" % old_milestone

-         messages.append(msg)

-     issue.last_updated = datetime.datetime.utcnow()

-     # uniquify the list of edited fields

-     edit = list(set(edit))

- 

-     pagure.lib.git.update_git(issue, repo=issue.project)

- 

-     if "status" in edit:

-         log_action(session, issue.status.lower(), issue, user_obj)

-         pagure.lib.notify.notify_status_change_issue(issue, user_obj)

- 

-     if not issue.private and edit:

-         pagure.lib.notify.log(

-             issue.project,

-             topic="issue.edit",

-             msg=dict(

-                 issue=issue.to_json(public=True),

-                 project=issue.project.to_json(public=True),

-                 fields=list(set(edit)),

-                 agent=user_obj.username,

-             ),

-             redis=REDIS,

-         )

- 

-     if REDIS and edit and not issue.project.private:

-         if issue.private:

-             REDIS.publish(

-                 "pagure.%s" % issue.uid,

-                 json.dumps({"issue": "private", "fields": edit}),

-             )

-         else:

-             REDIS.publish(

-                 "pagure.%s" % issue.uid,

-                 json.dumps(

-                     {

-                         "fields": edit,

-                         "issue": issue.to_json(

-                             public=True, with_comments=False

-                         ),

-                         "priorities": issue.project.priorities,

-                     }

-                 ),

-             )

- 

-     if edit:

-         session.add(issue)

-         session.flush()

-         return messages

- 

- 

- def update_project_settings(session, repo, settings, user):

-     """ Update the settings of a project. """

-     user_obj = get_user(session, user)

- 

-     update = []

-     new_settings = repo.settings

-     for key in new_settings:

-         if key in settings:

-             if key == "Minimum_score_to_merge_pull-request":

-                 try:

-                     settings[key] = int(settings[key]) if settings[key] else -1

-                 except (ValueError, TypeError):

-                     raise pagure.exceptions.PagureException(

-                         "Please enter a numeric value for the 'minimum "

-                         "score to merge pull request' field."

-                     )

-             elif key == "Web-hooks":

-                 settings[key] = settings[key] or None

-             else:

-                 # All the remaining keys are boolean, so True is provided

-                 # as 'y' by the html, let's convert it back

-                 settings[key] = settings[key] in ["y", True]

- 

-             if new_settings[key] != settings[key]:

-                 update.append(key)

-                 new_settings[key] = settings[key]

-         else:

-             val = False

-             if key == "Web-hooks":

-                 val = None

- 

-             # Ensure the default value is different from what is stored.

-             if new_settings[key] != val:

-                 update.append(key)

-                 new_settings[key] = val

- 

-     if not update:

-         return "No settings to change"

-     else:

-         repo.settings = new_settings

-         repo.date_modified = datetime.datetime.utcnow()

-         session.add(repo)

-         session.flush()

- 

-         pagure.lib.notify.log(

-             repo,

-             topic="project.edit",

-             msg=dict(

-                 project=repo.to_json(public=True),

-                 fields=update,

-                 agent=user_obj.username,

-             ),

-             redis=REDIS,

-         )

- 

-         if "pull_request_access_only" in update:

-             update_read_only_mode(session, repo, read_only=True)

-             session.add(repo)

-             session.flush()

-             pagure.lib.git.generate_gitolite_acls(project=repo)

- 

-         return "Edited successfully settings of repo: %s" % repo.fullname

- 

- 

- def update_user_settings(session, settings, user):

-     """ Update the settings of a project. """

-     user_obj = get_user(session, user)

- 

-     update = []

-     new_settings = user_obj.settings

-     for key in new_settings:

-         if key in settings:

-             if new_settings[key] != settings[key]:

-                 update.append(key)

-                 new_settings[key] = settings[key]

-         else:

-             if new_settings[key] is not False:

-                 update.append(key)

-                 new_settings[key] = False

- 

-     if not update:

-         return "No settings to change"

-     else:

-         user_obj.settings = new_settings

-         session.add(user_obj)

-         session.flush()

- 

-         return "Successfully edited your settings"

- 

- 

- def fork_project(session, user, repo, editbranch=None, editfile=None):

-     """ Fork a given project into the user's forks. """

-     if _get_project(session, repo.name, user, repo.namespace) is not None:

-         raise pagure.exceptions.RepoExistsException(

-             'Repo "forks/%s/%s" already exists' % (user, repo.name)

-         )

- 

-     user_obj = get_user(session, user)

- 

-     fork_repospanner_setting = pagure_config["REPOSPANNER_NEW_FORK"]

-     if fork_repospanner_setting is None:

-         repospanner_region = None

-     elif fork_repospanner_setting is True:

-         repospanner_region = repo.repospanner_region

-     else:

-         repospanner_region = fork_repospanner_setting

- 

-     project = model.Project(

-         name=repo.name,

-         namespace=repo.namespace,

-         description=repo.description,

-         repospanner_region=repospanner_region,

-         private=repo.private,

-         user_id=user_obj.id,

-         parent_id=repo.id,

-         is_fork=True,

-         hook_token=pagure.lib.login.id_generator(40),

-     )

- 

-     # disable issues, PRs in the fork by default

-     default_repo_settings = project.settings

-     default_repo_settings["issue_tracker"] = False

-     default_repo_settings["pull_requests"] = False

-     project.settings = default_repo_settings

- 

-     session.add(project)

-     # Make sure we won't have SQLAlchemy error before we create the repo

-     session.flush()

-     session.commit()

- 

-     task = tasks.fork.delay(

-         repo.name,

-         repo.namespace,

-         repo.user.username if repo.is_fork else None,

-         user,

-         editbranch,

-         editfile,

-     )

-     return task

- 

- 

- def search_projects(

-     session,

-     username=None,

-     fork=None,

-     tags=None,

-     namespace=None,

-     pattern=None,

-     start=None,

-     limit=None,

-     count=False,

-     sort=None,

-     exclude_groups=None,

-     private=None,

-     owner=None,

- ):

-     """List existing projects

-     """

-     projects = session.query(sqlalchemy.distinct(model.Project.id))

- 

-     if owner is not None and username is not None:

-         raise RuntimeError(

-             "You cannot supply both a username and an owner "

-             "as parameters in the `search_projects` function"

-         )

-     elif owner is not None:

-         projects = projects.join(model.User).filter(model.User.user == owner)

-     elif username is not None:

-         projects = projects.filter(

-             # User created the project

-             sqlalchemy.and_(

-                 model.User.user == username,

-                 model.User.id == model.Project.user_id,

-             )

-         )

-         sub_q2 = session.query(model.Project.id).filter(

-             # User got admin or commit right

-             sqlalchemy.and_(

-                 model.User.user == username,

-                 model.User.id == model.ProjectUser.user_id,

-                 model.ProjectUser.project_id == model.Project.id,

-                 sqlalchemy.or_(

-                     model.ProjectUser.access == "admin",

-                     model.ProjectUser.access == "commit",

-                 ),

-             )

-         )

-         sub_q3 = session.query(model.Project.id).filter(

-             # User created a group that has admin or commit right

-             sqlalchemy.and_(

-                 model.User.user == username,

-                 model.PagureGroup.user_id == model.User.id,

-                 model.PagureGroup.group_type == "user",

-                 model.PagureGroup.id == model.ProjectGroup.group_id,

-                 model.Project.id == model.ProjectGroup.project_id,

-                 sqlalchemy.or_(

-                     model.ProjectGroup.access == "admin",

-                     model.ProjectGroup.access == "commit",

-                 ),

-             )

-         )

-         sub_q4 = session.query(model.Project.id).filter(

-             # User is part of a group that has admin or commit right

-             sqlalchemy.and_(

-                 model.User.user == username,

-                 model.PagureUserGroup.user_id == model.User.id,

-                 model.PagureUserGroup.group_id == model.PagureGroup.id,

-                 model.PagureGroup.group_type == "user",

-                 model.PagureGroup.id == model.ProjectGroup.group_id,

-                 model.Project.id == model.ProjectGroup.project_id,

-                 sqlalchemy.or_(

-                     model.ProjectGroup.access == "admin",

-                     model.ProjectGroup.access == "commit",

-                 ),

-             )

-         )

- 

-         # Exclude projects that the user has accessed via a group that we

-         # do not want to include

-         if exclude_groups:

-             sub_q3 = sub_q3.filter(

-                 model.PagureGroup.group_name.notin_(exclude_groups)

-             )

-             sub_q4 = sub_q4.filter(

-                 model.PagureGroup.group_name.notin_(exclude_groups)

-             )

- 

-         projects = projects.union(sub_q2).union(sub_q3).union(sub_q4)

- 

-     if not private:

-         projects = projects.filter(

-             model.Project.private == False  # noqa: E712

-         )

-     # No filtering is done if private == username i.e  if the owner of the

-     # project is viewing the project

-     elif isinstance(private, six.string_types) and private != username:

-         # All the public repo

-         subquery0 = session.query(

-             sqlalchemy.distinct(model.Project.id)

-         ).filter(

-             model.Project.private == False  # noqa: E712

-         )

-         sub_q1 = session.query(sqlalchemy.distinct(model.Project.id)).filter(

-             sqlalchemy.and_(

-                 model.Project.private == True,  # noqa: E712

-                 model.User.id == model.Project.user_id,

-                 model.User.user == private,

-             )

-         )

-         sub_q2 = session.query(model.Project.id).filter(

-             # User got admin or commit right

-             sqlalchemy.and_(

-                 model.Project.private == True,  # noqa: E712

-                 model.User.user == private,

-                 model.User.id == model.ProjectUser.user_id,

-                 model.ProjectUser.project_id == model.Project.id,

-                 sqlalchemy.or_(

-                     model.ProjectUser.access == "admin",

-                     model.ProjectUser.access == "commit",

-                 ),

-             )

-         )

-         sub_q3 = session.query(model.Project.id).filter(

-             # User created a group that has admin or commit right

-             sqlalchemy.and_(

-                 model.Project.private == True,  # noqa: E712

-                 model.User.user == private,

-                 model.PagureGroup.user_id == model.User.id,

-                 model.PagureGroup.group_type == "user",

-                 model.PagureGroup.id == model.ProjectGroup.group_id,

-                 model.Project.id == model.ProjectGroup.project_id,

-                 sqlalchemy.or_(

-                     model.ProjectGroup.access == "admin",

-                     model.ProjectGroup.access == "commit",

-                 ),

-             )

-         )

-         sub_q4 = session.query(model.Project.id).filter(

-             # User is part of a group that has admin or commit right

-             sqlalchemy.and_(

-                 model.Project.private == True,  # noqa: E712

-                 model.User.user == private,

-                 model.PagureUserGroup.user_id == model.User.id,

-                 model.PagureUserGroup.group_id == model.PagureGroup.id,

-                 model.PagureGroup.group_type == "user",

-                 model.PagureGroup.id == model.ProjectGroup.group_id,

-                 model.Project.id == model.ProjectGroup.project_id,

-                 sqlalchemy.or_(

-                     model.ProjectGroup.access == "admin",

-                     model.ProjectGroup.access == "commit",

-                 ),

-             )

-         )

- 

-         # Exclude projects that the user has accessed via a group that we

-         # do not want to include

-         if exclude_groups:

-             sub_q3 = sub_q3.filter(

-                 model.PagureGroup.group_name.notin_(exclude_groups)

-             )

-             sub_q4 = sub_q4.filter(

-                 model.PagureGroup.group_name.notin_(exclude_groups)

-             )

- 

-         projects = projects.filter(

-             model.Project.id.in_(

-                 subquery0.union(sub_q1)

-                 .union(sub_q2)

-                 .union(sub_q3)

-                 .union(sub_q4)

-             )

-         )

- 

-     if fork is not None:

-         if fork is True:

-             projects = projects.filter(

-                 model.Project.is_fork == True  # noqa: E712

-             )

-         elif fork is False:

-             projects = projects.filter(

-                 model.Project.is_fork == False  # noqa: E712

-             )

- 

-     if tags:

-         if not isinstance(tags, (list, tuple)):

-             tags = [tags]

- 

-         projects = projects.filter(

-             model.Project.id == model.TagProject.project_id

-         ).filter(model.TagProject.tag.in_(tags))

- 

-     if pattern:

-         pattern = pattern.replace("*", "%")

-         if "%" in pattern:

-             projects = projects.filter(model.Project.name.ilike(pattern))

-         else:

-             projects = projects.filter(model.Project.name == pattern)

- 

-     if namespace:

-         projects = projects.filter(model.Project.namespace == namespace)

- 

-     query = session.query(model.Project).filter(

-         model.Project.id.in_(projects.subquery())

-     )

- 

-     if sort == "latest":

-         query = query.order_by(model.Project.date_created.desc())

-     elif sort == "oldest":

-         query = query.order_by(model.Project.date_created.asc())

-     else:

-         query = query.order_by(asc(func.lower(model.Project.name)))

- 

-     if start is not None:

-         query = query.offset(start)

- 

-     if limit is not None:

-         query = query.limit(limit)

- 

-     if count:

-         return query.count()

-     else:

-         return query.all()

- 

- 

- def list_users_projects(

-     session,

-     username,

-     fork=None,

-     tags=None,

-     namespace=None,

-     pattern=None,

-     start=None,

-     limit=None,

-     count=False,

-     sort=None,

-     exclude_groups=None,

-     private=None,

-     acls=None,

- ):

-     """List a users projects

-     """

-     projects = session.query(sqlalchemy.distinct(model.Project.id))

- 

-     if acls is None:

-         acls = ["main admin", "admin", "commit", "ticket"]

- 

-     if username is not None:

- 

-         projects = projects.filter(

-             # User created the project

-             sqlalchemy.and_(

-                 model.User.user == username,

-                 model.User.id == model.Project.user_id,

-             )

-         )

-         if "main admin" not in acls:

-             projects = projects.filter(model.User.id != model.Project.user_id)

- 

-         sub_q2 = session.query(model.Project.id).filter(

-             # User got admin or commit right

-             sqlalchemy.and_(

-                 model.User.user == username,

-                 model.User.id == model.ProjectUser.user_id,

-                 model.ProjectUser.project_id == model.Project.id,

-                 model.ProjectUser.access.in_(acls),

-             )

-         )

-         sub_q3 = session.query(model.Project.id).filter(

-             # User created a group that has admin or commit right

-             sqlalchemy.and_(

-                 model.User.user == username,

-                 model.PagureGroup.user_id == model.User.id,

-                 model.PagureGroup.group_type == "user",

-                 model.PagureGroup.id == model.ProjectGroup.group_id,

-                 model.Project.id == model.ProjectGroup.project_id,

-                 model.ProjectGroup.access.in_(acls),

-             )

-         )

-         sub_q4 = session.query(model.Project.id).filter(

-             # User is part of a group that has admin or commit right

-             sqlalchemy.and_(

-                 model.User.user == username,

-                 model.PagureUserGroup.user_id == model.User.id,

-                 model.PagureUserGroup.group_id == model.PagureGroup.id,

-                 model.PagureGroup.group_type == "user",

-                 model.PagureGroup.id == model.ProjectGroup.group_id,

-                 model.Project.id == model.ProjectGroup.project_id,

-                 model.ProjectGroup.access.in_(acls),

-             )

-         )

- 

-         # Exclude projects that the user has accessed via a group that we

-         # do not want to include

-         if exclude_groups:

-             sub_q3 = sub_q3.filter(

-                 model.PagureGroup.group_name.notin_(exclude_groups)

-             )

-             sub_q4 = sub_q4.filter(

-                 model.PagureGroup.group_name.notin_(exclude_groups)

-             )

- 

-         projects = projects.union(sub_q2).union(sub_q3).union(sub_q4)

- 

-     if not private:

-         projects = projects.filter(

-             model.Project.private == False  # noqa: E712

-         )

-     # No filtering is done if private == username i.e  if the owner of the

-     # project is viewing the project

-     elif isinstance(private, six.string_types) and private != username:

-         # All the public repo

-         subquery0 = session.query(

-             sqlalchemy.distinct(model.Project.id)

-         ).filter(

-             model.Project.private == False  # noqa: E712

-         )

-         sub_q1 = session.query(sqlalchemy.distinct(model.Project.id)).filter(

-             sqlalchemy.and_(

-                 model.Project.private == True,  # noqa: E712

-                 model.User.id == model.Project.user_id,

-                 model.User.user == private,

-             )

-         )

-         sub_q2 = session.query(model.Project.id).filter(

-             # User got admin or commit right

-             sqlalchemy.and_(

-                 model.Project.private == True,  # noqa: E712

-                 model.User.user == private,

-                 model.User.id == model.ProjectUser.user_id,

-                 model.ProjectUser.project_id == model.Project.id,

-                 model.ProjectUser.access.in_(acls),

-             )

-         )

-         sub_q3 = session.query(model.Project.id).filter(

-             # User created a group that has admin or commit right

-             sqlalchemy.and_(

-                 model.Project.private == True,  # noqa: E712

-                 model.User.user == private,

-                 model.PagureGroup.user_id == model.User.id,

-                 model.PagureGroup.group_type == "user",

-                 model.PagureGroup.id == model.ProjectGroup.group_id,

-                 model.Project.id == model.ProjectGroup.project_id,

-                 model.ProjectGroup.access.in_(acls),

-             )

-         )

-         sub_q4 = session.query(model.Project.id).filter(

-             # User is part of a group that has admin or commit right

-             sqlalchemy.and_(

-                 model.Project.private == True,  # noqa: E712

-                 model.User.user == private,

-                 model.PagureUserGroup.user_id == model.User.id,

-                 model.PagureUserGroup.group_id == model.PagureGroup.id,

-                 model.PagureGroup.group_type == "user",

-                 model.PagureGroup.id == model.ProjectGroup.group_id,

-                 model.Project.id == model.ProjectGroup.project_id,

-                 model.ProjectGroup.access.in_(acls),

-             )

-         )

- 

-         # Exclude projects that the user has accessed via a group that we

-         # do not want to include

-         if exclude_groups:

-             sub_q3 = sub_q3.filter(

-                 model.PagureGroup.group_name.notin_(exclude_groups)

-             )

-             sub_q4 = sub_q4.filter(

-                 model.PagureGroup.group_name.notin_(exclude_groups)

-             )

- 

-         projects = projects.filter(

-             model.Project.id.in_(

-                 subquery0.union(sub_q1)

-                 .union(sub_q2)

-                 .union(sub_q3)

-                 .union(sub_q4)

-             )

-         )

- 

-     if fork is not None:

-         if fork is True:

-             projects = projects.filter(

-                 model.Project.is_fork == True  # noqa: E712

-             )

-         elif fork is False:

-             projects = projects.filter(

-                 model.Project.is_fork == False  # noqa: E712

-             )

- 

-     if tags:

-         if not isinstance(tags, (list, tuple)):

-             tags = [tags]

- 

-         projects = projects.filter(

-             model.Project.id == model.TagProject.project_id

-         ).filter(model.TagProject.tag.in_(tags))

- 

-     if pattern:

-         pattern = pattern.replace("*", "%")

-         if "%" in pattern:

-             projects = projects.filter(model.Project.name.ilike(pattern))

-         else:

-             projects = projects.filter(model.Project.name == pattern)

- 

-     if namespace:

-         projects = projects.filter(model.Project.namespace == namespace)

- 

-     query = session.query(model.Project).filter(

-         model.Project.id.in_(projects.subquery())

-     )

- 

-     if sort == "latest":

-         query = query.order_by(model.Project.date_created.desc())

-     elif sort == "oldest":

-         query = query.order_by(model.Project.date_created.asc())

-     else:

-         query = query.order_by(asc(func.lower(model.Project.name)))

- 

-     if start is not None:

-         query = query.offset(start)

- 

-     if limit is not None:

-         query = query.limit(limit)

- 

-     if count:

-         return query.count()

-     else:

-         return query.all()

- 

- 

- def _get_project(session, name, user=None, namespace=None):

-     """Get a project from the database

-     """

-     case = pagure_config.get("CASE_SENSITIVE", False)

- 

-     query = session.query(model.Project)

- 

-     if not case:

-         query = query.filter(func.lower(model.Project.name) == name.lower())

-     else:

-         query = query.filter(model.Project.name == name)

- 

-     if namespace:

-         if not case:

-             query = query.filter(

-                 func.lower(model.Project.namespace) == namespace.lower()

-             )

-         else:

-             query = query.filter(model.Project.namespace == namespace)

-     else:

-         query = query.filter(model.Project.namespace == namespace)

- 

-     if user is not None:

-         query = (

-             query.filter(model.User.user == user)

-             .filter(model.User.id == model.Project.user_id)

-             .filter(model.Project.is_fork == True)  # noqa: E712

-         )

-     else:

-         query = query.filter(model.Project.is_fork == False)  # noqa: E712

- 

-     try:

-         return query.one()

-     except sqlalchemy.orm.exc.NoResultFound:

-         return None

- 

- 

- def search_issues(

-     session,

-     repo=None,

-     issueid=None,

-     issueuid=None,

-     status=None,

-     closed=False,

-     tags=None,

-     assignee=None,

-     author=None,

-     private=None,

-     priority=None,

-     milestones=None,

-     count=False,

-     offset=None,

-     limit=None,

-     search_pattern=None,

-     custom_search=None,

-     updated_after=None,

-     no_milestones=None,

-     order="desc",

-     order_key=None,

- ):

-     """ Retrieve one or more issues associated to a project with the given

-     criterias.

- 

-     Watch out that the closed argument is incompatible with the status

-     argument. The closed argument will return all the issues whose status

-     is not 'Open', otherwise it will return the issues having the specified

-     status.

-     The `tags` argument can be used to filter the issues returned based on

-     a certain tag.

-     If the `issueid` argument is specified a single Issue object (or None)

-     will be returned instead of a list of Issue objects.

- 

-     :arg session: the session to use to connect to the database.

-     :arg repo: a Project object to which the issues should be associated

-     :type repo: pagure.lib.model.Project

-     :kwarg issueid: the identifier of the issue to look for

-     :type issueid: int or None

-     :kwarg issueuid: the unique identifier of the issue to look for

-     :type issueuid: str or None

-     :kwarg status: the status of the issue to look for (incompatible with

-         the `closed` argument).

-     :type status: str or None

-     :kwarg closed: a boolean indicating whether the issue to retrieve are

-         closed or open (incompatible with the `status` argument).

-     :type closed: bool or None

-     :kwarg tags: a tag the issue(s) returned should be associated with

-     :type tags: str or list(str) or None

-     :kwarg assignee: the name of the user assigned to the issues to search

-     :type assignee: str or None

-     :kwarg author: the name of the user who created the issues to search

-     :type author: str or None

-     :kwarg private: boolean or string to use to include or exclude private

-         tickets. Defaults to False.

-         If False: private tickets are excluded

-         If None: private tickets are included

-         If user name is specified: private tickets reported by that user

-         are included.

-     :type private: False, None or str

-     :kwarg priority: the priority of the issues to search

-     :type priority: int or None

-     :kwarg milestones: a milestone the issue(s) returned should be

-         associated with.

-     :type milestones: str or list(str) or None

-     :kwarg count: a boolean to specify if the method should return the list

-         of Issues or just do a COUNT query.

-     :type count: boolean

-     :kwarg search_pattern: a string to search in issues title

-     :type search_pattern: str or None

-     :kwarg custom_search: a dictionary of key/values to be used when

-         searching issues with a custom key constraint

-     :type custom_search: dict or None

-     :kwarg updated_after: datetime's date format (e.g. 2016-11-15) used to

-         filter issues updated after that date

-     :type updated_after: str or None

-     :kwarg no_milestones: Request issues that do not have a milestone set yet

-     :type None, True, or False

-     :kwarg order: Order issues in 'asc' or 'desc' order.

-     :type order: None, str

-     :kwarg order_key: Order issues by database column

-     :type order_key: None, str

- 

-     :return: A single Issue object if issueid is specified, a list of Project

-         objects otherwise.

-     :rtype: Project or [Project]

- 

-     """

-     query = session.query(sqlalchemy.distinct(model.Issue.uid))

- 

-     if repo is not None:

-         query = query.filter(model.Issue.project_id == repo.id)

- 

-     if updated_after:

-         query = query.filter(model.Issue.last_updated >= updated_after)

- 

-     if issueid is not None:

-         query = query.filter(model.Issue.id == issueid)

- 

-     if issueuid is not None:

-         query = query.filter(model.Issue.uid == issueuid)

- 

-     if status is not None:

-         if status in ["Open", "Closed"]:

-             query = query.filter(model.Issue.status == status)

-         else:

-             query = query.filter(model.Issue.close_status == status)

-     if closed:

-         query = query.filter(model.Issue.status != "Open")

-     if priority:

-         query = query.filter(model.Issue.priority == priority)

-     if tags is not None and tags != []:

-         if isinstance(tags, six.string_types):

-             tags = [tags]

-         notags = []

-         ytags = []

-         for tag in tags:

-             if tag.startswith("!"):

-                 notags.append(tag[1:])

-             else:

-                 ytags.append(tag)

- 

-         if ytags:

-             sub_q2 = session.query(sqlalchemy.distinct(model.Issue.uid))

-             if repo is not None:

-                 sub_q2 = sub_q2.filter(model.Issue.project_id == repo.id)

-             sub_q2 = (

-                 sub_q2.filter(

-                     model.Issue.uid == model.TagIssueColored.issue_uid

-                 )

-                 .filter(model.TagIssueColored.tag_id == model.TagColored.id)

-                 .filter(model.TagColored.tag.in_(ytags))

-             )

-         if notags:

-             sub_q3 = session.query(sqlalchemy.distinct(model.Issue.uid))

-             if repo is not None:

-                 sub_q3 = sub_q3.filter(model.Issue.project_id == repo.id)

-             sub_q3 = (

-                 sub_q3.filter(

-                     model.Issue.uid == model.TagIssueColored.issue_uid

-                 )

-                 .filter(model.TagIssueColored.tag_id == model.TagColored.id)

-                 .filter(model.TagColored.tag.in_(notags))

-             )

-         # Adjust the main query based on the parameters specified

-         if ytags and not notags:

-             query = query.filter(model.Issue.uid.in_(sub_q2))

-         elif not ytags and notags:

-             query = query.filter(~model.Issue.uid.in_(sub_q3))

-         elif ytags and notags:

-             final_set = set([i[0] for i in sub_q2.all()]) - set(

-                 [i[0] for i in sub_q3.all()]

-             )

-             if final_set:

-                 query = query.filter(model.Issue.uid.in_(list(final_set)))

- 

-     if assignee is not None:

-         assignee = "%s" % assignee

-         if not pagure.utils.is_true(assignee, ["false", "0", "true", "1"]):

-             reverseassignee = False

-             if assignee.startswith("!"):

-                 reverseassignee = True

-                 assignee = assignee[1:]

- 

-             userassignee = (

-                 session.query(model.User.id)

-                 .filter(model.User.user == assignee)

-                 .subquery()

-             )

- 

-             if reverseassignee:

-                 sub = session.query(model.Issue.uid).filter(

-                     model.Issue.assignee_id == userassignee

-                 )

- 

-                 query = query.filter(~model.Issue.uid.in_(sub))

-             else:

-                 query = query.filter(model.Issue.assignee_id == userassignee)

-         elif pagure.utils.is_true(assignee):

-             query = query.filter(model.Issue.assignee_id.isnot(None))

-         else:

-             query = query.filter(model.Issue.assignee_id.is_(None))

-     if author is not None:

-         userauthor = (

-             session.query(model.User.id)

-             .filter(model.User.user == author)

-             .subquery()

-         )

-         query = query.filter(model.Issue.user_id == userauthor)

- 

-     if private is False:

-         query = query.filter(model.Issue.private == False)  # noqa: E712

-     elif isinstance(private, six.string_types):

-         userprivate = (

-             session.query(model.User.id)

-             .filter(model.User.user == private)

-             .subquery()

-         )

-         query = query.filter(

-             sqlalchemy.or_(

-                 model.Issue.private == False,  # noqa: E712

-                 sqlalchemy.and_(

-                     model.Issue.private == True,  # noqa: E712

-                     model.Issue.user_id == userprivate,

-                 ),

-                 sqlalchemy.and_(

-                     model.Issue.private == True,  # noqa: E712

-                     model.Issue.assignee_id == userprivate,

-                 ),

-             )

-         )

- 

-     if no_milestones and milestones is not None and milestones != []:

-         # Asking for issues with no milestone or a specific milestone

-         if isinstance(milestones, six.string_types):

-             milestones = [milestones]

-         query = query.filter(

-             (model.Issue.milestone.is_(None))

-             | (model.Issue.milestone.in_(milestones))

-         )

-     elif no_milestones:

-         # Asking for issues without a milestone

-         query = query.filter(model.Issue.milestone.is_(None))

-     elif milestones is not None and milestones != []:

-         # Asking for a single specific milestone

-         if isinstance(milestones, six.string_types):

-             milestones = [milestones]

-         query = query.filter(model.Issue.milestone.in_(milestones))

-     elif no_milestones is False:

-         # Asking for all ticket with a milestone

-         query = query.filter(model.Issue.milestone.isnot(None))

- 

-     if custom_search:

-         constraints = []

-         for key in custom_search:

-             value = custom_search[key]

-             if "*" in value:

-                 value = value.replace("*", "%")

-                 constraints.append(

-                     sqlalchemy.and_(

-                         model.IssueKeys.name == key,

-                         model.IssueValues.value.ilike(value),

-                     )

-                 )

-             else:

-                 constraints.append(

-                     sqlalchemy.and_(

-                         model.IssueKeys.name == key,

-                         model.IssueValues.value == value,

-                     )

-                 )

-         if constraints:

-             query = query.filter(

-                 model.Issue.uid == model.IssueValues.issue_uid

-             ).filter(model.IssueValues.key_id == model.IssueKeys.id)

-             query = query.filter(

-                 sqlalchemy.or_((const for const in constraints))

-             )

- 

-     query = session.query(model.Issue).filter(

-         model.Issue.uid.in_(query.subquery())

-     )

- 

-     if repo is not None:

-         query = query.filter(model.Issue.project_id == repo.id)

- 

-     if search_pattern is not None:

-         query = query.filter(

-             model.Issue.title.ilike("%%%s%%" % search_pattern)

-         )

- 

-     column = model.Issue.date_created

-     if order_key:

-         # If we are ordering by assignee, then order by the assignees'

-         # usernames

-         if order_key == "assignee":

-             # We must do a LEFT JOIN on model.Issue.assignee because there are

-             # two foreign keys on model.Issue tied to model.User. This tells

-             # SQLAlchemy which foreign key on model.User to order on.

-             query = query.outerjoin(

-                 model.User, model.Issue.assignee_id == model.User.id

-             )

-             column = model.User.user

-         # If we are ordering by user, then order by reporters' usernames

-         elif order_key == "user":

-             # We must do a LEFT JOIN on model.Issue.user because there are

-             # two foreign keys on model.Issue tied to model.User. This tells

-             # SQLAlchemy which foreign key on model.User to order on.

-             query = query.outerjoin(

-                 model.User, model.Issue.user_id == model.User.id

-             )

-             column = model.User.user

-         elif order_key in model.Issue.__table__.columns.keys():

-             column = getattr(model.Issue, order_key)

- 

-     if ("%s" % column.type) == "TEXT":

-         column = func.lower(column)

- 

-     # The priority is sorted differently because it is by weight and the lower

-     # the number, the higher the priority

-     if (order_key != "priority" and order == "asc") or (

-         order_key == "priority" and order == "desc"

-     ):

-         query = query.order_by(asc(column))

-     else:

-         query = query.order_by(desc(column))

- 

-     if issueid is not None or issueuid is not None:

-         output = query.first()

-     elif count:

-         output = query.count()

-     else:

-         if offset is not None:

-             query = query.offset(offset)

-         if limit:

-             query = query.limit(limit)

-         output = query.all()

- 

-     return output

- 

- 

- def get_tags_of_project(session, project, pattern=None):

-     """ Returns the list of tags associated with the issues of a project.

-     """

-     query = (

-         session.query(model.TagColored)

-         .filter(model.TagColored.tag != "")

-         .filter(model.TagColored.project_id == project.id)

-         .order_by(model.TagColored.tag)

-     )

- 

-     if pattern:

-         query = query.filter(

-             model.TagColored.tag.ilike(pattern.replace("*", "%"))

-         )

- 

-     return query.all()

- 

- 

- def get_tag(session, tag):

-     """ Returns a Tag object for the given tag text.

-     """

-     query = session.query(model.Tag).filter(model.Tag.tag == tag)

- 

-     return query.first()

- 

- 

- def get_colored_tag(session, tag, project_id):

-     """ Returns a TagColored object for the given tag text.

-     """

-     query = (

-         session.query(model.TagColored)

-         .filter(model.TagColored.tag == tag)

-         .filter(model.TagColored.project_id == project_id)

-     )

- 

-     return query.first()

- 

- 

- def search_pull_requests(

-     session,

-     requestid=None,

-     project_id=None,

-     project_id_from=None,

-     status=None,

-     author=None,

-     assignee=None,

-     count=False,

-     offset=None,

-     limit=None,

-     updated_after=None,

-     branch_from=None,

-     order="desc",

-     order_key=None,

-     search_pattern=None,

- ):

-     """ Retrieve the specified pull-requests.

-     """

- 

-     query = session.query(model.PullRequest)

- 

-     # by default sort request by date_created.

-     column = model.PullRequest.date_created

- 

-     if order_key == "last_updated":

-         column = model.PullRequest.last_updated

- 

-     if requestid:

-         query = query.filter(model.PullRequest.id == requestid)

- 

-     if updated_after:

-         query = query.filter(model.PullRequest.last_updated >= updated_after)

- 

-     if project_id:

-         query = query.filter(model.PullRequest.project_id == project_id)

- 

-     if project_id_from:

-         query = query.filter(

-             model.PullRequest.project_id_from == project_id_from

-         )

- 

-     if status is not None:

-         if isinstance(status, bool):

-             if status:

-                 query = query.filter(model.PullRequest.status == "Open")

-             else:

-                 query = query.filter(model.PullRequest.status != "Open")

-         else:

-             query = query.filter(model.PullRequest.status == status)

- 

-     if assignee is not None:

-         assignee = "%s" % assignee

-         if not pagure.utils.is_true(assignee, ["false", "0", "true", "1"]):

-             user2 = aliased(model.User)

-             if assignee.startswith("!"):

-                 sub = (

-                     session.query(model.PullRequest.uid)

-                     .filter(model.PullRequest.assignee_id == user2.id)

-                     .filter(user2.user == assignee[1:])

-                 )

- 

-                 query = query.filter(~model.PullRequest.uid.in_(sub))

-             else:

-                 query = query.filter(

-                     model.PullRequest.assignee_id == user2.id

-                 ).filter(user2.user == assignee)

-         elif pagure.utils.is_true(assignee):

-             query = query.filter(model.PullRequest.assignee_id.isnot(None))

-         else:

-             query = query.filter(model.PullRequest.assignee_id.is_(None))

- 

-     if author is not None:

-         user3 = aliased(model.User)

-         query = query.filter(model.PullRequest.user_id == user3.id).filter(

-             user3.user == author

-         )

- 

-     if branch_from is not None:

-         query = query.filter(model.PullRequest.branch_from == branch_from)

- 

-     if search_pattern is not None:

-         if "*" in search_pattern:

-             search_pattern = search_pattern.replace("*", "%")

-         else:

-             search_pattern = "%%%s%%" % search_pattern

-         query = query.filter(model.PullRequest.title.ilike(search_pattern))

- 

-     # Depending on the order, the query is sorted(default is desc)

-     if order == "asc":

-         query = query.order_by(asc(column))

-     else:

-         query = query.order_by(desc(column))

- 

-     if requestid:

-         output = query.first()

-     elif count:

-         output = query.count()

-     else:

-         if offset:

-             query = query.offset(offset)

-         if limit:

-             query = query.limit(limit)

-         output = query.all()

- 

-     return output

- 

- 

- def reopen_pull_request(session, request, user):

-     """ Re-Open the provided pull request

-     """

-     if request.status != "Closed":

-         raise pagure.exceptions.PagureException(

-             "Trying to reopen a pull request that is not closed"

-         )

-     user_obj = get_user(session, user)

-     request.status = "Open"

-     session.add(request)

-     session.flush()

-     log_action(session, request.status.lower(), request, user_obj)

-     pagure.lib.notify.notify_reopen_pull_request(request, user_obj)

-     pagure.lib.git.update_git(request, repo=request.project)

-     pagure.lib.add_pull_request_comment(

-         session,

-         request,

-         commit=None,

-         tree_id=None,

-         filename=None,

-         row=None,

-         comment="Pull-Request has been reopened by %s" % (user),

-         user=user,

-         notify=False,

-         notification=True,

-     )

-     pagure.lib.notify.log(

-         request.project,

-         topic="pull-request.reopened",

-         msg=dict(

-             pullrequest=request.to_json(public=True), agent=user_obj.username

-         ),

-         redis=REDIS,

-     )

- 

- 

- def close_pull_request(session, request, user, merged=True):

-     """ Close the provided pull-request.

-     """

-     user_obj = get_user(session, user)

- 

-     if merged is True:

-         request.status = "Merged"

-     else:

-         request.status = "Closed"

-     request.closed_by_id = user_obj.id

-     request.closed_at = datetime.datetime.utcnow()

-     session.add(request)

-     session.flush()

- 

-     log_action(session, request.status.lower(), request, user_obj)

- 

-     if merged is True:

-         pagure.lib.notify.notify_merge_pull_request(request, user_obj)

-     else:

-         pagure.lib.notify.notify_cancelled_pull_request(request, user_obj)

- 

-     pagure.lib.git.update_git(request, repo=request.project)

- 

-     pagure.lib.add_pull_request_comment(

-         session,

-         request,

-         commit=None,

-         tree_id=None,

-         filename=None,

-         row=None,

-         comment="Pull-Request has been %s by %s"

-         % (request.status.lower(), user),

-         user=user,

-         notify=False,

-         notification=True,

-     )

- 

-     pagure.lib.notify.log(

-         request.project,

-         topic="pull-request.closed",

-         msg=dict(

-             pullrequest=request.to_json(public=True),

-             merged=merged,

-             agent=user_obj.username,

-         ),

-         redis=REDIS,

-     )

- 

- 

- def reset_status_pull_request(session, project):

-     """ Reset the status of all opened Pull-Requests of a project.

-     """

-     session.query(model.PullRequest).filter(

-         model.PullRequest.project_id == project.id

-     ).filter(model.PullRequest.status == "Open").update(

-         {model.PullRequest.merge_status: None}

-     )

- 

-     session.commit()

- 

- 

- def add_attachment(repo, issue, attachmentfolder, user, filename, filestream):

-     """ Add a file to the attachments folder of repo and update git. """

-     _log.info(

-         "Adding file: %s to the git repo: %s",

-         repo.path,

-         werkzeug.secure_filename(filename),

-     )

- 

-     # Prefix the filename with a timestamp:

-     filename = "%s-%s" % (

-         hashlib.sha256(filestream.read()).hexdigest(),

-         werkzeug.secure_filename(filename),

-     )

-     filedir = os.path.join(attachmentfolder, repo.fullname, "files")

-     filepath = os.path.join(filedir, filename)

- 

-     if os.path.exists(filepath):

-         return filename

- 

-     if not os.path.exists(filedir):

-         os.makedirs(filedir)

- 

-     # Write file

-     filestream.seek(0)

-     with open(filepath, "wb") as stream:

-         stream.write(filestream.read())

- 

-     tasks.add_file_to_git.delay(

-         repo.name,

-         repo.namespace,

-         repo.user.username if repo.is_fork else None,

-         user.username,

-         issue.uid,

-         filename,

-     )

- 

-     return filename

- 

- 

- def get_issue_statuses(session):

-     """ Return the complete list of status an issue can have.

-     """

-     output = []

-     statuses = session.query(model.StatusIssue).all()

-     for status in statuses:

-         output.append(status.status)

-     return output

- 

- 

- def get_issue_comment(session, issue_uid, comment_id):

-     """ Return a specific comment of a specified issue.

-     """

-     query = (

-         session.query(model.IssueComment)

-         .filter(model.IssueComment.issue_uid == issue_uid)

-         .filter(model.IssueComment.id == comment_id)

-     )

- 

-     return query.first()

- 

- 

- def get_issue_comment_by_user_and_comment(

-     session, issue_uid, user_id, content

- ):

-     """ Return a specific comment of a specified issue.

-     """

-     query = (

-         session.query(model.IssueComment)

-         .filter(model.IssueComment.issue_uid == issue_uid)

-         .filter(model.IssueComment.user_id == user_id)

-         .filter(model.IssueComment.comment == content)

-     )

- 

-     return query.first()

- 

- 

- def get_request_comment(session, request_uid, comment_id):

-     """ Return a specific comment of a specified request.

-     """

-     query = (

-         session.query(model.PullRequestComment)

-         .filter(model.PullRequestComment.pull_request_uid == request_uid)

-         .filter(model.PullRequestComment.id == comment_id)

-     )

- 

-     return query.first()

- 

- 

- def get_issue_by_uid(session, issue_uid):

-     """ Return the issue corresponding to the specified unique identifier.

- 

-     :arg session: the session to use to connect to the database.

-     :arg issue_uid: the unique identifier of an issue. This identifier is

-         unique accross all projects on this pagure instance and should be

-         unique accross multiple pagure instances as well

-     :type issue_uid: str or None

- 

-     :return: A single Issue object.

-     :rtype: pagure.lib.model.Issue

- 

-     """

-     query = session.query(model.Issue).filter(model.Issue.uid == issue_uid)

-     return query.first()

- 

- 

- def get_request_by_uid(session, request_uid):

-     """ Return the request corresponding to the specified unique identifier.

- 

-     :arg session: the session to use to connect to the database.

-     :arg request_uid: the unique identifier of a request. This identifier is

-         unique accross all projects on this pagure instance and should be

-         unique accross multiple pagure instances as well

-     :type request_uid: str or None

- 

-     :return: A single Issue object.

-     :rtype: pagure.lib.model.PullRequest

- 

-     """

-     query = session.query(model.PullRequest).filter(

-         model.PullRequest.uid == request_uid

-     )

-     return query.first()

- 

- 

- def get_pull_request_flag_by_uid(session, request, flag_uid):

-     """ Return the flag corresponding to the specified unique identifier.

- 

-     :arg session: the session to use to connect to the database.

-     :arg request: the pull-request that was flagged

-     :arg flag_uid: the unique identifier of a request. This identifier is

-         unique accross all flags on this pagure instance and should be

-         unique accross multiple pagure instances as well

-     :type request_uid: str or None

- 

-     :return: A single Issue object.

-     :rtype: pagure.lib.model.PullRequestFlag

- 

-     """

-     query = (

-         session.query(model.PullRequestFlag)

-         .filter(model.PullRequestFlag.pull_request_uid == request.uid)

-         .filter(model.PullRequestFlag.uid == flag_uid.strip())

-     )

-     return query.first()

- 

- 

- def get_commit_flag_by_uid(session, commit_hash, flag_uid):

-     """ Return the flag corresponding to the specified unique identifier.

- 

-     :arg session: the session to use to connect to the database.

-     :arg commit_hash: the hash of the commit that got flagged

-     :arg flag_uid: the unique identifier of a request. This identifier is

-         unique accross all flags on this pagure instance and should be

-         unique accross multiple pagure instances as well

-     :type request_uid: str or None

- 

-     :return: A single Issue object.

-     :rtype: pagure.lib.model.PullRequestFlag

- 

-     """

-     query = (

-         session.query(model.CommitFlag)

-         .filter(model.CommitFlag.commit_hash == commit_hash)

-         .filter(model.CommitFlag.uid == flag_uid.strip() if flag_uid else None)

-     )

-     return query.first()

- 

- 

- def set_up_user(

-     session,

-     username,

-     fullname,

-     default_email,

-     emails=None,

-     ssh_key=None,

-     keydir=None,

- ):

-     """ Set up a new user into the database or update its information. """

-     user = search_user(session, username=username)

-     if not user:

-         user = model.User(

-             user=username, fullname=fullname, default_email=default_email

-         )

-         session.add(user)

-         session.flush()

- 

-     if user.fullname != fullname:

-         user.fullname = fullname

-         session.add(user)

-         session.flush()

- 

-     if emails:

-         emails = set(emails)

-     else:

-         emails = set()

-     emails.add(default_email)

-     for email in emails:

-         try:

-             add_email_to_user(session, user, email)

-         except pagure.exceptions.PagureException as err:

-             _log.exception(err)

- 

-     if ssh_key and not user.sshkeys:

-         update_user_ssh(session, user, ssh_key, keydir)

- 

-     return user

- 

- 

- def allowed_emailaddress(email):

-     """ check if email domains are restricted and if a given email address

-     is allowed. """

-     allowed_email_domains = pagure_config.get("ALLOWED_EMAIL_DOMAINS", None)

-     if allowed_email_domains:

-         for domain in allowed_email_domains:

-             if email.endswith(domain):

-                 return

-         raise pagure.exceptions.PagureException(

-             "The email address "

-             + email

-             + " "

-             + "is not in the list of allowed email domains:\n"

-             + "\n".join(allowed_email_domains)

-         )

- 

- 

- def add_email_to_user(session, user, user_email):

-     """ Add the provided email to the specified user. """

-     try:

-         allowed_emailaddress(user_email)

-     except pagure.exceptions.PagureException:

-         raise

-     emails = [email.email for email in user.emails]

-     if user_email not in emails:

-         useremail = model.UserEmail(user_id=user.id, email=user_email)

-         session.add(useremail)

-         session.flush()

-         if email_logs_count(session, user_email):

-             update_log_email_user(session, user_email, user)

- 

- 

- def update_user_ssh(session, user, ssh_key, keydir, update_only=False):

-     """ Set up a new user into the database or update its information. """

-     if isinstance(user, six.string_types):

-         user = get_user(session, user)

- 

-     if ssh_key:

-         for key in user.sshkeys:

-             session.delete(key)

-         for key in ssh_key.strip().split("\n"):

-             key = key.strip()

-             pagure.lib.add_sshkey_to_project_or_user(

-                 session=session,

-                 ssh_key=key,

-                 user=user,

-                 pushaccess=True,

-                 creator=user,

-             )

-         session.commit()

- 

-     if keydir:

-         create_user_ssh_keys_on_disk(user, keydir)

-         if update_only:

-             pagure.lib.tasks.gitolite_post_compile_only.delay()

-         else:

-             pagure.lib.git.generate_gitolite_acls(project=None)

-     session.add(user)

-     session.flush()

- 

- 

- def avatar_url_from_email(email, size=64, default="retro", dns=False):

-     """

-     Our own implementation since fas doesn't support this nicely yet.

-     """

-     if dns:  # pragma: no cover

-         # This makes an extra DNS SRV query, which can slow down our webapps.

-         # It is necessary for libravatar federation, though.

-         import libravatar

- 

-         return libravatar.libravatar_url(

-             openid=email, size=size, default=default

-         )

-     else:

-         query = urlencode({"s": size, "d": default})

-         email = email.encode("utf-8")

-         hashhex = hashlib.sha256(email).hexdigest()

-         return "https://seccdn.libravatar.org/avatar/%s?%s" % (hashhex, query)

- 

- 

- def update_tags(session, obj, tags, username):

-     """ Update the tags of a specified object (adding or removing them).

-     This object can be either an issue or a project.

- 

-     """

-     if isinstance(tags, six.string_types):

-         tags = [tags]

- 

-     toadd = set(tags) - set(obj.tags_text)

-     torm = set(obj.tags_text) - set(tags)

-     messages = []

-     if toadd:

-         add_tag_obj(session, obj=obj, tags=toadd, user=username)

-         messages.append(

-             "%s tagged with: %s"

-             % (obj.isa.capitalize(), ", ".join(sorted(toadd)))

-         )

- 

-     if torm:

-         remove_tags_obj(session, obj=obj, tags=torm, user=username)

-         messages.append(

-             "%s **un**tagged with: %s"

-             % (obj.isa.capitalize(), ", ".join(sorted(torm)))

-         )

- 

-     session.commit()

- 

-     return messages

- 

- 

- def update_dependency_issue(session, repo, issue, depends, username):

-     """ Update the dependency of a specified issue (adding or removing them)

- 

-     """

-     if isinstance(depends, six.string_types):

-         depends = [depends]

- 

-     toadd = set(depends) - set(issue.depending_text)

-     torm = set(issue.depending_text) - set(depends)

-     messages = []

- 

-     # Add issue depending

-     for depend in sorted([int(i) for i in toadd]):

-         messages.append("Issue marked as depending on: #%s" % depend)

-         issue_depend = search_issues(session, repo, issueid=depend)

-         if issue_depend is None:

-             continue

-         if issue_depend.id in issue.depending_text:  # pragma: no cover

-             # we should never be in this case but better safe than sorry...

-             continue

- 

-         add_issue_dependency(

-             session, issue=issue_depend, issue_blocked=issue, user=username

-         )

- 

-     # Remove issue depending

-     for depend in sorted([int(i) for i in torm]):

-         messages.append("Issue **un**marked as depending on: #%s" % depend)

-         issue_depend = search_issues(session, repo, issueid=depend)

-         if issue_depend is None:  # pragma: no cover

-             # We cannot test this as it would mean we managed to put in an

-             # invalid ticket as dependency earlier

-             continue

-         if issue_depend.id not in issue.depending_text:  # pragma: no cover

-             # we should never be in this case but better safe than sorry...

-             continue

- 

-         remove_issue_dependency(

-             session, issue=issue, issue_blocked=issue_depend, user=username

-         )

- 

-     session.commit()

-     return messages

- 

- 

- def update_blocked_issue(session, repo, issue, blocks, username):

-     """ Update the upstream dependency of a specified issue (adding or

-     removing them)

- 

-     """

-     if isinstance(blocks, six.string_types):

-         blocks = [blocks]

- 

-     toadd = set(blocks) - set(issue.blocking_text)

-     torm = set(issue.blocking_text) - set(blocks)

-     messages = []

- 

-     # Add issue blocked

-     for block in sorted([int(i) for i in toadd]):

-         messages.append("Issue marked as blocking: #%s" % block)

-         issue_block = search_issues(session, repo, issueid=block)

-         if issue_block is None:

-             continue

-         if issue_block.id in issue.blocking_text:  # pragma: no cover

-             # we should never be in this case but better safe than sorry...

-             continue

- 

-         add_issue_dependency(

-             session, issue=issue, issue_blocked=issue_block, user=username

-         )

-         session.commit()

- 

-     # Remove issue blocked

-     for block in sorted([int(i) for i in torm]):

-         messages.append("Issue **un**marked as blocking: #%s" % block)

-         issue_block = search_issues(session, repo, issueid=block)

-         if issue_block is None:  # pragma: no cover

-             # We cannot test this as it would mean we managed to put in an

-             # invalid ticket as dependency earlier

-             continue

- 

-         if issue_block.id not in issue.blocking_text:  # pragma: no cover

-             # we should never be in this case but better safe than sorry...

-             continue

- 

-         remove_issue_dependency(

-             session, issue=issue_block, issue_blocked=issue, user=username

-         )

- 

-     session.commit()

-     return messages

- 

- 

- def add_user_pending_email(session, userobj, email):

-     """ Add the provided email to the specified user.

-     """

-     try:

-         allowed_emailaddress(email)

-     except pagure.exceptions.PagureException:

-         raise

-     other_user = search_user(session, email=email)

-     if other_user and other_user != userobj:

-         raise pagure.exceptions.PagureException(

-             "Someone else has already registered this email"

-         )

- 

-     pending_email = search_pending_email(session, email=email)

-     if pending_email:

-         raise pagure.exceptions.PagureException(

-             "This email is already pending confirmation"

-         )

- 

-     tmpemail = pagure.lib.model.UserEmailPending(

-         user_id=userobj.id,

-         token=pagure.lib.login.id_generator(40),

-         email=email,

-     )

-     session.add(tmpemail)

-     session.flush()

- 

-     pagure.lib.notify.notify_new_email(tmpemail, user=userobj)

- 

- 

- def resend_pending_email(session, userobj, email):

-     """ Resend to the user the confirmation email for the provided email

-     address.

-     """

-     other_user = search_user(session, email=email)

-     if other_user and other_user != userobj:

-         raise pagure.exceptions.PagureException(

-             "Someone else has already registered this email address"

-         )

- 

-     pending_email = search_pending_email(session, email=email)

-     if not pending_email:

-         raise pagure.exceptions.PagureException(

-             "This email address has already been confirmed"

-         )

- 

-     pending_email.token = pagure.lib.login.id_generator(40)

-     session.add(pending_email)

-     session.flush()

- 

-     pagure.lib.notify.notify_new_email(pending_email, user=userobj)

- 

- 

- def search_pending_email(session, email=None, token=None):

-     """ Searches the database for the pending email matching the given

-     criterias.

- 

-     :arg session: the session to use to connect to the database.

-     :kwarg email: the email to look for

-     :type email: string or None

-     :kwarg token: the token of the pending email to look for

-     :type token: string or None

-     :return: A single UserEmailPending object

-     :rtype: UserEmailPending

- 

-     """

-     query = session.query(model.UserEmailPending)

- 

-     if email is not None:

-         query = query.filter(model.UserEmailPending.email == email)

- 

-     if token is not None:

-         query = query.filter(model.UserEmailPending.token == token)

- 

-     output = query.first()

- 

-     return output

- 

- 

- def generate_hook_token(session):

-     """ For each project in the database, re-generate a unique hook_token.

- 

-     """

- 

-     for project in search_projects(session):

-         project.hook_token = pagure.lib.login.id_generator(40)

-         session.add(project)

-     session.commit()

- 

- 

- def get_group_types(session, group_type=None):

-     """ Return the list of type a group can have.

- 

-     """

-     query = session.query(model.PagureGroupType).order_by(

-         model.PagureGroupType.group_type

-     )

- 

-     if group_type:

-         query = query.filter(model.PagureGroupType.group_type == group_type)

- 

-     return query.all()

- 

- 

- def search_groups(

-     session,

-     pattern=None,

-     group_name=None,

-     group_type=None,

-     display_name=None,

-     offset=None,

-     limit=None,

-     count=False,

- ):

-     """ Return the groups based on the criteria specified.

- 

-     """

-     query = session.query(model.PagureGroup).order_by(

-         model.PagureGroup.group_type

-     )

- 

-     if pattern:

-         pattern = pattern.replace("*", "%")

-         query = query.filter(

-             sqlalchemy.or_(

-                 model.PagureGroup.group_name.ilike(pattern),

-                 model.PagureGroup.display_name.ilike(pattern),

-             )

-         )

- 

-     if group_name:

-         query = query.filter(model.PagureGroup.group_name == group_name)

- 

-     if display_name:

-         query = query.filter(model.PagureGroup.display_name == display_name)

- 

-     if group_type:

-         query = query.filter(model.PagureGroup.group_type == group_type)

- 

-     if offset:

-         query = query.offset(offset)

-     if limit:

-         query = query.limit(limit)

- 

-     if group_name:

-         return query.first()

-     elif count:

-         return query.count()

-     else:

-         return query.all()

- 

- 

- def add_user_to_group(

-     session, username, group, user, is_admin, from_external=False

- ):

-     """ Add the specified user to the given group.

- 

-     from_external indicates whether this is a remotely synced group.

-     """

-     new_user = search_user(session, username=username)

-     if not new_user:

-         raise pagure.exceptions.PagureException(

-             "No user `%s` found" % username

-         )

- 

-     action_user = user

-     user = search_user(session, username=user)

-     if not user:

-         raise pagure.exceptions.PagureException(

-             "No user `%s` found" % action_user

-         )

- 

-     if (

-         not from_external

-         and group.group_name not in user.groups

-         and not is_admin

-         and user.username != group.creator.username

-     ):

-         raise pagure.exceptions.PagureException(

-             "You are not allowed to add user to this group"

-         )

- 

-     for guser in group.users:

-         if guser.username == new_user.username:

-             return "User `%s` already in the group, nothing to change." % (

-                 new_user.username

-             )

- 

-     grp = model.PagureUserGroup(group_id=group.id, user_id=new_user.id)

-     session.add(grp)

-     session.flush()

-     return "User `%s` added to the group `%s`." % (

-         new_user.username,

-         group.group_name,

-     )

- 

- 

- def edit_group_info(session, group, display_name, description, user, is_admin):

-     """ Edit the information regarding a given group.

-     """

-     action_user = user

-     user = search_user(session, username=user)

-     if not user:

-         raise pagure.exceptions.PagureException(

-             "No user `%s` found" % action_user

-         )

- 

-     if (

-         group.group_name not in user.groups

-         and not is_admin

-         and user.username != group.creator.username

-     ):

-         raise pagure.exceptions.PagureException(

-             "You are not allowed to edit this group"

-         )

- 

-     edits = []

-     if display_name and display_name != group.display_name:

-         group.display_name = display_name

-         edits.append("display_name")

-     if description and description != group.description:

-         group.description = description

-         edits.append("description")

- 

-     session.add(group)

-     session.flush()

- 

-     msg = "Nothing changed"

-     if edits:

-         pagure.lib.notify.log(

-             None,

-             topic="group.edit",

-             msg=dict(

-                 group=group.to_json(public=True),

-                 fields=edits,

-                 agent=user.username,

-             ),

-             redis=REDIS,

-         )

-         msg = 'Group "%s" (%s) edited' % (group.display_name, group.group_name)

- 

-     return msg

- 

- 

- def delete_user_of_group(

-     session,

-     username,

-     groupname,

-     user,

-     is_admin,

-     force=False,

-     from_external=False,

- ):

-     """ Removes the specified user from the given group.

-     """

-     group_obj = search_groups(session, group_name=groupname)

- 

-     if not group_obj:

-         raise pagure.exceptions.PagureException(

-             "No group `%s` found" % groupname

-         )

- 

-     drop_user = search_user(session, username=username)

-     if not drop_user:

-         raise pagure.exceptions.PagureException(

-             "No user `%s` found" % username

-         )

- 

-     action_user = user

-     user = search_user(session, username=user)

-     if not user:

-         raise pagure.exceptions.PagureException(

-             "Could not find user %s" % action_user

-         )

- 

-     if (

-         not from_external

-         and group_obj.group_name not in user.groups

-         and not is_admin

-     ):

-         raise pagure.exceptions.PagureException(

-             "You are not allowed to remove user from this group"

-         )

- 

-     if drop_user.username == group_obj.creator.username and not force:

-         raise pagure.exceptions.PagureException(

-             "The creator of a group cannot be removed"

-         )

- 

-     user_grp = get_user_group(session, drop_user.id, group_obj.id)

-     if not user_grp:

-         raise pagure.exceptions.PagureException(

-             "User `%s` could not be found in the group `%s`"

-             % (username, groupname)

-         )

- 

-     session.delete(user_grp)

-     session.flush()

- 

- 

- def add_group(

-     session,

-     group_name,

-     display_name,

-     description,

-     group_type,

-     user,

-     is_admin,

-     blacklist,

- ):

-     """ Creates a new group with the given information.

-     """

-     if " " in group_name:

-         raise pagure.exceptions.PagureException(

-             "Spaces are not allowed in group names: %s" % group_name

-         )

- 

-     if group_name in blacklist:

-         raise pagure.exceptions.PagureException(

-             "This group name has been blacklisted, "

-             "please choose another one"

-         )

- 

-     group_types = ["user"]

-     if is_admin:

-         group_types = [grp.group_type for grp in get_group_types(session)]

- 

-     if not is_admin:

-         group_type = "user"

- 

-     if group_type not in group_types:

-         raise pagure.exceptions.PagureException("Invalide type for this group")

- 

-     username = user

-     user = search_user(session, username=user)

-     if not user:

-         raise pagure.exceptions.PagureException(

-             "Could not find user %s" % username

-         )

- 

-     group = search_groups(session, group_name=group_name)

-     if group:

-         raise pagure.exceptions.PagureException(

-             "There is already a group named %s" % group_name

-         )

- 

-     display = search_groups(session, display_name=display_name)

-     if display:

-         raise pagure.exceptions.PagureException(

-             "There is already a group with display name `%s` created."

-             % display_name

-         )

- 

-     grp = pagure.lib.model.PagureGroup(

-         group_name=group_name,

-         display_name=display_name,

-         description=description,

-         group_type=group_type,

-         user_id=user.id,

-     )

-     session.add(grp)

-     session.flush()

- 

-     return add_user_to_group(

-         session, user.username, grp, user.username, is_admin

-     )

- 

- 

- def get_user_group(session, userid, groupid):

-     """ Return a specific user_group for the specified group and user

-     identifiers.

- 

-     :arg session: the session with which to connect to the database.

- 

-     """

-     query = (

-         session.query(model.PagureUserGroup)

-         .filter(model.PagureUserGroup.user_id == userid)

-         .filter(model.PagureUserGroup.group_id == groupid)

-     )

- 

-     return query.first()

- 

- 

- def is_group_member(session, user, groupname):

-     """ Return whether the user is a member of the specified group. """

-     if not user:

-         return False

- 

-     user = search_user(session, username=user)

-     if not user:

-         return False

- 

-     return groupname in user.groups

- 

- 

- def get_api_token(session, token_str):

-     """ Return the Token object corresponding to the provided token string

-     if there is any, returns None otherwise.

-     """

-     query = session.query(model.Token).filter(model.Token.id == token_str)

- 

-     return query.first()

- 

- 

- def get_acls(session, restrict=None):

-     """ Returns all the possible ACLs a token can have according to the

-     database.

-     """

-     query = session.query(model.ACL).order_by(model.ACL.name)

-     if restrict:

-         if isinstance(restrict, list):

-             query = query.filter(model.ACL.name.in_(restrict))

-         else:

-             query = query.filter(model.ACL.name == restrict)

- 

-     return query.all()

- 

- 

- def add_token_to_user(session, project, acls, username, description=None):

-     """ Create a new token for the specified user on the specified project

-     with the given ACLs.

-     """

-     acls_obj = session.query(model.ACL).filter(model.ACL.name.in_(acls)).all()

- 

-     user = search_user(session, username=username)

- 

-     token = pagure.lib.model.Token(

-         id=pagure.lib.login.id_generator(64),

-         user_id=user.id,

-         project_id=project.id if project else None,

-         description=description,

-         expiration=datetime.datetime.utcnow() + datetime.timedelta(days=60),

-     )

-     session.add(token)

-     session.flush()

- 

-     for acl in acls_obj:

-         item = pagure.lib.model.TokenAcl(token_id=token.id, acl_id=acl.id)

-         session.add(item)

- 

-     session.commit()

- 

-     return "Token created"

- 

- 

- def _convert_markdown(md_processor, text):

-     """ Small function converting the text to html using the given markdown

-     processor.

- 

-     This was done in order to make testing it easier.

-     """

-     return md_processor.convert(text)

- 

- 

- def text2markdown(text, extended=True, readme=False):

-     """ Simple text to html converter using the markdown library.

-     """

-     extensions = [

-         "markdown.extensions.def_list",

-         "markdown.extensions.fenced_code",

-         "markdown.extensions.tables",

-         "markdown.extensions.smart_strong",

-         # All of the above are the .extra extensions

-         # w/o the "attribute lists" one

-         "markdown.extensions.admonition",

-         "markdown.extensions.codehilite",

-         "markdown.extensions.sane_lists",

-         "markdown.extensions.toc",

-     ]

-     # Some extensions are enabled for READMEs and disabled otherwise

-     if readme:

-         extensions.extend(

-             ["markdown.extensions.abbr", "markdown.extensions.footnotes"]

-         )

-     else:

-         extensions.append("markdown.extensions.nl2br")

-     if extended:

-         # Install our markdown modifications

-         extensions.append("pagure.pfmarkdown")

- 

-     md_processor = markdown.Markdown(

-         extensions=extensions,

-         extension_configs={

-             "markdown.extensions.codehilite": {"guess_lang": False}

-         },

-         output_format="xhtml5",

-     )

- 

-     if text:

-         try:

-             text = _convert_markdown(md_processor, text)

-         except Exception:

-             _log.debug(

-                 "A markdown error occured while processing: ``%s``", text

-             )

-         return clean_input(text)

- 

-     return ""

- 

- 

- def filter_img_src(name, value):

-     """ Filter in img html tags images coming from a different domain. """

-     if name in ("alt", "height", "width", "class", "data-src"):

-         return True

-     if name == "src":

-         parsed = urlparse(value)

-         return (not parsed.netloc) or parsed.netloc == urlparse(

-             pagure_config["APP_URL"]

-         ).netloc

-     return False

- 

- 

- def clean_input(text, ignore=None):

-     """ For a given html text, escape everything we do not want to support

-     to avoid potential security breach.

-     """

-     if ignore and not isinstance(ignore, (tuple, set, list)):

-         ignore = [ignore]

- 

-     bleach_v = bleach.__version__.split(".")

-     for idx, val in enumerate(bleach_v):

-         try:

-             val = int(val)

-         except ValueError:  # pragma: no cover

-             pass

-         bleach_v[idx] = val

- 

-     attrs = bleach.ALLOWED_ATTRIBUTES.copy()

-     attrs["table"] = ["class"]

-     attrs["span"] = ["class", "id"]

-     attrs["div"] = ["class"]

-     attrs["td"] = ["align"]

-     attrs["th"] = ["align"]

-     if not ignore or "img" not in ignore:

-         # newer bleach need three args for attribute callable

-         if tuple(bleach_v) >= (2, 0, 0):  # pragma: no cover

-             attrs["img"] = lambda tag, name, val: filter_img_src(name, val)

-         else:

-             attrs["img"] = filter_img_src

- 

-     tags = bleach.ALLOWED_TAGS + [

-         "p",

-         "br",

-         "div",

-         "h1",

-         "h2",

-         "h3",

-         "h4",

-         "h5",

-         "h6",

-         "table",

-         "td",

-         "tr",

-         "th",

-         "thead",

-         "tbody",

-         "col",

-         "pre",

-         "img",

-         "hr",

-         "dl",

-         "dt",

-         "dd",

-         "span",

-         "kbd",

-         "var",

-         "del",

-         "cite",

-         "noscript",

-     ]

-     if ignore:

-         for tag in ignore:

-             if tag in tags:

-                 tags.remove(tag)

- 

-     kwargs = {"tags": tags, "attributes": attrs}

- 

-     # newer bleach allow to customize the protocol supported

-     if tuple(bleach_v) >= (1, 5, 0):  # pragma: no cover

-         protocols = bleach.ALLOWED_PROTOCOLS + ["irc", "ircs"]

-         kwargs["protocols"] = protocols

- 

-     return bleach.clean(text, **kwargs)

- 

- 

- def could_be_text(text):

-     """ Returns whether we think this chain of character could be text or not

-     """

-     try:

-         text.decode("utf-8")

-         return True

-     except (UnicodeDecodeError, UnicodeEncodeError):

-         return False

- 

- 

- def get_pull_request_of_user(

-     session,

-     username,

-     status=None,

-     filed=None,

-     actionable=None,

-     offset=None,

-     limit=None,

-     count=False,

- ):

-     """List the opened pull-requests of an user.

-     These pull-requests have either been opened by that user or against

-     projects that user has commit on.

- 

-     If filed: only the PRs opened/filed by the specified username will be

-     returned.

-     If actionable: only the PRs not opened/filed by the specified username

-     will be returned.

-     """

-     projects = session.query(sqlalchemy.distinct(model.Project.id))

- 

-     projects = projects.filter(

-         # User created the project

-         sqlalchemy.and_(

-             model.User.user == username, model.User.id == model.Project.user_id

-         )

-     )

-     sub_q2 = session.query(sqlalchemy.distinct(model.Project.id)).filter(

-         # User got commit right

-         sqlalchemy.and_(

-             model.User.user == username,

-             model.User.id == model.ProjectUser.user_id,

-             model.ProjectUser.project_id == model.Project.id,

-             sqlalchemy.or_(

-                 model.ProjectUser.access == "admin",

-                 model.ProjectUser.access == "commit",

-             ),

-         )

-     )

-     sub_q3 = session.query(sqlalchemy.distinct(model.Project.id)).filter(

-         # User created a group that has commit right

-         sqlalchemy.and_(

-             model.User.user == username,

-             model.PagureGroup.user_id == model.User.id,

-             model.PagureGroup.group_type == "user",

-             model.PagureGroup.id == model.ProjectGroup.group_id,

-             model.Project.id == model.ProjectGroup.project_id,

-             sqlalchemy.or_(

-                 model.ProjectGroup.access == "admin",

-                 model.ProjectGroup.access == "commit",

-             ),

-         )

-     )

-     sub_q4 = session.query(sqlalchemy.distinct(model.Project.id)).filter(

-         # User is part of a group that has commit right

-         sqlalchemy.and_(

-             model.User.user == username,

-             model.PagureUserGroup.user_id == model.User.id,

-             model.PagureUserGroup.group_id == model.PagureGroup.id,

-             model.PagureGroup.group_type == "user",

-             model.PagureGroup.id == model.ProjectGroup.group_id,

-             model.Project.id == model.ProjectGroup.project_id,

-             sqlalchemy.or_(

-                 model.ProjectGroup.access == "admin",

-                 model.ProjectGroup.access == "commit",

-             ),

-         )

-     )

- 

-     projects = projects.union(sub_q2).union(sub_q3).union(sub_q4)

- 

-     query = session.query(sqlalchemy.distinct(model.PullRequest.uid)).filter(

-         model.PullRequest.project_id.in_(projects.subquery())

-     )

- 

-     query_2 = session.query(sqlalchemy.distinct(model.PullRequest.uid)).filter(

-         # User open the PR

-         sqlalchemy.and_(

-             model.PullRequest.user_id == model.User.id,

-             model.User.user == username,

-         )

-     )

- 

-     final_sub = query.union(query_2)

- 

-     query = (

-         session.query(model.PullRequest)

-         .filter(model.PullRequest.uid.in_(final_sub.subquery()))

-         .order_by(model.PullRequest.date_created.desc())

-     )

- 

-     if status:

-         query = query.filter(model.PullRequest.status == status)

- 

-     if filed:

-         query = query.filter(

-             model.PullRequest.user_id == model.User.id,

-             model.User.user == filed,

-         )

-     elif actionable:

-         query = query.filter(

-             model.PullRequest.user_id == model.User.id,

-             model.User.user != actionable,

-         )

- 

-     if offset:

-         query = query.offset(offset)

-     if limit:

-         query = query.limit(limit)

- 

-     if count:

-         return query.count()

-     else:

-         return query.all()

- 

- 

- def update_watch_status(session, project, user, watch):

-     """ Update the user status for watching a project.

- 

-     The watch status can be:

-         -1: reset the watch status to default

-          0: unwatch, don't notify the user of anything

-          1: watch issues and PRs

-          2: watch commits

-          3: watch issues, PRs and commits

- 

-     """

-     if watch not in ["-1", "0", "1", "2", "3"]:

-         raise pagure.exceptions.PagureException(

-             'The watch value of "%s" is invalid' % watch

-         )

- 

-     user_obj = get_user(session, user)

- 

-     watcher = (

-         session.query(model.Watcher)

-         .filter(

-             sqlalchemy.and_(

-                 model.Watcher.project_id == project.id,

-                 model.Watcher.user_id == user_obj.id,

-             )

-         )

-         .first()

-     )

- 

-     if watch == "-1":

-         if not watcher:

-             return "Watch status is already reset"

- 

-         session.delete(watcher)

-         session.flush()

-         return "Watch status reset"

- 

-     should_watch_issues = False

-     should_watch_commits = False

-     if watch == "1":

-         should_watch_issues = True

-     elif watch == "2":

-         should_watch_commits = True

-     elif watch == "3":

-         should_watch_issues = True

-         should_watch_commits = True

- 

-     if not watcher:

-         watcher = model.Watcher(

-             project_id=project.id,

-             user_id=user_obj.id,

-             watch_issues=should_watch_issues,

-             watch_commits=should_watch_commits,

-         )

-     else:

-         watcher.watch_issues = should_watch_issues

-         watcher.watch_commits = should_watch_commits

- 

-     session.add(watcher)

-     session.flush()

- 

-     if should_watch_issues and should_watch_commits:

-         return "You are now watching issues, PRs, and commits on this project"

-     elif should_watch_issues:

-         return "You are now watching issues and PRs on this project"

-     elif should_watch_commits:

-         return "You are now watching commits on this project"

-     else:

-         return "You are no longer watching this project"

- 

- 

- def get_watch_level_on_repo(

-     session, user, repo, repouser=None, namespace=None

- ):

-     """ Get a list representing the watch level of the user on the project.

-     """

-     # If a user wasn't passed in, we can't determine their watch level

-     if user is None:

-         return []

-     elif isinstance(user, six.string_types):

-         user_obj = search_user(session, username=user)

-     else:

-         user_obj = search_user(session, username=user.username)

-     # If we can't find the user in the database, we can't determine their

-     # watch level

-     if not user_obj:

-         return []

- 

-     # If the project passed in a Project for the repo parameter, then we

-     # don't need to query for it

-     if isinstance(repo, model.Project):

-         project = repo

-     # If the project passed in a string, then assume it is a project name

-     elif isinstance(repo, six.string_types):

-         project = _get_project(

-             session, repo, user=repouser, namespace=namespace

-         )

-     else:

-         raise RuntimeError(

-             'The passed in repo is an invalid type of "{0}"'.format(

-                 type(repo).__name__

-             )

-         )

- 

-     # If the project is not found, we can't determine the involvement of the

-     # user in the project

-     if not project:

-         return []

- 

-     query = (

-         session.query(model.Watcher)

-         .filter(model.Watcher.user_id == user_obj.id)

-         .filter(model.Watcher.project_id == project.id)

-     )

- 

-     watcher = query.first()

-     # If there is a watcher issue, that means the user explicitly set a watch

-     # level on the project

-     if watcher:

-         if watcher.watch_issues and watcher.watch_commits:

-             return ["issues", "commits"]

-         elif watcher.watch_issues:

-             return ["issues"]

-         elif watcher.watch_commits:

-             return ["commits"]

-         else:

-             # If a watcher entry is set and both are set to False, that

-             # means the user explicitly asked to not be notified

-             return []

- 

-     # If the user is the project owner, by default they will be watching

-     # issues and PRs

-     if user_obj.username == project.user.username:

-         return ["issues"]

-     # If the user is a contributor, by default they will be watching issues

-     # and PRs

-     for contributor in project.users:

-         if user_obj.username == contributor.username:

-             return ["issues"]

-     # If the user is in a project group, by default they will be watching

-     # issues and PRs

-     for group in project.groups:

-         for guser in group.users:

-             if user_obj.username == guser.username:

-                 return ["issues"]

-     # If no other condition is true, then they are not explicitly watching

-     # the project or are not involved in the project to the point that

-     # comes with aq default watch level

-     return []

- 

- 

- def user_watch_list(session, user, exclude_groups=None):

-     """ Returns list of all the projects which the user is watching """

- 

-     user_obj = search_user(session, username=user)

-     if not user_obj:

-         return []

- 

-     unwatched = (

-         session.query(model.Watcher)

-         .filter(model.Watcher.user_id == user_obj.id)

-         .filter(model.Watcher.watch_issues == False)  # noqa: E712

-         .filter(model.Watcher.watch_commits == False)  # noqa: E712

-     )

- 

-     unwatched_list = []

-     if unwatched:

-         unwatched_list = [unwatch.project for unwatch in unwatched.all()]

- 

-     watched = (

-         session.query(model.Watcher)

-         .filter(model.Watcher.user_id == user_obj.id)

-         .filter(model.Watcher.watch_issues == True)  # noqa: E712

-         .filter(model.Watcher.watch_commits == True)  # noqa: E712

-     )

- 

-     watched_list = []

-     if watched:

-         watched_list = [watch.project for watch in watched.all()]

- 

-     user_projects = search_projects(

-         session, username=user_obj.user, exclude_groups=exclude_groups

-     )

-     watch = set(watched_list + user_projects)

- 

-     for project in user_projects:

-         if project in unwatched_list:

-             watch.remove(project)

- 

-     return sorted(list(watch), key=lambda proj: proj.name)

- 

- 

- def set_watch_obj(session, user, obj, watch_status):

-     """ Set the watch status of the user on the specified object.

- 

-     Objects can be either an issue or a pull-request

-     """

- 

-     user_obj = get_user(session, user)

- 

-     if obj.isa == "issue":

-         query = (

-             session.query(model.IssueWatcher)

-             .filter(model.IssueWatcher.user_id == user_obj.id)

-             .filter(model.IssueWatcher.issue_uid == obj.uid)

-         )

-     elif obj.isa == "pull-request":

-         query = (

-             session.query(model.PullRequestWatcher)

-             .filter(model.PullRequestWatcher.user_id == user_obj.id)

-             .filter(model.PullRequestWatcher.pull_request_uid == obj.uid)

-         )

-     else:

-         raise pagure.exceptions.InvalidObjectException(

-             'Unsupported object found: "%s"' % obj

-         )

- 

-     dbobj = query.first()

- 

-     if not dbobj:

-         if obj.isa == "issue":

-             dbobj = model.IssueWatcher(

-                 user_id=user_obj.id, issue_uid=obj.uid, watch=watch_status

-             )

-         elif obj.isa == "pull-request":

-             dbobj = model.PullRequestWatcher(

-                 user_id=user_obj.id,

-                 pull_request_uid=obj.uid,

-                 watch=watch_status,

-             )

-     else:

-         dbobj.watch = watch_status

- 

-     session.add(dbobj)

- 

-     output = "You are no longer watching this %s" % obj.isa

-     if watch_status:

-         output = "You are now watching this %s" % obj.isa

-     return output

- 

- 

- def get_watch_list(session, obj):

-     """ Return a list of all the users that are watching the "object"

-     """

-     private = False

-     if obj.isa == "issue":

-         private = obj.private

-         obj_watchers_query = session.query(model.IssueWatcher).filter(

-             model.IssueWatcher.issue_uid == obj.uid

-         )

-     elif obj.isa == "pull-request":

-         obj_watchers_query = session.query(model.PullRequestWatcher).filter(

-             model.PullRequestWatcher.pull_request_uid == obj.uid

-         )

-     else:

-         raise pagure.exceptions.InvalidObjectException(

-             'Unsupported object found: "%s"' % obj

-         )

- 

-     project_watchers_query = session.query(model.Watcher).filter(

-         model.Watcher.project_id == obj.project.id

-     )

- 

-     users = set()

- 

-     # Add the person who opened the object

-     users.add(obj.user.username)

- 

-     # Add all the people who commented on that object

-     for comment in obj.comments:

-         users.add(comment.user.username)

- 

-     # Add the user of the project

-     users.add(obj.project.user.username)

- 

-     # Add the regular contributors

-     for contributor in obj.project.users:

-         users.add(contributor.username)

- 

-     # Add people in groups with commit access

-     for group in obj.project.groups:

-         for member in group.users:

-             users.add(member.username)

- 

-     # If the issue isn't private:

-     if not private:

-         # Add all the people watching the repo, remove those who opted-out

-         for watcher in project_watchers_query.all():

-             if watcher.watch_issues:

-                 users.add(watcher.user.username)

-             else:

-                 if watcher.user.username in users:

-                     users.remove(watcher.user.username)

- 

-     # Add all the people watching this object, remove those who opted-out

-     for watcher in obj_watchers_query.all():

-         if watcher.watch:

-             users.add(watcher.user.username)

-         else:

-             if watcher.user.username in users:

-                 users.remove(watcher.user.username)

- 

-     return users

- 

- 

- def save_report(session, repo, name, url, username):

-     """ Save the report of issues based on the given URL of the project.

-     """

-     url_obj = urlparse(url)

-     url = url_obj.geturl().replace(url_obj.query, "")

-     query = {}

-     for k, v in parse_qsl(url_obj.query):

-         if k in query:

-             if isinstance(query[k], list):

-                 query[k].append(v)

-             else:

-                 query[k] = [query[k], v]

-         else:

-             query[k] = v

-     reports = repo.reports

-     reports[name] = query

-     repo.reports = reports

-     session.add(repo)

- 

- 

- def set_custom_key_fields(session, project, fields, types, data, notify=None):

-     """ Set or update the custom key fields of a project with the values

-     provided.  "data" is currently only used for lists

-     """

- 

-     current_keys = {}

-     for key in project.issue_keys:

-         current_keys[key.name] = key

- 

-     for idx, key in enumerate(fields):

-         if types[idx] != "list":

-             # Only Lists use data, strip it otherwise

-             data[idx] = None

-         else:

-             if data[idx]:

-                 data[idx] = [item.strip() for item in data[idx].split(",")]

- 

-         if notify and notify[idx] == "on":

-             notify_flag = True

-         else:

-             notify_flag = False

- 

-         if key in current_keys:

-             issuekey = current_keys[key]

-             issuekey.key_type = types[idx]

-             issuekey.data = data[idx]

-             issuekey.key_notify = notify_flag

-         else:

-             issuekey = model.IssueKeys(

-                 project_id=project.id,

-                 name=key,

-                 key_type=types[idx],

-                 data=data[idx],

-                 key_notify=notify_flag,

-             )

-         session.add(issuekey)

- 

-     # Delete keys

-     for key in current_keys:

-         if key not in fields:

-             session.delete(current_keys[key])

- 

-     return "List of custom fields updated"

- 

- 

- def set_custom_key_value(session, issue, key, value):

-     """ Set or update the value of the specified custom key.

-     """

- 

-     query = (

-         session.query(model.IssueValues)

-         .filter(model.IssueValues.key_id == key.id)

-         .filter(model.IssueValues.issue_uid == issue.uid)

-     )

- 

-     current_field = query.first()

-     updated = False

-     delete = False

-     old_value = None

-     if current_field:

-         old_value = current_field.value

-         if current_field.key.key_type == "boolean":

-             value = value or False

-         if value is None or value == "":

-             session.delete(current_field)

-             updated = True

-             delete = True

-         elif current_field.value != value:

-             current_field.value = value

-             updated = True

-     else:

-         if value is None or value == "":

-             delete = True

-         else:

-             current_field = model.IssueValues(

-                 issue_uid=issue.uid, key_id=key.id, value=value

-             )

-             updated = True

- 

-     if not delete:

-         session.add(current_field)

- 

-     if REDIS and updated:

-         if issue.private:

-             REDIS.publish(

-                 "pagure.%s" % issue.uid,

-                 json.dumps({"issue": "private", "custom_fields": [key.name]}),

-             )

-         else:

-             REDIS.publish(

-                 "pagure.%s" % issue.uid,

-                 json.dumps(

-                     {

-                         "custom_fields": [key.name],

-                         "issue": issue.to_json(

-                             public=True, with_comments=False

-                         ),

-                     }

-                 ),

-             )

- 

-     if updated and value:

-         output = "Custom field %s adjusted to %s" % (key.name, value)

-         if old_value:

-             output += " (was: %s)" % old_value

-         return output

-     elif updated and old_value:

-         return "Custom field %s reset (from %s)" % (key.name, old_value)

- 

- 

- def get_yearly_stats_user(session, user, date, tz="UTC"):

-     """ Return the activity of the specified user in the year preceding the

-     specified date. 'offset' is intended to be a timezone offset from UTC,

-     in minutes: you can discover the offset for a timezone and pass that

-     in order for the results to be relative to that timezone. Note, offset

-     should be the amount of minutes that should be added to the UTC time to

-     produce the local time - so for timezones behind UTC the number should

-     be negative, and for timezones ahead of UTC the number should be

-     positive. This is the opposite of what Javascript getTimezoneOffset()

-     does, so you have to invert any value you get from that.

-     """

-     start_date = datetime.datetime(date.year - 1, date.month, date.day)

- 

-     events = (

-         session.query(model.PagureLog)

-         .filter(model.PagureLog.date_created.between(start_date, date))

-         .filter(model.PagureLog.user_id == user.id)

-         .all()

-     )

-     # Counter very handily does exactly what we want here: it gives

-     # us a dict with the dates as keys and the number of times each

-     # date occurs in the data as the values, we return its items as

-     # a list of tuples

-     return list(Counter([event.date_tz(tz) for event in events]).items())

- 

- 

- def get_user_activity_day(session, user, date, tz="UTC"):

-     """ Return the activity of the specified user on the specified date.

-     'offset' is intended to be a timezone offset from UTC, in minutes:

-     you can discover the offset for a timezone and pass that, so this

-     will return activity that occurred on the specified date in the

-     desired timezone. Note, offset should be the amount of minutes

-     that should be added to the UTC time to produce the local time -

-     so for timezones behind UTC the number should be negative, and

-     for timezones ahead of UTC the number should be positive. This is

-     the opposite of what Javascript getTimezoneOffset() does, so you

-     have to invert any value you get from that.

-     """

-     dt = datetime.datetime.strptime(date, "%Y-%m-%d")

-     # if the offset is *negative* some of the events we want may be

-     # on the next day in UTC terms. if the offset is *positive* some

-     # of the events we want may be on the previous day in UTC terms.

-     # 'dt' will be at 00:00, so we subtract 1 day for prevday but add

-     # 2 days for nextday. e.g. 2018-02-15 00:00 - prevday will be

-     # 2018-02-14 00:00, nextday will be 2018-02-17 00:00. We'll get

-     # all events that occurred on 2018-02-14, 2018-02-15 or 2018-02-16

-     # in UTC time.

-     prevday = dt - datetime.timedelta(days=1)

-     nextday = dt + datetime.timedelta(days=2)

-     query = (

-         session.query(model.PagureLog)

-         .filter(model.PagureLog.date_created.between(prevday, nextday))

-         .filter(model.PagureLog.user_id == user.id)

-         .order_by(model.PagureLog.id.asc())

-     )

-     events = query.all()

-     # Now we filter down to the events that *really* occurred on the

-     # date we were asked for with the offset applied, and return

-     return [ev for ev in events if ev.date_tz(tz) == dt.date()]

- 

- 

- def get_watchlist_messages(session, user, limit=None):

- 

-     watched = user_watch_list(session, user.username)

- 

-     watched_list = [watch.id for watch in watched]

- 

-     events = (

-         session.query(model.PagureLog)

-         .filter(model.PagureLog.project_id.in_(watched_list))

-         .order_by(model.PagureLog.id.desc())

-     )

- 

-     if limit is not None:

-         events = events.limit(limit)

- 

-     events = events.all()

- 

-     return events

- 

- 

- def log_action(session, action, obj, user_obj):

-     """ Log an user action on a project/issue/PR. """

-     project_id = None

-     if obj.isa in ["issue", "pull-request"]:

-         project_id = obj.project_id

-         if obj.project.private:

-             return

-     elif obj.isa == "project":

-         project_id = obj.id

-         if obj.private:

-             return

-     else:

-         raise pagure.exceptions.InvalidObjectException(

-             'Unsupported object found: "%s"' % obj

-         )

- 

-     if obj.private:

-         return

- 

-     log = model.PagureLog(

-         user_id=user_obj.id,

-         project_id=project_id,

-         log_type=action,

-         ref_id=obj.id,

-     )

-     if obj.isa == "issue":

-         setattr(log, "issue_uid", obj.uid)

-     elif obj.isa == "pull-request":

-         setattr(log, "pull_request_uid", obj.uid)

- 

-     session.add(log)

-     session.commit()

- 

- 

- def email_logs_count(session, email):

-     """ Returns the number of logs associated with a given email."""

-     query = session.query(model.PagureLog).filter(

-         model.PagureLog.user_email == email

-     )

- 

-     return query.count()

- 

- 

- def update_log_email_user(session, email, user):

-     """ Update the logs with the provided email to point to the specified

-     user.

-     """

-     session.query(model.PagureLog).filter(

-         model.PagureLog.user_email == email

-     ).update({model.PagureLog.user_id: user.id}, synchronize_session=False)

- 

- 

- def get_custom_key(session, project, keyname):

-     """ Returns custom key object given it's name and the project """

- 

-     query = (

-         session.query(model.IssueKeys)

-         .filter(model.IssueKeys.project_id == project.id)

-         .filter(model.IssueKeys.name == keyname)

-     )

- 

-     return query.first()

- 

- 

- def get_active_milestones(session, project):

-     """ Returns the list of all the active milestones for a given project.

-     """

- 

-     query = (

-         session.query(model.Issue.milestone)

-         .filter(model.Issue.project_id == project.id)

-         .filter(model.Issue.status == "Open")

-         .filter(model.Issue.milestone.isnot(None))

-     )

- 

-     return sorted([item[0] for item in query.distinct()])

- 

- 

- def add_metadata_update_notif(session, obj, messages, user):

-     """ Add a notification to the specified issue with the given messages

-     which should reflect changes made to the meta-data of the issue.

-     """

-     if not messages:

-         return

- 

-     if not isinstance(messages, (list, set)):

-         messages = [messages]

- 

-     user_id = None

-     if user:

-         user_obj = get_user(session, user)

-         user_id = user_obj.id

- 

-     if obj.isa == "issue":

-         obj_comment = model.IssueComment(

-             issue_uid=obj.uid,

-             comment="**Metadata Update from @%s**:\n- %s"

-             % (user, "\n- ".join(sorted(messages))),

-             user_id=user_id,

-             notification=True,

-         )

-     elif obj.isa == "pull-request":

-         obj_comment = model.PullRequestComment(

-             pull_request_uid=obj.uid,

-             comment="**Metadata Update from @%s**:\n- %s"

-             % (user, "\n- ".join(sorted(messages))),

-             user_id=user_id,

-             notification=True,

-         )

-     obj.last_updated = datetime.datetime.utcnow()

-     session.add(obj)

-     session.add(obj_comment)

-     # Make sure we won't have SQLAlchemy error before we continue

-     session.commit()

- 

-     if REDIS:

-         REDIS.publish(

-             "pagure.%s" % obj.uid,

-             json.dumps(

-                 {

-                     "comment_id": obj_comment.id,

-                     "%s_id" % obj.isa: obj.id,

-                     "project": obj.project.fullname,

-                     "comment_added": text2markdown(obj_comment.comment),

-                     "comment_user": obj_comment.user.user,

-                     "avatar_url": avatar_url_from_email(

-                         obj_comment.user.default_email, size=16

-                     ),

-                     "comment_date": obj_comment.date_created.strftime(

-                         "%Y-%m-%d %H:%M:%S"

-                     ),

-                     "notification": True,

-                 }

-             ),

-         )

- 

-     pagure.lib.git.update_git(obj, repo=obj.project)

- 

- 

- def tokenize_search_string(pattern):

-     """This function tokenizes search patterns into key:value and rest.

- 

-     It will also correctly parse key values between quotes.

-     """

-     if pattern is None:

-         return {}, None

- 

-     def finalize_token(token, custom_search):

-         if ":" in token:

-             # This was a "key:value" parameter

-             key, value = token.split(":", 1)

-             custom_search[key] = value

-             return ""

-         else:

-             # This was a token without colon, thus a search pattern

-             return "%s " % token

- 

-     custom_search = {}

-     # Remaining is the remaining real search_pattern (aka, non-key:values)

-     remaining = ""

-     # Token is the current "search token" we are processing

-     token = ""

-     in_quotes = False

-     for char in pattern:

-         if char == " " and not in_quotes:

-             remaining += finalize_token(token, custom_search)

-             token = ""

-         elif char == '"':

-             in_quotes = not in_quotes

-         else:

-             token += char

- 

-     # Parse the final token

-     remaining += finalize_token(token, custom_search)

- 

-     return custom_search, remaining.strip()

- 

- 

- def get_access_levels(session):

-     """ Returns all the access levels a user/group can have for a project """

- 

-     access_level_objs = session.query(model.AccessLevels).all()

-     return [access_level.access for access_level in access_level_objs]

- 

- 

- def get_obj_access(session, project_obj, obj):

-     """ Returns the level of access the user/group has on the project.

- 

-     :arg session: the session to use to connect to the database.

-     :arg project_obj: SQLAlchemy object of Project class

-     :arg obj: SQLAlchemy object of either User or PagureGroup class

-     """

- 

-     if isinstance(obj, model.User):

-         query = (

-             session.query(model.ProjectUser)

-             .filter(model.ProjectUser.project_id == project_obj.id)

-             .filter(model.ProjectUser.user_id == obj.id)

-         )

-     else:

-         query = (

-             session.query(model.ProjectGroup)

-             .filter(model.ProjectGroup.project_id == project_obj.id)

-             .filter(model.ProjectGroup.group_id == obj.id)

-         )

- 

-     return query.first()

- 

- 

- def search_token(

-     session, acls, user=None, token=None, active=False, expired=False

- ):

-     """ Searches the API tokens corresponding to the criterias specified.

- 

-     :arg session: the session to use to connect to the database.

-     :arg acls: List of the ACL associated with these API tokens

-     :arg user: restrict the API tokens to this given user

-     :arg token: restrict the API tokens to this specified token (if it

-         exists)

-     """

-     query = (

-         session.query(model.Token)

-         .filter(model.Token.id == model.TokenAcl.token_id)

-         .filter(model.TokenAcl.acl_id == model.ACL.id)

-     )

- 

-     if acls:

-         if isinstance(acls, list):

-             query = query.filter(model.ACL.name.in_(acls))

-         else:

-             query = query.filter(model.ACL.name == acls)

- 

-     if user:

-         query = query.filter(model.Token.user_id == model.User.id).filter(

-             model.User.user == user

-         )

- 

-     if active:

-         query = query.filter(

-             model.Token.expiration > datetime.datetime.utcnow()

-         )

-     elif expired:

-         query = query.filter(

-             model.Token.expiration <= datetime.datetime.utcnow()

-         )

- 

-     if token:

-         query = query.filter(model.Token.id == token)

-         return query.first()

-     else:

-         return query.all()

- 

- 

- def set_project_owner(session, project, user, required_groups=None):

-     """ Set the ownership of a project

-     :arg session: the session to use to connect to the database.

-     :arg project: a Project object representing the project's ownership to

-     change.

-     :arg user: a User object representing the new owner of the project.

-     :arg required_groups: a dict of {pattern: [list of groups]} the new user

-         should be in to become owner if one of the pattern matches the

-         project fullname.

-     :return: None

-     """

- 

-     if required_groups:

-         for key in required_groups:

-             if fnmatch.fnmatch(project.fullname, key):

-                 user_grps = set(user.groups)

-                 req_grps = set(required_groups[key])

-                 if not user_grps.intersection(req_grps):

-                     raise pagure.exceptions.PagureException(

-                         "This user must be in one of the following groups "

-                         "to be allowed to be added to this project: %s"

-                         % ", ".join(req_grps)

-                     )

- 

-     for contributor in project.users:

-         if user.id == contributor.id:

-             project.users.remove(contributor)

-             break

-     project.user = user

-     session.add(project)

- 

- 

- def get_pagination_metadata(

-     flask_request, page, per_page, total, key_page="page"

- ):

-     """

-     Returns pagination metadata for an API. The code was inspired by

-     Flask-SQLAlchemy.

-     :param flask_request: flask.request object

-     :param page: int of the current page

-     :param per_page: int of results per page

-     :param total: int of total results

-     :param key_page: the name of the argument corresponding to the page

-     :return: dictionary of pagination metadata

-     """

-     pages = int(ceil(total / float(per_page)))

-     request_args_wo_page = dict(copy.deepcopy(flask_request.args))

-     # Remove pagination related args because those are handled elsewhere

-     # Also, remove any args that url_for accepts in case the user entered

-     # those in

-     for key in [key_page, "per_page", "endpoint"]:

-         if key in request_args_wo_page:

-             request_args_wo_page.pop(key)

-     for key in flask_request.args:

-         if key.startswith("_"):

-             request_args_wo_page.pop(key)

- 

-     request_args_wo_page.update(flask_request.view_args)

- 

-     next_page = None

-     if page < pages:

-         request_args_wo_page.update({key_page: page + 1})

-         next_page = url_for(

-             flask_request.endpoint,

-             per_page=per_page,

-             _external=True,

-             **request_args_wo_page

-         )

- 

-     prev_page = None

-     if page > 1:

-         request_args_wo_page.update({key_page: page - 1})

-         prev_page = url_for(

-             flask_request.endpoint,

-             per_page=per_page,

-             _external=True,

-             **request_args_wo_page

-         )

- 

-     request_args_wo_page.update({key_page: 1})

-     first_page = url_for(

-         flask_request.endpoint,

-         per_page=per_page,

-         _external=True,

-         **request_args_wo_page

-     )

- 

-     request_args_wo_page.update({key_page: pages})

-     last_page = url_for(

-         flask_request.endpoint,

-         per_page=per_page,

-         _external=True,

-         **request_args_wo_page

-     )

- 

-     return {

-         key_page: page,

-         "pages": pages,

-         "per_page": per_page,

-         "prev": prev_page,

-         "next": next_page,

-         "first": first_page,

-         "last": last_page,

-     }

- 

- 

- def update_star_project(session, repo, star, user):

-     """ Unset or set the star status depending on the star value.

- 

-     :arg session: the session to use to connect to the database.

-     :arg repo: a model.Project object representing the project to star/unstar

-     :arg star: '1' for starring and '0' for unstarring

-     :arg user: string representing the user

-     :return: None or string containing 'You starred this project' or

-             'You unstarred this project'

-     """

- 

-     if not all([repo, user, star]):

-         return

-     user_obj = get_user(session, user)

-     msg = None

-     if star == "1":

-         msg = _star_project(session, repo=repo, user=user_obj)

-     elif star == "0":

-         msg = _unstar_project(session, repo=repo, user=user_obj)

-     return msg

- 

- 

- def _star_project(session, repo, user):

-     """ Star a project

- 

-     :arg session: Session object to connect to db with

-     :arg repo: model.Project object representing the repo to star

-     :arg user: model.User object who is starring this repo

-     :return: None or string containing 'You starred this project'

-     """

- 

-     if not all([repo, user]):

-         return

-     stargazer_obj = model.Star(project_id=repo.id, user_id=user.id)

-     session.add(stargazer_obj)

-     return "You starred this project"

- 

- 

- def _unstar_project(session, repo, user):

-     """ Unstar a project

-     :arg session: Session object to connect to db with

-     :arg repo: model.Project object representing the repo to unstar

-     :arg user: model.User object who is unstarring this repo

-     :return: None or string containing 'You unstarred this project'

-             or 'You never starred the project'

-     """

- 

-     if not all([repo, user]):

-         return

-     # First find the stargazer_obj object

-     stargazer_obj = _get_stargazer_obj(session, repo, user)

-     if isinstance(stargazer_obj, model.Star):

-         session.delete(stargazer_obj)

-         msg = "You unstarred this project"

-     else:

-         msg = "You never starred the project"

-     return msg

- 

- 

- def _get_stargazer_obj(session, repo, user):

-     """ Query the db to find stargazer object with given repo and user

-     :arg session: Session object to connect to db with

-     :arg repo: model.Project object

-     :arg user: model.User object

-     :return: None or model.Star object

-     """

- 

-     if not all([repo, user]):

-         return

-     stargazer_obj = (

-         session.query(model.Star)

-         .filter(model.Star.project_id == repo.id)

-         .filter(model.Star.user_id == user.id)

-     )

- 

-     return stargazer_obj.first()

- 

- 

- def has_starred(session, repo, user):

-     """ Check if a given user has starred a particular project

- 

-     :arg session: The session object to query the db with

-     :arg repo: model.Project object for which the star is checked

-     :arg user: The username of the user in question

-     :return: True if user has starred the project, False otherwise

-     """

- 

-     if not all([repo, user]):

-         return

-     user_obj = search_user(session, username=user)

-     stargazer_obj = _get_stargazer_obj(session, repo, user_obj)

-     if isinstance(stargazer_obj, model.Star):

-         return True

-     return False

- 

- 

- def update_read_only_mode(session, repo, read_only=True):

-     """ Remove the read only mode from the project

- 

-     :arg session: The session object to query the db with

-     :arg repo: model.Project object to mark/unmark read only

-     :arg read_only: True if project is to be made read only,

-         False otherwise

-     """

- 

-     if (

-         not repo

-         or not isinstance(repo, model.Project)

-         or read_only not in [True, False]

-     ):

-         return

-     helper = pagure.lib.git_auth.get_git_auth_helper()

-     if helper.is_dynamic and read_only:

-         # No need to set a readonly flag if a dynamic auth backend is in use

-         return

-     if repo.read_only != read_only:

-         repo.read_only = read_only

-         session.add(repo)

- 

- 

- def issues_history_stats(session, project):

-     """ Returns the number of opened issues on the specified project over

-     the last 365 days

- 

-     :arg session: The session object to query the db with

-     :arg repo: model.Project object to get the issues stats about

- 

-     """

- 

-     # Some ticket got imported as closed but without a closed_at date, so

-     # let's ignore them all

-     to_ignore = (

-         session.query(model.Issue)

-         .filter(model.Issue.project_id == project.id)

-         .filter(model.Issue.closed_at == None)  # noqa

-         .filter(model.Issue.status == "Closed")

-         .count()

-     )

- 

-     # For each week from tomorrow, get the number of open tickets

-     tomorrow = datetime.datetime.utcnow() + datetime.timedelta(days=1)

-     output = {}

-     for week in range(53):

-         start = tomorrow - datetime.timedelta(days=(week * 7))

-         closed_ticket = (

-             session.query(model.Issue)

-             .filter(model.Issue.project_id == project.id)

-             .filter(model.Issue.closed_at >= start)

-             .filter(model.Issue.date_created <= start)

-         )

-         open_ticket = (

-             session.query(model.Issue)

-             .filter(model.Issue.project_id == project.id)

-             .filter(model.Issue.status == "Open")

-             .filter(model.Issue.date_created <= start)

-         )

-         cnt = open_ticket.count() + closed_ticket.count() - to_ignore

-         if cnt < 0:

-             cnt = 0

-         output[start.isoformat()] = cnt

- 

-     return output

- 

- 

- def get_authorized_project(

-     session, project_name, user=None, namespace=None, asuser=None

- ):

-     """ Retrieving the project with user permission constraint

- 

-     :arg session: The SQLAlchemy session to use

-     :type session: sqlalchemy.orm.session.Session

-     :arg project_name: Name of the project on pagure

-     :type project_name: String

-     :arg user: Pagure username

-     :type user: String

-     :arg namespace: Pagure namespace

-     :type namespace: String

-     :arg asuser: Username to check for access

-     :type asuser: String

-     :return: The project object if project is public or user has

-                 permissions for the project else it returns None

-     :rtype: Project

- 

-     """

-     repo = pagure.lib._get_project(session, project_name, user, namespace)

- 

-     if repo and repo.private and not pagure.utils.is_repo_user(repo, asuser):

-         return None

- 

-     return repo

- 

- 

- def get_project_family(session, project):

-     """ Retrieve the family of the specified project, ie: all the forks

-     of the main project.

-     If the specified project is a fork, let's work our way up the chain

-     until we find the main project so we can go down and get all the forks

-     and the forks of the forks (but not one level more).

- 

-     :arg session: The SQLAlchemy session to use

-     :type session: sqlalchemy.orm.session.Session

-     :arg project: The project whose family is searched

-     :type project: pagure.lib.model.Project

- 

-     """

-     parent = project

-     while parent.is_fork:

-         parent = parent.parent

- 

-     sub = session.query(sqlalchemy.distinct(model.Project.id)).filter(

-         model.Project.parent_id == parent.id

-     )

-     query = (

-         session.query(model.Project)

-         .filter(

-             sqlalchemy.or_(

-                 model.Project.parent_id.in_(sub.subquery()),

-                 model.Project.parent_id == parent.id,

-             )

-         )

-         .filter(model.Project.user_id == model.User.id)

-         .order_by(model.User.user)

-     )

- 

-     return [parent] + query.all()

- 

- 

- def link_pr_issue(session, issue, request):

-     """ Associate the specified issue with the specified pull-requets.

- 

-     :arg session: The SQLAlchemy session to use

-     :type session: sqlalchemy.orm.session.Session

-     :arg issue: The issue mentioned in the commits of the pull-requests to

-         be associated with

-     :type issue: pagure.lib.model.Issue

-     :arg request: A pull-request to associate the specified issue with

-     :type request: pagure.lib.model.PullRequest

- 

-     """

- 

-     associated_issues = [iss.uid for iss in request.related_issues]

-     if issue.uid not in associated_issues:

-         obj = model.PrToIssue(

-             pull_request_uid=request.uid, issue_uid=issue.uid

-         )

-         session.add(obj)

-         session.flush()

- 

- 

- def remove_user_of_project(session, user, project, agent):

-     """ Remove the specified user from the given project.

- 

-     :arg session: the session with which to connect to the database.

-     :arg user: an pagure.lib.model.User object to remove from the project.

-     :arg project: an pagure.lib.model.Project object from which to remove

-         the specified user.

-     :arg agent: the username of the user performing the action.

- 

-     """

- 

-     userids = [u.id for u in project.users]

- 

-     if user.id not in userids:

-         raise pagure.exceptions.PagureException(

-             "User does not have any access on the repo"

-         )

- 

-     for u in project.users:

-         if u.id == user.id:

-             user = u

-             project.users.remove(u)

-             break

- 

-     # Mark the project as read_only, celery will unmark it

-     update_read_only_mode(session, project, read_only=True)

-     session.commit()

- 

-     pagure.lib.git.generate_gitolite_acls(project=project)

-     pagure.lib.notify.log(

-         project,

-         topic="project.user.removed",

-         msg=dict(

-             project=project.to_json(public=True),

-             removed_user=user.username,

-             agent=agent,

-         ),

-     )

- 

-     return "User removed"

file modified
+54 -44
@@ -35,7 +35,7 @@ 

  

  import pagure.utils

  import pagure.exceptions

- import pagure.lib

+ import pagure.lib.query

  import pagure.lib.notify

  from pagure.config import config as pagure_config

  from pagure.lib import model
@@ -383,15 +383,15 @@ 

      if not username and not useremails:

          return

  

-     user = pagure.lib.search_user(session, username=username)

+     user = pagure.lib.query.search_user(session, username=username)

      if not user:

          for email in useremails:

-             user = pagure.lib.search_user(session, email=email)

+             user = pagure.lib.query.search_user(session, email=email)

              if user:

                  break

  

      if not user:

-         user = pagure.lib.set_up_user(

+         user = pagure.lib.query.set_up_user(

              session=session,

              username=username,

              fullname=fullname or username,
@@ -417,7 +417,7 @@ 

      if jsondata.get("parent"):

          project_user = user.username

  

-     project = pagure.lib._get_project(

+     project = pagure.lib.query._get_project(

          session, name, user=project_user, namespace=namespace

      )

  
@@ -426,12 +426,12 @@ 

          if jsondata.get("parent"):

              parent = get_project_from_json(session, jsondata.get("parent"))

  

-             pagure.lib.fork_project(

+             pagure.lib.query.fork_project(

                  session=session, repo=parent, user=user.username

              )

  

          else:

-             pagure.lib.new_project(

+             pagure.lib.query.new_project(

                  session,

                  user=user.username,

                  name=name,
@@ -447,13 +447,13 @@ 

              )

  

          session.commit()

-         project = pagure.lib._get_project(

+         project = pagure.lib.query._get_project(

              session, name, user=user.username, namespace=namespace

          )

  

          tags = jsondata.get("tags", None)

          if tags:

-             pagure.lib.add_tag_obj(

+             pagure.lib.query.add_tag_obj(

                  session, project, tags=tags, user=user.username

              )

  
@@ -496,12 +496,14 @@ 

                  continue

  

          # The key should be present in the database now

-         key_obj = pagure.lib.get_custom_key(session, repo, new_key["name"])

+         key_obj = pagure.lib.query.get_custom_key(

+             session, repo, new_key["name"]

+         )

  

          value = new_key.get("value")

          if value:

              value = value.strip()

-         pagure.lib.set_custom_key_value(

+         pagure.lib.query.set_custom_key_value(

              session, issue=issue, key=key_obj, value=value

          )

          try:
@@ -529,7 +531,7 @@ 

  

      """

  

-     repo = pagure.lib._get_project(

+     repo = pagure.lib.query._get_project(

          session, reponame, user=username, namespace=namespace

      )

  
@@ -542,13 +544,13 @@ 

      user = get_user_from_json(session, json_data)

      # rely on the agent provided, but if something goes wrong, behave as

      # ticket creator

-     agent = pagure.lib.search_user(session, username=agent) or user

+     agent = pagure.lib.query.search_user(session, username=agent) or user

  

-     issue = pagure.lib.get_issue_by_uid(session, issue_uid=issue_uid)

+     issue = pagure.lib.query.get_issue_by_uid(session, issue_uid=issue_uid)

      messages = []

      if not issue:

          # Create new issue

-         pagure.lib.new_issue(

+         pagure.lib.query.new_issue(

              session,

              repo=repo,

              title=json_data.get("title"),
@@ -568,7 +570,7 @@ 

  

      else:

          # Edit existing issue

-         msgs = pagure.lib.edit_issue(

+         msgs = pagure.lib.query.edit_issue(

              session,

              issue=issue,

              user=agent.username,
@@ -584,7 +586,7 @@ 

  

      session.commit()

  

-     issue = pagure.lib.get_issue_by_uid(session, issue_uid=issue_uid)

+     issue = pagure.lib.query.get_issue_by_uid(session, issue_uid=issue_uid)

  

      update_custom_field_from_json(

          session, repo=repo, issue=issue, json_data=json_data
@@ -605,7 +607,7 @@ 

              except SQLAlchemyError:

                  session.rollback()

      try:

-         msgs = pagure.lib.edit_issue(

+         msgs = pagure.lib.query.edit_issue(

              session,

              issue=issue,

              user=agent.username,
@@ -635,14 +637,16 @@ 

  

      # Update tags

      tags = json_data.get("tags", [])

-     msgs = pagure.lib.update_tags(session, issue, tags, username=user.user)

+     msgs = pagure.lib.query.update_tags(

+         session, issue, tags, username=user.user

+     )

      if msgs:

          messages.extend(msgs)

  

      # Update assignee

      assignee = get_user_from_json(session, json_data, key="assignee")

      if assignee:

-         msg = pagure.lib.add_issue_assignee(

+         msg = pagure.lib.query.add_issue_assignee(

              session, issue, assignee.username, user=agent.user, notify=False

          )

          if msg:
@@ -650,7 +654,7 @@ 

  

      # Update depends

      depends = json_data.get("depends", [])

-     msgs = pagure.lib.update_dependency_issue(

+     msgs = pagure.lib.query.update_dependency_issue(

          session, issue.project, issue, depends, username=agent.user

      )

      if msgs:
@@ -658,7 +662,7 @@ 

  

      # Update blocks

      blocks = json_data.get("blocks", [])

-     msgs = pagure.lib.update_blocked_issue(

+     msgs = pagure.lib.query.update_blocked_issue(

          session, issue.project, issue, blocks, username=agent.user

      )

      if msgs:
@@ -666,11 +670,11 @@ 

  

      for comment in json_data["comments"]:

          usercomment = get_user_from_json(session, comment)

-         commentobj = pagure.lib.get_issue_comment_by_user_and_comment(

+         commentobj = pagure.lib.query.get_issue_comment_by_user_and_comment(

              session, issue_uid, usercomment.id, comment["comment"]

          )

          if not commentobj:

-             pagure.lib.add_issue_comment(

+             pagure.lib.query.add_issue_comment(

                  session,

                  issue=issue,

                  comment=comment["comment"],
@@ -682,7 +686,7 @@ 

              )

  

      if messages:

-         pagure.lib.add_metadata_update_notif(

+         pagure.lib.query.add_metadata_update_notif(

              session=session, obj=issue, messages=messages, user=agent.username

          )

      session.commit()
@@ -704,7 +708,7 @@ 

  

      """

  

-     repo = pagure.lib._get_project(

+     repo = pagure.lib.query._get_project(

          session, reponame, user=username, namespace=namespace

      )

  
@@ -716,7 +720,9 @@ 

  

      user = get_user_from_json(session, json_data)

  

-     request = pagure.lib.get_request_by_uid(session, request_uid=request_uid)

+     request = pagure.lib.query.get_request_by_uid(

+         session, request_uid=request_uid

+     )

  

      if not request:

          repo_from = get_project_from_json(session, json_data.get("repo_from"))
@@ -730,7 +736,7 @@ 

              status = "Merged"

  

          # Create new request

-         pagure.lib.new_pull_request(

+         pagure.lib.query.new_pull_request(

              session,

              repo_from=repo_from,

              branch_from=json_data.get("branch_from"),
@@ -746,7 +752,9 @@ 

          )

          session.commit()

  

-     request = pagure.lib.get_request_by_uid(session, request_uid=request_uid)

+     request = pagure.lib.query.get_request_by_uid(

+         session, request_uid=request_uid

+     )

  

      # Update start and stop commits

      request.commit_start = json_data.get("commit_start")
@@ -755,17 +763,17 @@ 

      # Update assignee

      assignee = get_user_from_json(session, json_data, key="assignee")

      if assignee:

-         pagure.lib.add_pull_request_assignee(

+         pagure.lib.query.add_pull_request_assignee(

              session, request, assignee.username, user=user.user

          )

  

      for comment in json_data["comments"]:

          user = get_user_from_json(session, comment)

-         commentobj = pagure.lib.get_request_comment(

+         commentobj = pagure.lib.query.get_request_comment(

              session, request_uid, comment["id"]

          )

          if not commentobj:

-             pagure.lib.add_pull_request_comment(

+             pagure.lib.query.add_pull_request_comment(

                  session,

                  request,

                  commit=comment["commit"],
@@ -875,7 +883,7 @@ 

              action (string): Type of action performing, used in the

                  temporary directory name

          """

-         if repotype not in pagure.lib.REPOTYPES:

+         if repotype not in pagure.lib.query.REPOTYPES:

              raise NotImplementedError("Repotype %s not known" % repotype)

  

          self._project = project
@@ -1517,7 +1525,7 @@ 

                      commit = repo_commit.oid.hex

                  else:

                      tree = new_repo.index.write_tree()

-                     user_obj = pagure.lib.get_user(session, username)

+                     user_obj = pagure.lib.query.get_user(session, username)

                      commitname = user_obj.fullname or user_obj.user

                      author = _make_signature(

                          commitname, user_obj.default_email
@@ -1541,7 +1549,7 @@ 

  

                  # Update status

                  _log.info("  Closing the PR in the DB")

-                 pagure.lib.close_pull_request(session, request, username)

+                 pagure.lib.query.close_pull_request(session, request, username)

  

                  return "Changes merged!"

              else:
@@ -1587,7 +1595,7 @@ 

  

              if domerge:

                  _log.info("  PR up to date, closing it")

-                 pagure.lib.close_pull_request(session, request, username)

+                 pagure.lib.query.close_pull_request(session, request, username)

                  try:

                      session.commit()

                  except SQLAlchemyError:  # pragma: no cover
@@ -1621,7 +1629,7 @@ 

                      commit = repo_commit.oid.hex

                  else:

                      tree = new_repo.index.write_tree()

-                     user_obj = pagure.lib.get_user(session, username)

+                     user_obj = pagure.lib.query.get_user(session, username)

                      commitname = user_obj.fullname or user_obj.user

                      author = _make_signature(

                          commitname, user_obj.default_email
@@ -1690,7 +1698,7 @@ 

                  _log.info(

                      "  Basing on: %s - %s", head.hex, repo_commit.oid.hex

                  )

-                 user_obj = pagure.lib.get_user(session, username)

+                 user_obj = pagure.lib.query.get_user(session, username)

                  commitname = user_obj.fullname or user_obj.user

                  author = _make_signature(commitname, user_obj.default_email)

  
@@ -1729,7 +1737,7 @@ 

  

      # Update status

      _log.info("  Closing the PR in the DB")

-     pagure.lib.close_pull_request(session, request, username)

+     pagure.lib.query.close_pull_request(session, request, username)

  

      return "Changes merged!"

  
@@ -1967,7 +1975,7 @@ 

          if commenttext:

              tasks.link_pr_to_ticket.delay(request.uid)

              if notify:

-                 pagure.lib.add_pull_request_comment(

+                 pagure.lib.query.add_pull_request_comment(

                      session,

                      request,

                      commit=None,
@@ -2098,7 +2106,9 @@ 

              continue

  

          try:

-             author_obj = pagure.lib.get_user(session, commit.author.email)

+             author_obj = pagure.lib.query.get_user(

+                 session, commit.author.email

+             )

          except pagure.exceptions.PagureException:

              author_obj = None

  
@@ -2189,7 +2199,7 @@ 

      Args:

          project (Project): Project to delete repos for

      """

-     for repotype in pagure.lib.REPOTYPES:

+     for repotype in pagure.lib.query.REPOTYPES:

          if project.is_on_repospanner:

              _, regioninfo = project.repospanner_repo_info(repotype)

  
@@ -2254,7 +2264,7 @@ 

              # No hooks to set up for this region

              return

  

-         for repotype in pagure.lib.REPOTYPES:

+         for repotype in pagure.lib.query.REPOTYPES:

              data = {

                  "Reponame": project._repospanner_repo_name(repotype, region),

                  "UpdateRequest": {
@@ -2373,7 +2383,7 @@ 

      created_dirs = []

  

      try:

-         for repotype in pagure.lib.REPOTYPES:

+         for repotype in pagure.lib.query.REPOTYPES:

              created = _create_project_repo(

                  project, region, templ, ignore_existing, repotype

              )

file modified
+4 -3
@@ -23,6 +23,7 @@ 

  from six.moves import dbm_gnu

  

  import pagure.exceptions

+ import pagure.lib.query

  from pagure.config import config as pagure_config

  from pagure.lib import model

  
@@ -157,8 +158,8 @@ 

              - revto (string): The commit hash the update is happening to.

              - pull_request (model.PullRequest or None): The PR that is trying

                  to be merged.

-             - repotype (string): The pagure.lib.REPOTYPES value for the repo

-                 being pushed to.

+             - repotype (string): The pagure.lib.query.REPOTYPES value for the

+                 repo being pushed to.

              - repodir (string): A directory containing the current

                  repository, including the new objects to be approved.

                  Note that this might or might not be directly writable, and any
@@ -751,7 +752,7 @@ 

          _log.info("Refresh gitolite configuration")

  

          if project is not None or group is not None:

-             session = pagure.lib.create_session(pagure_config["DB_URL"])

+             session = pagure.lib.query.create_session(pagure_config["DB_URL"])

              cls.write_gitolite_acls(

                  session,

                  project=project,

file modified
+7 -6
@@ -16,11 +16,8 @@ 

  import logging

  import time

  import pagure.exceptions

- import pagure.lib

+ import pagure.lib.query

  

- # This import is needed as pagure.lib relies on Project.ci_hook to be

- # defined and accessible and this happens in pagure.hooks.pagure_ci

- from pagure.hooks import pagure_ci  # noqa: E402,F401

  from pagure.config import config as pagure_config

  

  _log = logging.getLogger(__name__)
@@ -39,6 +36,10 @@ 

      """

      import jenkins

  

+     # This import is needed as pagure.lib relies on Project.ci_hook to be

+     # defined and accessible and this happens in pagure.hooks.pagure_ci

+     from pagure.hooks import pagure_ci  # noqa: E402,F401

+ 

      # Jenkins Base URL

      _log.info("Querying jenkins at: %s", project.ci_hook.ci_url)

      jenk = jenkins.Jenkins(project.ci_hook.ci_url)
@@ -90,7 +91,7 @@ 

              "Unknown build status: %s" % result

          )

  

-     request = pagure.lib.search_pull_requests(

+     request = pagure.lib.query.search_pull_requests(

          session, project_id=project.id, requestid=pr_id

      )

  
@@ -113,7 +114,7 @@ 

              break

  

      _log.info("Flag's UID: %s", uid)

-     pagure.lib.add_pull_request_flag(

+     pagure.lib.query.add_pull_request_flag(

          session,

          request=request,

          username=username,

file modified
+4 -4
@@ -13,7 +13,7 @@ 

  from __future__ import unicode_literals

  

  import re

- import pagure

+ import pagure.lib.query

  import pagure.exceptions

  

  
@@ -73,7 +73,7 @@ 

  

      """

  

-     repo = pagure.lib.get_authorized_project(

+     repo = pagure.lib.query.get_authorized_project(

          session, reponame, user=username, namespace=namespace

      )

      if not repo:
@@ -95,12 +95,12 @@ 

                  relid = motif.match(text).group(1)

  

          if relid:

-             relation = pagure.lib.search_issues(

+             relation = pagure.lib.query.search_issues(

                  session, repo=repo, issueid=relid

              )

  

              if relation is None and include_prs:

-                 relation = pagure.lib.search_pull_requests(

+                 relation = pagure.lib.query.search_pull_requests(

                      session, project_id=repo.id, requestid=relid

                  )

  

file modified
+1 -1
@@ -1049,7 +1049,7 @@ 

          self.ltype = ltype

  

      def __enter__(self):

-         from pagure.lib import create_session

+         from pagure.lib.query import create_session

  

          self.session = create_session()

  

file modified
+3 -3
@@ -28,7 +28,7 @@ 

  from six.moves.urllib_parse import urljoin

  

  import flask

- import pagure.lib

+ import pagure.lib.query

  import pagure.lib.tasks_services

  from pagure.config import config as pagure_config

  
@@ -133,7 +133,7 @@ 

      """

      mentio_re = r"@(\w+)"

      for username in re.findall(mentio_re, comment):

-         user = pagure.lib.search_user(flask.g.session, username=username)

+         user = pagure.lib.query.search_user(flask.g.session, username=username)

          if user:

              emails.add(user.default_email)

      return emails
@@ -326,7 +326,7 @@ 

      smtp = None

      for mailto in to_mail.split(","):

          try:

-             pagure.lib.allowed_emailaddress(mailto)

+             pagure.lib.query.allowed_emailaddress(mailto)

          except pagure.exceptions.PagureException:

              continue

          msg = MIMEText(text.encode("utf-8"), "plain", "utf-8")

file added
+5591
The added file is too large to be shown here, see it at: pagure/lib/query.py
file modified
+45 -41
@@ -32,10 +32,10 @@ 

  from celery.utils.log import get_task_logger

  from sqlalchemy.exc import SQLAlchemyError

  

- import pagure.lib

  import pagure.lib.git

  import pagure.lib.git_auth

  import pagure.lib.link

+ import pagure.lib.query

  import pagure.lib.repo

  import pagure.utils

  from pagure.config import config as pagure_config
@@ -75,7 +75,7 @@ 

                  self.update_state(state="RUNNING")

              except TypeError:

                  pass

-         session = pagure.lib.create_session(pagure_config["DB_URL"])

+         session = pagure.lib.query.create_session(pagure_config["DB_URL"])

          try:

              return function(self, session, *args, **kwargs)

          except:  # noqa: E722
@@ -135,7 +135,7 @@ 

      """

      project = None

      if name and name != -1:

-         project = pagure.lib._get_project(

+         project = pagure.lib.query._get_project(

              session, namespace=namespace, name=name, user=user

          )

  
@@ -146,7 +146,7 @@ 

  

      group_obj = None

      if group:

-         group_obj = pagure.lib.search_groups(session, group_name=group)

+         group_obj = pagure.lib.query.search_groups(session, group_name=group)

      _log.debug(

          "Calling helper: %s with arg: project=%s, group=%s",

          helper,
@@ -155,7 +155,7 @@ 

      )

      helper.generate_acls(project=project, group=group_obj)

  

-     pagure.lib.update_read_only_mode(session, project, read_only=False)

+     pagure.lib.query.update_read_only_mode(session, project, read_only=False)

      try:

          session.commit()

          _log.debug("Project %s is no longer in Read Only Mode", project)
@@ -204,7 +204,7 @@ 

      :type action_user: None or str

  

      """

-     project = pagure.lib._get_project(

+     project = pagure.lib.query._get_project(

          session, namespace=namespace, name=name, user=user

      )

  
@@ -269,9 +269,11 @@ 

      :type ignore_existing_repo: bool

  

      """

-     project = pagure.lib._get_project(session, namespace=namespace, name=name)

+     project = pagure.lib.query._get_project(

+         session, namespace=namespace, name=name

+     )

  

-     userobj = pagure.lib.search_user(session, username=username)

+     userobj = pagure.lib.query.search_user(session, username=username)

  

      # Add the readme file if it was asked

      templ = None
@@ -363,7 +365,7 @@ 

      """ Update the JSON representation of either a ticket or a pull-request

      depending on the argument specified.

      """

-     project = pagure.lib._get_project(

+     project = pagure.lib.query._get_project(

          session, namespace=namespace, name=name, user=user

      )

  
@@ -375,9 +377,9 @@ 

  

      with project.lock(project_lock):

          if ticketuid is not None:

-             obj = pagure.lib.get_issue_by_uid(session, ticketuid)

+             obj = pagure.lib.query.get_issue_by_uid(session, ticketuid)

          elif requestuid is not None:

-             obj = pagure.lib.get_request_by_uid(session, requestuid)

+             obj = pagure.lib.query.get_request_by_uid(session, requestuid)

          else:

              raise NotImplementedError("No ticket ID or request ID provided")

  
@@ -395,7 +397,7 @@ 

      """ Remove the JSON representation of a ticket on the git repository

      for tickets.

      """

-     project = pagure.lib._get_project(

+     project = pagure.lib.query._get_project(

          session, namespace=namespace, name=name, user=user

      )

  
@@ -423,8 +425,8 @@ 

  ):

      """ Update a file in the specified git repo.

      """

-     userobj = pagure.lib.search_user(session, username=username)

-     project = pagure.lib._get_project(

+     userobj = pagure.lib.query.search_user(session, username=username)

+     project = pagure.lib.query._get_project(

          session, namespace=namespace, name=name, user=user

      )

  
@@ -454,7 +456,7 @@ 

  def delete_branch(self, session, name, namespace, user, branchname):

      """ Delete a branch from a git repo.

      """

-     project = pagure.lib._get_project(

+     project = pagure.lib.query._get_project(

          session, namespace=namespace, name=name, user=user

      )

  
@@ -502,11 +504,11 @@ 

      :type editfile: str

  

      """

-     repo_from = pagure.lib._get_project(

+     repo_from = pagure.lib.query._get_project(

          session, namespace=namespace, name=name, user=user_owner

      )

  

-     repo_to = pagure.lib._get_project(

+     repo_to = pagure.lib.query._get_project(

          session, namespace=namespace, name=name, user=user_forker

      )

  
@@ -602,11 +604,11 @@ 

      """ Refresh the local clone of a git repository used in a remote

      pull-request.

      """

-     project = pagure.lib._get_project(

+     project = pagure.lib.query._get_project(

          session, namespace=namespace, name=name, user=user

      )

  

-     request = pagure.lib.search_pull_requests(

+     request = pagure.lib.query.search_pull_requests(

          session, project_id=project.id, requestid=requestid

      )

      _log.debug(
@@ -638,7 +640,7 @@ 

  def move_to_repospanner(self, session, name, namespace, user, region):

      """ Move a repository to a repoSpanner region.

      """

-     project = pagure.lib._get_project(

+     project = pagure.lib.query._get_project(

          session, namespace=namespace, name=name, user=user

      )

      regioninfo = pagure_config.get("REPOSPANNER_REGIONS", {}).get(region)
@@ -651,9 +653,9 @@ 

              raise Exception("Project is already on repoSpanner")

  

          #  Make sure that no non-runner hooks are enabled for this project

-         compatible_targets = [pagure.lib.HOOK_DNE_TARGET]

+         compatible_targets = [pagure.lib.query.HOOK_DNE_TARGET]

          incompatible_hooks = []

-         for repotype in pagure.lib.REPOTYPES:

+         for repotype in pagure.lib.query.REPOTYPES:

              path = project.repopath(repotype)

              if path is None:

                  continue
@@ -680,7 +682,7 @@ 

          # Create the repositories

          pagure.lib.git.create_project_repos(project, region, None, False)

  

-         for repotype in pagure.lib.REPOTYPES:

+         for repotype in pagure.lib.query.REPOTYPES:

              repopath = project.repopath(repotype)

              if repopath is None:

                  continue
@@ -706,7 +708,7 @@ 

              )

              _log.debug("Out: %s" % out)

  

-         for repotype in pagure.lib.REPOTYPES:

+         for repotype in pagure.lib.query.REPOTYPES:

              repopath = project.repopath(repotype)

              if repopath is None:

                  continue
@@ -740,11 +742,11 @@ 

  def refresh_pr_cache(self, session, name, namespace, user):

</