Browse Source

Move the code in pagure/lib/__init__.py into pagure/lib/query.py

This will help untangling some of the circular imports we have in our
code.

Signed-off-by: Pierre-Yves Chibon <pingou@pingoured.fr>
Pierre-Yves Chibon 5 years ago
parent
commit
9300737e8d
100 changed files with 7385 additions and 7320 deletions
  1. 1 1
      alembic/versions/f16ab75e4d32_sshkeys.py
  2. 25 24
      dev-data.py
  3. 3 2
      files/api_key_expire_mail.py
  4. 6 5
      pagure-ev/pagure_stream_server.py
  5. 3 3
      pagure-milters/comment_email_milter.py
  6. 6 6
      pagure/api/__init__.py
  7. 2 2
      pagure/api/ci/jenkins.py
  8. 22 22
      pagure/api/fork.py
  9. 5 5
      pagure/api/group.py
  10. 29 27
      pagure/api/issue.py
  11. 32 26
      pagure/api/project.py
  12. 25 25
      pagure/api/user.py
  13. 26 22
      pagure/cli/admin.py
  14. 2 2
      pagure/doc_utils.py
  15. 3 3
      pagure/docs_server.py
  16. 12 12
      pagure/flask_app.py
  17. 2 2
      pagure/forms.py
  18. 6 6
      pagure/hooks/__init__.py
  19. 3 2
      pagure/hooks/default.py
  20. 4 4
      pagure/hooks/files/repospannerhook
  21. 1 1
      pagure/hooks/pagure_ci.py
  22. 6 5
      pagure/hooks/pagure_hook.py
  23. 1 0
      pagure/hooks/pagure_request_hook.py
  24. 2 1
      pagure/hooks/pagure_ticket_hook.py
  25. 1 0
      pagure/hooks/pagure_unsigned_commits.py
  26. 21 19
      pagure/internal/__init__.py
  27. 0 5580
      pagure/lib/__init__.py
  28. 54 44
      pagure/lib/git.py
  29. 4 3
      pagure/lib/git_auth.py
  30. 3 3
      pagure/lib/lib_ci.py
  31. 4 4
      pagure/lib/link.py
  32. 1 1
      pagure/lib/model.py
  33. 3 3
      pagure/lib/notify.py
  34. 5591 0
      pagure/lib/query.py
  35. 45 41
      pagure/lib/tasks.py
  36. 4 4
      pagure/lib/tasks_mirror.py
  37. 7 7
      pagure/lib/tasks_services.py
  38. 9 9
      pagure/pfmarkdown.py
  39. 52 48
      pagure/ui/app.py
  40. 2 2
      pagure/ui/clone.py
  41. 8 8
      pagure/ui/fas_login.py
  42. 9 9
      pagure/ui/filters.py
  43. 45 43
      pagure/ui/fork.py
  44. 18 14
      pagure/ui/groups.py
  45. 67 53
      pagure/ui/issues.py
  46. 14 10
      pagure/ui/login.py
  47. 7 7
      pagure/ui/oidc_login.py
  48. 0 1
      pagure/ui/plugins.py
  49. 42 38
      pagure/ui/repo.py
  50. 3 2
      pagure/utils.py
  51. 9 8
      tests/__init__.py
  52. 21 21
      tests/test_pagure_admin.py
  53. 15 16
      tests/test_pagure_exclude_group_index.py
  54. 23 23
      tests/test_pagure_flask.py
  55. 2 1
      tests/test_pagure_flask_api.py
  56. 117 118
      tests/test_pagure_flask_api_fork.py
  57. 10 10
      tests/test_pagure_flask_api_group.py
  58. 128 129
      tests/test_pagure_flask_api_issue.py
  59. 13 14
      tests/test_pagure_flask_api_issue_change_status.py
  60. 24 25
      tests/test_pagure_flask_api_issue_comment.py
  61. 1 2
      tests/test_pagure_flask_api_issue_create.py
  62. 12 13
      tests/test_pagure_flask_api_issue_custom_fields.py
  63. 23 24
      tests/test_pagure_flask_api_pr_flag.py
  64. 56 56
      tests/test_pagure_flask_api_project.py
  65. 3 4
      tests/test_pagure_flask_api_project_update_watch.py
  66. 66 66
      tests/test_pagure_flask_api_ui_private_repo.py
  67. 48 48
      tests/test_pagure_flask_api_user.py
  68. 5 6
      tests/test_pagure_flask_docs.py
  69. 16 17
      tests/test_pagure_flask_dump_load_ticket.py
  70. 53 54
      tests/test_pagure_flask_internal.py
  71. 46 46
      tests/test_pagure_flask_ui_app.py
  72. 22 22
      tests/test_pagure_flask_ui_app_browse.py
  73. 12 12
      tests/test_pagure_flask_ui_app_give_project.py
  74. 1 1
      tests/test_pagure_flask_ui_app_index.py
  75. 13 13
      tests/test_pagure_flask_ui_app_userdash.py
  76. 3 3
      tests/test_pagure_flask_ui_clone.py
  77. 72 73
      tests/test_pagure_flask_ui_fork.py
  78. 1 1
      tests/test_pagure_flask_ui_groups.py
  79. 8 8
      tests/test_pagure_flask_ui_issue_pr_link.py
  80. 145 146
      tests/test_pagure_flask_ui_issues.py
  81. 43 43
      tests/test_pagure_flask_ui_issues_acl_checks.py
  82. 65 65
      tests/test_pagure_flask_ui_issues_open_access.py
  83. 16 17
      tests/test_pagure_flask_ui_issues_private.py
  84. 7 8
      tests/test_pagure_flask_ui_issues_read_only.py
  85. 2 3
      tests/test_pagure_flask_ui_issues_templates.py
  86. 23 23
      tests/test_pagure_flask_ui_login.py
  87. 1 1
      tests/test_pagure_flask_ui_no_master_branch.py
  88. 3 2
      tests/test_pagure_flask_ui_old_commit.py
  89. 0 1
      tests/test_pagure_flask_ui_plugins.py
  90. 6 6
      tests/test_pagure_flask_ui_plugins_default_hook.py
  91. 1 1
      tests/test_pagure_flask_ui_plugins_fedmsg.py
  92. 0 1
      tests/test_pagure_flask_ui_plugins_irc.py
  93. 0 1
      tests/test_pagure_flask_ui_plugins_mail.py
  94. 0 1
      tests/test_pagure_flask_ui_plugins_mirror.py
  95. 0 1
      tests/test_pagure_flask_ui_plugins_noff.py
  96. 0 1
      tests/test_pagure_flask_ui_plugins_pagure_ci.py
  97. 1 1
      tests/test_pagure_flask_ui_plugins_pagure_hook.py
  98. 1 1
      tests/test_pagure_flask_ui_plugins_pagure_no_new_branch.py
  99. 0 1
      tests/test_pagure_flask_ui_plugins_pagure_request_hook.py
  100. 7 1
      tests/test_pagure_flask_ui_plugins_pagure_ticket_hook.py

+ 1 - 1
alembic/versions/f16ab75e4d32_sshkeys.py

@@ -15,7 +15,7 @@ import datetime
 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():

+ 25 - 24
dev-data.py

@@ -17,7 +17,8 @@ from sqlalchemy import create_engine, MetaData
 
 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 @@ def init_database():
         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 @@ def insert_data(session, username, user_email):
 
     ######################################
     # 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 @@ def insert_data(session, username, user_email):
     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 @@ def insert_data(session, username, user_email):
     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 @@ def insert_data(session, username, user_email):
 
     ######################################
     # 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 @@ def insert_data(session, username, user_email):
     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 @@ def insert_data(session, username, user_email):
 
     ######################################
     # 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 @@ def insert_data(session, username, user_email):
 
     ######################################
     # 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 @@ def insert_data(session, username, user_email):
     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 @@ def insert_data(session, username, user_email):
 
     ######################################
     # 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 @@ def insert_data(session, username, user_email):
     ######################################
     # 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 @@ def insert_data(session, username, user_email):
 
     ######################################
     # 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 @@ def insert_data(session, username, user_email):
     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()
 

+ 3 - 2
files/api_key_expire_mail.py

@@ -8,7 +8,8 @@ from datetime import datetime, timedelta
 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 @@ def main(check=False, debug=False):
     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:

+ 6 - 5
pagure-ev/pagure_stream_server.py

@@ -40,7 +40,7 @@ if 'PAGURE_CONFIG' not in os.environ \
 
 
 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 @@ def _get_session():
     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 @@ def _get_issue(repo, objid):
         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 @@ def _get_pull_request(repo, objid):
             "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 @@ def get_obj_from_path(path):
     """
     (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:

+ 3 - 3
pagure-milters/comment_email_milter.py

@@ -22,7 +22,7 @@ import requests
 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 @@ class PagureMilter(Milter.Base):
         # 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" %

+ 6 - 6
pagure/api/__init__.py

@@ -30,7 +30,7 @@ from six.moves.urllib_parse import urljoin
 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 @@ class APIERROR(enum.Enum):
 
 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 @@ def check_api_acls(acls, optional=False):
 
     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 @@ def api_users():
     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 @@ def api_users():
                 {
                     "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 @@ def api_project_tags(repo, username=None):
         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
     )
 

+ 2 - 2
pagure/api/ci/jenkins.py

@@ -19,7 +19,7 @@ from kitchen.text.converters import to_bytes
 
 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 @@ def jenkins_ci_notification(
 
     """
 
-    project = pagure.lib._get_project(
+    project = pagure.lib.query._get_project(
         flask.g.session, repo, user=username, namespace=namespace
     )
     flask.g.repo_locked = True

+ 22 - 22
pagure/api/fork.py

@@ -18,7 +18,7 @@ from sqlalchemy.exc import SQLAlchemyError
 
 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 @@ def api_pull_request_views(repo, username=None, namespace=None):
     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 @@ def api_pull_request_views(repo, username=None, namespace=None):
         )
 
     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 @@ def api_pull_request_views(repo, username=None, namespace=None):
         )
 
     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 @@ def api_pull_request_views(repo, username=None, namespace=None):
     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 @@ def api_pull_request_by_uid_view(uid):
         }
 
     """
-    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 @@ def api_pull_request_view(repo, requestid, username=None, namespace=None):
             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 @@ def api_pull_request_merge(repo, requestid, username=None, namespace=None):
     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 @@ def api_pull_request_close(repo, requestid, username=None, namespace=None):
     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 @@ def api_pull_request_close(repo, requestid, username=None, namespace=None):
         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 @@ def api_pull_request_add_comment(
     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 @@ def api_pull_request_add_comment(
         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 @@ def api_pull_request_add_flag(repo, requestid, username=None, namespace=None):
     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 @@ def api_pull_request_add_flag(repo, requestid, username=None, namespace=None):
                 )
         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 @@ def api_pull_request_add_flag(repo, requestid, username=None, namespace=None):
                 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 @@ def api_pull_request_add_flag(repo, requestid, username=None, namespace=None):
             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 @@ def api_subscribe_pull_request(repo, requestid, username=None, namespace=None):
     ) 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 @@ def api_subscribe_pull_request(repo, requestid, username=None, namespace=None):
         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 @@ def api_subscribe_pull_request(repo, requestid, username=None, namespace=None):
             )
             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 @@ def api_pull_request_create(repo, username=None, namespace=None):
         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 @@ def api_pull_request_diffstats(repo, requestid, username=None, namespace=None):
             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
     )
 

+ 5 - 5
pagure/api/group.py

@@ -15,7 +15,7 @@ import flask
 
 import pagure
 import pagure.exceptions
-import pagure.lib
+import pagure.lib.query
 from pagure.api import (
     API,
     APIERROR,
@@ -87,16 +87,16 @@ def api_groups():
 
     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 @@ def api_view_group(group):
     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)
 

+ 29 - 27
pagure/api/issue.py

@@ -18,7 +18,7 @@ import arrow
 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 @@ def _get_issue(repo, issueid, issueuid=None):
     :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 @@ def api_new_issue(repo, username=None, namespace=None):
     _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 @@ def api_new_issue(repo, username=None, namespace=None):
         ]
 
         try:
-            issue = pagure.lib.new_issue(
+            issue = pagure.lib.query.new_issue(
                 flask.g.session,
                 repo=repo,
                 title=title,
@@ -314,7 +316,7 @@ def api_new_issue(repo, username=None, namespace=None):
             # 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 @@ def api_view_issues(repo, username=None, namespace=None):
     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 @@ def api_view_issues(repo, username=None, namespace=None):
     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 @@ def api_view_issue_comment(
     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 @@ def api_change_status_issue(repo, issueid, username=None, namespace=None):
     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 @@ def api_change_status_issue(repo, issueid, username=None, namespace=None):
     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 @@ def api_change_status_issue(repo, issueid, username=None, namespace=None):
                 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 @@ def api_change_milestone_issue(repo, issueid, username=None, namespace=None):
         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 @@ def api_change_milestone_issue(repo, issueid, username=None, namespace=None):
                 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 @@ def api_comment_issue(repo, issueid, username=None, namespace=None):
         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 @@ def api_comment_issue(repo, issueid, username=None, namespace=None):
             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 @@ def api_assign_issue(repo, issueid, username=None, namespace=None):
         # 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 @@ def api_assign_issue(repo, issueid, username=None, namespace=None):
             )
             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 @@ def api_subscribe_issue(repo, issueid, username=None, namespace=None):
         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 @@ def api_subscribe_issue(repo, issueid, username=None, namespace=None):
             )
             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 @@ def api_update_custom_field(
     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 @@ def api_update_custom_fields(repo, issueid, username=None, namespace=None):
         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 @@ def api_view_issues_history_stats(repo, username=None, namespace=None):
     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

+ 32 - 26
pagure/api/project.py

@@ -20,8 +20,8 @@ from pygit2 import GitError, Repository
 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 @@ def api_project_watchers(repo, username=None, namespace=None):
 
     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 @@ def api_project_watchers(repo, username=None, namespace=None):
         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 @@ def api_project_watchers(repo, username=None, namespace=None):
         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 @@ def api_projects():
     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 @@ def api_projects():
     # 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 @@ def api_new_project():
         }
 
     """  # 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 @@ def api_new_project():
             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 @@ def api_new_project():
 
             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 @@ def api_modify_project(repo, namespace=None):
             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 @@ def api_fork_project():
             )
 
         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 @@ def api_commit_flags(repo, commit_hash, username=None, namespace=None):
     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 @@ def api_commit_add_flag(repo, commit_hash, username=None, namespace=None):
         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 @@ def api_commit_add_flag(repo, commit_hash, username=None, namespace=None):
                 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 @@ def api_update_project_watchers(repo, username=None, namespace=None):
         )
 
     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 @@ def api_update_project_watchers(repo, username=None, namespace=None):
     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 @@ def api_modify_acls(repo, namespace=None, username=None):
             )
 
         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 @@ def api_modify_acls(repo, namespace=None, username=None):
                 _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 @@ def api_modify_acls(repo, namespace=None, username=None):
                 _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 @@ def api_modify_acls(repo, namespace=None, username=None):
                     project.fullname,
                 )
                 try:
-                    pagure.lib.remove_user_of_project(
+                    pagure.lib.query.remove_user_of_project(
                         flask.g.session,
                         user_obj,
                         project,

+ 25 - 25
pagure/api/user.py

@@ -19,7 +19,7 @@ import six
 
 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 @@ def _get_user(username):
     """ 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 @@ def api_view_user(username):
     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 @@ def api_view_user(username):
         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 @@ def api_view_user_issues(username):
         # 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 @@ def api_view_user_issues(username):
         # 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 @@ def api_view_user_activity_stats(username):
 
     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 @@ def api_view_user_activity_date(username, date):
 
     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 @@ def api_view_user_activity_date(username, date):
         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 @@ def api_view_user_activity_date(username, date):
 
     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 @@ def api_view_user_requests_filed(username):
     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 @@ def api_view_user_requests_actionable(username):
     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,

+ 26 - 22
pagure/cli/admin.py

@@ -29,14 +29,14 @@ if "PAGURE_CONFIG" not in os.environ and os.path.exists(
 
 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 @@ def _get_project(arg_project, user=None):
     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 @@ def do_generate_acl(args):
 
     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 @@ def do_generate_hook_token(_):
         "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 @@ def do_list_admin_token(args):
     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 @@ def do_info_admin_token(args):
     """
     _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 @@ def do_expire_admin_token(args):
     _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 @@ def do_update_admin_token(args):
     _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 @@ def do_create_admin_token(args):
     """
     _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 @@ def do_create_admin_token(args):
 
     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 @@ def do_get_watch_status(args):
     _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 @@ def do_get_watch_status(args):
         )
 
     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 @@ def do_update_watch_status(args):
     _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 @@ def do_update_watch_status(args):
         % (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 @@ def do_read_only(args):
     _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 @@ def do_read_only(args):
             % (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 @@ def do_new_group(args):
     _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 @@ def do_new_group(args):
         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 @@ def do_list_groups(args):
 
     """
 
-    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 @@ def do_block_user(args):
         )
 
     # 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 @@ def main():
 
         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:

+ 2 - 2
pagure/doc_utils.py

@@ -20,7 +20,7 @@ import markupsafe
 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 @@ def convert_readme(content, ext, view_file_url=None):
         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

+ 3 - 3
pagure/docs_server.py

@@ -21,7 +21,7 @@ from binaryornot.helpers import is_binary_string
 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 @@ APP = flask.Flask(__name__)
 # 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 @@ def view_docs(repo, username=None, namespace=None, filename=None):
     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
     )
 

+ 12 - 12
pagure/flask_app.py

@@ -22,8 +22,8 @@ import pygit2
 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 @@ if (
     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 (
 
 
 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 @@ def generate_user_key_files():
     """
     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 @@ def set_request():
     """ 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 @@ def set_request():
     # 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 @@ def set_request():
 
         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 @@ def auth_login():  # pragma: no cover
         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 @@ def _get_user(username):
     """ 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)

+ 2 - 2
pagure/forms.py

@@ -28,7 +28,7 @@ except ImportError:
 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 file_virus_validator(form, field):
 
 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")
 
 

+ 6 - 6
pagure/hooks/__init__.py

@@ -20,7 +20,7 @@ import wtforms
 
 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 @@ class BaseHook(object):
             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 @@ def run_project_hooks(
             # 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 @@ def run_hook_file(hooktype):
         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 @@ def run_hook_file(hooktype):
     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 @@ def run_hook_file(hooktype):
         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:

+ 3 - 2
pagure/hooks/default.py

@@ -26,6 +26,7 @@ from sqlalchemy.orm import backref
 
 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 @@ def send_notifications(session, project, repodir, user, refname, revs, forced):
     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 @@ def inform_pull_request_urls(
         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",

+ 4 - 4
pagure/hooks/files/repospannerhook

@@ -22,7 +22,7 @@ if PYPATH:
     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 @@ pruid = os.environ.get("extra_pull_request_uid", None)
 
 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 @@ if not project:
 
 pull_request = None
 if pruid:
-    pull_request = pagure.lib.get_request_by_uid(
+    pull_request = pagure.lib.query.get_request_by_uid(
         session, pruid
     )
 

+ 1 - 1
pagure/hooks/pagure_ci.py

@@ -21,7 +21,7 @@ except ImportError:
 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
 

+ 6 - 5
pagure/hooks/pagure_hook.py

@@ -25,6 +25,7 @@ from sqlalchemy.orm import relation
 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 @@ def relates_commit(session, username, commitid, issue, app_url=None):
     )
 
     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 @@ def fixes_relation(session, username, commitid, relation, app_url=None):
 
     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 @@ def fixes_relation(session, username, commitid, relation, app_url=None):
 
     try:
         if relation.isa == "issue":
-            pagure.lib.edit_issue(
+            pagure.lib.query.edit_issue(
                 session,
                 relation,
                 user=username,
@@ -198,7 +199,7 @@ def fixes_relation(session, username, commitid, relation, app_url=None):
                 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()

+ 1 - 0
pagure/hooks/pagure_request_hook.py

@@ -21,6 +21,7 @@ from sqlalchemy.orm import relation
 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
 

+ 2 - 1
pagure/hooks/pagure_ticket_hook.py

@@ -23,7 +23,8 @@ except ImportError:
 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

+ 1 - 0
pagure/hooks/pagure_unsigned_commits.py

@@ -21,6 +21,7 @@ from sqlalchemy.orm import relation
 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
 

+ 21 - 19
pagure/internal/__init__.py

@@ -28,8 +28,8 @@ PV = flask.Blueprint("internal_ns", __name__, url_prefix="/pv")
 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 @@ def lookup_ssh_key():
     """ 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 @@ def check_ssh_access():
     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 @@ def pull_request_add_comment():
     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 @@ def pull_request_add_comment():
     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 @@ def ticket_add_comment():
     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 @@ def ticket_add_comment():
     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 @@ def mergeable_request_pull():
 
     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 @@ def get_pull_request_ready_branch():
     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 @@ def get_ticket_template(repo, namespace=None, username=None):
         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 @@ def get_branches_of_commit():
         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 @@ def get_branches_head():
         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 @@ def get_stats_commits():
         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 @@ def get_stats_commits_trend():
         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 @@ def get_project_family(repo, namespace=None, username=None):
         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 @@ def get_project_family(repo, namespace=None, username=None):
     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})

+ 0 - 5580
pagure/lib/__init__.py

@@ -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"

+ 54 - 44
pagure/lib/git.py

@@ -35,7 +35,7 @@ from pygit2.remote import RemoteCollection
 
 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 @@ def get_user_from_json(session, jsondata, key="user"):
     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 @@ def get_project_from_json(session, jsondata):
     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 @@ def get_project_from_json(session, jsondata):
         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 @@ def get_project_from_json(session, jsondata):
             )
 
         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 @@ def update_custom_field_from_json(session, repo, issue, json_data):
                 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 @@ def update_ticket_from_git(
 
     """
 
-    repo = pagure.lib._get_project(
+    repo = pagure.lib.query._get_project(
         session, reponame, user=username, namespace=namespace
     )
 
@@ -542,13 +544,13 @@ def update_ticket_from_git(
     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 @@ def update_ticket_from_git(
 
     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 @@ def update_ticket_from_git(
 
     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 @@ def update_ticket_from_git(
             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 @@ def update_ticket_from_git(
 
     # 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 @@ def update_ticket_from_git(
 
     # 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 @@ def update_ticket_from_git(
 
     # 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 @@ def update_ticket_from_git(
 
     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 @@ def update_ticket_from_git(
             )
 
     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 @@ def update_request_from_git(
 
     """
 
-    repo = pagure.lib._get_project(
+    repo = pagure.lib.query._get_project(
         session, reponame, user=username, namespace=namespace
     )
 
@@ -716,7 +720,9 @@ def update_request_from_git(
 
     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 @@ def update_request_from_git(
             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 @@ def update_request_from_git(
         )
         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 @@ def update_request_from_git(
     # 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 @@ class TemporaryClone(object):
             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 @@ def merge_pull_request(session, request, username, domerge=True):
                     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 @@ def merge_pull_request(session, request, username, domerge=True):
 
                 # 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 @@ def merge_pull_request(session, request, username, domerge=True):
 
             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 @@ def merge_pull_request(session, request, username, domerge=True):
                     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 @@ def merge_pull_request(session, request, username, domerge=True):
                 _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 @@ def merge_pull_request(session, request, username, domerge=True):
 
     # 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 @@ def diff_pull_request(
         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 @@ def log_commits_to_db(session, project, commits, gitdir):
             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 @@ def delete_project_repos(project):
     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 @@ def set_up_project_hooks(project, region, hook=None):
             # 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 @@ def create_project_repos(project, region, templ, ignore_existing):
     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
             )

+ 4 - 3
pagure/lib/git_auth.py

@@ -23,6 +23,7 @@ from six import with_metaclass
 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 @@ class GitAuthHelper(with_metaclass(abc.ABCMeta, object)):
             - 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 @@ class Gitolite2Auth(GitAuthHelper):
         _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,

+ 3 - 3
pagure/lib/lib_ci.py

@@ -16,7 +16,7 @@ from __future__ import unicode_literals
 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
@@ -90,7 +90,7 @@ def process_jenkins_build(session, project, build_id, iteration=0):
             "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 +113,7 @@ def process_jenkins_build(session, project, build_id, iteration=0):
             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,

+ 4 - 4
pagure/lib/link.py

@@ -13,7 +13,7 @@
 from __future__ import unicode_literals
 
 import re
-import pagure
+import pagure.lib.query
 import pagure.exceptions
 
 
@@ -73,7 +73,7 @@ def get_relation(
 
     """
 
-    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 @@ def get_relation(
                 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
                 )
 

+ 1 - 1
pagure/lib/model.py

@@ -1049,7 +1049,7 @@ class ProjectLocker(object):
         self.ltype = ltype
 
     def __enter__(self):
-        from pagure.lib import create_session
+        from pagure.lib.query import create_session
 
         self.session = create_session()
 

+ 3 - 3
pagure/lib/notify.py

@@ -28,7 +28,7 @@ from email.mime.text import MIMEText
 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 @@ def _add_mentioned_users(emails, comment):
     """
     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 @@ def send_email(
     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")

+ 5591 - 0
pagure/lib/query.py

@@ -0,0 +1,5591 @@
+# -*- coding: utf-8 -*-
+
+"""
+ (c) 2014-2018 - Copyright Red Hat Inc
+
+ Authors:
+   Pierre-Yves Chibon <pingou@pingoured.fr>
+   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)
+    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)
+
+    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()
+            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 as err:
+            print(err)
+            _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 = _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"

+ 45 - 41
pagure/lib/tasks.py

@@ -32,10 +32,10 @@ from celery.signals import after_setup_task_logger
 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 @@ def pagure_task(function):
                 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 @@ def generate_gitolite_acls(
     """
     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 @@ def generate_gitolite_acls(
 
     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 @@ def generate_gitolite_acls(
     )
     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 @@ def delete_project(
     :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 @@ def create_project(
     :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 @@ def update_git(
     """ 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 @@ def update_git(
 
     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 @@ def clean_git(self, session, name, namespace, user, obj_repotype, obj_uid):
     """ 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 @@ def update_file_in_git(
 ):
     """ 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 update_file_in_git(
 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 @@ def fork(
     :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 @@ def refresh_remote_pr(self, session, name, namespace, user, requestid):
     """ 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 refresh_remote_pr(self, session, name, namespace, user, requestid):
 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 @@ def move_to_repospanner(self, session, name, namespace, user, region):
             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 @@ def move_to_repospanner(self, session, name, namespace, user, region):
         # 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 @@ def move_to_repospanner(self, session, name, namespace, user, region):
             )
             _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 move_to_repospanner(self, session, name, namespace, user, region):
 def refresh_pr_cache(self, session, name, namespace, user):
     """ Refresh the merge status cached of pull-requests.
     """
-    project = pagure.lib._get_project(
+    project = pagure.lib.query._get_project(
         session, namespace=namespace, name=name, user=user
     )
 
-    pagure.lib.reset_status_pull_request(session, project)
+    pagure.lib.query.reset_status_pull_request(session, project)
 
 
 @conn.task(queue=pagure_config.get("FAST_CELERY_QUEUE", None), bind=True)
@@ -761,12 +763,12 @@ def merge_pull_request(
 ):
     """ Merge pull-request.
     """
-    project = pagure.lib._get_project(
+    project = pagure.lib.query._get_project(
         session, namespace=namespace, name=name, user=user
     )
 
     with project.lock("WORKER"):
-        request = pagure.lib.search_pull_requests(
+        request = pagure.lib.query.search_pull_requests(
             session, project_id=project.id, requestid=requestid
         )
         _log.debug(
@@ -807,13 +809,15 @@ def add_file_to_git(
 ):
     """ Add a file to the specified git repo.
     """
-    project = pagure.lib._get_project(
+    project = pagure.lib.query._get_project(
         session, namespace=namespace, name=name, user=user
     )
 
     with project.lock("WORKER"):
-        issue = pagure.lib.get_issue_by_uid(session, issueuid)
-        user_attacher = pagure.lib.search_user(session, username=user_attacher)
+        issue = pagure.lib.query.get_issue_by_uid(session, issueuid)
+        user_attacher = pagure.lib.query.search_user(
+            session, username=user_attacher
+        )
 
         from_folder = pagure_config["ATTACHMENTS_FOLDER"]
         _log.info(
@@ -837,7 +841,7 @@ def project_dowait(self, session, name, namespace, user):
     repeatedly. """
     assert pagure_config.get("ALLOW_PROJECT_DOWAIT", False)
 
-    project = pagure.lib._get_project(
+    project = pagure.lib.query._get_project(
         session, namespace=namespace, name=name, user=user
     )
 
@@ -855,12 +859,12 @@ def sync_pull_ref(self, session, name, namespace, user, requestid):
     """ Synchronize a pull/ reference from the content in the forked repo,
     allowing local checkout of the pull-request.
     """
-    project = pagure.lib._get_project(
+    project = pagure.lib.query._get_project(
         session, namespace=namespace, name=name, user=user
     )
 
     with project.lock("WORKER"):
-        request = pagure.lib.search_pull_requests(
+        request = pagure.lib.query.search_pull_requests(
             session, project_id=project.id, requestid=requestid
         )
         _log.debug(
@@ -887,7 +891,7 @@ def update_pull_request(self, session, pr_uid):
     """ Updates a pull-request in the DB once a commit was pushed to it in
     git.
     """
-    request = pagure.lib.get_request_by_uid(session, pr_uid)
+    request = pagure.lib.query.get_request_by_uid(session, pr_uid)
 
     with request.project.lock("WORKER"):
 
@@ -990,7 +994,7 @@ def commits_author_stats(self, session, repopath):
             continue
         # For each recorded user info, check if we know the e-mail address of
         # the user.
-        user = pagure.lib.search_user(session, email=email)
+        user = pagure.lib.query.search_user(session, email=email)
         if user and (user.default_email != email or user.fullname != name):
             # We know the the user, but the name or e-mail used in Git commit
             # does not match their default e-mail address and full name. Let's
@@ -1053,7 +1057,7 @@ def link_pr_to_ticket(self, session, pr_uid):
     """
     _log.info("LINK_PR_TO_TICKET: Linking ticket(s) to PR for: %s" % pr_uid)
 
-    request = pagure.lib.get_request_by_uid(session, pr_uid)
+    request = pagure.lib.query.get_request_by_uid(session, pr_uid)
     if not request:
         _log.info("LINK_PR_TO_TICKET: Not PR found for: %s" % pr_uid)
         return
@@ -1096,7 +1100,7 @@ def link_pr_to_ticket(self, session, pr_uid):
                 "LINK_PR_TO_TICKET: Link ticket %s to PRs %s"
                 % (issue, request)
             )
-            pagure.lib.link_pr_issue(session, issue, request)
+            pagure.lib.query.link_pr_issue(session, issue, request)
 
         for issue in pagure.lib.link.get_relation(
             session, name, user, namespace, line, "relates"
@@ -1105,7 +1109,7 @@ def link_pr_to_ticket(self, session, pr_uid):
                 "LINK_PR_TO_TICKET: Link ticket %s to PRs %s"
                 % (issue, request)
             )
-            pagure.lib.link_pr_issue(session, issue, request)
+            pagure.lib.query.link_pr_issue(session, issue, request)
 
     try:
         session.commit()
@@ -1117,7 +1121,7 @@ def link_pr_to_ticket(self, session, pr_uid):
 @conn.task(queue=pagure_config.get("MEDIUM_CELERY_QUEUE", None), bind=True)
 @pagure_task
 def pull_request_ready_branch(self, session, namespace, name, user):
-    repo = pagure.lib._get_project(
+    repo = pagure.lib.query._get_project(
         session, name, user=user, namespace=namespace
     )
     repo_obj = pygit2.Repository(pagure.utils.get_repo_path(repo))
@@ -1183,7 +1187,7 @@ def pull_request_ready_branch(self, session, namespace, name, user):
                     "target_branch": compare_branch or "master",
                 }
 
-    prs = pagure.lib.search_pull_requests(
+    prs = pagure.lib.query.search_pull_requests(
         session, project_id_from=repo.id, status="Open"
     )
     branches_pr = {}

+ 4 - 4
pagure/lib/tasks_mirror.py

@@ -25,7 +25,7 @@ from cryptography.hazmat.backends import default_backend
 from cryptography.hazmat.primitives.asymmetric import rsa
 from cryptography.hazmat.primitives import serialization
 
-import pagure.lib
+import pagure.lib.query
 from pagure.config import config as pagure_config
 from pagure.lib.tasks import pagure_task
 from pagure.utils import ssh_urlpattern
@@ -113,7 +113,7 @@ def setup_mirroring(self, session, username, namespace, name):
     plugin = pagure.lib.plugins.get_plugin("Mirroring")
     plugin.db_object()
 
-    project = pagure.lib._get_project(
+    project = pagure.lib.query._get_project(
         session, namespace=namespace, name=name, user=username
     )
 
@@ -167,7 +167,7 @@ def teardown_mirroring(self, session, username, namespace, name):
     plugin = pagure.lib.plugins.get_plugin("Mirroring")
     plugin.db_object()
 
-    project = pagure.lib._get_project(
+    project = pagure.lib.query._get_project(
         session, namespace=namespace, name=name, user=username
     )
 
@@ -196,7 +196,7 @@ def mirror_project(self, session, username, namespace, name):
     plugin = pagure.lib.plugins.get_plugin("Mirroring")
     plugin.db_object()
 
-    project = pagure.lib._get_project(
+    project = pagure.lib.query._get_project(
         session, namespace=namespace, name=name, user=username
     )
 

+ 7 - 7
pagure/lib/tasks_services.py

@@ -28,7 +28,7 @@ from celery.utils.log import get_task_logger
 from kitchen.text.converters import to_bytes
 from sqlalchemy.exc import SQLAlchemyError
 
-import pagure.lib
+import pagure.lib.query
 from pagure.config import config as pagure_config
 from pagure.lib.tasks import pagure_task
 from pagure.mail_logging import format_callstack
@@ -133,7 +133,7 @@ def webhook_notification(
     :type user: None or str
 
     """
-    project = pagure.lib._get_project(
+    project = pagure.lib.query._get_project(
         session, namespace=namespace, name=name, user=user
     )
 
@@ -189,7 +189,7 @@ def log_commit_send_notifications(
         name,
         username,
     )
-    project = pagure.lib._get_project(
+    project = pagure.lib.query._get_project(
         session, name, user=username, namespace=namespace
     )
 
@@ -288,7 +288,7 @@ def load_json_commits_to_db(
         username,
     )
 
-    project = pagure.lib._get_project(
+    project = pagure.lib.query._get_project(
         session, name, user=username, namespace=namespace
     )
 
@@ -376,7 +376,7 @@ def load_json_commits_to_db(
                     "No agent found: %s" % agent
                 )
             if agent != "pagure":
-                user_obj = pagure.lib.get_user(session, agent)
+                user_obj = pagure.lib.query.get_user(session, agent)
                 pagure.lib.notify.send_email(
                     "\n".join(mail_body),
                     "Issue import report",
@@ -406,7 +406,7 @@ def trigger_ci_build(
         return
 
     if pr_uid:
-        pr = pagure.lib.get_request_by_uid(session, pr_uid)
+        pr = pagure.lib.query.get_request_by_uid(session, pr_uid)
         if pr.remote:
             project_name = pr.project_to.fullname
         else:
@@ -415,7 +415,7 @@ def trigger_ci_build(
     user, namespace, project_name = split_project_fullname(project_name)
 
     _log.info("Pagure-CI: Looking for project: %s", project_name)
-    project = pagure.lib.get_authorized_project(
+    project = pagure.lib.query.get_authorized_project(
         session=session,
         project_name=project_name,
         user=user,

+ 9 - 9
pagure/pfmarkdown.py

@@ -30,7 +30,7 @@ import pygit2
 import re
 import six
 
-import pagure.lib
+import pagure.lib.query
 from pagure.config import config as pagure_config
 
 
@@ -81,7 +81,7 @@ class MentionPattern(markdown.inlinepatterns.Pattern):
         """ When the pattern matches, update the text. """
         name = markdown.util.AtomicString(m.group(2))
         text = "@%s" % name
-        user = pagure.lib.search_user(flask.g.session, username=name)
+        user = pagure.lib.query.search_user(flask.g.session, username=name)
         if not user:
             return text
 
@@ -157,7 +157,7 @@ class CommitLinkPattern(markdown.inlinepatterns.Pattern):
             user = user.rstrip("/")
             text = "%s/%s" % (user.rstrip("/"), text)
 
-        if pagure.lib.search_projects(
+        if pagure.lib.query.search_projects(
             flask.g.session,
             username=user,
             fork=is_fork,
@@ -285,7 +285,7 @@ class ImplicitCommitPattern(markdown.inlinepatterns.Pattern):
         except RuntimeError:
             return text
 
-        if pagure.lib.search_projects(
+        if pagure.lib.query.search_projects(
             flask.g.session, username=user, namespace=namespace, pattern=repo
         ) and _commit_exists(user, namespace, repo, githash):
             return _obj_anchor_tag(user, namespace, repo, githash, text[:7])
@@ -402,14 +402,14 @@ def makeExtension(*arg, **kwargs):
 def _issue_exists(user, namespace, repo, idx):
     """ Utility method checking if a given issue exists. """
 
-    repo_obj = pagure.lib.get_authorized_project(
+    repo_obj = pagure.lib.query.get_authorized_project(
         flask.g.session, project_name=repo, user=user, namespace=namespace
     )
 
     if not repo_obj:
         return False
 
-    issue_obj = pagure.lib.search_issues(
+    issue_obj = pagure.lib.query.search_issues(
         flask.g.session, repo=repo_obj, issueid=idx
     )
     if not issue_obj:
@@ -420,14 +420,14 @@ def _issue_exists(user, namespace, repo, idx):
 
 def _pr_exists(user, namespace, repo, idx):
     """ Utility method checking if a given PR exists. """
-    repo_obj = pagure.lib.get_authorized_project(
+    repo_obj = pagure.lib.query.get_authorized_project(
         flask.g.session, project_name=repo, user=user, namespace=namespace
     )
 
     if not repo_obj:
         return False
 
-    pr_obj = pagure.lib.search_pull_requests(
+    pr_obj = pagure.lib.query.search_pull_requests(
         flask.g.session, project_id=repo_obj.id, requestid=idx
     )
     if not pr_obj:
@@ -438,7 +438,7 @@ def _pr_exists(user, namespace, repo, idx):
 
 def _commit_exists(user, namespace, repo, githash):
     """ Utility method checking if a given commit exists. """
-    repo_obj = pagure.lib.get_authorized_project(
+    repo_obj = pagure.lib.query.get_authorized_project(
         flask.g.session, project_name=repo, user=user, namespace=namespace
     )
     if not repo_obj:

+ 52 - 48
pagure/ui/app.py

@@ -19,8 +19,8 @@ import flask
 from sqlalchemy.exc import SQLAlchemyError
 
 import pagure.exceptions
-import pagure.lib
 import pagure.lib.git
+import pagure.lib.query
 import pagure.forms
 import pagure.ui.filters
 from pagure.config import config as pagure_config
@@ -82,7 +82,7 @@ def index():
     if authenticated():
         private = flask.g.fas_user.username
 
-    repos = pagure.lib.search_projects(
+    repos = pagure.lib.query.search_projects(
         flask.g.session,
         fork=False,
         start=start,
@@ -91,7 +91,7 @@ def index():
         private=private,
     )
 
-    num_repos = pagure.lib.search_projects(
+    num_repos = pagure.lib.query.search_projects(
         flask.g.session, fork=False, private=private, count=True
     )
     total_page = int(ceil(num_repos / float(limit)) if num_repos > 0 else 1)
@@ -111,7 +111,7 @@ def index():
 def get_userdash_common(user):
     userdash_counts = {}
 
-    userdash_counts["repos_length"] = pagure.lib.list_users_projects(
+    userdash_counts["repos_length"] = pagure.lib.query.list_users_projects(
         flask.g.session,
         username=flask.g.fas_user.username,
         exclude_groups=None,
@@ -120,7 +120,7 @@ def get_userdash_common(user):
         count=True,
     )
 
-    userdash_counts["forks_length"] = pagure.lib.search_projects(
+    userdash_counts["forks_length"] = pagure.lib.query.search_projects(
         flask.g.session,
         username=flask.g.fas_user.username,
         fork=True,
@@ -129,7 +129,7 @@ def get_userdash_common(user):
     )
 
     userdash_counts["watchlist_length"] = len(
-        pagure.lib.user_watch_list(
+        pagure.lib.query.user_watch_list(
             flask.g.session,
             user=flask.g.fas_user.username,
             exclude_groups=pagure_config.get("EXCLUDE_GROUP_INDEX"),
@@ -138,7 +138,7 @@ def get_userdash_common(user):
 
     userdash_counts["groups_length"] = len(user.groups)
 
-    search_data = pagure.lib.list_users_projects(
+    search_data = pagure.lib.query.list_users_projects(
         flask.g.session,
         username=flask.g.fas_user.username,
         private=flask.g.fas_user.username,
@@ -160,7 +160,7 @@ def userdash_projects():
 
     for group in user.groups:
         groups.append(
-            pagure.lib.search_groups(
+            pagure.lib.query.search_groups(
                 flask.g.session, group_name=group, group_type="user"
             )
         )
@@ -183,7 +183,7 @@ def userdash_projects():
     pattern = "*" + search_pattern + "*" if search_pattern else search_pattern
 
     start = limit * (repopage - 1)
-    repos = pagure.lib.list_users_projects(
+    repos = pagure.lib.query.list_users_projects(
         flask.g.session,
         username=flask.g.fas_user.username,
         exclude_groups=None,
@@ -195,7 +195,7 @@ def userdash_projects():
         acls=[acl] if acl else None,
     )
 
-    filtered_repos_count = pagure.lib.list_users_projects(
+    filtered_repos_count = pagure.lib.query.list_users_projects(
         flask.g.session,
         username=flask.g.fas_user.username,
         exclude_groups=None,
@@ -261,7 +261,7 @@ def userdash_activity():
     user = _get_user(username=flask.g.fas_user.username)
     userdash_counts, search_data = get_userdash_common(user)
 
-    messages = pagure.lib.get_watchlist_messages(
+    messages = pagure.lib.query.get_watchlist_messages(
         flask.g.session, user, limit=20
     )
 
@@ -289,7 +289,7 @@ def userdash_groups():
 
     for group in user.groups:
         groups.append(
-            pagure.lib.search_groups(
+            pagure.lib.query.search_groups(
                 flask.g.session, group_name=group, group_type="user"
             )
         )
@@ -326,7 +326,7 @@ def userdash_forks():
         forkpage = 1
 
     start = limit * (forkpage - 1)
-    forks = pagure.lib.search_projects(
+    forks = pagure.lib.query.search_projects(
         flask.g.session,
         username=flask.g.fas_user.username,
         fork=True,
@@ -361,7 +361,7 @@ def userdash_watchlist():
     """ User Dashboard page for a user's watchlist
     """
 
-    watch_list = pagure.lib.user_watch_list(
+    watch_list = pagure.lib.query.user_watch_list(
         flask.g.session,
         user=flask.g.fas_user.username,
         exclude_groups=pagure_config.get("EXCLUDE_GROUP_INDEX"),
@@ -400,7 +400,7 @@ def index_auth():
 
     # PROJECTS
     start = limit * (repopage - 1)
-    repos = pagure.lib.search_projects(
+    repos = pagure.lib.query.search_projects(
         flask.g.session,
         username=flask.g.fas_user.username,
         exclude_groups=pagure_config.get("EXCLUDE_GROUP_INDEX"),
@@ -412,7 +412,7 @@ def index_auth():
     if repos and acl:
         repos = _filter_acls(repos, acl, user)
 
-    repos_length = pagure.lib.search_projects(
+    repos_length = pagure.lib.query.search_projects(
         flask.g.session,
         username=flask.g.fas_user.username,
         exclude_groups=pagure_config.get("EXCLUDE_GROUP_INDEX"),
@@ -434,7 +434,7 @@ def index_auth():
         forkpage = 1
 
     start = limit * (forkpage - 1)
-    forks = pagure.lib.search_projects(
+    forks = pagure.lib.query.search_projects(
         flask.g.session,
         username=flask.g.fas_user.username,
         fork=True,
@@ -443,7 +443,7 @@ def index_auth():
         limit=limit,
     )
 
-    forks_length = pagure.lib.search_projects(
+    forks_length = pagure.lib.query.search_projects(
         flask.g.session,
         username=flask.g.fas_user.username,
         fork=True,
@@ -456,7 +456,7 @@ def index_auth():
         ceil(forks_length / float(limit)) if forks_length > 0 else 1
     )
 
-    watch_list = pagure.lib.user_watch_list(
+    watch_list = pagure.lib.query.user_watch_list(
         flask.g.session,
         user=flask.g.fas_user.username,
         exclude_groups=pagure_config.get("EXCLUDE_GROUP_INDEX"),
@@ -526,7 +526,7 @@ def view_users(username=None):
     except ValueError:
         page = 1
 
-    users = pagure.lib.search_user(flask.g.session, pattern=username)
+    users = pagure.lib.query.search_user(flask.g.session, pattern=username)
 
     private = False
     # Condition to check non-authorized user should't be able to access private
@@ -543,7 +543,7 @@ def view_users(username=None):
     total_page = int(ceil(users_length / float(limit)))
 
     for user in users:
-        repos_length = pagure.lib.search_projects(
+        repos_length = pagure.lib.query.search_projects(
             flask.g.session,
             username=user.user,
             fork=False,
@@ -551,7 +551,7 @@ def view_users(username=None):
             private=private,
         )
 
-        forks_length = pagure.lib.search_projects(
+        forks_length = pagure.lib.query.search_projects(
             flask.g.session,
             username=user.user,
             fork=True,
@@ -603,7 +603,7 @@ def view_projects(pattern=None, namespace=None):
     limit = pagure_config["ITEM_PER_PAGE"]
     start = limit * (page - 1)
 
-    projects = pagure.lib.search_projects(
+    projects = pagure.lib.query.search_projects(
         flask.g.session,
         pattern=pattern,
         namespace=namespace,
@@ -626,7 +626,7 @@ def view_projects(pattern=None, namespace=None):
             )
         )
 
-    projects_length = pagure.lib.search_projects(
+    projects_length = pagure.lib.query.search_projects(
         flask.g.session,
         pattern=pattern,
         namespace=namespace,
@@ -654,7 +654,7 @@ def view_projects(pattern=None, namespace=None):
 def get_userprofile_common(user):
     userprofile_counts = {}
 
-    userprofile_counts["repos_length"] = pagure.lib.search_projects(
+    userprofile_counts["repos_length"] = pagure.lib.query.search_projects(
         flask.g.session,
         username=user.username,
         fork=False,
@@ -663,7 +663,7 @@ def get_userprofile_common(user):
         count=True,
     )
 
-    userprofile_counts["forks_length"] = pagure.lib.search_projects(
+    userprofile_counts["forks_length"] = pagure.lib.query.search_projects(
         flask.g.session,
         username=user.username,
         fork=True,
@@ -685,7 +685,7 @@ def view_user(username):
     # even if the user is viewing themself
     private = False
 
-    owned_repos = pagure.lib.list_users_projects(
+    owned_repos = pagure.lib.query.list_users_projects(
         flask.g.session,
         username=username,
         exclude_groups=None,
@@ -726,7 +726,7 @@ def userprofile_projects(username):
     limit = pagure_config["ITEM_PER_PAGE"]
     repo_start = limit * (repopage - 1)
 
-    repos = pagure.lib.search_projects(
+    repos = pagure.lib.query.search_projects(
         flask.g.session,
         username=username,
         fork=False,
@@ -772,7 +772,7 @@ def userprofile_forks(username):
     limit = pagure_config["ITEM_PER_PAGE"]
     fork_start = limit * (forkpage - 1)
 
-    forks = pagure.lib.search_projects(
+    forks = pagure.lib.query.search_projects(
         flask.g.session,
         username=username,
         fork=True,
@@ -833,7 +833,7 @@ def view_user2(username):
     if authenticated() and username == flask.g.fas_user.username:
         private = flask.g.fas_user.username
 
-    repos = pagure.lib.search_projects(
+    repos = pagure.lib.query.search_projects(
         flask.g.session,
         username=username,
         fork=False,
@@ -846,7 +846,7 @@ def view_user2(username):
     if repos and acl:
         repos = _filter_acls(repos, acl, user)
 
-    repos_length = pagure.lib.search_projects(
+    repos_length = pagure.lib.query.search_projects(
         flask.g.session,
         username=username,
         fork=False,
@@ -855,7 +855,7 @@ def view_user2(username):
         count=True,
     )
 
-    forks = pagure.lib.search_projects(
+    forks = pagure.lib.query.search_projects(
         flask.g.session,
         username=username,
         fork=True,
@@ -864,7 +864,7 @@ def view_user2(username):
         private=private,
     )
 
-    forks_length = pagure.lib.search_projects(
+    forks_length = pagure.lib.query.search_projects(
         flask.g.session,
         username=username,
         fork=True,
@@ -897,7 +897,7 @@ def view_user_requests(username):
     """
     user = _get_user(username=username)
 
-    requests = pagure.lib.get_pull_request_of_user(
+    requests = pagure.lib.query.get_pull_request_of_user(
         flask.g.session, username=username
     )
 
@@ -976,7 +976,9 @@ def userprofile_groups(username):
     groups = []
     for groupname in user.groups:
         groups.append(
-            pagure.lib.search_groups(flask.g.session, group_name=groupname)
+            pagure.lib.query.search_groups(
+                flask.g.session, group_name=groupname
+            )
         )
 
     return flask.render_template(
@@ -997,7 +999,7 @@ def new_project():
     """ Form to create a new project.
     """
 
-    user = pagure.lib.search_user(
+    user = pagure.lib.query.search_user(
         flask.g.session, username=flask.g.fas_user.username
     )
 
@@ -1040,7 +1042,7 @@ def new_project():
             ignore_existing_repos = False
 
         try:
-            task = pagure.lib.new_project(
+            task = pagure.lib.query.new_project(
                 flask.g.session,
                 name=name,
                 private=private,
@@ -1143,7 +1145,7 @@ def update_user_settings():
             settings[key] = flask.request.form[key]
 
         try:
-            message = pagure.lib.update_user_settings(
+            message = pagure.lib.query.update_user_settings(
                 flask.g.session, settings=settings, user=user.username
             )
             flask.g.session.commit()
@@ -1175,7 +1177,7 @@ def add_user_sshkey():
     if form.validate_on_submit():
         user = _get_user(username=flask.g.fas_user.username)
         try:
-            msg = pagure.lib.add_sshkey_to_project_or_user(
+            msg = pagure.lib.query.add_sshkey_to_project_or_user(
                 flask.g.session,
                 ssh_key=form.ssh_key.data,
                 pushaccess=True,
@@ -1183,7 +1185,7 @@ def add_user_sshkey():
                 user=user,
             )
             flask.g.session.commit()
-            pagure.lib.create_user_ssh_keys_on_disk(
+            pagure.lib.query.create_user_ssh_keys_on_disk(
                 user, pagure_config.get("GITOLITE_KEYDIR", None)
             )
             pagure.lib.tasks.gitolite_post_compile_only.delay()
@@ -1234,7 +1236,7 @@ def remove_user_sshkey(keyid):
 
         try:
             flask.g.session.commit()
-            pagure.lib.create_user_ssh_keys_on_disk(
+            pagure.lib.query.create_user_ssh_keys_on_disk(
                 user, pagure_config.get("GITOLITE_KEYDIR", None)
             )
             pagure.lib.tasks.gitolite_post_compile_only.delay()
@@ -1326,7 +1328,9 @@ def add_user_email():
         email = form.email.data
 
         try:
-            pagure.lib.add_user_pending_email(flask.g.session, user, email)
+            pagure.lib.query.add_user_pending_email(
+                flask.g.session, user, email
+            )
             flask.g.session.commit()
             flask.flash("Email pending validation")
             return flask.redirect(flask.url_for("ui_ns.user_settings"))
@@ -1395,7 +1399,7 @@ def reconfirm_email():
         email = form.email.data
 
         try:
-            pagure.lib.resend_pending_email(flask.g.session, user, email)
+            pagure.lib.query.resend_pending_email(flask.g.session, user, email)
             flask.g.session.commit()
             flask.flash("Confirmation email re-sent")
         except pagure.exceptions.PagureException as err:
@@ -1418,12 +1422,12 @@ def confirm_email(token):
             flask.url_for("auth_login", next=flask.request.url)
         )
 
-    email = pagure.lib.search_pending_email(flask.g.session, token=token)
+    email = pagure.lib.query.search_pending_email(flask.g.session, token=token)
     if not email:
         flask.flash("No email associated with this token.", "error")
     else:
         try:
-            pagure.lib.add_email_to_user(
+            pagure.lib.query.add_email_to_user(
                 flask.g.session, email.user, email.email
             )
             flask.g.session.delete(email)
@@ -1469,14 +1473,14 @@ def add_api_user_token():
     # Ensure the user is in the DB at least
     user = _get_user(username=flask.g.fas_user.username)
 
-    acls = pagure.lib.get_acls(
+    acls = pagure.lib.query.get_acls(
         flask.g.session, restrict=pagure_config.get("CROSS_PROJECT_ACLS")
     )
     form = pagure.forms.NewTokenForm(acls=acls)
 
     if form.validate_on_submit():
         try:
-            msg = pagure.lib.add_token_to_user(
+            msg = pagure.lib.query.add_token_to_user(
                 flask.g.session,
                 project=None,
                 description=form.description.data.strip() or None,
@@ -1513,7 +1517,7 @@ def revoke_api_user_token(token_id):
         url = flask.url_for(".user_settings")
         return flask.redirect(flask.url_for("auth_login", next=url))
 
-    token = pagure.lib.get_api_token(flask.g.session, token_id)
+    token = pagure.lib.query.get_api_token(flask.g.session, token_id)
 
     if not token or token.user.username != flask.g.fas_user.username:
         flask.abort(404, "Token not found")

+ 2 - 2
pagure/ui/clone.py

@@ -20,10 +20,10 @@ import requests
 import werkzeug
 
 import pagure.exceptions
-import pagure.lib
 import pagure.lib.git
 import pagure.lib.mimetype
 import pagure.lib.plugins
+import pagure.lib.query
 import pagure.lib.tasks
 import pagure.forms
 import pagure.ui.plugins
@@ -218,7 +218,7 @@ def clone_proxy(project, username=None, namespace=None):
             # Anonymous pushing... nope
             flask.abort(403, "Unauthenticated push not allowed")
 
-    project = pagure.lib.get_authorized_project(
+    project = pagure.lib.query.get_authorized_project(
         flask.g.session,
         project,
         user=username,

+ 8 - 8
pagure/ui/fas_login.py

@@ -17,7 +17,7 @@ from flask import Markup
 
 from sqlalchemy.exc import SQLAlchemyError
 
-import pagure
+import pagure.lib.query
 import pagure.utils
 from pagure.flask_app import logout
 from pagure.config import config as pagure_config
@@ -42,13 +42,13 @@ def set_user(return_url):
         return flask.redirect(return_url)
 
     flask.session["_new_user"] = False
-    user = pagure.lib.search_user(
+    user = pagure.lib.query.search_user(
         flask.g.session, username=flask.g.fas_user.username
     )
     if not user:
         flask.session["_new_user"] = True
     else:
-        user_email = pagure.lib.search_user(
+        user_email = pagure.lib.query.search_user(
             flask.g.session, email=flask.g.fas_user.email
         )
         if user_email and user_email.user != user.user:
@@ -61,7 +61,7 @@ def set_user(return_url):
             return flask.redirect(return_url)
 
     try:
-        pagure.lib.set_up_user(
+        pagure.lib.query.set_up_user(
             session=flask.g.session,
             username=flask.g.fas_user.username,
             fullname=flask.g.fas_user.fullname,
@@ -72,7 +72,7 @@ def set_user(return_url):
 
         # If groups are managed outside pagure, set up the user at login
         if not pagure_config.get("ENABLE_GROUP_MNGT", False):
-            user = pagure.lib.search_user(
+            user = pagure.lib.query.search_user(
                 flask.g.session, username=flask.g.fas_user.username
             )
             groups = set(user.groups)
@@ -81,12 +81,12 @@ def set_user(return_url):
             for group in fas_groups - groups:
                 groupobj = None
                 if group:
-                    groupobj = pagure.lib.search_groups(
+                    groupobj = pagure.lib.query.search_groups(
                         flask.g.session, group_name=group
                     )
                 if groupobj:
                     try:
-                        pagure.lib.add_user_to_group(
+                        pagure.lib.query.add_user_to_group(
                             session=flask.g.session,
                             username=flask.g.fas_user.username,
                             group=groupobj,
@@ -100,7 +100,7 @@ def set_user(return_url):
             for group in groups - fas_groups:
                 if group:
                     try:
-                        pagure.lib.delete_user_of_group(
+                        pagure.lib.query.delete_user_of_group(
                             session=flask.g.session,
                             username=flask.g.fas_user.username,
                             groupname=group,

+ 9 - 9
pagure/ui/filters.py

@@ -25,7 +25,7 @@ from six.moves.urllib.parse import urlparse, parse_qsl
 from jinja2 import escape
 
 import pagure.exceptions
-import pagure.lib
+import pagure.lib.query
 import pagure.forms
 from pagure.config import config as pagure_config
 from pagure.ui import UI_NS
@@ -463,7 +463,7 @@ def avatar(packager, size=64, css_class=None):
         packager = packager.decode("utf-8")
 
     if "@" not in packager:
-        user = pagure.lib.search_user(flask.g.session, username=packager)
+        user = pagure.lib.query.search_user(flask.g.session, username=packager)
         if user:
             packager = user.default_email
 
@@ -483,7 +483,7 @@ def avatar(packager, size=64, css_class=None):
 def avatar_url(email, size=64):
     """ Template filter that returns html for avatar of any given Email.
     """
-    return pagure.lib.avatar_url_from_email(email, size)
+    return pagure.lib.query.avatar_url_from_email(email, size)
 
 
 @UI_NS.app_template_filter("short")
@@ -497,7 +497,7 @@ def markdown_filter(text):
     """ Template filter converting a string into html content using the
     markdown library.
     """
-    return pagure.lib.text2markdown(text)
+    return pagure.lib.query.text2markdown(text)
 
 
 @UI_NS.app_template_filter("patch_to_diff")
@@ -535,7 +535,7 @@ def author_to_user(author, size=16, cssclass=None, with_name=True):
     output = escape(author.name)
     if not author.email:
         return output
-    user = pagure.lib.search_user(flask.g.session, email=author.email)
+    user = pagure.lib.query.search_user(flask.g.session, email=author.email)
     if user:
         output = (
             "%(avatar)s <a title='%(name)s' href='%(url)s' "
@@ -568,7 +568,7 @@ def author_to_avatar(author, size=32):
     """
     if not author.email:
         return ""
-    user = pagure.lib.search_user(flask.g.session, email=author.email)
+    user = pagure.lib.query.search_user(flask.g.session, email=author.email)
     output = user.default_email if user else author.email
     return avatar(output.encode("utf-8"), size)
 
@@ -581,7 +581,7 @@ def author_to_user_commits(author, link, size=16, cssclass=None):
     output = author.name
     if not author.email:
         return output
-    user = pagure.lib.search_user(flask.g.session, email=author.email)
+    user = pagure.lib.query.search_user(flask.g.session, email=author.email)
     if user:
         output = "<a href='%s'>%s</a> <a href='%s' %s>%s</a>" % (
             flask.url_for("ui_ns.view_user", username=user.username),
@@ -625,7 +625,7 @@ def no_js(content, ignore=None):
     """ Template filter replacing <script by &lt;script and </script> by
     &lt;/script&gt;
     """
-    return pagure.lib.clean_input(content, ignore=ignore)
+    return pagure.lib.query.clean_input(content, ignore=ignore)
 
 
 @UI_NS.app_template_filter("toRGB")
@@ -763,7 +763,7 @@ def user_can_clone_ssh(username):
     if flask.g.authenticated:
         has_ssh_keys = (
             len(
-                pagure.lib.search_user(
+                pagure.lib.query.search_user(
                     flask.g.session, username=flask.g.fas_user.username
                 ).sshkeys
             )

+ 45 - 43
pagure/ui/fork.py

@@ -29,8 +29,8 @@ from sqlalchemy.exc import SQLAlchemyError
 import pagure
 import pagure.doc_utils
 import pagure.exceptions
-import pagure.lib
 import pagure.lib.git
+import pagure.lib.query
 import pagure.lib.tasks
 import pagure.forms
 from pagure.config import config as pagure_config
@@ -79,17 +79,17 @@ def request_pulls(repo, username=None, namespace=None):
     if not repo.settings.get("pull_requests", True):
         flask.abort(404, "No pull-requests found for this project")
 
-    total_open = pagure.lib.search_pull_requests(
+    total_open = pagure.lib.query.search_pull_requests(
         flask.g.session, project_id=repo.id, status=True, count=True
     )
 
-    total_merged = pagure.lib.search_pull_requests(
+    total_merged = pagure.lib.query.search_pull_requests(
         flask.g.session, project_id=repo.id, status="Merged", count=True
     )
 
     if status.lower() == "merged" or is_true(status, ["false", "0"]):
         status_filter = "Merged"
-        requests = pagure.lib.search_pull_requests(
+        requests = pagure.lib.query.search_pull_requests(
             flask.g.session,
             project_id=repo.id,
             status="Merged",
@@ -103,7 +103,7 @@ def request_pulls(repo, username=None, namespace=None):
         )
     elif is_true(status, ["true", "1", "open"]):
         status_filter = "Open"
-        requests = pagure.lib.search_pull_requests(
+        requests = pagure.lib.query.search_pull_requests(
             flask.g.session,
             project_id=repo.id,
             status="Open",
@@ -117,7 +117,7 @@ def request_pulls(repo, username=None, namespace=None):
         )
     elif status.lower() == "closed":
         status_filter = "Closed"
-        requests = pagure.lib.search_pull_requests(
+        requests = pagure.lib.query.search_pull_requests(
             flask.g.session,
             project_id=repo.id,
             status="Closed",
@@ -131,7 +131,7 @@ def request_pulls(repo, username=None, namespace=None):
         )
     else:
         status_filter = None
-        requests = pagure.lib.search_pull_requests(
+        requests = pagure.lib.query.search_pull_requests(
             flask.g.session,
             project_id=repo.id,
             status=None,
@@ -144,7 +144,7 @@ def request_pulls(repo, username=None, namespace=None):
             limit=flask.g.limit,
         )
 
-    open_cnt = pagure.lib.search_pull_requests(
+    open_cnt = pagure.lib.query.search_pull_requests(
         flask.g.session,
         project_id=repo.id,
         status="Open",
@@ -154,7 +154,7 @@ def request_pulls(repo, username=None, namespace=None):
         count=True,
     )
 
-    merged_cnt = pagure.lib.search_pull_requests(
+    merged_cnt = pagure.lib.query.search_pull_requests(
         flask.g.session,
         project_id=repo.id,
         status="Merged",
@@ -164,7 +164,7 @@ def request_pulls(repo, username=None, namespace=None):
         count=True,
     )
 
-    closed_cnt = pagure.lib.search_pull_requests(
+    closed_cnt = pagure.lib.query.search_pull_requests(
         flask.g.session,
         project_id=repo.id,
         status="Closed",
@@ -237,7 +237,7 @@ def request_pull(repo, requestid, username=None, namespace=None):
     if not repo.settings.get("pull_requests", True):
         flask.abort(404, "No pull-requests found for this project")
 
-    request = pagure.lib.search_pull_requests(
+    request = pagure.lib.query.search_pull_requests(
         flask.g.session, project_id=repo.id, requestid=requestid
     )
 
@@ -325,8 +325,8 @@ def request_pull(repo, requestid, username=None, namespace=None):
         diff_commits=diff_commits,
         diff=diff,
         mergeform=form,
-        subscribers=pagure.lib.get_watch_list(flask.g.session, request),
-        tag_list=pagure.lib.get_tags_of_project(flask.g.session, repo),
+        subscribers=pagure.lib.query.get_watch_list(flask.g.session, request),
+        tag_list=pagure.lib.query.get_tags_of_project(flask.g.session, repo),
         can_delete_branch=can_delete_branch,
     )
 
@@ -386,7 +386,7 @@ def request_pull_to_diff_or_patch(
     if not repo.settings.get("pull_requests", True):
         flask.abort(404, "No pull-requests found for this project")
 
-    request = pagure.lib.search_pull_requests(
+    request = pagure.lib.query.search_pull_requests(
         flask.g.session, project_id=repo.id, requestid=requestid
     )
 
@@ -494,7 +494,7 @@ def request_pull_edit(repo, requestid, username=None, namespace=None):
     if not repo.settings.get("pull_requests", True):
         flask.abort(404, "No pull-requests found for this project")
 
-    request = pagure.lib.search_pull_requests(
+    request = pagure.lib.query.search_pull_requests(
         flask.g.session, project_id=repo.id, requestid=requestid
     )
 
@@ -598,7 +598,7 @@ def pull_request_add_comment(
     if not repo.settings.get("pull_requests", True):
         flask.abort(404, "No pull-requests found for this project")
 
-    request = pagure.lib.search_pull_requests(
+    request = pagure.lib.query.search_pull_requests(
         flask.g.session, project_id=repo.id, requestid=requestid
     )
 
@@ -619,7 +619,7 @@ def pull_request_add_comment(
         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,
@@ -698,7 +698,7 @@ def pull_request_drop_comment(repo, requestid, username=None, namespace=None):
     if not repo.settings.get("pull_requests", True):
         flask.abort(404, "No pull-requests found for this project")
 
-    request = pagure.lib.search_pull_requests(
+    request = pagure.lib.query.search_pull_requests(
         flask.g.session, project_id=repo.id, requestid=requestid
     )
 
@@ -719,7 +719,7 @@ def pull_request_drop_comment(repo, requestid, username=None, namespace=None):
         if flask.request.form.get("drop_comment"):
             commentid = flask.request.form.get("drop_comment")
 
-            comment = pagure.lib.get_request_comment(
+            comment = pagure.lib.query.get_request_comment(
                 flask.g.session, request.uid, commentid
             )
             if comment is None or comment.pull_request.project != repo:
@@ -789,14 +789,14 @@ def pull_request_edit_comment(
     if not project.settings.get("pull_requests", True):
         flask.abort(404, "No pull-requests found for this project")
 
-    request = pagure.lib.search_pull_requests(
+    request = pagure.lib.query.search_pull_requests(
         flask.g.session, project_id=project.id, requestid=requestid
     )
 
     if not request:
         flask.abort(404, "Pull-request not found")
 
-    comment = pagure.lib.get_request_comment(
+    comment = pagure.lib.query.get_request_comment(
         flask.g.session, request.uid, commentid
     )
 
@@ -815,7 +815,7 @@ def pull_request_edit_comment(
 
         updated_comment = form.update_comment.data
         try:
-            message = pagure.lib.edit_comment(
+            message = pagure.lib.query.edit_comment(
                 flask.g.session,
                 parent=request,
                 comment=comment,
@@ -884,7 +884,7 @@ def reopen_request_pull(repo, requestid, username=None, namespace=None):
         if not flask.g.repo.settings.get("pull_requests", True):
             flask.abort(404, "No pull-requests found for this project")
 
-        request = pagure.lib.search_pull_requests(
+        request = pagure.lib.query.search_pull_requests(
             flask.g.session, project_id=flask.g.repo.id, requestid=requestid
         )
 
@@ -901,7 +901,7 @@ def reopen_request_pull(repo, requestid, username=None, namespace=None):
             )
 
         try:
-            pagure.lib.reopen_pull_request(
+            pagure.lib.query.reopen_pull_request(
                 flask.g.session, request, flask.g.fas_user.username
             )
         except pagure.exceptions.PagureException as err:
@@ -972,7 +972,7 @@ def merge_request_pull(repo, requestid, username=None, namespace=None):
     if not repo.settings.get("pull_requests", True):
         flask.abort(404, "No pull-requests found for this project")
 
-    request = pagure.lib.search_pull_requests(
+    request = pagure.lib.query.search_pull_requests(
         flask.g.session, project_id=repo.id, requestid=requestid
     )
 
@@ -1146,7 +1146,7 @@ def cancel_request_pull(repo, requestid, username=None, namespace=None):
         if not flask.g.repo.settings.get("pull_requests", True):
             flask.abort(404, "No pull-requests found for this project")
 
-        request = pagure.lib.search_pull_requests(
+        request = pagure.lib.query.search_pull_requests(
             flask.g.session, project_id=flask.g.repo.id, requestid=requestid
         )
 
@@ -1162,7 +1162,7 @@ def cancel_request_pull(repo, requestid, username=None, namespace=None):
                 "You are not allowed to cancel pull-request for this project",
             )
 
-        pagure.lib.close_pull_request(
+        pagure.lib.query.close_pull_request(
             flask.g.session, request, flask.g.fas_user.username, merged=False
         )
         try:
@@ -1212,7 +1212,7 @@ def refresh_request_pull(repo, requestid, username=None, namespace=None):
         if not flask.g.repo.settings.get("pull_requests", True):
             flask.abort(404, "No pull-requests found for this project")
 
-        request = pagure.lib.search_pull_requests(
+        request = pagure.lib.query.search_pull_requests(
             flask.g.session, project_id=flask.g.repo.id, requestid=requestid
         )
 
@@ -1274,7 +1274,7 @@ def update_pull_requests(repo, requestid, username=None, namespace=None):
     if not repo.settings.get("pull_requests", True):
         flask.abort(404, "No pull-request allowed on this project")
 
-    request = pagure.lib.search_pull_requests(
+    request = pagure.lib.query.search_pull_requests(
         flask.g.session, project_id=repo.id, requestid=requestid
     )
 
@@ -1298,7 +1298,7 @@ def update_pull_requests(repo, requestid, username=None, namespace=None):
         messages = set()
         try:
             # Adjust (add/remove) tags
-            msgs = pagure.lib.update_tags(
+            msgs = pagure.lib.query.update_tags(
                 flask.g.session,
                 obj=request,
                 tags=tags,
@@ -1308,7 +1308,7 @@ def update_pull_requests(repo, requestid, username=None, namespace=None):
 
             if flask.g.repo_committer:
                 # Assign or update assignee of the ticket
-                msg = pagure.lib.add_pull_request_assignee(
+                msg = pagure.lib.query.add_pull_request_assignee(
                     flask.g.session,
                     request=request,
                     assignee=flask.request.form.get("user", "").strip()
@@ -1321,7 +1321,7 @@ def update_pull_requests(repo, requestid, username=None, namespace=None):
             if messages:
                 # Add the comment for field updates:
                 not_needed = set(["Comment added", "Updated comment"])
-                pagure.lib.add_metadata_update_notif(
+                pagure.lib.query.add_metadata_update_notif(
                     session=flask.g.session,
                     obj=request,
                     messages=messages - not_needed,
@@ -1369,7 +1369,7 @@ def fork_project(repo, username=None, namespace=None):
     if not form.validate_on_submit():
         flask.abort(400)
 
-    if pagure.lib._get_project(
+    if pagure.lib.query._get_project(
         flask.g.session,
         repo.name,
         user=flask.g.fas_user.username,
@@ -1385,7 +1385,7 @@ def fork_project(repo, username=None, namespace=None):
         )
 
     try:
-        task = pagure.lib.fork_project(
+        task = pagure.lib.query.fork_project(
             session=flask.g.session, repo=repo, user=flask.g.fas_user.username
         )
 
@@ -1484,13 +1484,15 @@ def new_request_pull(
             p_namespace, p_name = left.split("/", 1)
         else:
             p_name = left
-        parent = pagure.lib.get_authorized_project(
+        parent = pagure.lib.query.get_authorized_project(
             flask.g.session, p_name, user=p_username, namespace=p_namespace
         )
         if parent:
             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 parent.url_path not in family:
                 flask.abort(
@@ -1543,7 +1545,7 @@ def new_request_pull(
             if diff_commits:
                 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,
@@ -1770,7 +1772,7 @@ def new_remote_request_pull(repo, username=None, namespace=None):
             if repo.parent:
                 parent = repo.parent
 
-            request = pagure.lib.new_pull_request(
+            request = pagure.lib.query.new_pull_request(
                 flask.g.session,
                 repo_to=parent,
                 branch_to=branch_to,
@@ -1782,7 +1784,7 @@ def new_remote_request_pull(repo, username=None, namespace=None):
             )
 
             if form.initial_comment.data.strip() != "":
-                pagure.lib.add_pull_request_comment(
+                pagure.lib.query.add_pull_request_comment(
                     flask.g.session,
                     request=request,
                     commit=None,
@@ -1876,7 +1878,7 @@ def fork_edit_file(repo, branchname, filename, username=None, namespace=None):
     if not form.validate_on_submit():
         flask.abort(400)
 
-    if pagure.lib._get_project(
+    if pagure.lib.query._get_project(
         flask.g.session,
         repo.name,
         namespace=repo.namespace,
@@ -1895,7 +1897,7 @@ def fork_edit_file(repo, branchname, filename, username=None, namespace=None):
         )
 
     try:
-        task = pagure.lib.fork_project(
+        task = pagure.lib.query.fork_project(
             session=flask.g.session,
             repo=repo,
             user=flask.g.fas_user.username,
@@ -1958,14 +1960,14 @@ def pull_request_comment_add_reaction(
     if not form.validate_on_submit():
         flask.abort(400, "CSRF token not valid")
 
-    request = pagure.lib.search_pull_requests(
+    request = pagure.lib.query.search_pull_requests(
         flask.g.session, requestid=requestid, project_id=repo.id
     )
 
     if not request:
         flask.abort(404, "Comment not found")
 
-    comment = pagure.lib.get_request_comment(
+    comment = pagure.lib.query.get_request_comment(
         flask.g.session, request.uid, commentid
     )
 

+ 18 - 14
pagure/ui/groups.py

@@ -16,8 +16,8 @@ import flask
 from sqlalchemy.exc import SQLAlchemyError
 
 import pagure.forms
-import pagure.lib
 import pagure.lib.git
+import pagure.lib.query
 from pagure.config import config as pagure_config
 from pagure.ui import UI_NS
 from pagure.utils import login_required
@@ -34,13 +34,15 @@ def group_lists():
     group_type = "user"
     if pagure.utils.is_admin():
         group_type = None
-    groups = pagure.lib.search_groups(flask.g.session, group_type=group_type)
+    groups = pagure.lib.query.search_groups(
+        flask.g.session, group_type=group_type
+    )
 
     group_types = ["user"]
     if pagure.utils.is_admin():
         group_types = [
             grp.group_type
-            for grp in pagure.lib.get_group_types(flask.g.session)
+            for grp in pagure.lib.query.get_group_types(flask.g.session)
         ]
         # Make sure the admin type is always the last one
         group_types.remove("admin")
@@ -63,7 +65,7 @@ def view_group(group):
     group_type = "user"
     if pagure.utils.is_admin():
         group_type = None
-    group = pagure.lib.search_groups(
+    group = pagure.lib.query.search_groups(
         flask.g.session, group_name=group, group_type=group_type
     )
 
@@ -81,7 +83,7 @@ def view_group(group):
         username = form.user.data
 
         try:
-            msg = pagure.lib.add_user_to_group(
+            msg = pagure.lib.query.add_user_to_group(
                 flask.g.session,
                 username=username,
                 group=group,
@@ -113,7 +115,7 @@ def view_group(group):
 
     member = False
     if flask.g.authenticated:
-        member = pagure.lib.is_group_member(
+        member = pagure.lib.query.is_group_member(
             flask.g.session, flask.g.fas_user.username, group.group_name
         )
 
@@ -134,7 +136,7 @@ def edit_group(group):
     is_admin = pagure.utils.is_admin()
     if is_admin:
         group_type = None
-    group = pagure.lib.search_groups(
+    group = pagure.lib.query.search_groups(
         flask.g.session, group_name=group, group_type=group_type
     )
 
@@ -146,7 +148,7 @@ def edit_group(group):
     if form.validate_on_submit():
 
         try:
-            msg = pagure.lib.edit_group_info(
+            msg = pagure.lib.query.edit_group_info(
                 flask.g.session,
                 group=group,
                 display_name=form.display_name.data,
@@ -193,7 +195,7 @@ def group_user_delete(user, group):
     if form.validate_on_submit():
 
         try:
-            pagure.lib.delete_user_of_group(
+            pagure.lib.query.delete_user_of_group(
                 flask.g.session,
                 username=user,
                 groupname=group,
@@ -239,13 +241,15 @@ def group_delete(group):
 
     form = pagure.forms.ConfirmationForm()
     if form.validate_on_submit():
-        group_obj = pagure.lib.search_groups(flask.g.session, group_name=group)
+        group_obj = pagure.lib.query.search_groups(
+            flask.g.session, group_name=group
+        )
 
         if not group_obj:
             flask.flash("No group `%s` found" % group, "error")
             return flask.redirect(flask.url_for("ui_ns.group_lists"))
 
-        user = pagure.lib.search_user(
+        user = pagure.lib.query.search_user(
             flask.g.session, username=flask.g.fas_user.username
         )
         if not user:
@@ -278,7 +282,7 @@ def add_group():
     if not pagure_config.get("ENABLE_GROUP_MNGT", False):
         flask.abort(404)
 
-    user = pagure.lib.search_user(
+    user = pagure.lib.query.search_user(
         flask.g.session, username=flask.g.fas_user.username
     )
     if not user:  # pragma: no cover
@@ -288,7 +292,7 @@ def add_group():
     if pagure.utils.is_admin():
         group_types = [
             grp.group_type
-            for grp in pagure.lib.get_group_types(flask.g.session)
+            for grp in pagure.lib.query.get_group_types(flask.g.session)
         ]
         # Make sure the admin type is always the last one
         group_types.remove("admin")
@@ -306,7 +310,7 @@ def add_group():
             display_name = form.display_name.data.strip()
             description = form.description.data.strip()
 
-            msg = pagure.lib.add_group(
+            msg = pagure.lib.query.add_group(
                 session=flask.g.session,
                 group_name=group_name,
                 display_name=display_name,

+ 67 - 53
pagure/ui/issues.py

@@ -30,7 +30,7 @@ from binaryornot.helpers import is_binary_string
 
 import pagure.doc_utils
 import pagure.exceptions
-import pagure.lib
+import pagure.lib.query
 import pagure.lib.mimetype
 from pagure.decorators import has_issue_tracker, is_repo_admin
 
@@ -94,7 +94,9 @@ def update_issue(repo, issueid, username=None, namespace=None):
             )
         )
 
-    issue = pagure.lib.search_issues(flask.g.session, repo, issueid=issueid)
+    issue = pagure.lib.query.search_issues(
+        flask.g.session, repo, issueid=issueid
+    )
 
     if issue is None or issue.project != repo:
         flask.abort(404, "Issue not found")
@@ -119,7 +121,7 @@ def update_issue(repo, issueid, username=None, namespace=None):
                 repo.name, issueid, commentid, username=username
             )
 
-    status = pagure.lib.get_issue_statuses(flask.g.session)
+    status = pagure.lib.query.get_issue_statuses(flask.g.session)
     form = pagure.forms.UpdateIssueForm(
         status=status,
         priorities=repo.priorities,
@@ -135,7 +137,7 @@ def update_issue(repo, issueid, username=None, namespace=None):
         if flask.request.form.get("drop_comment"):
             commentid = flask.request.form.get("drop_comment")
 
-            comment = pagure.lib.get_issue_comment(
+            comment = pagure.lib.query.get_issue_comment(
                 flask.g.session, issue.uid, commentid
             )
             if comment is None or comment.issue.project != repo:
@@ -224,7 +226,7 @@ def update_issue(repo, issueid, username=None, namespace=None):
             # Update status
             if is_contributor or is_author:
                 if new_status in status:
-                    msgs = pagure.lib.edit_issue(
+                    msgs = pagure.lib.query.edit_issue(
                         flask.g.session,
                         issue=issue,
                         status=new_status,
@@ -242,7 +244,7 @@ def update_issue(repo, issueid, username=None, namespace=None):
             # reset if we let them
             if is_contributor or is_open_access:
                 # Adjust (add/remove) tags
-                msgs = pagure.lib.update_tags(
+                msgs = pagure.lib.query.update_tags(
                     flask.g.session,
                     issue,
                     tags,
@@ -255,7 +257,7 @@ def update_issue(repo, issueid, username=None, namespace=None):
                 # let them
 
                 # Assign or update assignee of the ticket
-                message = pagure.lib.add_issue_assignee(
+                message = pagure.lib.query.add_issue_assignee(
                     flask.g.session,
                     issue=issue,
                     assignee=assignee or None,
@@ -270,7 +272,7 @@ def update_issue(repo, issueid, username=None, namespace=None):
                     new_priority = None
 
                 # Update core metadata
-                msgs = pagure.lib.edit_issue(
+                msgs = pagure.lib.query.edit_issue(
                     flask.g.session,
                     repo=repo,
                     issue=issue,
@@ -298,7 +300,7 @@ def update_issue(repo, issueid, username=None, namespace=None):
                                         % (key.name, link),
                                     )
 
-                    msg = pagure.lib.set_custom_key_value(
+                    msg = pagure.lib.query.set_custom_key_value(
                         flask.g.session, issue, key, value
                     )
                     if key.key_notify and msg is not None:
@@ -310,7 +312,7 @@ def update_issue(repo, issueid, username=None, namespace=None):
                         messages.add(msg)
 
                 # Update ticket this one depends on
-                msgs = pagure.lib.update_dependency_issue(
+                msgs = pagure.lib.query.update_dependency_issue(
                     flask.g.session,
                     repo,
                     issue,
@@ -320,7 +322,7 @@ def update_issue(repo, issueid, username=None, namespace=None):
                 messages = messages.union(set(msgs))
 
                 # Update ticket(s) depending on this one
-                msgs = pagure.lib.update_blocked_issue(
+                msgs = pagure.lib.query.update_blocked_issue(
                     flask.g.session,
                     repo,
                     issue,
@@ -333,7 +335,7 @@ def update_issue(repo, issueid, username=None, namespace=None):
 
             # New comment
             if comment:
-                message = pagure.lib.add_issue_comment(
+                message = pagure.lib.query.add_issue_comment(
                     flask.g.session,
                     issue=issue,
                     comment=comment,
@@ -353,7 +355,7 @@ def update_issue(repo, issueid, username=None, namespace=None):
             # Add the comment for field updates:
             if messages:
                 not_needed = set(["Comment added", "Updated comment"])
-                pagure.lib.add_metadata_update_notif(
+                pagure.lib.query.add_metadata_update_notif(
                     session=flask.g.session,
                     obj=issue,
                     messages=messages - not_needed,
@@ -421,7 +423,9 @@ def issue_comment_add_reaction(
     """Add a reaction to a comment of an issue"""
     repo = flask.g.repo
 
-    issue = pagure.lib.search_issues(flask.g.session, repo, issueid=issueid)
+    issue = pagure.lib.query.search_issues(
+        flask.g.session, repo, issueid=issueid
+    )
 
     if not issue or issue.project != repo:
         flask.abort(404, "Comment not found")
@@ -440,7 +444,7 @@ def issue_comment_add_reaction(
     ):
         flask.abort(404, "No such issue")
 
-    comment = pagure.lib.get_issue_comment(
+    comment = pagure.lib.query.get_issue_comment(
         flask.g.session, issue.uid, commentid
     )
 
@@ -522,7 +526,7 @@ def view_issues(repo, username=None, namespace=None):
         milestones.remove("none")
 
     search_string = search_pattern
-    extra_fields, search_pattern = pagure.lib.tokenize_search_string(
+    extra_fields, search_pattern = pagure.lib.query.tokenize_search_string(
         search_pattern
     )
 
@@ -544,11 +548,11 @@ def view_issues(repo, username=None, namespace=None):
     if flask.g.repo_committer:
         private = None
 
-    total_closed = pagure.lib.search_issues(
+    total_closed = pagure.lib.query.search_issues(
         flask.g.session, repo, status="Closed", private=private, count=True
     )
 
-    total_open = pagure.lib.search_issues(
+    total_open = pagure.lib.query.search_issues(
         flask.g.session, repo, status="Open", private=private, count=True
     )
 
@@ -559,7 +563,7 @@ def view_issues(repo, username=None, namespace=None):
         status = None
 
     oth_issues_cnt = None
-    total_issues_cnt = pagure.lib.search_issues(
+    total_issues_cnt = pagure.lib.query.search_issues(
         flask.g.session, repo, private=private, count=True, **fields
     )
 
@@ -572,7 +576,7 @@ def view_issues(repo, username=None, namespace=None):
             status = status.capitalize()
             status_count = "Closed"
             other_status_count = "Open"
-            close_status_cnt = pagure.lib.search_issues(
+            close_status_cnt = pagure.lib.query.search_issues(
                 flask.g.session,
                 repo,
                 private=private,
@@ -593,7 +597,7 @@ def view_issues(repo, username=None, namespace=None):
                 status_count = "Closed"
                 other_status_count = "Open"
 
-        issues = pagure.lib.search_issues(
+        issues = pagure.lib.query.search_issues(
             flask.g.session,
             repo,
             private=private,
@@ -607,7 +611,7 @@ def view_issues(repo, username=None, namespace=None):
             status=status,
             **fields
         )
-        issues_cnt = pagure.lib.search_issues(
+        issues_cnt = pagure.lib.query.search_issues(
             flask.g.session,
             repo,
             private=private,
@@ -618,7 +622,7 @@ def view_issues(repo, username=None, namespace=None):
             status=status_count,
             **fields
         )
-        oth_issues_cnt = pagure.lib.search_issues(
+        oth_issues_cnt = pagure.lib.query.search_issues(
             flask.g.session,
             repo,
             private=private,
@@ -630,7 +634,7 @@ def view_issues(repo, username=None, namespace=None):
             **fields
         )
     else:
-        issues = pagure.lib.search_issues(
+        issues = pagure.lib.query.search_issues(
             flask.g.session,
             repo,
             private=private,
@@ -642,7 +646,7 @@ def view_issues(repo, username=None, namespace=None):
             order_key=order_key,
             **fields
         )
-        issues_cnt = pagure.lib.search_issues(
+        issues_cnt = pagure.lib.query.search_issues(
             flask.g.session,
             repo,
             private=private,
@@ -651,7 +655,7 @@ def view_issues(repo, username=None, namespace=None):
             count=True,
             **fields
         )
-        oth_issues_cnt = pagure.lib.search_issues(
+        oth_issues_cnt = pagure.lib.query.search_issues(
             flask.g.session,
             repo,
             private=private,
@@ -662,7 +666,7 @@ def view_issues(repo, username=None, namespace=None):
             status="Open",
             **fields
         )
-    tag_list = pagure.lib.get_tags_of_project(flask.g.session, repo)
+    tag_list = pagure.lib.query.get_tags_of_project(flask.g.session, repo)
 
     total_page = 1
 
@@ -755,7 +759,7 @@ def view_roadmap(repo, username=None, namespace=None):
             ):
                 milestones_list.append(key)
 
-    issues = pagure.lib.search_issues(
+    issues = pagure.lib.query.search_issues(
         flask.g.session,
         repo,
         milestones=milestones_list,
@@ -822,7 +826,7 @@ def view_milestone(repo, username=None, namespace=None, milestone=None):
     if flask.g.repo_committer:
         private = None
 
-    open_issues = pagure.lib.search_issues(
+    open_issues = pagure.lib.query.search_issues(
         flask.g.session,
         repo,
         milestones=[milestone],
@@ -830,7 +834,7 @@ def view_milestone(repo, username=None, namespace=None, milestone=None):
         status="Open",
     )
 
-    closed_issues = pagure.lib.search_issues(
+    closed_issues = pagure.lib.query.search_issues(
         flask.g.session,
         repo,
         milestones=[milestone],
@@ -887,7 +891,7 @@ def new_issue(repo, username=None, namespace=None):
         private = form.private.data
 
         try:
-            user_obj = pagure.lib.get_user(
+            user_obj = pagure.lib.query.get_user(
                 flask.g.session, flask.g.fas_user.username
             )
         except pagure.exceptions.PagureException:
@@ -919,7 +923,7 @@ def new_issue(repo, username=None, namespace=None):
                     if tag.strip()
                 ]
 
-            issue = pagure.lib.new_issue(
+            issue = pagure.lib.query.new_issue(
                 flask.g.session,
                 repo=repo,
                 title=title,
@@ -940,7 +944,7 @@ def new_issue(repo, username=None, namespace=None):
                 n_img = issue.content.count("<!!image>")
                 if n_img == len(streams):
                     for filestream in streams:
-                        new_filename = pagure.lib.add_attachment(
+                        new_filename = pagure.lib.query.add_attachment(
                             repo=repo,
                             issue=issue,
                             attachmentfolder=pagure_config[
@@ -1014,7 +1018,7 @@ def new_issue(repo, username=None, namespace=None):
                     default_file.data, "md"
                 )
 
-    tag_list = pagure.lib.get_tags_of_project(flask.g.session, repo)
+    tag_list = pagure.lib.query.get_tags_of_project(flask.g.session, repo)
     if flask.request.method == "GET":
         form.private.data = repo.settings.get(
             "issues_default_to_private", False
@@ -1058,7 +1062,9 @@ def view_issue(repo, issueid, username=None, namespace=None):
 
     repo = flask.g.repo
 
-    issue = pagure.lib.search_issues(flask.g.session, repo, issueid=issueid)
+    issue = pagure.lib.query.search_issues(
+        flask.g.session, repo, issueid=issueid
+    )
 
     if issue is None or issue.project != repo:
         flask.abort(404, "Issue not found")
@@ -1072,7 +1078,7 @@ def view_issue(repo, issueid, username=None, namespace=None):
         ):
             flask.abort(404, "Issue not found")
 
-    status = pagure.lib.get_issue_statuses(flask.g.session)
+    status = pagure.lib.query.get_issue_statuses(flask.g.session)
     milestones = []
     for m in repo.milestones_keys or repo.milestones:
         if m in repo.milestones and repo.milestones[m]["active"]:
@@ -1093,7 +1099,7 @@ def view_issue(repo, issueid, username=None, namespace=None):
     form.close_status.data = ""
     if issue.close_status:
         form.close_status.data = issue.close_status
-    tag_list = pagure.lib.get_tags_of_project(flask.g.session, repo)
+    tag_list = pagure.lib.query.get_tags_of_project(flask.g.session, repo)
 
     knowns_keys = {}
     for key in issue.other_fields:
@@ -1112,7 +1118,7 @@ def view_issue(repo, issueid, username=None, namespace=None):
         form=form,
         knowns_keys=knowns_keys,
         open_access=open_access,
-        subscribers=pagure.lib.get_watch_list(flask.g.session, issue),
+        subscribers=pagure.lib.query.get_watch_list(flask.g.session, issue),
         attachments=issue.attachments,
     )
 
@@ -1133,7 +1139,9 @@ def delete_issue(repo, issueid, username=None, namespace=None):
 
     repo = flask.g.repo
 
-    issue = pagure.lib.search_issues(flask.g.session, repo, issueid=issueid)
+    issue = pagure.lib.query.search_issues(
+        flask.g.session, repo, issueid=issueid
+    )
 
     if issue is None or issue.project != repo:
         flask.abort(404, "Issue not found")
@@ -1146,7 +1154,7 @@ def delete_issue(repo, issueid, username=None, namespace=None):
     form = pagure.forms.ConfirmationForm()
     if form.validate_on_submit():
         try:
-            pagure.lib.drop_issue(
+            pagure.lib.query.drop_issue(
                 flask.g.session, issue, user=flask.g.fas_user.username
             )
             flask.g.session.commit()
@@ -1205,7 +1213,9 @@ def edit_issue(repo, issueid, username=None, namespace=None):
     """
     repo = flask.g.repo
 
-    issue = pagure.lib.search_issues(flask.g.session, repo, issueid=issueid)
+    issue = pagure.lib.query.search_issues(
+        flask.g.session, repo, issueid=issueid
+    )
 
     if issue is None or issue.project != repo:
         flask.abort(404, "Issue not found")
@@ -1216,7 +1226,7 @@ def edit_issue(repo, issueid, username=None, namespace=None):
     ):
         flask.abort(403, "You are not allowed to edit issues for this project")
 
-    status = pagure.lib.get_issue_statuses(flask.g.session)
+    status = pagure.lib.query.get_issue_statuses(flask.g.session)
     form = pagure.forms.IssueForm(status=status)
     if form.validate_on_submit():
         title = form.title.data
@@ -1225,7 +1235,7 @@ def edit_issue(repo, issueid, username=None, namespace=None):
         private = form.private.data
 
         try:
-            user_obj = pagure.lib.get_user(
+            user_obj = pagure.lib.query.get_user(
                 flask.g.session, flask.g.fas_user.username
             )
         except pagure.exceptions.PagureException:
@@ -1236,7 +1246,7 @@ def edit_issue(repo, issueid, username=None, namespace=None):
             )
 
         try:
-            messages = pagure.lib.edit_issue(
+            messages = pagure.lib.query.edit_issue(
                 flask.g.session,
                 issue=issue,
                 title=title,
@@ -1247,7 +1257,7 @@ def edit_issue(repo, issueid, username=None, namespace=None):
             )
             flask.g.session.commit()
             if messages:
-                pagure.lib.add_metadata_update_notif(
+                pagure.lib.query.add_metadata_update_notif(
                     session=flask.g.session,
                     obj=issue,
                     messages=messages,
@@ -1257,7 +1267,7 @@ def edit_issue(repo, issueid, username=None, namespace=None):
             # 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"],
@@ -1337,13 +1347,15 @@ def upload_issue(repo, issueid, username=None, namespace=None):
     """
     repo = flask.g.repo
 
-    issue = pagure.lib.search_issues(flask.g.session, repo, issueid=issueid)
+    issue = pagure.lib.query.search_issues(
+        flask.g.session, repo, issueid=issueid
+    )
 
     if issue is None or issue.project != repo:
         flask.abort(404, "Issue not found")
 
     try:
-        user_obj = pagure.lib.get_user(
+        user_obj = pagure.lib.query.get_user(
             flask.g.session, flask.g.fas_user.username
         )
     except pagure.exceptions.PagureException:
@@ -1358,7 +1370,7 @@ def upload_issue(repo, issueid, username=None, namespace=None):
     if form.validate_on_submit():
         filenames = []
         for filestream in flask.request.files.getlist("filestream"):
-            new_filename = pagure.lib.add_attachment(
+            new_filename = pagure.lib.query.add_attachment(
                 repo=repo,
                 issue=issue,
                 attachmentfolder=pagure_config["ATTACHMENTS_FOLDER"],
@@ -1494,12 +1506,14 @@ def edit_comment_issue(
 
     project = flask.g.repo
 
-    issue = pagure.lib.search_issues(flask.g.session, project, issueid=issueid)
+    issue = pagure.lib.query.search_issues(
+        flask.g.session, project, issueid=issueid
+    )
 
     if issue is None or issue.project != project:
         flask.abort(404, "Issue not found")
 
-    comment = pagure.lib.get_issue_comment(
+    comment = pagure.lib.query.get_issue_comment(
         flask.g.session, issue.uid, commentid
     )
 
@@ -1518,7 +1532,7 @@ def edit_comment_issue(
 
         updated_comment = form.update_comment.data
         try:
-            message = pagure.lib.edit_comment(
+            message = pagure.lib.query.edit_comment(
                 flask.g.session,
                 parent=issue,
                 comment=comment,
@@ -1588,7 +1602,7 @@ def save_reports(repo, username=None, namespace=None):
     name = form.report_name.data
 
     try:
-        msg = pagure.lib.save_report(
+        msg = pagure.lib.query.save_report(
             flask.g.session,
             flask.g.repo,
             name=name,

+ 14 - 10
pagure/ui/login.py

@@ -20,10 +20,10 @@ from sqlalchemy.exc import SQLAlchemyError
 from six.moves.urllib.parse import urljoin
 
 import pagure.login_forms as forms
-import pagure.lib
 import pagure.lib.login
 import pagure.lib.model as model
 import pagure.lib.notify
+import pagure.lib.query
 from pagure.utils import login_required
 from pagure.lib.login import generate_hashed_value, check_password
 from pagure.ui import UI_NS
@@ -41,12 +41,12 @@ def new_user():
     if form.validate_on_submit():
 
         username = form.user.data
-        if pagure.lib.search_user(flask.g.session, username=username):
+        if pagure.lib.query.search_user(flask.g.session, username=username):
             flask.flash("Username already taken.", "error")
             return flask.redirect(flask.request.url)
 
         email = form.email_address.data
-        if pagure.lib.search_user(flask.g.session, email=email):
+        if pagure.lib.query.search_user(flask.g.session, email=email):
             flask.flash("Email address already taken.", "error")
             return flask.redirect(flask.request.url)
 
@@ -62,7 +62,7 @@ def new_user():
         flask.g.session.flush()
 
         try:
-            pagure.lib.add_email_to_user(
+            pagure.lib.query.add_email_to_user(
                 flask.g.session, user, form.email_address.data
             )
             flask.g.session.commit()
@@ -97,7 +97,9 @@ def do_login():
 
     if form.validate_on_submit():
         username = form.username.data
-        user_obj = pagure.lib.search_user(flask.g.session, username=username)
+        user_obj = pagure.lib.query.search_user(
+            flask.g.session, username=username
+        )
         if not user_obj:
             flask.flash("Username or password invalid.", "error")
             return flask.redirect(flask.url_for("auth_login"))
@@ -169,7 +171,7 @@ def do_login():
 def confirm_user(token):
     """ Confirm a user account.
     """
-    user_obj = pagure.lib.search_user(flask.g.session, token=token)
+    user_obj = pagure.lib.query.search_user(flask.g.session, token=token)
     if not user_obj:
         flask.flash("No user associated with this token.", "error")
     else:
@@ -201,7 +203,9 @@ def lost_password():
     if form.validate_on_submit():
 
         username = form.username.data
-        user_obj = pagure.lib.search_user(flask.g.session, username=username)
+        user_obj = pagure.lib.query.search_user(
+            flask.g.session, username=username
+        )
         if not user_obj:
             flask.flash("Username invalid.", "error")
             return flask.redirect(flask.url_for("auth_login"))
@@ -247,7 +251,7 @@ def reset_password(token):
     """
     form = forms.ResetPasswordForm()
 
-    user_obj = pagure.lib.search_user(flask.g.session, token=token)
+    user_obj = pagure.lib.query.search_user(flask.g.session, token=token)
     if not user_obj:
         flask.flash("No user associated with this token.", "error")
         return flask.redirect(flask.url_for("auth_login"))
@@ -293,7 +297,7 @@ def change_password():
     """
 
     form = forms.ChangePasswordForm()
-    user_obj = pagure.lib.search_user(
+    user_obj = pagure.lib.query.search_user(
         flask.g.session, username=flask.g.fas_user.username
     )
 
@@ -431,7 +435,7 @@ def _check_session_cookie():
     """ Set the user into flask.g if the user is logged in.
     """
     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"]
         )
 

+ 7 - 7
pagure/ui/oidc_login.py

@@ -17,7 +17,7 @@ from flask import Markup
 import munch
 from sqlalchemy.exc import SQLAlchemyError
 
-import pagure
+import pagure.lib.query
 from pagure.config import config as pagure_config
 from pagure.flask_app import logout
 from pagure.utils import is_admin
@@ -74,13 +74,13 @@ def set_user():
         return
 
     flask.session["_new_user"] = False
-    if not pagure.lib.search_user(
+    if not pagure.lib.query.search_user(
         flask.g.session, username=flask.g.fas_user.username
     ):
         flask.session["_new_user"] = True
 
     try:
-        pagure.lib.set_up_user(
+        pagure.lib.query.set_up_user(
             session=flask.g.session,
             username=flask.g.fas_user.username,
             fullname=flask.g.fas_user.fullname,
@@ -91,7 +91,7 @@ def set_user():
 
         # If groups are managed outside pagure, set up the user at login
         if not pagure_config.get("ENABLE_GROUP_MNGT", False):
-            user = pagure.lib.search_user(
+            user = pagure.lib.query.search_user(
                 flask.g.session, username=flask.g.fas_user.username
             )
             old_groups = set(user.groups)
@@ -100,12 +100,12 @@ def set_user():
             for group in fas_groups - old_groups:
                 groupobj = None
                 if group:
-                    groupobj = pagure.lib.search_groups(
+                    groupobj = pagure.lib.query.search_groups(
                         flask.g.session, group_name=group
                     )
                 if groupobj:
                     try:
-                        pagure.lib.add_user_to_group(
+                        pagure.lib.query.add_user_to_group(
                             session=flask.g.session,
                             username=flask.g.fas_user.username,
                             group=groupobj,
@@ -119,7 +119,7 @@ def set_user():
             for group in old_groups - fas_groups:
                 if group:
                     try:
-                        pagure.lib.delete_user_of_group(
+                        pagure.lib.query.delete_user_of_group(
                             session=flask.g.session,
                             username=flask.g.fas_user.username,
                             groupname=group,

+ 0 - 1
pagure/ui/plugins.py

@@ -21,7 +21,6 @@ from flask import Markup
 from sqlalchemy.exc import SQLAlchemyError
 
 import pagure.exceptions
-import pagure.lib
 import pagure.lib.plugins
 import pagure.forms
 from pagure.exceptions import FileNotFoundException

+ 42 - 38
pagure/ui/repo.py

@@ -39,10 +39,10 @@ from sqlalchemy.exc import SQLAlchemyError
 from binaryornot.helpers import is_binary_string
 
 import pagure.exceptions
-import pagure.lib
 import pagure.lib.git
 import pagure.lib.mimetype
 import pagure.lib.plugins
+import pagure.lib.query
 import pagure.lib.tasks
 import pagure.forms
 import pagure.ui.plugins
@@ -144,7 +144,7 @@ def view_repo(repo, username=None, namespace=None):
         branchname = repo_obj.head.shorthand
     else:
         branchname = None
-    project = pagure.lib.get_authorized_project(
+    project = pagure.lib.query.get_authorized_project(
         flask.g.session, repo, user=username, namespace=namespace
     )
     watch_users = set()
@@ -340,7 +340,7 @@ def view_commits(repo, branchname=None, username=None, namespace=None):
     author_obj = None
     if author:
         try:
-            author_obj = pagure.lib.get_user(flask.g.session, author)
+            author_obj = pagure.lib.query.get_user(flask.g.session, author)
         except pagure.exceptions.PagureException:
             pass
         if not author_obj:
@@ -846,7 +846,9 @@ def view_commit(repo, commitid, username=None, namespace=None):
         commit=commit,
         diff=diff,
         splitview=splitview,
-        flags=pagure.lib.get_commit_flag(flask.g.session, repo, commitid),
+        flags=pagure.lib.query.get_commit_flag(
+            flask.g.session, repo, commitid
+        ),
     )
 
 
@@ -1186,7 +1188,7 @@ def view_settings(repo, username=None, namespace=None):
     plugins = pagure.lib.plugins.get_plugin_names(
         pagure_config.get("DISABLED_PLUGINS")
     )
-    tags = pagure.lib.get_tags_of_project(flask.g.session, repo)
+    tags = pagure.lib.query.get_tags_of_project(flask.g.session, repo)
 
     form = pagure.forms.ConfirmationForm()
     tag_form = pagure.forms.AddIssueTagForm()
@@ -1205,7 +1207,7 @@ def view_settings(repo, username=None, namespace=None):
             settings[key] = flask.request.form[key]
 
         try:
-            message = pagure.lib.update_project_settings(
+            message = pagure.lib.query.update_project_settings(
                 flask.g.session,
                 repo=repo,
                 settings=settings,
@@ -1320,7 +1322,7 @@ def update_project(repo, username=None, namespace=None):
             repo.url = form.url.data.strip()
             if repo.private:
                 repo.private = form.private.data
-            pagure.lib.update_tags(
+            pagure.lib.query.update_tags(
                 flask.g.session,
                 repo,
                 tags=[t.strip() for t in form.tags.data.split(",")],
@@ -1753,7 +1755,7 @@ def remove_deploykey(repo, keyid, username=None, namespace=None):
 
         try:
             flask.g.session.commit()
-            pagure.lib.create_deploykeys_ssh_keys_on_disk(
+            pagure.lib.query.create_deploykeys_ssh_keys_on_disk(
                 repo, pagure_config.get("GITOLITE_KEYDIR", None)
             )
             pagure.lib.tasks.gitolite_post_compile_only.delay()
@@ -1797,9 +1799,11 @@ def remove_user(repo, userid, username=None, namespace=None):
     delete_themselves = False
     if form.validate_on_submit():
         try:
-            user = pagure.lib.get_user_by_id(flask.g.session, int(userid))
+            user = pagure.lib.query.get_user_by_id(
+                flask.g.session, int(userid)
+            )
             delete_themselves = user.username == flask.g.fas_user.username
-            msg = pagure.lib.remove_user_of_project(
+            msg = pagure.lib.query.remove_user_of_project(
                 flask.g.session, user, repo, flask.g.fas_user.username
             )
             flask.flash(msg)
@@ -1862,7 +1866,7 @@ def add_deploykey(repo, username=None, namespace=None):
     if form.validate_on_submit():
         user = _get_user(username=flask.g.fas_user.username)
         try:
-            msg = pagure.lib.add_sshkey_to_project_or_user(
+            msg = pagure.lib.query.add_sshkey_to_project_or_user(
                 flask.g.session,
                 ssh_key=form.ssh_key.data,
                 creator=user,
@@ -1870,7 +1874,7 @@ def add_deploykey(repo, username=None, namespace=None):
                 pushaccess=form.pushaccess.data,
             )
             flask.g.session.commit()
-            pagure.lib.create_deploykeys_ssh_keys_on_disk(
+            pagure.lib.query.create_deploykeys_ssh_keys_on_disk(
                 repo, pagure_config.get("GITOLITE_KEYDIR", None)
             )
             pagure.lib.tasks.gitolite_post_compile_only.delay()
@@ -1928,10 +1932,10 @@ def add_user(repo, username=None, namespace=None):
     user_to_update_obj = None
     user_access = None
     if user_to_update:
-        user_to_update_obj = pagure.lib.search_user(
+        user_to_update_obj = pagure.lib.query.search_user(
             flask.g.session, username=user_to_update
         )
-        user_access = pagure.lib.get_obj_access(
+        user_access = pagure.lib.query.get_obj_access(
             flask.g.session, repo, user_to_update_obj
         )
 
@@ -1944,7 +1948,7 @@ def add_user(repo, username=None, namespace=None):
 
     if form.validate_on_submit():
         try:
-            msg = pagure.lib.add_user_to_project(
+            msg = pagure.lib.query.add_user_to_project(
                 flask.g.session,
                 repo,
                 new_user=form.user.data,
@@ -1973,7 +1977,7 @@ def add_user(repo, username=None, namespace=None):
             _log.exception(err)
             flask.flash("User could not be added", "error")
 
-    access_levels = pagure.lib.get_access_levels(flask.g.session)
+    access_levels = pagure.lib.query.get_access_levels(flask.g.session)
     return flask.render_template(
         "add_user.html",
         form=form,
@@ -2032,7 +2036,7 @@ def remove_group_project(repo, groupid, username=None, namespace=None):
                 break
         try:
             # Mark the project as read_only, celery will unmark it
-            pagure.lib.update_read_only_mode(
+            pagure.lib.query.update_read_only_mode(
                 flask.g.session, repo, read_only=True
             )
             flask.g.session.commit()
@@ -2084,10 +2088,10 @@ def add_group_project(repo, username=None, namespace=None):
     group_to_update_obj = None
     group_access = None
     if group_to_update:
-        group_to_update_obj = pagure.lib.search_groups(
+        group_to_update_obj = pagure.lib.query.search_groups(
             flask.g.session, group_name=group_to_update
         )
-        group_access = pagure.lib.get_obj_access(
+        group_access = pagure.lib.query.get_obj_access(
             flask.g.session, repo, group_to_update_obj
         )
 
@@ -2100,7 +2104,7 @@ def add_group_project(repo, username=None, namespace=None):
 
     if form.validate_on_submit():
         try:
-            msg = pagure.lib.add_group_to_project(
+            msg = pagure.lib.query.add_group_to_project(
                 flask.g.session,
                 repo,
                 new_group=form.group.data,
@@ -2130,7 +2134,7 @@ def add_group_project(repo, username=None, namespace=None):
             _log.exception(err)
             flask.flash("Group could not be added", "error")
 
-    access_levels = pagure.lib.get_access_levels(flask.g.session)
+    access_levels = pagure.lib.query.get_access_levels(flask.g.session)
     return flask.render_template(
         "add_group_project.html",
         form=form,
@@ -2237,14 +2241,14 @@ def add_token(repo, username=None, namespace=None):
             403, "You are not allowed to change the settings for this project"
         )
 
-    acls = pagure.lib.get_acls(
+    acls = pagure.lib.query.get_acls(
         flask.g.session, restrict=pagure_config.get("USER_ACLS")
     )
     form = pagure.forms.NewTokenForm(acls=acls)
 
     if form.validate_on_submit():
         try:
-            msg = pagure.lib.add_token_to_user(
+            msg = pagure.lib.query.add_token_to_user(
                 flask.g.session,
                 repo,
                 description=form.description.data.strip() or None,
@@ -2299,7 +2303,7 @@ def renew_api_token(repo, token_id, username=None, namespace=None):
 
     repo = flask.g.repo
 
-    token = pagure.lib.get_api_token(flask.g.session, token_id)
+    token = pagure.lib.query.get_api_token(flask.g.session, token_id)
 
     if (
         not token
@@ -2313,7 +2317,7 @@ def renew_api_token(repo, token_id, username=None, namespace=None):
     if form.validate_on_submit():
         acls = [acl.name for acl in token.acls]
         try:
-            msg = pagure.lib.add_token_to_user(
+            msg = pagure.lib.query.add_token_to_user(
                 flask.g.session,
                 repo,
                 description=token.description or None,
@@ -2365,7 +2369,7 @@ def revoke_api_token(repo, token_id, username=None, namespace=None):
 
     repo = flask.g.repo
 
-    token = pagure.lib.get_api_token(flask.g.session, token_id)
+    token = pagure.lib.query.get_api_token(flask.g.session, token_id)
 
     if (
         not token
@@ -2427,7 +2431,7 @@ def edit_file(repo, branchname, filename, username=None, namespace=None):
     repo = flask.g.repo
     repo_obj = flask.g.repo_obj
 
-    user = pagure.lib.search_user(
+    user = pagure.lib.query.search_user(
         flask.g.session, username=flask.g.fas_user.username
     )
 
@@ -2633,7 +2637,7 @@ def star_project(repo, star, username=None, namespace=None):
         flask.abort(400)
 
     try:
-        msg = pagure.lib.update_star_project(
+        msg = pagure.lib.query.update_star_project(
             flask.g.session,
             user=flask.g.fas_user.username,
             repo=flask.g.repo,
@@ -2673,7 +2677,7 @@ def watch_repo(repo, watch, username=None, namespace=None):
         flask.abort(400)
 
     try:
-        msg = pagure.lib.update_watch_status(
+        msg = pagure.lib.query.update_watch_status(
             flask.g.session, flask.g.repo, flask.g.fas_user.username, watch
         )
         flask.g.session.commit()
@@ -2870,7 +2874,7 @@ def update_custom_keys(repo, username=None, namespace=None):
             )
 
         try:
-            msg = pagure.lib.set_custom_key_fields(
+            msg = pagure.lib.query.set_custom_key_fields(
                 flask.g.session,
                 repo,
                 custom_keys,
@@ -3029,14 +3033,14 @@ def give_project(repo, username=None, namespace=None):
         new_username = flask.request.form.get("user", "").strip()
         if not new_username:
             flask.abort(404, "No user specified")
-        new_owner = pagure.lib.search_user(
+        new_owner = pagure.lib.query.search_user(
             flask.g.session, username=new_username
         )
         if not new_owner:
             flask.abort(404, "No such user %s found" % new_username)
         try:
             old_main_admin = repo.user.user
-            pagure.lib.set_project_owner(
+            pagure.lib.query.set_project_owner(
                 flask.g.session,
                 repo,
                 new_owner,
@@ -3045,7 +3049,7 @@ def give_project(repo, username=None, namespace=None):
             # If the person doing the action is the former main admin, keep
             # them as admins
             if flask.g.fas_user.username == old_main_admin:
-                pagure.lib.add_user_to_project(
+                pagure.lib.query.add_user_to_project(
                     flask.g.session,
                     repo,
                     new_user=flask.g.fas_user.username,
@@ -3197,7 +3201,7 @@ def update_tags(repo, username=None, namespace=None):
                     flask.flash("Duplicated tag: %s" % tag, "error")
                     break
                 try:
-                    pagure.lib.new_tag(
+                    pagure.lib.query.new_tag(
                         flask.g.session,
                         tag,
                         tag_descriptions[idx],
@@ -3238,7 +3242,7 @@ def remove_tag(repo, username=None, namespace=None):
         tags = form.tag.data
         tags = [tag.strip() for tag in tags.split(",")]
 
-        msgs = pagure.lib.remove_tags(
+        msgs = pagure.lib.query.remove_tags(
             flask.g.session, repo, tags, user=flask.g.fas_user.username
         )
 
@@ -3286,12 +3290,12 @@ def edit_tag(repo, tag, username=None, namespace=None):
     """
     repo = flask.g.repo
 
-    tags = pagure.lib.get_tags_of_project(flask.g.session, repo)
+    tags = pagure.lib.query.get_tags_of_project(flask.g.session, repo)
     if not tags:
         flask.abort(404, "Project has no tags to edit")
 
     # Check the tag exists, and get its old/original color
-    tagobj = pagure.lib.get_colored_tag(flask.g.session, tag, repo.id)
+    tagobj = pagure.lib.query.get_colored_tag(flask.g.session, tag, repo.id)
     if not tagobj:
         flask.abort(404, "Tag %s not found in this project" % tag)
 
@@ -3301,7 +3305,7 @@ def edit_tag(repo, tag, username=None, namespace=None):
         new_tag_description = form.tag_description.data
         new_tag_color = form.tag_color.data
 
-        msgs = pagure.lib.edit_issue_tags(
+        msgs = pagure.lib.query.edit_issue_tags(
             flask.g.session,
             repo,
             tagobj,

+ 3 - 2
pagure/utils.py

@@ -23,7 +23,6 @@ import six
 import werkzeug
 
 from pagure.config import config as pagure_config
-import pagure.lib
 
 
 _log = logging.getLogger(__name__)
@@ -123,6 +122,8 @@ def is_repo_admin(repo_obj, username=None):
 
 def is_repo_committer(repo_obj, username=None, session=None):
     """ Return whether the user is a committer of the provided repo. """
+    import pagure.lib.query
+
     usergroups = set()
     if username is None:
         if not authenticated():
@@ -135,7 +136,7 @@ def is_repo_committer(repo_obj, username=None, session=None):
     if not session:
         session = flask.g.session
     try:
-        user = pagure.lib.get_user(session, username)
+        user = pagure.lib.query.get_user(session, username)
         usergroups = usergroups.union(set(user.groups))
     except pagure.exceptions.PagureException:
         return False

+ 9 - 8
tests/__init__.py

@@ -58,9 +58,9 @@ import pagure
 import pagure.api
 from pagure.api.ci import jenkins
 import pagure.flask_app
-import pagure.lib
 import pagure.lib.git
 import pagure.lib.model
+import pagure.lib.query
 import pagure.lib.tasks_mirror
 import pagure.perfrepo as perfrepo
 from pagure.config import config as pagure_config, reload_config
@@ -367,12 +367,9 @@ class SimplePagureTest(unittest.TestCase):
         for folder in ['repos', 'forks', 'releases', 'remotes', 'attachments']:
             os.mkdir(os.path.join(self.path, folder))
 
-        if hasattr(pagure, 'REDIS') and pagure.REDIS:
-            pagure.REDIS.connection_pool.disconnect()
-            pagure.REDIS = None
-        if hasattr(pagure.lib, 'REDIS') and pagure.lib.REDIS:
-            pagure.lib.REDIS.connection_pool.disconnect()
-            pagure.lib.REDIS = None
+        if hasattr(pagure.lib.query, 'REDIS') and pagure.lib.query.REDIS:
+            pagure.lib.query.REDIS.connection_pool.disconnect()
+            pagure.lib.query.REDIS = None
 
         # Database
         self._prepare_db()
@@ -447,7 +444,7 @@ class SimplePagureTest(unittest.TestCase):
             _populate_db(self.session)
 
     def _clear_database(self):
-        tables = reversed(pagure.lib.model.BASE.metadata.sorted_tables)
+        tables = reversed(pagure.lib.model_base.BASE.metadata.sorted_tables)
         if self.dbpath.startswith('postgresql'):
             self.session.execute("TRUNCATE %s CASCADE" % ", ".join(
                 [t.name for t in tables]))
@@ -616,6 +613,8 @@ def create_projects(session, is_fork=False, user_id=1, hook_token_suffix=''):
     )
     item.close_status = ['Invalid', 'Insufficient data', 'Fixed', 'Duplicate']
     session.add(item)
+    session.flush()
+    create_locks(session, item)
 
     item = pagure.lib.model.Project(
         user_id=user_id,  # pingou
@@ -628,6 +627,8 @@ def create_projects(session, is_fork=False, user_id=1, hook_token_suffix=''):
     )
     item.close_status = ['Invalid', 'Insufficient data', 'Fixed', 'Duplicate']
     session.add(item)
+    session.flush()
+    create_locks(session, item)
 
     session.commit()
 

+ 21 - 21
tests/test_pagure_admin.py

@@ -103,7 +103,7 @@ class PagureAdminAdminRefreshGitolitetests(tests.Modeltests):
         tests.create_projects(self.session)
 
         # Add a group
-        msg = pagure.lib.add_group(
+        msg = pagure.lib.query.add_group(
             self.session,
             group_name='foo',
             display_name='foo group',
@@ -300,7 +300,7 @@ class PagureAdminAdminTokentests(tests.Modeltests):
     def test_do_list_admin_token_non_admin_acls(self):
         """ Test the do_list_admin_token function of pagure-admin for a token
         without any admin ACL. """
-        pagure.lib.add_token_to_user(
+        pagure.lib.query.add_token_to_user(
             self.session,
             project=None,
             acls=['issue_assign', 'pull_request_subscribe'],
@@ -377,7 +377,7 @@ class PagureAdminAdminTokentests(tests.Modeltests):
     def test_do_info_admin_token_non_admin_acl(self):
         """ Test the do_info_admin_token function of pagure-admin for a
         token not having any admin ACL. """
-        pagure.lib.add_token_to_user(
+        pagure.lib.query.add_token_to_user(
             self.session,
             project=None,
             acls=['issue_assign', 'pull_request_subscribe'],
@@ -1224,7 +1224,7 @@ class PagureNewGroupTests(tests.Modeltests):
         # Make the imported pagure use the correct db session
         pagure.cli.admin.session = self.session
 
-        groups = pagure.lib.search_groups(self.session)
+        groups = pagure.lib.query.search_groups(self.session)
         self.assertEqual(len(groups), 0)
 
     def test_missing_display_name(self):
@@ -1245,7 +1245,7 @@ class PagureNewGroupTests(tests.Modeltests):
             'A display name must be provided for the group'
         )
 
-        groups = pagure.lib.search_groups(self.session)
+        groups = pagure.lib.query.search_groups(self.session)
         self.assertEqual(len(groups), 0)
 
     def test_missing_username(self):
@@ -1268,7 +1268,7 @@ class PagureNewGroupTests(tests.Modeltests):
             'An username must be provided to associate with the group'
         )
 
-        groups = pagure.lib.search_groups(self.session)
+        groups = pagure.lib.query.search_groups(self.session)
         self.assertEqual(len(groups), 0)
 
     def test_new_group(self):
@@ -1285,7 +1285,7 @@ class PagureNewGroupTests(tests.Modeltests):
 
         pagure.cli.admin.do_new_group(args)
 
-        groups = pagure.lib.search_groups(self.session)
+        groups = pagure.lib.query.search_groups(self.session)
         self.assertEqual(len(groups), 1)
 
     @patch.dict('pagure.config.config', {'ENABLE_GROUP_MNGT': False})
@@ -1306,7 +1306,7 @@ class PagureNewGroupTests(tests.Modeltests):
 
         pagure.cli.admin.do_new_group(args)
 
-        groups = pagure.lib.search_groups(self.session)
+        groups = pagure.lib.query.search_groups(self.session)
         self.assertEqual(len(groups), 0)
 
     @patch.dict('pagure.config.config', {'ENABLE_GROUP_MNGT': False})
@@ -1327,7 +1327,7 @@ class PagureNewGroupTests(tests.Modeltests):
 
         pagure.cli.admin.do_new_group(args)
 
-        groups = pagure.lib.search_groups(self.session)
+        groups = pagure.lib.query.search_groups(self.session)
         self.assertEqual(len(groups), 1)
 
     @patch.dict('pagure.config.config', {'BLACKLISTED_GROUPS': ['foob']})
@@ -1351,7 +1351,7 @@ class PagureNewGroupTests(tests.Modeltests):
             'This group name has been blacklisted, please choose another one'
         )
 
-        groups = pagure.lib.search_groups(self.session)
+        groups = pagure.lib.query.search_groups(self.session)
         self.assertEqual(len(groups), 0)
 
 
@@ -1383,7 +1383,7 @@ class PagureListGroupEmptyTests(tests.Modeltests):
         # Make the imported pagure use the correct db session
         pagure.cli.admin.session = self.session
 
-        groups = pagure.lib.search_groups(self.session)
+        groups = pagure.lib.query.search_groups(self.session)
         self.assertEqual(len(groups), 0)
 
     @patch('sys.stdout', new_callable=StringIO)
@@ -1400,7 +1400,7 @@ class PagureListGroupEmptyTests(tests.Modeltests):
             'No groups found in this pagure instance.\n'
         )
 
-        groups = pagure.lib.search_groups(self.session)
+        groups = pagure.lib.query.search_groups(self.session)
         self.assertEqual(len(groups), 0)
 
 
@@ -1428,7 +1428,7 @@ class PagureListGroupTests(tests.Modeltests):
         self.session.add(item)
 
         # Create a group
-        pagure.lib.add_group(
+        pagure.lib.query.add_group(
             self.session,
             group_name='JL',
             display_name='Justice League',
@@ -1444,7 +1444,7 @@ class PagureListGroupTests(tests.Modeltests):
         # Make the imported pagure use the correct db session
         pagure.cli.admin.session = self.session
 
-        groups = pagure.lib.search_groups(self.session)
+        groups = pagure.lib.query.search_groups(self.session)
         self.assertEqual(len(groups), 1)
 
     @patch('sys.stdout', new_callable=StringIO)
@@ -1462,7 +1462,7 @@ class PagureListGroupTests(tests.Modeltests):
             'Group: 1 - name JL\n'
         )
 
-        groups = pagure.lib.search_groups(self.session)
+        groups = pagure.lib.query.search_groups(self.session)
         self.assertEqual(len(groups), 1)
 
 
@@ -1494,7 +1494,7 @@ class PagureBlockUserTests(tests.Modeltests):
         # Make the imported pagure use the correct db session
         pagure.cli.admin.session = self.session
 
-        user = pagure.lib.get_user(self.session, 'pingou')
+        user = pagure.lib.query.get_user(self.session, 'pingou')
         self.assertIsNone(user.refuse_sessions_before)
 
     def test_missing_date(self):
@@ -1513,7 +1513,7 @@ class PagureBlockUserTests(tests.Modeltests):
             'Invalid date submitted: None, not of the format YYYY-MM-DD'
         )
 
-        user = pagure.lib.get_user(self.session, 'pingou')
+        user = pagure.lib.query.get_user(self.session, 'pingou')
         self.assertIsNone(user.refuse_sessions_before)
 
     def test_missing_username(self):
@@ -1534,7 +1534,7 @@ class PagureBlockUserTests(tests.Modeltests):
             'An username must be specified'
         )
 
-        user = pagure.lib.get_user(self.session, 'pingou')
+        user = pagure.lib.query.get_user(self.session, 'pingou')
         self.assertIsNone(user.refuse_sessions_before)
 
     def test_invalid_username(self):
@@ -1555,7 +1555,7 @@ class PagureBlockUserTests(tests.Modeltests):
             'No user "invalid" found'
         )
 
-        user = pagure.lib.get_user(self.session, 'pingou')
+        user = pagure.lib.query.get_user(self.session, 'pingou')
         self.assertIsNone(user.refuse_sessions_before)
 
     def test_invalide_date(self):
@@ -1576,7 +1576,7 @@ class PagureBlockUserTests(tests.Modeltests):
             'Invalid date submitted: 2018-14-05, not of the format YYYY-MM-DD'
         )
 
-        user = pagure.lib.get_user(self.session, 'pingou')
+        user = pagure.lib.query.get_user(self.session, 'pingou')
         self.assertIsNone(user.refuse_sessions_before)
 
     @patch('pagure.cli.admin._ask_confirmation', MagicMock(return_value=True))
@@ -1592,7 +1592,7 @@ class PagureBlockUserTests(tests.Modeltests):
 
         pagure.cli.admin.do_block_user(args)
 
-        user = pagure.lib.get_user(self.session, 'pingou')
+        user = pagure.lib.query.get_user(self.session, 'pingou')
         self.assertIsNotNone(user.refuse_sessions_before)
 
 

+ 15 - 16
tests/test_pagure_exclude_group_index.py

@@ -23,8 +23,7 @@ import mock
 sys.path.insert(0, os.path.join(os.path.dirname(
     os.path.abspath(__file__)), '..'))
 
-import pagure
-import pagure.lib
+import pagure.lib.query
 import pagure.lib.model
 import tests
 
@@ -39,7 +38,7 @@ class PagureExcludeGroupIndex(tests.Modeltests):
         tests.create_projects_git(os.path.join(self.path, 'repos'), bare=True)
 
         # Create a ``provenpackger`` group:
-        msg = pagure.lib.add_group(
+        msg = pagure.lib.query.add_group(
             self.session,
             group_name='provenpackager',
             display_name='Proven Packagers',
@@ -54,8 +53,8 @@ class PagureExcludeGroupIndex(tests.Modeltests):
             msg, 'User `pingou` added to the group `provenpackager`.')
 
         # Add the `provenpackager` group to the test2 project
-        project = pagure.lib._get_project(self.session, 'test2')
-        msg = pagure.lib.add_group_to_project(
+        project = pagure.lib.query._get_project(self.session, 'test2')
+        msg = pagure.lib.query.add_group_to_project(
             session=self.session,
             project=project,
             new_group='provenpackager',
@@ -67,7 +66,7 @@ class PagureExcludeGroupIndex(tests.Modeltests):
     def test_defaults_pingou(self):
         """ Test which repo pingou has by default. """
 
-        repos = pagure.lib.search_projects(
+        repos = pagure.lib.query.search_projects(
             self.session,
             username='pingou',
             fork=False,
@@ -80,7 +79,7 @@ class PagureExcludeGroupIndex(tests.Modeltests):
     def test_defaults_foo(self):
         """ Test which repo foo has by default. """
 
-        repos = pagure.lib.search_projects(
+        repos = pagure.lib.query.search_projects(
             self.session,
             username='foo',
             fork=False,
@@ -92,12 +91,12 @@ class PagureExcludeGroupIndex(tests.Modeltests):
     def test_add_foo_test(self):
         """ Test adding foo to the test project. """
 
-        group = pagure.lib.search_groups(
+        group = pagure.lib.query.search_groups(
             self.session, group_name='provenpackager')
         self.assertEqual(group.group_name, 'provenpackager')
 
         # List all foo's project before (ie: there should be none)
-        repos = pagure.lib.search_projects(
+        repos = pagure.lib.query.search_projects(
             self.session,
             username='foo',
             fork=False,
@@ -106,7 +105,7 @@ class PagureExcludeGroupIndex(tests.Modeltests):
         self.assertEqual(len(repos), 0)
 
         # Adding `foo` to the `provenpackager` group
-        msg = pagure.lib.add_user_to_group(
+        msg = pagure.lib.query.add_user_to_group(
             self.session,
             username='foo',
             group=group,
@@ -117,7 +116,7 @@ class PagureExcludeGroupIndex(tests.Modeltests):
             msg, 'User `foo` added to the group `provenpackager`.')
 
         # Test that foo has now one project, via the provenpackager group
-        repos = pagure.lib.search_projects(
+        repos = pagure.lib.query.search_projects(
             self.session,
             username='foo',
             fork=False,
@@ -130,11 +129,11 @@ class PagureExcludeGroupIndex(tests.Modeltests):
         """ Test retrieving user's repo with a group excluded. """
 
         # Add `foo` to `provenpackager`
-        group = pagure.lib.search_groups(
+        group = pagure.lib.query.search_groups(
             self.session, group_name='provenpackager')
         self.assertEqual(group.group_name, 'provenpackager')
 
-        msg = pagure.lib.add_user_to_group(
+        msg = pagure.lib.query.add_user_to_group(
             self.session,
             username='foo',
             group=group,
@@ -145,7 +144,7 @@ class PagureExcludeGroupIndex(tests.Modeltests):
             msg, 'User `foo` added to the group `provenpackager`.')
 
         # Get foo's project outside of proven packager
-        repos = pagure.lib.search_projects(
+        repos = pagure.lib.query.search_projects(
             self.session,
             username='foo',
             exclude_groups=['provenpackager'],
@@ -155,13 +154,13 @@ class PagureExcludeGroupIndex(tests.Modeltests):
         self.assertEqual(len(repos), 0)
 
         # Get pingou's project outside of proven packager (nothing changes)
-        repos = pagure.lib.search_projects(
+        repos = pagure.lib.query.search_projects(
             self.session,
             username='pingou',
             exclude_groups=['provenpackager'],
             fork=False,
         )
-        repos2 = pagure.lib.search_projects(
+        repos2 = pagure.lib.query.search_projects(
             self.session,
             username='pingou',
             fork=False,

+ 23 - 23
tests/test_pagure_flask.py

@@ -26,7 +26,7 @@ import werkzeug
 sys.path.insert(0, os.path.join(os.path.dirname(
     os.path.abspath(__file__)), '..'))
 
-import pagure.lib
+import pagure.lib.query
 import pagure.lib.model
 import pagure.utils
 import tests
@@ -57,7 +57,7 @@ class PagureGetRemoteRepoPath(tests.SimplePagureTest):
     def test_is_repo_committer_logged_out(self):
         """ Test is_repo_committer in pagure when there is no logged in user.
         """
-        repo = pagure.lib._get_project(self.session, 'test')
+        repo = pagure.lib.query._get_project(self.session, 'test')
         with self.app.application.app_context():
             output = pagure.utils.is_repo_committer(repo)
         self.assertFalse(output)
@@ -65,7 +65,7 @@ class PagureGetRemoteRepoPath(tests.SimplePagureTest):
     def test_is_repo_committer_logged_in(self):
         """ Test is_repo_committer in pagure with the appropriate user logged
         in. """
-        repo = pagure.lib._get_project(self.session, 'test')
+        repo = pagure.lib.query._get_project(self.session, 'test')
 
         g = munch.Munch()
         g.fas_user = tests.FakeUser(username='pingou')
@@ -79,7 +79,7 @@ class PagureGetRemoteRepoPath(tests.SimplePagureTest):
         """ Test is_repo_committer in pagure with the appropriate user logged
         in. """
         # Create group
-        msg = pagure.lib.add_group(
+        msg = pagure.lib.query.add_group(
             self.session,
             group_name='packager',
             display_name='packager',
@@ -92,8 +92,8 @@ class PagureGetRemoteRepoPath(tests.SimplePagureTest):
         self.assertEqual(msg, 'User `pingou` added to the group `packager`.')
 
         # Add user to group
-        group = pagure.lib.search_groups(self.session, group_name='packager')
-        msg = pagure.lib.add_user_to_group(
+        group = pagure.lib.query.search_groups(self.session, group_name='packager')
+        msg = pagure.lib.query.add_user_to_group(
             self.session,
             username='foo',
             group=group,
@@ -103,8 +103,8 @@ class PagureGetRemoteRepoPath(tests.SimplePagureTest):
         self.assertEqual(msg, 'User `foo` added to the group `packager`.')
 
         # Add group packager to project test
-        project = pagure.lib._get_project(self.session, 'test')
-        msg = pagure.lib.add_group_to_project(
+        project = pagure.lib.query._get_project(self.session, 'test')
+        msg = pagure.lib.query.add_group_to_project(
             self.session,
             project=project,
             new_group='packager',
@@ -113,7 +113,7 @@ class PagureGetRemoteRepoPath(tests.SimplePagureTest):
         self.session.commit()
         self.assertEqual(msg, 'Group added')
 
-        repo = pagure.lib._get_project(self.session, 'test')
+        repo = pagure.lib.query._get_project(self.session, 'test')
 
         g = munch.Munch()
         g.fas_user = tests.FakeUser(username='foo')
@@ -127,7 +127,7 @@ class PagureGetRemoteRepoPath(tests.SimplePagureTest):
         """ Test is_repo_committer in pagure with the appropriate user logged
         in. """
         # Create group
-        msg = pagure.lib.add_group(
+        msg = pagure.lib.query.add_group(
             self.session,
             group_name='packager',
             display_name='packager',
@@ -140,8 +140,8 @@ class PagureGetRemoteRepoPath(tests.SimplePagureTest):
         self.assertEqual(msg, 'User `pingou` added to the group `packager`.')
 
         # Add user to group
-        group = pagure.lib.search_groups(self.session, group_name='packager')
-        msg = pagure.lib.add_user_to_group(
+        group = pagure.lib.query.search_groups(self.session, group_name='packager')
+        msg = pagure.lib.query.add_user_to_group(
             self.session,
             username='foo',
             group=group,
@@ -151,8 +151,8 @@ class PagureGetRemoteRepoPath(tests.SimplePagureTest):
         self.assertEqual(msg, 'User `foo` added to the group `packager`.')
 
         # Add group packager to project test
-        project = pagure.lib._get_project(self.session, 'test')
-        msg = pagure.lib.add_group_to_project(
+        project = pagure.lib.query._get_project(self.session, 'test')
+        msg = pagure.lib.query.add_group_to_project(
             self.session,
             project=project,
             new_group='packager',
@@ -162,7 +162,7 @@ class PagureGetRemoteRepoPath(tests.SimplePagureTest):
         self.session.commit()
         self.assertEqual(msg, 'Group added')
 
-        repo = pagure.lib._get_project(self.session, 'test')
+        repo = pagure.lib.query._get_project(self.session, 'test')
 
         g = munch.Munch()
         g.fas_user = tests.FakeUser(username='foo')
@@ -175,7 +175,7 @@ class PagureGetRemoteRepoPath(tests.SimplePagureTest):
     def test_is_repo_committer_logged_in_wrong_user(self):
         """ Test is_repo_committer in pagure with the wrong user logged in.
         """
-        repo = pagure.lib._get_project(self.session, 'test')
+        repo = pagure.lib.query._get_project(self.session, 'test')
 
         g = munch.Munch()
         g.fas_user = tests.FakeUser()
@@ -196,7 +196,7 @@ class PagureGetRemoteRepoPath(tests.SimplePagureTest):
         configured to give access to all the provenpackager, but the user
         is not one.
         """
-        repo = pagure.lib._get_project(self.session, 'test')
+        repo = pagure.lib.query._get_project(self.session, 'test')
 
         user = tests.FakeUser()
         g = munch.Munch()
@@ -213,7 +213,7 @@ class PagureGetRemoteRepoPath(tests.SimplePagureTest):
         configured to give access to all the provenpackager, and the user
         is one
         """
-        repo = pagure.lib._get_project(self.session, 'test')
+        repo = pagure.lib.query._get_project(self.session, 'test')
 
         g = munch.Munch()
         g.fas_user = tests.FakeUser(username='foo')
@@ -236,7 +236,7 @@ class PagureGetRemoteRepoPath(tests.SimplePagureTest):
         configured to give access to all the provenpackager but for this
         one repo
         """
-        repo = pagure.lib._get_project(self.session, 'test')
+        repo = pagure.lib.query._get_project(self.session, 'test')
 
         g = munch.Munch()
         g.fas_user = tests.FakeUser()
@@ -253,7 +253,7 @@ class PagureGetRemoteRepoPath(tests.SimplePagureTest):
         configured to give access to all the provenpackager but for this
         one repo, but the user is still a direct committer
         """
-        repo = pagure.lib._get_project(self.session, 'test')
+        repo = pagure.lib.query._get_project(self.session, 'test')
 
         g = munch.Munch()
         g.fas_user = tests.FakeUser(username='pingou')
@@ -275,7 +275,7 @@ class PagureGetRemoteRepoPath(tests.SimplePagureTest):
         """ Test is_repo_committer in pagure with EXTERNAL_COMMITTER
         configured to give access the provenpackager just for one repo
         """
-        repo = pagure.lib._get_project(self.session, 'test')
+        repo = pagure.lib.query._get_project(self.session, 'test')
 
         g = munch.Munch()
         g.fas_user = tests.FakeUser()
@@ -290,7 +290,7 @@ class PagureGetRemoteRepoPath(tests.SimplePagureTest):
         """ Test is_repo_committer in pagure with EXTERNAL_COMMITTER
         configured to give access the provenpackager just for one repo
         """
-        repo = pagure.lib._get_project(self.session, 'test')
+        repo = pagure.lib.query._get_project(self.session, 'test')
 
         g = munch.Munch()
         g.fas_user = tests.FakeUser(username='foo')
@@ -307,7 +307,7 @@ class PagureGetRemoteRepoPath(tests.SimplePagureTest):
         configured to give access the provenpackager just for one repo not
         this one
         """
-        repo = pagure.lib._get_project(self.session, 'test2')
+        repo = pagure.lib.query._get_project(self.session, 'test2')
 
         g = munch.Munch()
         g.fas_user = tests.FakeUser(username='foo')

+ 2 - 1
tests/test_pagure_flask_api.py

@@ -26,7 +26,7 @@ sys.path.insert(0, os.path.join(os.path.dirname(
 
 import pagure.api
 import pagure.flask_app
-import pagure.lib
+import pagure.lib.query
 import tests
 
 
@@ -37,6 +37,7 @@ class PagureFlaskApitests(tests.SimplePagureTest):
 
     def test_api_doc(self):
         """ Test the API documentation page. """
+        print(dir(self.app))
         output = self.app.get('/api/0/')
         output_text = output.get_data(as_text=True)
         self.assertIn(

+ 117 - 118
tests/test_pagure_flask_api_fork.py

@@ -25,8 +25,7 @@ from mock import patch, MagicMock
 sys.path.insert(0, os.path.join(os.path.dirname(
     os.path.abspath(__file__)), '..'))
 
-import pagure
-import pagure.lib
+import pagure.lib.query
 import tests
 
 
@@ -51,10 +50,10 @@ class PagureFlaskApiForktests(tests.Modeltests):
         tests.create_tokens_acl(self.session)
 
         # Create a pull-request
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        forked_repo = pagure.lib.get_authorized_project(
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        forked_repo = pagure.lib.query.get_authorized_project(
             self.session, 'test')
-        req = pagure.lib.new_pull_request(
+        req = pagure.lib.query.new_pull_request(
             session=self.session,
             repo_from=forked_repo,
             branch_from='master',
@@ -67,7 +66,7 @@ class PagureFlaskApiForktests(tests.Modeltests):
         self.assertEqual(req.id, 1)
         self.assertEqual(req.title, 'test pull-request')
 
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
         settings = repo.settings
         settings['pull_requests'] = False
         repo.settings = settings
@@ -95,10 +94,10 @@ class PagureFlaskApiForktests(tests.Modeltests):
         tests.create_tokens_acl(self.session)
 
         # Create a pull-request
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        forked_repo = pagure.lib.get_authorized_project(
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        forked_repo = pagure.lib.query.get_authorized_project(
             self.session, 'test')
-        req = pagure.lib.new_pull_request(
+        req = pagure.lib.query.new_pull_request(
             session=self.session,
             repo_from=forked_repo,
             branch_from='master',
@@ -142,7 +141,7 @@ class PagureFlaskApiForktests(tests.Modeltests):
         )
 
         # Close the PR and try again
-        pagure.lib.close_pull_request(
+        pagure.lib.query.close_pull_request(
             self.session, request=req, user='pingou',
             merged=False)
 
@@ -174,10 +173,10 @@ class PagureFlaskApiForktests(tests.Modeltests):
         tests.create_tokens_acl(self.session)
 
         # Create a pull-request
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        forked_repo = pagure.lib.get_authorized_project(
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        forked_repo = pagure.lib.query.get_authorized_project(
             self.session, 'test')
-        req = pagure.lib.new_pull_request(
+        req = pagure.lib.query.new_pull_request(
             session=self.session,
             repo_from=forked_repo,
             branch_from='master',
@@ -209,7 +208,7 @@ class PagureFlaskApiForktests(tests.Modeltests):
         self.assertEqual(data['total_requests'], 1)
 
         # Close the PR and try again
-        pagure.lib.close_pull_request(
+        pagure.lib.query.close_pull_request(
             self.session, request=req, user='pingou',
             merged=False)
 
@@ -241,10 +240,10 @@ class PagureFlaskApiForktests(tests.Modeltests):
         tests.create_tokens_acl(self.session)
 
         # Create a pull-request
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        forked_repo = pagure.lib.get_authorized_project(
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        forked_repo = pagure.lib.query.get_authorized_project(
             self.session, 'test')
-        req = pagure.lib.new_pull_request(
+        req = pagure.lib.query.new_pull_request(
             session=self.session,
             repo_from=forked_repo,
             branch_from='master',
@@ -428,9 +427,9 @@ class PagureFlaskApiForktests(tests.Modeltests):
         tests.create_tokens_acl(self.session)
 
         # Create a pull-request
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        forked_repo = pagure.lib.get_authorized_project(self.session, 'test')
-        req = pagure.lib.new_pull_request(
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        forked_repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        req = pagure.lib.query.new_pull_request(
             session=self.session,
             repo_from=forked_repo,
             branch_from='master',
@@ -443,7 +442,7 @@ class PagureFlaskApiForktests(tests.Modeltests):
         self.assertEqual(req.id, 1)
         self.assertEqual(req.title, 'test pull-request')
 
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
         settings = repo.settings
         settings['pull_requests'] = False
         repo.settings = settings
@@ -470,9 +469,9 @@ class PagureFlaskApiForktests(tests.Modeltests):
         tests.create_tokens_acl(self.session)
 
         # Create a pull-request
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        forked_repo = pagure.lib.get_authorized_project(self.session, 'test')
-        req = pagure.lib.new_pull_request(
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        forked_repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        req = pagure.lib.query.new_pull_request(
             session=self.session,
             repo_from=forked_repo,
             branch_from='master',
@@ -642,9 +641,9 @@ class PagureFlaskApiForktests(tests.Modeltests):
         tests.create_tokens_acl(self.session)
 
         # Create a pull-request
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        forked_repo = pagure.lib.get_authorized_project(self.session, 'test')
-        req = pagure.lib.new_pull_request(
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        forked_repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        req = pagure.lib.query.new_pull_request(
             session=self.session,
             repo_from=forked_repo,
             branch_from='master',
@@ -802,9 +801,9 @@ class PagureFlaskApiForktests(tests.Modeltests):
         tests.create_tokens_acl(self.session)
 
         # Create the pull-request to close
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        forked_repo = pagure.lib.get_authorized_project(self.session, 'test')
-        req = pagure.lib.new_pull_request(
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        forked_repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        req = pagure.lib.query.new_pull_request(
             session=self.session,
             repo_from=forked_repo,
             branch_from='master',
@@ -817,7 +816,7 @@ class PagureFlaskApiForktests(tests.Modeltests):
         self.assertEqual(req.id, 1)
         self.assertEqual(req.title, 'test pull-request')
 
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
         settings = repo.settings
         settings['pull_requests'] = False
         repo.settings = settings
@@ -848,9 +847,9 @@ class PagureFlaskApiForktests(tests.Modeltests):
         tests.create_tokens_acl(self.session)
 
         # Create the pull-request to close
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        forked_repo = pagure.lib.get_authorized_project(self.session, 'test')
-        req = pagure.lib.new_pull_request(
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        forked_repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        req = pagure.lib.query.new_pull_request(
             session=self.session,
             repo_from=forked_repo,
             branch_from='master',
@@ -909,7 +908,7 @@ class PagureFlaskApiForktests(tests.Modeltests):
         self.session.commit()
 
         # Allow the token to close PR
-        acls = pagure.lib.get_acls(self.session)
+        acls = pagure.lib.query.get_acls(self.session)
         for acl in acls:
             if acl.name == 'pull_request_close':
                 break
@@ -965,9 +964,9 @@ class PagureFlaskApiForktests(tests.Modeltests):
         tests.create_tokens_acl(self.session)
 
         # Create the pull-request to close
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        forked_repo = pagure.lib.get_authorized_project(self.session, 'test')
-        req = pagure.lib.new_pull_request(
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        forked_repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        req = pagure.lib.query.new_pull_request(
             session=self.session,
             repo_from=forked_repo,
             branch_from='test',
@@ -980,7 +979,7 @@ class PagureFlaskApiForktests(tests.Modeltests):
         self.assertEqual(req.id, 1)
         self.assertEqual(req.title, 'test pull-request')
 
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
         settings = repo.settings
         settings['pull_requests'] = False
         repo.settings = settings
@@ -1018,9 +1017,9 @@ class PagureFlaskApiForktests(tests.Modeltests):
         tests.create_tokens_acl(self.session)
 
         # Create the pull-request to close
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        forked_repo = pagure.lib.get_authorized_project(self.session, 'test')
-        req = pagure.lib.new_pull_request(
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        forked_repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        req = pagure.lib.query.new_pull_request(
             session=self.session,
             repo_from=forked_repo,
             branch_from='test',
@@ -1033,7 +1032,7 @@ class PagureFlaskApiForktests(tests.Modeltests):
         self.assertEqual(req.id, 1)
         self.assertEqual(req.title, 'test pull-request')
 
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
         settings = repo.settings
         settings['Only_assignee_can_merge_pull-request'] = True
         repo.settings = settings
@@ -1073,9 +1072,9 @@ class PagureFlaskApiForktests(tests.Modeltests):
         tests.create_tokens_acl(self.session)
 
         # Create the pull-request to close
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        forked_repo = pagure.lib.get_authorized_project(self.session, 'test')
-        req = pagure.lib.new_pull_request(
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        forked_repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        req = pagure.lib.query.new_pull_request(
             session=self.session,
             repo_from=forked_repo,
             branch_from='test',
@@ -1087,11 +1086,11 @@ class PagureFlaskApiForktests(tests.Modeltests):
         self.session.commit()
         self.assertEqual(req.id, 1)
         self.assertEqual(req.title, 'test pull-request')
-        req.assignee = pagure.lib.search_user(self.session, 'foo')
+        req.assignee = pagure.lib.query.search_user(self.session, 'foo')
         self.session.add(req)
         self.session.commit()
 
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
         settings = repo.settings
         settings['Only_assignee_can_merge_pull-request'] = True
         repo.settings = settings
@@ -1129,9 +1128,9 @@ class PagureFlaskApiForktests(tests.Modeltests):
         tests.create_tokens_acl(self.session)
 
         # Create the pull-request to close
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        forked_repo = pagure.lib.get_authorized_project(self.session, 'test')
-        req = pagure.lib.new_pull_request(
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        forked_repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        req = pagure.lib.query.new_pull_request(
             session=self.session,
             repo_from=forked_repo,
             branch_from='test',
@@ -1144,7 +1143,7 @@ class PagureFlaskApiForktests(tests.Modeltests):
         self.assertEqual(req.id, 1)
         self.assertEqual(req.title, 'test pull-request')
 
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
         settings = repo.settings
         settings['Minimum_score_to_merge_pull-request'] = 2
         repo.settings = settings
@@ -1182,9 +1181,9 @@ class PagureFlaskApiForktests(tests.Modeltests):
         tests.create_tokens_acl(self.session)
 
         # Create the pull-request to close
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        forked_repo = pagure.lib.get_authorized_project(self.session, 'test')
-        req = pagure.lib.new_pull_request(
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        forked_repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        req = pagure.lib.query.new_pull_request(
             session=self.session,
             repo_from=forked_repo,
             branch_from='test',
@@ -1243,7 +1242,7 @@ class PagureFlaskApiForktests(tests.Modeltests):
         self.session.commit()
 
         # Allow the token to merge PR
-        acls = pagure.lib.get_acls(self.session)
+        acls = pagure.lib.query.get_acls(self.session)
         for acl in acls:
             if acl.name == 'pull_request_merge':
                 break
@@ -1298,9 +1297,9 @@ class PagureFlaskApiForktests(tests.Modeltests):
         tests.create_tokens_acl(self.session)
 
         # Create the pull-request to close
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        forked_repo = pagure.lib.get_authorized_project(self.session, 'test')
-        req = pagure.lib.new_pull_request(
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        forked_repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        req = pagure.lib.query.new_pull_request(
             session=self.session,
             repo_from=forked_repo,
             branch_from='test',
@@ -1360,7 +1359,7 @@ class PagureFlaskApiForktests(tests.Modeltests):
         self.session.commit()
 
         # Allow the token to merge PR
-        acls = pagure.lib.get_acls(self.session)
+        acls = pagure.lib.query.get_acls(self.session)
         acl = None
         for acl in acls:
             if acl.name == 'pull_request_merge':
@@ -1447,9 +1446,9 @@ class PagureFlaskApiForktests(tests.Modeltests):
         )
 
         # Create a pull-request
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        forked_repo = pagure.lib.get_authorized_project(self.session, 'test')
-        req = pagure.lib.new_pull_request(
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        forked_repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        req = pagure.lib.query.new_pull_request(
             session=self.session,
             repo_from=forked_repo,
             branch_from='master',
@@ -1464,7 +1463,7 @@ class PagureFlaskApiForktests(tests.Modeltests):
 
         # Check comments before
         self.session.commit()
-        request = pagure.lib.search_pull_requests(
+        request = pagure.lib.query.search_pull_requests(
             self.session, project_id=1, requestid=1)
         self.assertEqual(len(request.comments), 0)
 
@@ -1488,7 +1487,7 @@ class PagureFlaskApiForktests(tests.Modeltests):
 
         # No change
         self.session.commit()
-        request = pagure.lib.search_pull_requests(
+        request = pagure.lib.query.search_pull_requests(
             self.session, project_id=1, requestid=1)
         self.assertEqual(len(request.comments), 0)
 
@@ -1508,7 +1507,7 @@ class PagureFlaskApiForktests(tests.Modeltests):
 
         # One comment added
         self.session.commit()
-        request = pagure.lib.search_pull_requests(
+        request = pagure.lib.query.search_pull_requests(
             self.session, project_id=1, requestid=1)
         self.assertEqual(len(request.comments), 1)
 
@@ -1524,9 +1523,9 @@ class PagureFlaskApiForktests(tests.Modeltests):
         headers = {'Authorization': 'token aaabbbcccddd'}
 
         # Create a pull-request
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        forked_repo = pagure.lib.get_authorized_project(self.session, 'test')
-        req = pagure.lib.new_pull_request(
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        forked_repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        req = pagure.lib.query.new_pull_request(
             session=self.session,
             repo_from=forked_repo,
             branch_from='master',
@@ -1544,7 +1543,7 @@ class PagureFlaskApiForktests(tests.Modeltests):
         }
 
         # Valid request
-        with patch('pagure.lib.add_pull_request_comment',
+        with patch('pagure.lib.query.add_pull_request_comment',
                    side_effect=pagure.exceptions.PagureException('error')):
             output = self.app.post(
                 '/api/0/test/pull-request/1/comment', data=data, headers=headers)
@@ -1567,9 +1566,9 @@ class PagureFlaskApiForktests(tests.Modeltests):
         headers = {'Authorization': 'token aaabbbcccddd'}
 
         # Create a pull-request
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        forked_repo = pagure.lib.get_authorized_project(self.session, 'test')
-        req = pagure.lib.new_pull_request(
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        forked_repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        req = pagure.lib.query.new_pull_request(
             session=self.session,
             repo_from=forked_repo,
             branch_from='master',
@@ -1582,7 +1581,7 @@ class PagureFlaskApiForktests(tests.Modeltests):
         self.assertEqual(req.id, 1)
         self.assertEqual(req.title, 'test pull-request')
 
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
         settings = repo.settings
         settings['pull_requests'] = False
         repo.settings = settings
@@ -1608,7 +1607,7 @@ class PagureFlaskApiForktests(tests.Modeltests):
 
         # no comment added
         self.session.commit()
-        request = pagure.lib.search_pull_requests(
+        request = pagure.lib.query.search_pull_requests(
             self.session, project_id=1, requestid=1)
         self.assertEqual(len(request.comments), 0)
 
@@ -1663,9 +1662,9 @@ class PagureFlaskApiForktests(tests.Modeltests):
         )
 
         # Create a pull-request
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        forked_repo = pagure.lib.get_authorized_project(self.session, 'test')
-        req = pagure.lib.new_pull_request(
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        forked_repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        req = pagure.lib.query.new_pull_request(
             session=self.session,
             repo_from=forked_repo,
             branch_from='master',
@@ -1680,7 +1679,7 @@ class PagureFlaskApiForktests(tests.Modeltests):
 
         # Check comments before
         self.session.commit()
-        request = pagure.lib.search_pull_requests(
+        request = pagure.lib.query.search_pull_requests(
             self.session, project_id=1, requestid=1)
         self.assertEqual(len(request.comments), 0)
 
@@ -1704,7 +1703,7 @@ class PagureFlaskApiForktests(tests.Modeltests):
 
         # No change
         self.session.commit()
-        request = pagure.lib.search_pull_requests(
+        request = pagure.lib.query.search_pull_requests(
             self.session, project_id=1, requestid=1)
         self.assertEqual(len(request.comments), 0)
 
@@ -1724,7 +1723,7 @@ class PagureFlaskApiForktests(tests.Modeltests):
 
         # One comment added
         self.session.commit()
-        request = pagure.lib.search_pull_requests(
+        request = pagure.lib.query.search_pull_requests(
             self.session, project_id=1, requestid=1)
         self.assertEqual(len(request.comments), 1)
 
@@ -1737,7 +1736,7 @@ class PagureFlaskApiForktests(tests.Modeltests):
         tests.create_tokens(self.session)
         tests.create_tokens_acl(self.session)
 
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
         settings = repo.settings
         settings['pull_requests'] = False
         repo.settings = settings
@@ -1787,8 +1786,8 @@ class PagureFlaskApiForktests(tests.Modeltests):
         headers = {'Authorization': 'token aaabbbcccddd'}
 
         # Create pull-request
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        req = pagure.lib.new_pull_request(
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        req = pagure.lib.query.new_pull_request(
             session=self.session,
             repo_from=repo,
             branch_from='feature',
@@ -1802,11 +1801,11 @@ class PagureFlaskApiForktests(tests.Modeltests):
         self.assertEqual(req.title, 'test pull-request')
 
         # Check subscribtion before
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        request = pagure.lib.search_pull_requests(
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        request = pagure.lib.query.search_pull_requests(
             self.session, project_id=1, requestid=1)
         self.assertEqual(
-            pagure.lib.get_watch_list(self.session, request),
+            pagure.lib.query.get_watch_list(self.session, request),
             set(['pingou']))
 
         data = {}
@@ -1888,8 +1887,8 @@ class PagureFlaskApiForktests(tests.Modeltests):
         )
 
         # Create pull-request
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        req = pagure.lib.new_pull_request(
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        req = pagure.lib.query.new_pull_request(
             session=self.session,
             repo_from=repo,
             branch_from='feature',
@@ -1903,11 +1902,11 @@ class PagureFlaskApiForktests(tests.Modeltests):
         self.assertEqual(req.title, 'test pull-request')
 
         # Check subscribtion before
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        request = pagure.lib.search_pull_requests(
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        request = pagure.lib.query.search_pull_requests(
             self.session, project_id=1, requestid=1)
         self.assertEqual(
-            pagure.lib.get_watch_list(self.session, request),
+            pagure.lib.query.get_watch_list(self.session, request),
             set(['pingou']))
 
         # Unsubscribe - no changes
@@ -1942,11 +1941,11 @@ class PagureFlaskApiForktests(tests.Modeltests):
         )
 
         # No change
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        request = pagure.lib.search_pull_requests(
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        request = pagure.lib.query.search_pull_requests(
             self.session, project_id=1, requestid=1)
         self.assertEqual(
-            pagure.lib.get_watch_list(self.session, request),
+            pagure.lib.query.get_watch_list(self.session, request),
             set(['pingou']))
 
         # Subscribe
@@ -1981,11 +1980,11 @@ class PagureFlaskApiForktests(tests.Modeltests):
             }
         )
 
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        request = pagure.lib.search_pull_requests(
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        request = pagure.lib.query.search_pull_requests(
             self.session, project_id=1, requestid=1)
         self.assertEqual(
-            pagure.lib.get_watch_list(self.session, request),
+            pagure.lib.query.get_watch_list(self.session, request),
             set(['pingou', 'bar']))
 
         # Unsubscribe
@@ -2004,11 +2003,11 @@ class PagureFlaskApiForktests(tests.Modeltests):
             }
         )
 
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        request = pagure.lib.search_pull_requests(
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        request = pagure.lib.query.search_pull_requests(
             self.session, project_id=1, requestid=1)
         self.assertEqual(
-            pagure.lib.get_watch_list(self.session, request),
+            pagure.lib.query.get_watch_list(self.session, request),
             set(['pingou']))
 
     @patch('pagure.lib.git.update_git')
@@ -2038,8 +2037,8 @@ class PagureFlaskApiForktests(tests.Modeltests):
         tests.create_tokens_acl(self.session)
 
         # Create pull-request
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        req = pagure.lib.new_pull_request(
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        req = pagure.lib.query.new_pull_request(
             session=self.session,
             repo_from=repo,
             branch_from='feature',
@@ -2053,11 +2052,11 @@ class PagureFlaskApiForktests(tests.Modeltests):
         self.assertEqual(req.title, 'test pull-request')
 
         # Check subscribtion before
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        request = pagure.lib.search_pull_requests(
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        request = pagure.lib.query.search_pull_requests(
             self.session, project_id=1, requestid=1)
         self.assertEqual(
-            pagure.lib.get_watch_list(self.session, request),
+            pagure.lib.query.get_watch_list(self.session, request),
             set(['pingou']))
 
         # Subscribe
@@ -2078,11 +2077,11 @@ class PagureFlaskApiForktests(tests.Modeltests):
             )
 
         # Check subscribtions after
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        request = pagure.lib.search_pull_requests(
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        request = pagure.lib.query.search_pull_requests(
             self.session, project_id=1, requestid=1)
         self.assertEqual(
-            pagure.lib.get_watch_list(self.session, request),
+            pagure.lib.query.get_watch_list(self.session, request),
             set(['pingou', 'foo']))
 
     @patch('pagure.lib.notify.send_email', MagicMock(return_value=True))
@@ -2242,7 +2241,7 @@ class PagureFlaskApiForktests(tests.Modeltests):
         tests.create_tokens_acl(self.session)
 
         # Check the behavior if the project disabled the issue tracker
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
         settings = repo.settings
         settings['pull_requests'] = False
         repo.settings = settings
@@ -2286,7 +2285,7 @@ class PagureFlaskApiForktests(tests.Modeltests):
         tests.create_tokens_acl(self.session)
 
         # Check the behavior if the project disabled the issue tracker
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
         settings = repo.settings
         settings['Enforce_signed-off_commits_in_pull-request'] = True
         repo.settings = settings
@@ -2331,7 +2330,7 @@ class PagureFlaskApiForktests(tests.Modeltests):
         tests.create_tokens_acl(self.session)
 
         # Check the behavior if the project disabled the issue tracker
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
         settings = repo.settings
         settings['Enforce_signed-off_commits_in_pull-request'] = True
         repo.settings = settings
@@ -2451,7 +2450,7 @@ class PagureFlaskApiForktests(tests.Modeltests):
         tests.create_tokens_acl(self.session)
 
         # Check the behavior if the project disabled the issue tracker
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
         settings = repo.settings
         settings['Enforce_signed-off_commits_in_pull-request'] = True
         repo.settings = settings
@@ -2726,8 +2725,8 @@ class PagureFlaskApiForkPRDiffStatstests(tests.Modeltests):
             os.path.join(self.path, 'repos', 'test.git'), branch='test')
 
         # Create the pull-request to close
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        req = pagure.lib.new_pull_request(
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        req = pagure.lib.query.new_pull_request(
             session=self.session,
             repo_from=repo,
             branch_from='test',
@@ -2793,7 +2792,7 @@ class PagureFlaskApiForkPRDiffStatstests(tests.Modeltests):
             os.path.join(self.path, 'repos', 'test.git'),
             readme_name='README.md', branch='test')
 
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
         self.assertEqual(len(repo.requests), 1)
 
         output = self.app.get('/api/0/test/pull-request/1/diffstats')
@@ -2837,7 +2836,7 @@ class PagureFlaskApiForkPRDiffStatstests(tests.Modeltests):
     @patch('pagure.lib.notify.send_email', MagicMock(return_value=True))
     def test_api_pull_request_diffstats_file_modified_deleted(self):
         """ Test the api_pull_request_merge method of the flask api. """
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
         self.assertEqual(len(repo.requests), 1)
         pagure.lib.tasks.update_pull_request(repo.requests[0].uid)
 
@@ -2848,7 +2847,7 @@ class PagureFlaskApiForkPRDiffStatstests(tests.Modeltests):
             os.path.join(self.path, 'repos', 'test.git'),
             filename='sources', branch='test')
 
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
         self.assertEqual(len(repo.requests), 1)
         pagure.lib.tasks.update_pull_request(repo.requests[0].uid)
 

+ 10 - 10
tests/test_pagure_flask_api_group.py

@@ -21,7 +21,7 @@ sys.path.insert(0, os.path.join(os.path.dirname(
     os.path.abspath(__file__)), '..'))
 
 import pagure.api
-import pagure.lib
+import pagure.lib.query
 import tests
 
 
@@ -36,7 +36,7 @@ class PagureFlaskApiGroupTests(tests.SimplePagureTest):
 
         pagure.config.config['REQUESTS_FOLDER'] = None
 
-        msg = pagure.lib.add_group(
+        msg = pagure.lib.query.add_group(
             self.session,
             group_name='some_group',
             display_name='Some Group',
@@ -50,8 +50,8 @@ class PagureFlaskApiGroupTests(tests.SimplePagureTest):
 
         tests.create_projects(self.session)
 
-        project = pagure.lib._get_project(self.session, 'test2')
-        msg = pagure.lib.add_group_to_project(
+        project = pagure.lib.query._get_project(self.session, 'test2')
+        msg = pagure.lib.query.add_group_to_project(
             session=self.session,
             project=project,
             new_group='some_group',
@@ -223,8 +223,8 @@ class PagureFlaskApiGroupTests(tests.SimplePagureTest):
         )
         self.session.add(user)
         self.session.commit()
-        group = pagure.lib.search_groups(self.session, group_name='some_group')
-        result = pagure.lib.add_user_to_group(
+        group = pagure.lib.query.search_groups(self.session, group_name='some_group')
+        result = pagure.lib.query.add_user_to_group(
             self.session, user.username, group, user.username, True)
         self.assertEqual(
             result, 'User `mprahl` added to the group `some_group`.')
@@ -508,8 +508,8 @@ class PagureFlaskApiGroupTests(tests.SimplePagureTest):
         """
 
         # Make the group having only commit access
-        project = pagure.lib._get_project(self.session, 'test2')
-        msg = pagure.lib.add_group_to_project(
+        project = pagure.lib.query._get_project(self.session, 'test2')
+        msg = pagure.lib.query.add_group_to_project(
             session=self.session,
             project=project,
             new_group='some_group',
@@ -546,8 +546,8 @@ class PagureFlaskApiGroupTests(tests.SimplePagureTest):
         """
 
         # Make the group having only ticket access
-        project = pagure.lib._get_project(self.session, 'test2')
-        msg = pagure.lib.add_group_to_project(
+        project = pagure.lib.query._get_project(self.session, 'test2')
+        msg = pagure.lib.query.add_group_to_project(
             session=self.session,
             project=project,
             new_group='some_group',

+ 128 - 129
tests/test_pagure_flask_api_issue.py

@@ -31,8 +31,7 @@ from sqlalchemy.exc import SQLAlchemyError
 sys.path.insert(0, os.path.join(os.path.dirname(
     os.path.abspath(__file__)), '..'))
 
-import pagure
-import pagure.lib
+import pagure.lib.query
 import tests
 
 FULL_ISSUE_LIST = [
@@ -516,7 +515,7 @@ class PagureFlaskApiIssuetests(tests.SimplePagureTest):
         headers = {'Authorization': 'token aaabbbcccddd'}
 
         # Set some milestones
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
         repo.milestones = {'milestone-1.0': '', 'milestone-2.0': 'Tomorrow!'}
         self.session.add(repo)
         self.session.commit()
@@ -898,7 +897,7 @@ class PagureFlaskApiIssuetests(tests.SimplePagureTest):
         headers = {'Authorization': 'token aaabbbcccddd'}
 
         # Set some milestones
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
         repo.milestones = {'milestone-1.0': '', 'milestone-2.0': 'Tomorrow!'}
         self.session.add(repo)
         self.session.commit()
@@ -1177,8 +1176,8 @@ class PagureFlaskApiIssuetests(tests.SimplePagureTest):
         )
 
         # Create private issue
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        msg = pagure.lib.new_issue(
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        msg = pagure.lib.query.new_issue(
             session=self.session,
             repo=repo,
             title='Test issue',
@@ -1626,12 +1625,12 @@ class PagureFlaskApiIssuetests(tests.SimplePagureTest):
         tests.create_tokens(self.session)
         tests.create_tokens_acl(self.session)
 
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
 
         # Create 2 tickets but only 1 has a milestone
         start = arrow.utcnow().timestamp
         issue = pagure.lib.model.Issue(
-            id=pagure.lib.get_next_id(self.session, repo.id),
+            id=pagure.lib.query.get_next_id(self.session, repo.id),
             project_id=repo.id,
             title='Issue #1',
             content='Description',
@@ -1643,7 +1642,7 @@ class PagureFlaskApiIssuetests(tests.SimplePagureTest):
         self.session.commit()
 
         issue = pagure.lib.model.Issue(
-            id=pagure.lib.get_next_id(self.session, repo.id),
+            id=pagure.lib.query.get_next_id(self.session, repo.id),
             project_id=repo.id,
             title='Issue #2',
             content='Description',
@@ -1745,12 +1744,12 @@ class PagureFlaskApiIssuetests(tests.SimplePagureTest):
         tests.create_tokens(self.session)
         tests.create_tokens_acl(self.session)
 
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
 
         # Create 2 tickets but only 1 has a priority
         start = arrow.utcnow().timestamp
         issue = pagure.lib.model.Issue(
-            id=pagure.lib.get_next_id(self.session, repo.id),
+            id=pagure.lib.query.get_next_id(self.session, repo.id),
             project_id=repo.id,
             title='Issue #1',
             content='Description',
@@ -1762,7 +1761,7 @@ class PagureFlaskApiIssuetests(tests.SimplePagureTest):
         self.session.commit()
 
         issue = pagure.lib.model.Issue(
-            id=pagure.lib.get_next_id(self.session, repo.id),
+            id=pagure.lib.query.get_next_id(self.session, repo.id),
             project_id=repo.id,
             title='Issue #2',
             content='Description',
@@ -1929,12 +1928,12 @@ class PagureFlaskApiIssuetests(tests.SimplePagureTest):
         tests.create_tokens(self.session)
         tests.create_tokens_acl(self.session)
 
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
 
         # Create 2 tickets but only 1 has a milestone
         start = arrow.utcnow().timestamp
         issue = pagure.lib.model.Issue(
-            id=pagure.lib.get_next_id(self.session, repo.id),
+            id=pagure.lib.query.get_next_id(self.session, repo.id),
             project_id=repo.id,
             title='Issue #1',
             content='Description',
@@ -1946,7 +1945,7 @@ class PagureFlaskApiIssuetests(tests.SimplePagureTest):
         self.session.commit()
 
         issue = pagure.lib.model.Issue(
-            id=pagure.lib.get_next_id(self.session, repo.id),
+            id=pagure.lib.query.get_next_id(self.session, repo.id),
             project_id=repo.id,
             title='Issue #2',
             content='Description',
@@ -2086,12 +2085,12 @@ class PagureFlaskApiIssuetests(tests.SimplePagureTest):
         tests.create_tokens(self.session)
         tests.create_tokens_acl(self.session)
 
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
 
         # Create 1st tickets
         start = arrow.utcnow().timestamp
         issue = pagure.lib.model.Issue(
-            id=pagure.lib.get_next_id(self.session, repo.id),
+            id=pagure.lib.query.get_next_id(self.session, repo.id),
             project_id=repo.id,
             title='Issue #1',
             content='Description',
@@ -2107,7 +2106,7 @@ class PagureFlaskApiIssuetests(tests.SimplePagureTest):
 
         # Create 2nd tickets
         issue = pagure.lib.model.Issue(
-            id=pagure.lib.get_next_id(self.session, repo.id),
+            id=pagure.lib.query.get_next_id(self.session, repo.id),
             project_id=repo.id,
             title='Issue #2',
             content='Description',
@@ -2123,7 +2122,7 @@ class PagureFlaskApiIssuetests(tests.SimplePagureTest):
 
         # Create private issue
         issue = pagure.lib.model.Issue(
-            id=pagure.lib.get_next_id(self.session, repo.id),
+            id=pagure.lib.query.get_next_id(self.session, repo.id),
             project_id=repo.id,
             title='Issue #3',
             content='Description',
@@ -2428,8 +2427,8 @@ class PagureFlaskApiIssuetests(tests.SimplePagureTest):
         )
 
         # Create private issue
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        msg = pagure.lib.new_issue(
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        msg = pagure.lib.query.new_issue(
             session=self.session,
             repo=repo,
             title='Test issue',
@@ -2566,7 +2565,7 @@ class PagureFlaskApiIssuetests(tests.SimplePagureTest):
         tests.create_tokens_acl(self.session)
 
         # Set some milestones to the project
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
         repo.milestones = {'v1.0': None, 'v2.0': 'Soon'}
         self.session.add(repo)
         self.session.commit()
@@ -2593,7 +2592,7 @@ class PagureFlaskApiIssuetests(tests.SimplePagureTest):
         tests.create_tokens_acl(self.session)
 
         # Set some milestones to the project
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
         repo.milestones = {'v1.0': None, 'v2.0': 'Soon'}
         self.session.add(repo)
         self.session.commit()
@@ -2618,7 +2617,7 @@ class PagureFlaskApiIssuetests(tests.SimplePagureTest):
         tests.create_tokens_acl(self.session)
 
         # Set some milestones to the project
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
         repo.milestones = {'v1.0': None, 'v2.0': 'Soon'}
         self.session.add(repo)
         self.session.commit()
@@ -2645,15 +2644,15 @@ class PagureFlaskApiIssuetests(tests.SimplePagureTest):
         tests.create_tokens_acl(self.session)
 
         # Set some milestones to the project
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
         repo.milestones = {'v1.0': None, 'v2.0': 'Soon'}
         self.session.add(repo)
         self.session.commit()
 
         headers = {'Authorization': 'token aaabbbcccddd'}
         # Create normal issue
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        msg = pagure.lib.new_issue(
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        msg = pagure.lib.query.new_issue(
             session=self.session,
             repo=repo,
             title='Test issue #1',
@@ -2665,8 +2664,8 @@ class PagureFlaskApiIssuetests(tests.SimplePagureTest):
         self.assertEqual(msg.title, 'Test issue #1')
 
         # Check milestone before
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        issue = pagure.lib.search_issues(self.session, repo, issueid=1)
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        issue = pagure.lib.query.search_issues(self.session, repo, issueid=1)
         self.assertEqual(issue.milestone, None)
 
         data = {
@@ -2684,8 +2683,8 @@ class PagureFlaskApiIssuetests(tests.SimplePagureTest):
         )
 
         # No change
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        issue = pagure.lib.search_issues(self.session, repo, issueid=1)
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        issue = pagure.lib.query.search_issues(self.session, repo, issueid=1)
         self.assertEqual(issue.milestone, None)
 
     def test_api_change_milestone_issue_invalid_milestone(self):
@@ -2696,15 +2695,15 @@ class PagureFlaskApiIssuetests(tests.SimplePagureTest):
         tests.create_tokens_acl(self.session)
 
         # Set some milestones to the project
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
         repo.milestones = {'v1.0': None, 'v2.0': 'Soon'}
         self.session.add(repo)
         self.session.commit()
 
         headers = {'Authorization': 'token aaabbbcccddd'}
         # Create normal issue
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        msg = pagure.lib.new_issue(
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        msg = pagure.lib.query.new_issue(
             session=self.session,
             repo=repo,
             title='Test issue #1',
@@ -2716,8 +2715,8 @@ class PagureFlaskApiIssuetests(tests.SimplePagureTest):
         self.assertEqual(msg.title, 'Test issue #1')
 
         # Check milestone before
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        issue = pagure.lib.search_issues(self.session, repo, issueid=1)
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        issue = pagure.lib.query.search_issues(self.session, repo, issueid=1)
         self.assertEqual(issue.milestone, None)
 
         data = {
@@ -2750,15 +2749,15 @@ class PagureFlaskApiIssuetests(tests.SimplePagureTest):
         tests.create_tokens_acl(self.session)
 
         # Set some milestones to the project
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
         repo.milestones = {'v1.0': None, 'v2.0': 'Soon'}
         self.session.add(repo)
         self.session.commit()
 
         headers = {'Authorization': 'token aaabbbcccddd'}
         # Create normal issue
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        msg = pagure.lib.new_issue(
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        msg = pagure.lib.query.new_issue(
             session=self.session,
             repo=repo,
             title='Test issue #1',
@@ -2770,8 +2769,8 @@ class PagureFlaskApiIssuetests(tests.SimplePagureTest):
         self.assertEqual(msg.title, 'Test issue #1')
 
         # Check milestone before
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        issue = pagure.lib.search_issues(self.session, repo, issueid=1)
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        issue = pagure.lib.query.search_issues(self.session, repo, issueid=1)
         self.assertEqual(issue.milestone, None)
 
         data = {
@@ -2800,15 +2799,15 @@ class PagureFlaskApiIssuetests(tests.SimplePagureTest):
         tests.create_tokens_acl(self.session)
 
         # Set some milestones to the project
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
         repo.milestones = {'v1.0': None, 'v2.0': 'Soon'}
         self.session.add(repo)
         self.session.commit()
 
         headers = {'Authorization': 'token aaabbbcccddd'}
         # Create normal issue
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        msg = pagure.lib.new_issue(
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        msg = pagure.lib.query.new_issue(
             session=self.session,
             repo=repo,
             title='Test issue #1',
@@ -2820,8 +2819,8 @@ class PagureFlaskApiIssuetests(tests.SimplePagureTest):
         self.assertEqual(msg.title, 'Test issue #1')
 
         # Check milestone before
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        issue = pagure.lib.search_issues(self.session, repo, issueid=1)
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        issue = pagure.lib.query.search_issues(self.session, repo, issueid=1)
         self.assertEqual(issue.milestone, None)
 
         data = {
@@ -2862,8 +2861,8 @@ class PagureFlaskApiIssuetests(tests.SimplePagureTest):
         )
 
         # Change recorded
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        issue = pagure.lib.search_issues(self.session, repo, issueid=1)
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        issue = pagure.lib.query.search_issues(self.session, repo, issueid=1)
         self.assertEqual(issue.milestone, None)
 
     def test_api_change_milestone_issue_remove_milestone2(self):
@@ -2874,15 +2873,15 @@ class PagureFlaskApiIssuetests(tests.SimplePagureTest):
         tests.create_tokens_acl(self.session)
 
         # Set some milestones to the project
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
         repo.milestones = {'v1.0': None, 'v2.0': 'Soon'}
         self.session.add(repo)
         self.session.commit()
 
         headers = {'Authorization': 'token aaabbbcccddd'}
         # Create normal issue
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        msg = pagure.lib.new_issue(
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        msg = pagure.lib.query.new_issue(
             session=self.session,
             repo=repo,
             title='Test issue #1',
@@ -2894,8 +2893,8 @@ class PagureFlaskApiIssuetests(tests.SimplePagureTest):
         self.assertEqual(msg.title, 'Test issue #1')
 
         # Check milestone before
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        issue = pagure.lib.search_issues(self.session, repo, issueid=1)
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        issue = pagure.lib.query.search_issues(self.session, repo, issueid=1)
         self.assertEqual(issue.milestone, None)
 
         data = {
@@ -2934,8 +2933,8 @@ class PagureFlaskApiIssuetests(tests.SimplePagureTest):
         )
 
         # Change recorded
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        issue = pagure.lib.search_issues(self.session, repo, issueid=1)
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        issue = pagure.lib.query.search_issues(self.session, repo, issueid=1)
         self.assertEqual(issue.milestone, None)
 
     def test_api_change_milestone_issue_unauthorized(self):
@@ -2946,15 +2945,15 @@ class PagureFlaskApiIssuetests(tests.SimplePagureTest):
         tests.create_tokens_acl(self.session)
 
         # Set some milestones to the project
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
         repo.milestones = {'v1.0': None, 'v2.0': 'Soon'}
         self.session.add(repo)
         self.session.commit()
 
         headers = {'Authorization': 'token aaabbbcccddd'}
         # Create normal issue
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        msg = pagure.lib.new_issue(
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        msg = pagure.lib.query.new_issue(
             session=self.session,
             repo=repo,
             title='Test issue #1',
@@ -2981,7 +2980,7 @@ class PagureFlaskApiIssuetests(tests.SimplePagureTest):
 
     @patch('pagure.lib.notify.send_email', MagicMock(return_value=True))
     @patch(
-        'pagure.lib.add_metadata_update_notif',
+        'pagure.lib.query.add_metadata_update_notif',
         MagicMock(side_effect=pagure.exceptions.PagureException('error')))
     def test_api_change_milestone_issue_raises_exception(self):
         """ Test the api_change_milestone_issue method of the flask api. """
@@ -2991,15 +2990,15 @@ class PagureFlaskApiIssuetests(tests.SimplePagureTest):
         tests.create_tokens_acl(self.session)
 
         # Set some milestones to the project
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
         repo.milestones = {'v1.0': None, 'v2.0': 'Soon'}
         self.session.add(repo)
         self.session.commit()
 
         headers = {'Authorization': 'token aaabbbcccddd'}
         # Create normal issue
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        msg = pagure.lib.new_issue(
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        msg = pagure.lib.query.new_issue(
             session=self.session,
             repo=repo,
             title='Test issue #1',
@@ -3037,8 +3036,8 @@ class PagureFlaskApiIssuetests(tests.SimplePagureTest):
         tests.create_tokens_acl(self.session)
 
         # Create normal issue in test
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        msg = pagure.lib.new_issue(
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        msg = pagure.lib.query.new_issue(
             session=self.session,
             repo=repo,
             title='Test issue #1',
@@ -3071,8 +3070,8 @@ class PagureFlaskApiIssuetests(tests.SimplePagureTest):
         )
 
         # One comment added
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        issue = pagure.lib.search_issues(self.session, repo, issueid=1)
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        issue = pagure.lib.query.search_issues(self.session, repo, issueid=1)
         self.assertEqual(len(issue.comments), 1)
 
         # View a comment that does not exist
@@ -3150,8 +3149,8 @@ class PagureFlaskApiIssuetests(tests.SimplePagureTest):
         tests.create_tokens_acl(self.session)
 
         # Create normal issue in test
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        msg = pagure.lib.new_issue(
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        msg = pagure.lib.query.new_issue(
             session=self.session,
             repo=repo,
             title='Test issue #1',
@@ -3282,8 +3281,8 @@ class PagureFlaskApiIssuetests(tests.SimplePagureTest):
         )
 
         # Create normal issue
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        msg = pagure.lib.new_issue(
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        msg = pagure.lib.query.new_issue(
             session=self.session,
             repo=repo,
             title='Test issue #1',
@@ -3296,13 +3295,13 @@ class PagureFlaskApiIssuetests(tests.SimplePagureTest):
         self.assertEqual(msg.title, 'Test issue #1')
 
         # Check comments before
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        issue = pagure.lib.search_issues(self.session, repo, issueid=1)
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        issue = pagure.lib.query.search_issues(self.session, repo, issueid=1)
         self.assertEqual(len(issue.comments), 0)
 
         # No change
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        issue = pagure.lib.search_issues(self.session, repo, issueid=1)
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        issue = pagure.lib.query.search_issues(self.session, repo, issueid=1)
         self.assertEqual(issue.status, 'Open')
 
         data = {
@@ -3329,8 +3328,8 @@ class PagureFlaskApiIssuetests(tests.SimplePagureTest):
             {'message': 'Assignee reset'}
         )
         # No change
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        issue = pagure.lib.search_issues(self.session, repo, issueid=1)
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        issue = pagure.lib.query.search_issues(self.session, repo, issueid=1)
         self.assertEqual(issue.assignee, None)
 
         # Un-assign
@@ -3343,8 +3342,8 @@ class PagureFlaskApiIssuetests(tests.SimplePagureTest):
             data,
             {'message': 'Nothing to change'}
         )
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        issue = pagure.lib.search_issues(self.session, repo, issueid=1)
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        issue = pagure.lib.query.search_issues(self.session, repo, issueid=1)
         self.assertEqual(issue.assignee, None)
 
         # Re-assign for the rest of the tests
@@ -3382,8 +3381,8 @@ class PagureFlaskApiIssuetests(tests.SimplePagureTest):
 
         # One comment added
         self.session.commit()
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        issue = pagure.lib.search_issues(self.session, repo, issueid=1)
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        issue = pagure.lib.query.search_issues(self.session, repo, issueid=1)
         self.assertEqual(issue.assignee.user, 'pingou')
 
         # Create another project
@@ -3416,9 +3415,9 @@ class PagureFlaskApiIssuetests(tests.SimplePagureTest):
         self.session.add(item)
         self.session.commit()
 
-        repo = pagure.lib.get_authorized_project(self.session, 'foo')
+        repo = pagure.lib.query.get_authorized_project(self.session, 'foo')
         # Create private issue
-        msg = pagure.lib.new_issue(
+        msg = pagure.lib.query.new_issue(
             session=self.session,
             repo=repo,
             title='Test issue',
@@ -3431,8 +3430,8 @@ class PagureFlaskApiIssuetests(tests.SimplePagureTest):
         self.assertEqual(msg.title, 'Test issue')
 
         # Check before
-        repo = pagure.lib.get_authorized_project(self.session, 'foo')
-        issue = pagure.lib.search_issues(self.session, repo, issueid=1)
+        repo = pagure.lib.query.get_authorized_project(self.session, 'foo')
+        issue = pagure.lib.query.search_issues(self.session, repo, issueid=1)
         self.assertEqual(len(issue.comments), 0)
 
         data = {
@@ -3452,8 +3451,8 @@ class PagureFlaskApiIssuetests(tests.SimplePagureTest):
             pagure.api.APIERROR.EINVALIDTOK.name, data['error_code'])
 
         # No comment added
-        repo = pagure.lib.get_authorized_project(self.session, 'foo')
-        issue = pagure.lib.search_issues(self.session, repo, issueid=1)
+        repo = pagure.lib.query.get_authorized_project(self.session, 'foo')
+        issue = pagure.lib.query.search_issues(self.session, repo, issueid=1)
         self.assertEqual(len(issue.comments), 0)
 
         # Create token for user foo
@@ -3496,8 +3495,8 @@ class PagureFlaskApiIssuetests(tests.SimplePagureTest):
         headers = {'Authorization': 'token aaabbbcccddd'}
 
         # Create normal issue
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        msg = pagure.lib.new_issue(
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        msg = pagure.lib.query.new_issue(
             session=self.session,
             repo=repo,
             title='Test issue #1',
@@ -3511,8 +3510,8 @@ class PagureFlaskApiIssuetests(tests.SimplePagureTest):
         self.assertEqual(msg.title, 'Test issue #1')
 
         # Check comments before
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        issue = pagure.lib.search_issues(self.session, repo, issueid=1)
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        issue = pagure.lib.query.search_issues(self.session, repo, issueid=1)
         self.assertEqual(len(issue.comments), 0)
 
         # Un-assign
@@ -3607,8 +3606,8 @@ class PagureFlaskApiIssuetests(tests.SimplePagureTest):
         )
 
         # Create normal issue
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        msg = pagure.lib.new_issue(
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        msg = pagure.lib.query.new_issue(
             session=self.session,
             repo=repo,
             title='Test issue #1',
@@ -3621,10 +3620,10 @@ class PagureFlaskApiIssuetests(tests.SimplePagureTest):
         self.assertEqual(msg.title, 'Test issue #1')
 
         # Check subscribtion before
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        issue = pagure.lib.search_issues(self.session, repo, issueid=1)
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        issue = pagure.lib.query.search_issues(self.session, repo, issueid=1)
         self.assertEqual(
-            pagure.lib.get_watch_list(self.session, issue),
+            pagure.lib.query.get_watch_list(self.session, issue),
             set(['pingou', 'foo']))
 
 
@@ -3656,10 +3655,10 @@ class PagureFlaskApiIssuetests(tests.SimplePagureTest):
         )
 
         # No change
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        issue = pagure.lib.search_issues(self.session, repo, issueid=1)
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        issue = pagure.lib.query.search_issues(self.session, repo, issueid=1)
         self.assertEqual(
-            pagure.lib.get_watch_list(self.session, issue),
+            pagure.lib.query.get_watch_list(self.session, issue),
             set(['pingou', 'foo']))
 
         # Subscribe
@@ -3690,10 +3689,10 @@ class PagureFlaskApiIssuetests(tests.SimplePagureTest):
             'user': 'bar'}
         )
 
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        issue = pagure.lib.search_issues(self.session, repo, issueid=1)
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        issue = pagure.lib.query.search_issues(self.session, repo, issueid=1)
         self.assertEqual(
-            pagure.lib.get_watch_list(self.session, issue),
+            pagure.lib.query.get_watch_list(self.session, issue),
             set(['pingou', 'foo', 'bar']))
 
         # Unsubscribe
@@ -3710,10 +3709,10 @@ class PagureFlaskApiIssuetests(tests.SimplePagureTest):
             'user': 'bar'}
         )
 
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        issue = pagure.lib.search_issues(self.session, repo, issueid=1)
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        issue = pagure.lib.query.search_issues(self.session, repo, issueid=1)
         self.assertEqual(
-            pagure.lib.get_watch_list(self.session, issue),
+            pagure.lib.query.get_watch_list(self.session, issue),
             set(['pingou', 'foo']))
 
     def test_api_update_custom_field(self):
@@ -3763,8 +3762,8 @@ class PagureFlaskApiIssuetests(tests.SimplePagureTest):
         )
 
         # Create normal issue
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        msg = pagure.lib.new_issue(
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        msg = pagure.lib.query.new_issue(
             session=self.session,
             repo=repo,
             title='Test issue #1',
@@ -3789,7 +3788,7 @@ class PagureFlaskApiIssuetests(tests.SimplePagureTest):
         )
 
         # Check the behavior if the project disabled the issue tracker
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
         settings = repo.settings
         settings['issue_tracker'] = False
         repo.settings = settings
@@ -3808,7 +3807,7 @@ class PagureFlaskApiIssuetests(tests.SimplePagureTest):
             }
         )
 
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
         settings = repo.settings
         settings['issue_tracker'] = True
         repo.settings = settings
@@ -3831,8 +3830,8 @@ class PagureFlaskApiIssuetests(tests.SimplePagureTest):
         headers = {'Authorization': 'token aaabbbcccddd'}
 
         # Set some custom fields
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        msg = pagure.lib.set_custom_key_fields(
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        msg = pagure.lib.query.set_custom_key_fields(
             self.session, repo,
             ['bugzilla', 'upstream', 'reviewstatus'],
             ['link', 'boolean', 'list'],
@@ -3865,8 +3864,8 @@ class PagureFlaskApiIssuetests(tests.SimplePagureTest):
             }
         )
 
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        issue = pagure.lib.search_issues(self.session, repo, issueid=1)
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        issue = pagure.lib.query.search_issues(self.session, repo, issueid=1)
         self.assertEqual(issue.other_fields, [])
         self.assertEqual(len(issue.other_fields), 0)
 
@@ -3885,8 +3884,8 @@ class PagureFlaskApiIssuetests(tests.SimplePagureTest):
             }
         )
 
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        issue = pagure.lib.search_issues(self.session, repo, issueid=1)
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        issue = pagure.lib.query.search_issues(self.session, repo, issueid=1)
         self.assertEqual(issue.other_fields, [])
         self.assertEqual(len(issue.other_fields), 0)
 
@@ -3905,8 +3904,8 @@ class PagureFlaskApiIssuetests(tests.SimplePagureTest):
         )
 
         self.session.commit()
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        issue = pagure.lib.search_issues(self.session, repo, issueid=1)
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        issue = pagure.lib.query.search_issues(self.session, repo, issueid=1)
         self.assertEqual(len(issue.other_fields), 1)
         self.assertEqual(issue.other_fields[0].key.name, 'bugzilla')
         self.assertEqual(
@@ -3928,12 +3927,12 @@ class PagureFlaskApiIssuetests(tests.SimplePagureTest):
         )
 
         self.session.commit()
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        issue = pagure.lib.search_issues(self.session, repo, issueid=1)
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        issue = pagure.lib.query.search_issues(self.session, repo, issueid=1)
         self.assertEqual(len(issue.other_fields), 0)
 
     @patch(
-        'pagure.lib.set_custom_key_value',
+        'pagure.lib.query.set_custom_key_value',
         MagicMock(side_effect=pagure.exceptions.PagureException('error')))
     def test_api_update_custom_field_raises_error(self):
         """ Test the api_update_custom_field method of the flask api. """
@@ -3945,8 +3944,8 @@ class PagureFlaskApiIssuetests(tests.SimplePagureTest):
         headers = {'Authorization': 'token aaabbbcccddd'}
 
         # Create normal issue
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        msg = pagure.lib.new_issue(
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        msg = pagure.lib.query.new_issue(
             session=self.session,
             repo=repo,
             title='Test issue #1',
@@ -3958,8 +3957,8 @@ class PagureFlaskApiIssuetests(tests.SimplePagureTest):
         self.assertEqual(msg.title, 'Test issue #1')
 
         # Set some custom fields
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        msg = pagure.lib.set_custom_key_fields(
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        msg = pagure.lib.query.set_custom_key_fields(
             self.session, repo,
             ['bugzilla', 'upstream', 'reviewstatus'],
             ['link', 'boolean', 'list'],
@@ -3995,8 +3994,8 @@ class PagureFlaskApiIssuetests(tests.SimplePagureTest):
         self.test_api_new_issue()
 
         # Create private issue
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        msg = pagure.lib.new_issue(
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        msg = pagure.lib.query.new_issue(
             session=self.session,
             repo=repo,
             title='Test issue',
@@ -4025,8 +4024,8 @@ class PagureFlaskApiIssuetests(tests.SimplePagureTest):
         self.test_api_new_issue()
 
         # Create private issue
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        msg = pagure.lib.new_issue(
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        msg = pagure.lib.query.new_issue(
             session=self.session,
             repo=repo,
             title='Test issue',
@@ -4143,8 +4142,8 @@ class PagureFlaskApiIssuetests(tests.SimplePagureTest):
         self.test_api_new_issue()
 
         # Create private issue
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        msg = pagure.lib.new_issue(
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        msg = pagure.lib.query.new_issue(
             session=self.session,
             repo=repo,
             title='Test issue',

+ 13 - 14
tests/test_pagure_flask_api_issue_change_status.py

@@ -27,8 +27,7 @@ from mock import patch, MagicMock
 sys.path.insert(0, os.path.join(os.path.dirname(
     os.path.abspath(__file__)), '..'))
 
-import pagure
-import pagure.lib
+import pagure.lib.query
 import pagure.lib.model
 import tests
 
@@ -51,8 +50,8 @@ class PagureFlaskApiIssueChangeStatustests(tests.Modeltests):
         tests.create_tokens_acl(self.session)
 
         # Create normal issue
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        msg = pagure.lib.new_issue(
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        msg = pagure.lib.query.new_issue(
             session=self.session,
             repo=repo,
             title='Test issue #1',
@@ -64,7 +63,7 @@ class PagureFlaskApiIssueChangeStatustests(tests.Modeltests):
         self.assertEqual(msg.title, 'Test issue #1')
 
         # Create private issue
-        msg = pagure.lib.new_issue(
+        msg = pagure.lib.query.new_issue(
             session=self.session,
             repo=repo,
             title='Test issue #2',
@@ -153,8 +152,8 @@ class PagureFlaskApiIssueChangeStatustests(tests.Modeltests):
         headers = {'Authorization': 'token aaabbbcccddd'}
 
         # Check status before
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        issue = pagure.lib.search_issues(self.session, repo, issueid=1)
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        issue = pagure.lib.query.search_issues(self.session, repo, issueid=1)
         self.assertEqual(issue.status, 'Open')
 
         data = {
@@ -176,8 +175,8 @@ class PagureFlaskApiIssueChangeStatustests(tests.Modeltests):
         )
 
         # No change
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        issue = pagure.lib.search_issues(self.session, repo, issueid=1)
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        issue = pagure.lib.query.search_issues(self.session, repo, issueid=1)
         self.assertEqual(issue.status, 'Open')
 
     def test_api_change_status_issue_no_change(self):
@@ -200,17 +199,17 @@ class PagureFlaskApiIssueChangeStatustests(tests.Modeltests):
         )
 
         # No change
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        issue = pagure.lib.search_issues(self.session, repo, issueid=1)
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        issue = pagure.lib.query.search_issues(self.session, repo, issueid=1)
         self.assertEqual(issue.status, 'Open')
 
     @patch('pagure.lib.notify.send_email', MagicMock(return_value=True))
     @patch(
-        'pagure.lib.edit_issue',
+        'pagure.lib.query.edit_issue',
         MagicMock(side_effect=pagure.exceptions.PagureException('error')))
     def test_api_change_status_issue_raise_error(self):
         """ Test the api_change_status_issue method of the flask api. """
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
         close_status = repo.close_status
         close_status = ['Fixed', 'Upstream', 'Invalid']
         repo.close_status = close_status
@@ -274,7 +273,7 @@ class PagureFlaskApiIssueChangeStatustests(tests.Modeltests):
     @patch('pagure.lib.notify.send_email', MagicMock(return_value=True))
     def test_api_change_status_issue_closed_status(self):
         """ Test the api_change_status_issue method of the flask api. """
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
         close_status = repo.close_status
         close_status = ['Fixed', 'Upstream', 'Invalid']
         repo.close_status = close_status

+ 24 - 25
tests/test_pagure_flask_api_issue_comment.py

@@ -22,8 +22,7 @@ from mock import patch, MagicMock
 sys.path.insert(0, os.path.join(os.path.dirname(
     os.path.abspath(__file__)), '..'))
 
-import pagure  # noqa: E402
-import pagure.lib  # noqa: E402
+import pagure.lib.query  # noqa: E402
 import tests  # noqa: E402
 
 
@@ -45,8 +44,8 @@ class PagureFlaskApiIssueCommenttests(tests.Modeltests):
         tests.create_tokens_acl(self.session)
 
         # Create normal issue
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        msg = pagure.lib.new_issue(
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        msg = pagure.lib.query.new_issue(
             session=self.session,
             repo=repo,
             title='Test issue #1',
@@ -58,7 +57,7 @@ class PagureFlaskApiIssueCommenttests(tests.Modeltests):
         self.assertEqual(msg.title, 'Test issue #1')
 
         # Create private issue
-        msg = pagure.lib.new_issue(
+        msg = pagure.lib.query.new_issue(
             session=self.session,
             repo=repo,
             title='Test issue #2',
@@ -132,8 +131,8 @@ class PagureFlaskApiIssueCommenttests(tests.Modeltests):
 
         headers = {'Authorization': 'token aaabbbcccddd'}
         # Check comments before
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        issue = pagure.lib.search_issues(self.session, repo, issueid=1)
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        issue = pagure.lib.query.search_issues(self.session, repo, issueid=1)
         self.assertEqual(len(issue.comments), 0)
 
         data = {
@@ -155,8 +154,8 @@ class PagureFlaskApiIssueCommenttests(tests.Modeltests):
         )
 
         # No change
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        issue = pagure.lib.search_issues(self.session, repo, issueid=1)
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        issue = pagure.lib.query.search_issues(self.session, repo, issueid=1)
         self.assertEqual(issue.status, 'Open')
 
     def test_api_comment_issue(self):
@@ -182,16 +181,16 @@ class PagureFlaskApiIssueCommenttests(tests.Modeltests):
         )
 
         # One comment added
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        issue = pagure.lib.search_issues(self.session, repo, issueid=1)
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        issue = pagure.lib.query.search_issues(self.session, repo, issueid=1)
         self.assertEqual(len(issue.comments), 1)
 
     def test_api_comment_issue_private_un_authorized(self):
         """ Test the api_comment_issue method of the flask api. """
 
         # Check before
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        issue = pagure.lib.search_issues(self.session, repo, issueid=2)
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        issue = pagure.lib.query.search_issues(self.session, repo, issueid=2)
         self.assertEqual(len(issue.comments), 0)
 
         data = {
@@ -209,8 +208,8 @@ class PagureFlaskApiIssueCommenttests(tests.Modeltests):
         self.assertEqual(pagure.api.APIERROR.EINVALIDTOK.value, data['error'])
 
         # No comment added
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        issue = pagure.lib.search_issues(self.session, repo, issueid=2)
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        issue = pagure.lib.query.search_issues(self.session, repo, issueid=2)
         self.assertEqual(len(issue.comments), 0)
 
     @patch('pagure.lib.notify.send_email', MagicMock(return_value=True))
@@ -301,8 +300,8 @@ class PagureFlaskApiIssueCommenttests(tests.Modeltests):
 
         headers = {'Authorization': 'token project-less-foo'}
         # Check comments before
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        issue = pagure.lib.search_issues(self.session, repo, issueid=1)
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        issue = pagure.lib.query.search_issues(self.session, repo, issueid=1)
         self.assertEqual(len(issue.comments), 0)
 
         data = {
@@ -324,8 +323,8 @@ class PagureFlaskApiIssueCommenttests(tests.Modeltests):
         )
 
         # No change
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        issue = pagure.lib.search_issues(self.session, repo, issueid=1)
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        issue = pagure.lib.query.search_issues(self.session, repo, issueid=1)
         self.assertEqual(issue.status, 'Open')
 
     @patch('pagure.lib.notify.send_email', MagicMock(return_value=True))
@@ -352,16 +351,16 @@ class PagureFlaskApiIssueCommenttests(tests.Modeltests):
         )
 
         # One comment added
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        issue = pagure.lib.search_issues(self.session, repo, issueid=1)
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        issue = pagure.lib.query.search_issues(self.session, repo, issueid=1)
         self.assertEqual(len(issue.comments), 1)
 
     def test_api_comment_issue_private_un_authorized_project_less(self):
         """ Test the api_comment_issue method of the flask api. """
 
         # Check before
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        issue = pagure.lib.search_issues(self.session, repo, issueid=2)
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        issue = pagure.lib.query.search_issues(self.session, repo, issueid=2)
         self.assertEqual(len(issue.comments), 0)
 
         data = {
@@ -379,8 +378,8 @@ class PagureFlaskApiIssueCommenttests(tests.Modeltests):
         self.assertEqual(pagure.api.APIERROR.EINVALIDTOK.value, data['error'])
 
         # No comment added
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        issue = pagure.lib.search_issues(self.session, repo, issueid=2)
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        issue = pagure.lib.query.search_issues(self.session, repo, issueid=2)
         self.assertEqual(len(issue.comments), 0)
 
     @patch('pagure.lib.notify.send_email', MagicMock(return_value=True))

+ 1 - 2
tests/test_pagure_flask_api_issue_create.py

@@ -21,8 +21,7 @@ from mock import patch, MagicMock
 sys.path.insert(0, os.path.join(os.path.dirname(
     os.path.abspath(__file__)), '..'))
 
-import pagure  # noqa: E402
-import pagure.lib  # noqa: E402
+import pagure.lib.query  # noqa: E402
 import tests  # noqa: E402
 
 

+ 12 - 13
tests/test_pagure_flask_api_issue_custom_fields.py

@@ -18,8 +18,7 @@ from mock import patch, MagicMock
 sys.path.insert(0, os.path.join(os.path.dirname(
     os.path.abspath(__file__)), '..'))
 
-import pagure  # noqa: E402
-import pagure.lib  # noqa: E402
+import pagure.lib.query  # noqa: E402
 import tests  # noqa: E402
 
 
@@ -39,8 +38,8 @@ class PagureFlaskApiCustomFieldIssuetests(tests.Modeltests):
         tests.create_tokens_acl(self.session)
 
         # Create normal issue
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        pagure.lib.new_issue(
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        pagure.lib.query.new_issue(
             session=self.session,
             repo=repo,
             title='Test issue #1',
@@ -92,7 +91,7 @@ class PagureFlaskApiCustomFieldIssuetests(tests.Modeltests):
         )
 
     @patch(
-        'pagure.lib.set_custom_key_value',
+        'pagure.lib.query.set_custom_key_value',
         MagicMock(side_effect=pagure.exceptions.PagureException('error')))
     def test_api_update_custom_field_raise_error(self):
         """ Test the api_update_custom_field method of the flask api.
@@ -102,8 +101,8 @@ class PagureFlaskApiCustomFieldIssuetests(tests.Modeltests):
         headers = {'Authorization': 'token aaabbbcccddd'}
 
         # Set some custom fields
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        msg = pagure.lib.set_custom_key_fields(
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        msg = pagure.lib.query.set_custom_key_fields(
             self.session, repo,
             ['bugzilla', 'upstream', 'reviewstatus'],
             ['link', 'boolean', 'list'],
@@ -128,8 +127,8 @@ class PagureFlaskApiCustomFieldIssuetests(tests.Modeltests):
         headers = {'Authorization': 'token aaabbbcccddd'}
 
         # Set some custom fields
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        msg = pagure.lib.set_custom_key_fields(
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        msg = pagure.lib.query.set_custom_key_fields(
             self.session, repo,
             ['bugzilla', 'upstream', 'reviewstatus'],
             ['link', 'boolean', 'list'],
@@ -155,8 +154,8 @@ class PagureFlaskApiCustomFieldIssuetests(tests.Modeltests):
         )
 
         self.session.commit()
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        issue = pagure.lib.search_issues(self.session, repo, issueid=1)
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        issue = pagure.lib.query.search_issues(self.session, repo, issueid=1)
         self.assertEqual(len(issue.other_fields), 1)
 
         payload = {'bugzilla': 'https://bugzilla.redhat.com/1234',
@@ -182,8 +181,8 @@ class PagureFlaskApiCustomFieldIssuetests(tests.Modeltests):
         )
 
         self.session.commit()
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        issue = pagure.lib.search_issues(self.session, repo, issueid=1)
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        issue = pagure.lib.query.search_issues(self.session, repo, issueid=1)
         self.assertEqual(len(issue.other_fields), 3)
 
         # Reset the value

+ 23 - 24
tests/test_pagure_flask_api_pr_flag.py

@@ -20,9 +20,8 @@ from mock import patch, MagicMock
 sys.path.insert(0, os.path.join(os.path.dirname(
     os.path.abspath(__file__)), '..'))
 
-import pagure  # noqa
 import pagure.config  # noqa
-import pagure.lib  # noqa
+import pagure.lib.query  # noqa
 import tests  # noqa
 
 
@@ -43,9 +42,9 @@ class PagureFlaskApiPRFlagtests(tests.Modeltests):
         tests.create_tokens_acl(self.session)
 
         # Create a pull-request
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        forked_repo = pagure.lib.get_authorized_project(self.session, 'test')
-        req = pagure.lib.new_pull_request(
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        forked_repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        req = pagure.lib.query.new_pull_request(
             session=self.session,
             repo_from=forked_repo,
             branch_from='master',
@@ -60,7 +59,7 @@ class PagureFlaskApiPRFlagtests(tests.Modeltests):
 
         # Check flags before
         self.session.commit()
-        request = pagure.lib.search_pull_requests(
+        request = pagure.lib.query.search_pull_requests(
             self.session, project_id=1, requestid=1)
         self.assertEqual(len(request.flags), 0)
 
@@ -98,7 +97,7 @@ class PagureFlaskApiPRFlagtests(tests.Modeltests):
     def test_pr_disabled(self):
         """ Test the flagging a PR when PRs are disabled. """
 
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
         settings = repo.settings
         settings['pull_requests'] = False
         repo.settings = settings
@@ -186,12 +185,12 @@ class PagureFlaskApiPRFlagtests(tests.Modeltests):
 
         # No change
         self.session.commit()
-        request = pagure.lib.search_pull_requests(
+        request = pagure.lib.query.search_pull_requests(
             self.session, project_id=1, requestid=1)
         self.assertEqual(len(request.flags), 0)
 
     @patch(
-        'pagure.lib.add_pull_request_flag',
+        'pagure.lib.query.add_pull_request_flag',
         MagicMock(side_effect=pagure.exceptions.PagureException('error')))
     def test_raise_exception(self):
         """ Test the flagging a PR when adding a flag raises an exception. """
@@ -218,7 +217,7 @@ class PagureFlaskApiPRFlagtests(tests.Modeltests):
         headers = {'Authorization': 'token aaabbbcccddd'}
 
         # Enable PR notifications
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
         settings = repo.settings
         settings['notify_on_pull-request_flag'] = True
         repo.settings = settings
@@ -267,7 +266,7 @@ class PagureFlaskApiPRFlagtests(tests.Modeltests):
 
         # One flag added
         self.session.commit()
-        request = pagure.lib.search_pull_requests(
+        request = pagure.lib.query.search_pull_requests(
             self.session, project_id=1, requestid=1)
         self.assertEqual(len(request.flags), 1)
         self.assertEqual(request.flags[0].comment, 'Tests running')
@@ -333,7 +332,7 @@ class PagureFlaskApiPRFlagtests(tests.Modeltests):
 
         # One flag added
         self.session.commit()
-        request = pagure.lib.search_pull_requests(
+        request = pagure.lib.query.search_pull_requests(
             self.session, project_id=1, requestid=1)
         self.assertEqual(len(request.flags), 1)
         self.assertEqual(request.flags[0].comment, 'Tests running')
@@ -381,7 +380,7 @@ class PagureFlaskApiPRFlagtests(tests.Modeltests):
 
         # One flag added
         self.session.commit()
-        request = pagure.lib.search_pull_requests(
+        request = pagure.lib.query.search_pull_requests(
             self.session, project_id=1, requestid=1)
         self.assertEqual(len(request.flags), 1)
         self.assertEqual(request.flags[0].comment, 'Tests passed')
@@ -434,7 +433,7 @@ class PagureFlaskApiPRFlagtests(tests.Modeltests):
 
         # One flag added
         self.session.commit()
-        request = pagure.lib.search_pull_requests(
+        request = pagure.lib.query.search_pull_requests(
             self.session, project_id=1, requestid=1)
         self.assertEqual(len(request.flags), 1)
         self.assertEqual(request.flags[0].comment, 'Tests passed')
@@ -483,7 +482,7 @@ class PagureFlaskApiPRFlagtests(tests.Modeltests):
 
         # Two flag added
         self.session.commit()
-        request = pagure.lib.search_pull_requests(
+        request = pagure.lib.query.search_pull_requests(
             self.session, project_id=1, requestid=1)
         self.assertEqual(len(request.flags), 2)
         self.assertEqual(request.flags[0].comment, 'Tests running again')
@@ -581,9 +580,9 @@ class PagureFlaskApiPRFlagUserTokentests(tests.Modeltests):
         tests.create_tokens_acl(self.session)
 
         # Create a pull-request
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        forked_repo = pagure.lib.get_authorized_project(self.session, 'test')
-        req = pagure.lib.new_pull_request(
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        forked_repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        req = pagure.lib.query.new_pull_request(
             session=self.session,
             repo_from=forked_repo,
             branch_from='master',
@@ -598,7 +597,7 @@ class PagureFlaskApiPRFlagUserTokentests(tests.Modeltests):
 
         # Check flags before
         self.session.commit()
-        request = pagure.lib.search_pull_requests(
+        request = pagure.lib.query.search_pull_requests(
             self.session, project_id=1, requestid=1)
         self.assertEqual(len(request.flags), 0)
 
@@ -685,7 +684,7 @@ class PagureFlaskApiPRFlagUserTokentests(tests.Modeltests):
 
         # No change
         self.session.commit()
-        request = pagure.lib.search_pull_requests(
+        request = pagure.lib.query.search_pull_requests(
             self.session, project_id=1, requestid=1)
         self.assertEqual(len(request.flags), 0)
 
@@ -718,7 +717,7 @@ class PagureFlaskApiPRFlagUserTokentests(tests.Modeltests):
 
         # No change
         self.session.commit()
-        request = pagure.lib.search_pull_requests(
+        request = pagure.lib.query.search_pull_requests(
             self.session, project_id=1, requestid=1)
         self.assertEqual(len(request.flags), 0)
 
@@ -772,7 +771,7 @@ class PagureFlaskApiPRFlagUserTokentests(tests.Modeltests):
 
         # One flag added
         self.session.commit()
-        request = pagure.lib.search_pull_requests(
+        request = pagure.lib.query.search_pull_requests(
             self.session, project_id=1, requestid=1)
         self.assertEqual(len(request.flags), 1)
         self.assertEqual(request.flags[0].comment, 'Tests failed')
@@ -828,7 +827,7 @@ class PagureFlaskApiPRFlagUserTokentests(tests.Modeltests):
 
         # One flag added
         self.session.commit()
-        request = pagure.lib.search_pull_requests(
+        request = pagure.lib.query.search_pull_requests(
             self.session, project_id=1, requestid=1)
         self.assertEqual(len(request.flags), 1)
         self.assertEqual(request.flags[0].comment, 'Tests failed')
@@ -877,7 +876,7 @@ class PagureFlaskApiPRFlagUserTokentests(tests.Modeltests):
 
         # Still only one flag
         self.session.commit()
-        request = pagure.lib.search_pull_requests(
+        request = pagure.lib.query.search_pull_requests(
             self.session, project_id=1, requestid=1)
         self.assertEqual(len(request.flags), 1)
         self.assertEqual(request.flags[0].comment, 'Tests passed')

+ 56 - 56
tests/test_pagure_flask_api_project.py

@@ -30,7 +30,7 @@ sys.path.insert(0, os.path.join(os.path.dirname(
     os.path.abspath(__file__)), '..'))
 
 import pagure.flask_app
-import pagure.lib
+import pagure.lib.query
 import tests
 from pagure.lib.repo import PagureRepo
 
@@ -217,7 +217,7 @@ class PagureFlaskApiProjecttests(tests.Modeltests):
         tests.create_tokens_acl(self.session, 'aaabbbcccddd')
         headers = {'Authorization': 'token aaabbbcccddd'}
 
-        test_project = pagure.lib._get_project(self.session, 'test')
+        test_project = pagure.lib.query._get_project(self.session, 'test')
         test_project.private = True
         self.session.add(test_project)
         self.session.commit()
@@ -240,7 +240,7 @@ class PagureFlaskApiProjecttests(tests.Modeltests):
         project is private and the user is not logged in.
         """
         tests.create_projects(self.session)
-        test_project = pagure.lib._get_project(self.session, 'test')
+        test_project = pagure.lib.query._get_project(self.session, 'test')
         test_project.private = True
         self.session.add(test_project)
         self.session.commit()
@@ -370,16 +370,16 @@ class PagureFlaskApiProjecttests(tests.Modeltests):
         tests.create_projects(self.session)
 
         # Check before adding
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
         self.assertEqual(repo.tags, [])
 
         # Adding a tag
-        output = pagure.lib.update_tags(
+        output = pagure.lib.query.update_tags(
             self.session, repo, 'infra', 'pingou')
         self.assertEqual(output, ['Project tagged with: infra'])
 
         # Check after adding
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
         self.assertEqual(len(repo.tags), 1)
         self.assertEqual(repo.tags_text, ['infra'])
 
@@ -851,16 +851,16 @@ class PagureFlaskApiProjecttests(tests.Modeltests):
         tests.create_projects(self.session)
 
         # Check before adding
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
         self.assertEqual(repo.tags, [])
 
         # Adding a tag
-        output = pagure.lib.update_tags(
+        output = pagure.lib.query.update_tags(
             self.session, repo, 'infra', 'pingou')
         self.assertEqual(output, ['Project tagged with: infra'])
 
         # Check after adding
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
         self.assertEqual(len(repo.tags), 1)
         self.assertEqual(repo.tags_text, ['infra'])
 
@@ -921,20 +921,20 @@ class PagureFlaskApiProjecttests(tests.Modeltests):
     def test_api_project_group(self):
         """ Test the api_project method of the flask api. """
         tests.create_projects(self.session)
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
 
         # Adding a tag
-        output = pagure.lib.update_tags(
+        output = pagure.lib.query.update_tags(
             self.session, repo, 'infra', 'pingou')
         self.assertEqual(output, ['Project tagged with: infra'])
 
         # Check after adding
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
         self.assertEqual(len(repo.tags), 1)
         self.assertEqual(repo.tags_text, ['infra'])
 
         # Add a group to the project
-        msg = pagure.lib.add_group(
+        msg = pagure.lib.query.add_group(
             self.session,
             group_name='some_group',
             display_name='Some Group',
@@ -946,11 +946,11 @@ class PagureFlaskApiProjecttests(tests.Modeltests):
         )
         self.session.commit()
 
-        project = pagure.lib.get_authorized_project(self.session, 'test')
-        group = pagure.lib.search_groups(
+        project = pagure.lib.query.get_authorized_project(self.session, 'test')
+        group = pagure.lib.query.search_groups(
             self.session, group_name='some_group')
 
-        pagure.lib.add_group_to_project(
+        pagure.lib.query.add_group_to_project(
             self.session,
             project,
             new_group='some_group',
@@ -1016,15 +1016,15 @@ class PagureFlaskApiProjecttests(tests.Modeltests):
         group details while there are none associated.
         """
         tests.create_projects(self.session)
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
 
         # Adding a tag
-        output = pagure.lib.update_tags(
+        output = pagure.lib.query.update_tags(
             self.session, repo, 'infra', 'pingou')
         self.assertEqual(output, ['Project tagged with: infra'])
 
         # Check after adding
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
         self.assertEqual(len(repo.tags), 1)
         self.assertEqual(repo.tags_text, ['infra'])
 
@@ -1525,8 +1525,8 @@ class PagureFlaskApiProjecttests(tests.Modeltests):
         tests.create_tokens_acl(self.session, 'aaabbbcccddd', 'modify_project')
         headers = {'Authorization': 'token aaabbbcccddd'}
 
-        project = pagure.lib._get_project(self.session, 'test')
-        pagure.lib.add_user_to_project(
+        project = pagure.lib.query._get_project(self.session, 'test')
+        pagure.lib.query.add_user_to_project(
             self.session, project,
             new_user='foo',
             user='pingou',
@@ -1714,7 +1714,7 @@ class PagureFlaskApiProjecttests(tests.Modeltests):
         the main_admin.
         """
         tests.create_projects(self.session)
-        project_user = pagure.lib.model.ProjectUser(
+        project_user = pagure.lib.query.model.ProjectUser(
             project_id=1,
             user_id=2,
             access='admin',
@@ -1858,10 +1858,10 @@ class PagureFlaskApiProjecttests(tests.Modeltests):
             }
             self.assertDictEqual(json.loads(output.get_data(as_text=True)), expected_data)
 
-            project = pagure.lib.get_authorized_project(self.session, 'test')
+            project = pagure.lib.query.get_authorized_project(self.session, 'test')
 
             # The owner is watching issues and commits explicitly
-            pagure.lib.update_watch_status(
+            pagure.lib.query.update_watch_status(
                 self.session, project, 'pingou', '3')
             self.session.commit()
             output = self.app.get('/api/0/test/watchers')
@@ -1878,7 +1878,7 @@ class PagureFlaskApiProjecttests(tests.Modeltests):
             self.assertDictEqual(json.loads(output.get_data(as_text=True)), expected_data)
 
             # The owner is watching issues explicitly
-            pagure.lib.update_watch_status(
+            pagure.lib.query.update_watch_status(
                 self.session, project, 'pingou', '1')
             self.session.commit()
             output = self.app.get('/api/0/test/watchers')
@@ -1894,7 +1894,7 @@ class PagureFlaskApiProjecttests(tests.Modeltests):
             self.assertDictEqual(json.loads(output.get_data(as_text=True)), expected_data)
 
             # The owner is watching commits explicitly
-            pagure.lib.update_watch_status(
+            pagure.lib.query.update_watch_status(
                 self.session, project, 'pingou', '2')
             self.session.commit()
             output = self.app.get('/api/0/test/watchers')
@@ -1916,7 +1916,7 @@ class PagureFlaskApiProjecttests(tests.Modeltests):
                 user_id=2,
                 access='commit',
             )
-            pagure.lib.update_watch_status(
+            pagure.lib.query.update_watch_status(
                 self.session, project, 'pingou', '2')
             self.session.add(project_user)
             self.session.commit()
@@ -1933,7 +1933,7 @@ class PagureFlaskApiProjecttests(tests.Modeltests):
             self.assertDictEqual(json.loads(output.get_data(as_text=True)), expected_data)
 
             # The owner and foo are watching issues implicitly
-            pagure.lib.update_watch_status(
+            pagure.lib.query.update_watch_status(
                 self.session, project, 'pingou', '-1')
             self.session.commit()
 
@@ -1950,7 +1950,7 @@ class PagureFlaskApiProjecttests(tests.Modeltests):
 
             # The owner and foo through group membership are watching issues
             # implicitly
-            pagure.lib.update_watch_status(
+            pagure.lib.query.update_watch_status(
                 self.session, project, 'pingou', '-1')
             project_membership = self.session.query(
                 pagure.lib.model.ProjectUser).filter_by(
@@ -1958,7 +1958,7 @@ class PagureFlaskApiProjecttests(tests.Modeltests):
             self.session.delete(project_membership)
             self.session.commit()
 
-            msg = pagure.lib.add_group(
+            msg = pagure.lib.query.add_group(
                 self.session,
                 group_name='some_group',
                 display_name='Some Group',
@@ -1970,13 +1970,13 @@ class PagureFlaskApiProjecttests(tests.Modeltests):
             )
             self.session.commit()
 
-            project = pagure.lib.get_authorized_project(self.session, 'test')
-            group = pagure.lib.search_groups(
+            project = pagure.lib.query.get_authorized_project(self.session, 'test')
+            group = pagure.lib.query.search_groups(
                 self.session, group_name='some_group')
-            pagure.lib.add_user_to_group(
+            pagure.lib.query.add_user_to_group(
                 self.session, 'foo', group, 'pingou', False)
 
-            pagure.lib.add_group_to_project(
+            pagure.lib.query.add_group_to_project(
                 self.session,
                 project,
                 new_group='some_group',
@@ -2000,9 +2000,9 @@ class PagureFlaskApiProjecttests(tests.Modeltests):
 
             # The owner is watching issues implicitly and foo will be watching
             # commits explicitly but is in a group with commit access
-            pagure.lib.update_watch_status(
+            pagure.lib.query.update_watch_status(
                 self.session, project, 'pingou', '-1')
-            pagure.lib.update_watch_status(
+            pagure.lib.query.update_watch_status(
                 self.session, project, 'foo', '2')
             self.session.commit()
 
@@ -2112,7 +2112,7 @@ class PagureFlaskApiProjecttests(tests.Modeltests):
     def test_adopt_repos(self):
         """ Test the new_project endpoint with existing git repo. """
         # Before
-        projects = pagure.lib.search_projects(self.session)
+        projects = pagure.lib.query.search_projects(self.session)
         self.assertEqual(len(projects), 0)
 
         tests.create_projects_git(os.path.join(self.path, 'repos'), bare=True)
@@ -2616,7 +2616,7 @@ class PagureFlaskApiProjecttests(tests.Modeltests):
             self.session, 'aaabbbcccddd', 'generate_acls_project')
         headers = {'Authorization': 'token aaabbbcccddd'}
 
-        user = pagure.lib.get_user(self.session, 'pingou')
+        user = pagure.lib.query.get_user(self.session, 'pingou')
         output = self.app.post(
             '/api/0/test/git/generateacls', headers=headers,
             data={'wait': False})
@@ -2639,7 +2639,7 @@ class PagureFlaskApiProjecttests(tests.Modeltests):
         headers = {'Authorization': 'token aaabbbcccddd',
                    'Content-Type': 'application/json'}
 
-        user = pagure.lib.get_user(self.session, 'pingou')
+        user = pagure.lib.query.get_user(self.session, 'pingou')
 
         output = self.app.post(
             '/api/0/test/git/generateacls', headers=headers,
@@ -2667,7 +2667,7 @@ class PagureFlaskApiProjecttests(tests.Modeltests):
         task_result.id = 'abc-1234'
         self.mock_gen_acls.return_value = task_result
 
-        user = pagure.lib.get_user(self.session, 'pingou')
+        user = pagure.lib.query.get_user(self.session, 'pingou')
         output = self.app.post(
             '/api/0/test/git/generateacls', headers=headers,
             data={'wait': True})
@@ -2690,7 +2690,7 @@ class PagureFlaskApiProjecttests(tests.Modeltests):
             self.session, 'aaabbbcccddd', 'generate_acls_project')
         headers = {'Authorization': 'token aaabbbcccddd'}
 
-        user = pagure.lib.get_user(self.session, 'pingou')
+        user = pagure.lib.query.get_user(self.session, 'pingou')
         output = self.app.post(
             '/api/0/test12345123/git/generateacls', headers=headers,
             data={'wait': False})
@@ -3101,7 +3101,7 @@ class PagureFlaskApiProjectFlagtests(tests.Modeltests):
         """ Test flagging a commit with notification enabled. """
 
         # Enable commit notifications
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
         settings = repo.settings
         settings['notify_on_commit_flag'] = True
         repo.settings = settings
@@ -3215,7 +3215,7 @@ class PagureFlaskApiProjectFlagtests(tests.Modeltests):
 
     def test_commit_flags(self):
         """ Test retrieving commit flags. """
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
         repo_obj = pygit2.Repository(self.git_path)
         commit = repo_obj.revparse_single('HEAD')
 
@@ -3225,7 +3225,7 @@ class PagureFlaskApiProjectFlagtests(tests.Modeltests):
         self.assertEqual(output.status_code, 200)
 
         # add some flags and retrieve them
-        pagure.lib.add_commit_flag(
+        pagure.lib.query.add_commit_flag(
             session=self.session,
             repo=repo,
             commit_hash=commit.oid.hex,
@@ -3239,7 +3239,7 @@ class PagureFlaskApiProjectFlagtests(tests.Modeltests):
             token='aaabbbcccddd'
         )
 
-        pagure.lib.add_commit_flag(
+        pagure.lib.query.add_commit_flag(
             session=self.session,
             repo=repo,
             commit_hash=commit.oid.hex,
@@ -3309,7 +3309,7 @@ class PagureFlaskApiProjectModifyAclTests(tests.Modeltests):
         tests.create_tokens_acl(
             self.session, 'aaabbbcccddd', 'modify_project')
 
-        project = pagure.lib._get_project(self.session, 'test')
+        project = pagure.lib.query._get_project(self.session, 'test')
         self.assertEquals(
             project.access_users,
             {u'admin': [], u'commit': [], u'ticket': []}
@@ -3505,7 +3505,7 @@ class PagureFlaskApiProjectModifyAclTests(tests.Modeltests):
         headers = {'Authorization': 'token aaabbbcccddd'}
 
         # Create a group
-        msg = pagure.lib.add_group(
+        msg = pagure.lib.query.add_group(
             self.session,
             group_name='baz',
             display_name='baz group',
@@ -3572,7 +3572,7 @@ class PagureFlaskApiProjectModifyAclTests(tests.Modeltests):
         are specified. """
         headers = {'Authorization': 'token aaabbbcccddd'}
 
-        project = pagure.lib._get_project(self.session, 'test')
+        project = pagure.lib.query._get_project(self.session, 'test')
         self.assertEquals(
             project.access_users,
             {u'admin': [], u'commit': [], u'ticket': []}
@@ -3624,8 +3624,8 @@ class PagureFlaskApiProjectModifyAclTests(tests.Modeltests):
         self.test_api_modify_acls_user()
 
         # Ensure `foo` was properly added:
-        project = pagure.lib._get_project(self.session, 'test')
-        user_foo = pagure.lib.search_user(self.session, username='foo')
+        project = pagure.lib.query._get_project(self.session, 'test')
+        user_foo = pagure.lib.query.search_user(self.session, username='foo')
         self.assertEquals(
             project.access_users,
             {u'admin': [], u'commit': [user_foo], u'ticket': []}
@@ -3698,8 +3698,8 @@ class PagureFlaskApiProjectModifyAclTests(tests.Modeltests):
         self.assertEqual(data, expected_output)
 
         # Ensure `foo` was properly removed
-        self.session = pagure.lib.create_session(self.dbpath)
-        project = pagure.lib._get_project(self.session, 'test')
+        self.session = pagure.lib.query.create_session(self.dbpath)
+        project = pagure.lib.query._get_project(self.session, 'test')
         self.assertEquals(
             project.access_users,
             {u'admin': [], u'commit': [], u'ticket': []}
@@ -3712,8 +3712,8 @@ class PagureFlaskApiProjectModifyAclTests(tests.Modeltests):
         self.test_api_modify_acls_user()
 
         # Ensure `foo` was properly added:
-        project = pagure.lib._get_project(self.session, 'test')
-        user_foo = pagure.lib.search_user(self.session, username='foo')
+        project = pagure.lib.query._get_project(self.session, 'test')
+        user_foo = pagure.lib.query.search_user(self.session, username='foo')
         self.assertEquals(
             project.access_users,
             {u'admin': [], u'commit': [user_foo], u'ticket': []}
@@ -3773,8 +3773,8 @@ class PagureFlaskApiProjectModifyAclTests(tests.Modeltests):
         self.assertEqual(data, expected_output)
 
         # Ensure `foo` was properly removed
-        self.session = pagure.lib.create_session(self.dbpath)
-        project = pagure.lib._get_project(self.session, 'test')
+        self.session = pagure.lib.query.create_session(self.dbpath)
+        project = pagure.lib.query._get_project(self.session, 'test')
         self.assertEquals(
             project.access_users,
             {u'admin': [], u'commit': [], u'ticket': []}

+ 3 - 4
tests/test_pagure_flask_api_project_update_watch.py

@@ -27,8 +27,7 @@ from mock import patch, MagicMock
 sys.path.insert(0, os.path.join(os.path.dirname(
     os.path.abspath(__file__)), '..'))
 
-import pagure
-import pagure.lib
+import pagure.lib.query
 import tests
 
 
@@ -48,8 +47,8 @@ class PagureFlaskApiProjectUpdateWatchTests(tests.Modeltests):
         tests.create_tokens_acl(self.session)
 
         # Create normal issue
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        msg = pagure.lib.new_issue(
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        msg = pagure.lib.query.new_issue(
             session=self.session,
             repo=repo,
             title='Test issue #1',

+ 66 - 66
tests/test_pagure_flask_api_ui_private_repo.py

@@ -19,7 +19,7 @@ from mock import patch, MagicMock
 sys.path.insert(0, os.path.join(os.path.dirname(
     os.path.abspath(__file__)), '..'))
 
-import pagure.lib
+import pagure.lib.query
 import tests
 from pagure.lib.repo import PagureRepo
 
@@ -357,8 +357,8 @@ class PagurePrivateRepotest(tests.Modeltests):
             PagureRepo.push(ori_remote, refname)
 
         # Create a PR for these changes
-        project = pagure.lib._get_project(self.session, 'pmc')
-        req = pagure.lib.new_pull_request(
+        project = pagure.lib.query._get_project(self.session, 'pmc')
+        req = pagure.lib.query.new_pull_request(
             session=self.session,
             repo_from=project,
             branch_from=branch_from,
@@ -610,9 +610,9 @@ class PagurePrivateRepotest(tests.Modeltests):
             self.assertEqual(
                 output_text.count('<span class="d-none d-md-inline">Groups'), 0)
 
-        repo = pagure.lib._get_project(self.session, 'test3')
+        repo = pagure.lib.query._get_project(self.session, 'test3')
 
-        msg = pagure.lib.add_user_to_project(
+        msg = pagure.lib.query.add_user_to_project(
             session=self.session,
             project=repo,
             new_user='pingou',
@@ -721,7 +721,7 @@ class PagurePrivateRepotest(tests.Modeltests):
                 output.get_data(as_text=True))
 
             self.session.commit()
-            repo = pagure.lib._get_project(self.session, 'test4')
+            repo = pagure.lib.query._get_project(self.session, 'test4')
             self.assertTrue(repo.private)
 
             # Make the project public
@@ -741,7 +741,7 @@ class PagurePrivateRepotest(tests.Modeltests):
                 output.get_data(as_text=True))
 
             self.session.commit()
-            repo = pagure.lib._get_project(self.session, 'test4')
+            repo = pagure.lib.query._get_project(self.session, 'test4')
             self.assertFalse(repo.private)
 
     @patch('pagure.decorators.admin_session_timedout')
@@ -776,7 +776,7 @@ class PagurePrivateRepotest(tests.Modeltests):
                 output.get_data(as_text=True))
 
             self.session.commit()
-            repo = pagure.lib._get_project(self.session, 'test4')
+            repo = pagure.lib.query._get_project(self.session, 'test4')
             self.assertFalse(repo.private)
 
             # Make the project private
@@ -797,7 +797,7 @@ class PagurePrivateRepotest(tests.Modeltests):
 
             # No change since we can't do public -> private
             self.session.commit()
-            repo = pagure.lib._get_project(self.session, 'test4')
+            repo = pagure.lib.query._get_project(self.session, 'test4')
             self.assertFalse(repo.private)
 
     @patch('pagure.lib.notify.send_email')
@@ -817,9 +817,9 @@ class PagurePrivateRepotest(tests.Modeltests):
         self.session.add(item)
         self.session.commit()
 
-        repo = pagure.lib._get_project(self.session, 'pmc')
+        repo = pagure.lib.query._get_project(self.session, 'pmc')
 
-        msg = pagure.lib.add_user_to_project(
+        msg = pagure.lib.query.add_user_to_project(
             session=self.session,
             project=repo,
             new_user='foo',
@@ -879,7 +879,7 @@ class PagurePrivateRepotest(tests.Modeltests):
             </div>""", output.get_data(as_text=True))
 
             self.set_up_git_repo(new_project=None, branch_from='feature')
-            project = pagure.lib._get_project(self.session, 'pmc')
+            project = pagure.lib.query._get_project(self.session, 'pmc')
             self.assertEqual(len(project.requests), 1)
 
             output = self.app.get('/pmc/pull-request/1')
@@ -932,8 +932,8 @@ class PagurePrivateRepotest(tests.Modeltests):
         self.assertEqual(output.status_code, 404)
 
         # Create issues to play with
-        repo = pagure.lib._get_project(self.session, 'test4')
-        msg = pagure.lib.new_issue(
+        repo = pagure.lib.query._get_project(self.session, 'test4')
+        msg = pagure.lib.query.new_issue(
             session=self.session,
             repo=repo,
             title='Test issue',
@@ -976,9 +976,9 @@ class PagurePrivateRepotest(tests.Modeltests):
             output = self.app.get('/test4/issue/1')
             self.assertEqual(output.status_code, 200)
 
-        repo = pagure.lib._get_project(self.session, 'test4')
+        repo = pagure.lib.query._get_project(self.session, 'test4')
 
-        msg = pagure.lib.add_user_to_project(
+        msg = pagure.lib.query.add_user_to_project(
             session=self.session,
             project=repo,
             new_user='foo',
@@ -1018,7 +1018,7 @@ class PagurePrivateRepotest(tests.Modeltests):
         self.session.add(item)
         self.session.commit()
 
-        repo = pagure.lib._get_project(self.session, "test4")
+        repo = pagure.lib.query._get_project(self.session, "test4")
         # Add a git repo
         repo_path = os.path.join(
             pagure.config.config.get('GIT_FOLDER'), 'test4.git')
@@ -1039,7 +1039,7 @@ class PagurePrivateRepotest(tests.Modeltests):
             self.assertEqual(output.status_code, 404)
 
         # Add commit access to a user
-        pagure.lib.add_user_to_project(
+        pagure.lib.query.add_user_to_project(
             self.session,
             project=repo,
             new_user="foo",
@@ -1049,7 +1049,7 @@ class PagurePrivateRepotest(tests.Modeltests):
         self.session.commit()
 
 
-        repo = pagure.lib._get_project(self.session, "test4")
+        repo = pagure.lib.query._get_project(self.session, "test4")
         self.assertEqual(len(repo.users), 1)
 
         # Check if the user can access private repo
@@ -1082,7 +1082,7 @@ class PagurePrivateRepotest(tests.Modeltests):
             self.assertEqual(output.status_code, 404)
 
         # Adding a ticket level access to bar
-        pagure.lib.add_user_to_project(
+        pagure.lib.query.add_user_to_project(
             self.session,
             project=repo,
             new_user="bar",
@@ -1091,7 +1091,7 @@ class PagurePrivateRepotest(tests.Modeltests):
         )
         self.session.commit()
 
-        repo = pagure.lib._get_project(self.session, "test4")
+        repo = pagure.lib.query._get_project(self.session, "test4")
         self.assertEqual(len(repo.users), 2)
 
         # Check if the ticket level access user can access the project
@@ -1197,16 +1197,16 @@ class PagurePrivateRepotest(tests.Modeltests):
         shutil.rmtree(newpath)
 
         # Check before adding
-        repo = pagure.lib._get_project(self.session, 'test4')
+        repo = pagure.lib.query._get_project(self.session, 'test4')
         self.assertEqual(repo.tags, [])
 
         # Adding a tag
-        output = pagure.lib.update_tags(
+        output = pagure.lib.query.update_tags(
             self.session, repo, 'infra', 'pingou')
         self.assertEqual(output, ['Project tagged with: infra'])
 
         # Check after adding
-        repo = pagure.lib._get_project(self.session, 'test4')
+        repo = pagure.lib.query._get_project(self.session, 'test4')
         self.assertEqual(len(repo.tags), 1)
         self.assertEqual(repo.tags_text, ['infra'])
 
@@ -1452,9 +1452,9 @@ class PagurePrivateRepotest(tests.Modeltests):
 
         headers = {'Authorization': 'token aaabbbcccddd'}
         # Create a pull-request
-        repo = pagure.lib._get_project(self.session, 'test4')
-        forked_repo = pagure.lib._get_project(self.session, 'test4')
-        req = pagure.lib.new_pull_request(
+        repo = pagure.lib.query._get_project(self.session, 'test4')
+        forked_repo = pagure.lib.query._get_project(self.session, 'test4')
+        req = pagure.lib.query.new_pull_request(
             session=self.session,
             repo_from=forked_repo,
             branch_from='master',
@@ -1771,9 +1771,9 @@ class PagurePrivateRepotest(tests.Modeltests):
 
         headers = {'Authorization': 'token aaabbbcccddd'}
         # Create a pull-request
-        repo = pagure.lib._get_project(self.session, 'test4')
-        forked_repo = pagure.lib._get_project(self.session, 'test4')
-        req = pagure.lib.new_pull_request(
+        repo = pagure.lib.query._get_project(self.session, 'test4')
+        forked_repo = pagure.lib.query._get_project(self.session, 'test4')
+        req = pagure.lib.query.new_pull_request(
             session=self.session,
             repo_from=forked_repo,
             branch_from='master',
@@ -1788,7 +1788,7 @@ class PagurePrivateRepotest(tests.Modeltests):
 
         # Check comments before
         self.session.commit()
-        request = pagure.lib.search_pull_requests(
+        request = pagure.lib.query.search_pull_requests(
             self.session, project_id=1, requestid=1)
         self.assertEqual(len(request.comments), 0)
 
@@ -1812,7 +1812,7 @@ class PagurePrivateRepotest(tests.Modeltests):
 
         # No change
         self.session.commit()
-        request = pagure.lib.search_pull_requests(
+        request = pagure.lib.query.search_pull_requests(
             self.session, project_id=1, requestid=1)
         self.assertEqual(len(request.comments), 0)
 
@@ -1832,7 +1832,7 @@ class PagurePrivateRepotest(tests.Modeltests):
 
         # One comment added
         self.session.commit()
-        request = pagure.lib.search_pull_requests(
+        request = pagure.lib.query.search_pull_requests(
             self.session, project_id=1, requestid=1)
         self.assertEqual(len(request.comments), 1)
 
@@ -1907,9 +1907,9 @@ class PagurePrivateRepotest(tests.Modeltests):
         )
 
         # Create a pull-request
-        repo = pagure.lib._get_project(self.session, 'test4')
-        forked_repo = pagure.lib._get_project(self.session, 'test4')
-        req = pagure.lib.new_pull_request(
+        repo = pagure.lib.query._get_project(self.session, 'test4')
+        forked_repo = pagure.lib.query._get_project(self.session, 'test4')
+        req = pagure.lib.query.new_pull_request(
             session=self.session,
             repo_from=forked_repo,
             branch_from='master',
@@ -1924,7 +1924,7 @@ class PagurePrivateRepotest(tests.Modeltests):
 
         # Check comments before
         self.session.commit()
-        request = pagure.lib.search_pull_requests(
+        request = pagure.lib.query.search_pull_requests(
             self.session, project_id=1, requestid=1)
         self.assertEqual(len(request.flags), 0)
 
@@ -1951,7 +1951,7 @@ class PagurePrivateRepotest(tests.Modeltests):
 
         # No change
         self.session.commit()
-        request = pagure.lib.search_pull_requests(
+        request = pagure.lib.query.search_pull_requests(
             self.session, project_id=1, requestid=1)
         self.assertEqual(len(request.flags), 0)
 
@@ -1996,7 +1996,7 @@ class PagurePrivateRepotest(tests.Modeltests):
 
         # One flag added
         self.session.commit()
-        request = pagure.lib.search_pull_requests(
+        request = pagure.lib.query.search_pull_requests(
             self.session, project_id=1, requestid=1)
         self.assertEqual(len(request.flags), 1)
         self.assertEqual(request.flags[0].comment, 'Tests failed')
@@ -2043,7 +2043,7 @@ class PagurePrivateRepotest(tests.Modeltests):
 
         # One flag added
         self.session.commit()
-        request = pagure.lib.search_pull_requests(
+        request = pagure.lib.query.search_pull_requests(
             self.session, project_id=1, requestid=1)
         self.assertEqual(len(request.flags), 1)
         self.assertEqual(request.flags[0].comment, 'Tests passed')
@@ -2082,9 +2082,9 @@ class PagurePrivateRepotest(tests.Modeltests):
         self.session.commit()
 
         # Create the pull-request to close
-        repo = pagure.lib._get_project(self.session, 'test4')
-        forked_repo = pagure.lib._get_project(self.session, 'test4')
-        req = pagure.lib.new_pull_request(
+        repo = pagure.lib.query._get_project(self.session, 'test4')
+        forked_repo = pagure.lib.query._get_project(self.session, 'test4')
+        req = pagure.lib.query.new_pull_request(
             session=self.session,
             repo_from=forked_repo,
             branch_from='master',
@@ -2144,7 +2144,7 @@ class PagurePrivateRepotest(tests.Modeltests):
         self.session.add(item)
         self.session.commit()
         # Allow the token to close PR
-        acls = pagure.lib.get_acls(self.session)
+        acls = pagure.lib.query.get_acls(self.session)
         acl = None
         for acl in acls:
             if acl.name == 'pull_request_close':
@@ -2224,9 +2224,9 @@ class PagurePrivateRepotest(tests.Modeltests):
         self.session.commit()
 
         # Create the pull-request to close
-        repo = pagure.lib._get_project(self.session, 'test4')
-        forked_repo = pagure.lib._get_project(self.session, 'test4')
-        req = pagure.lib.new_pull_request(
+        repo = pagure.lib.query._get_project(self.session, 'test4')
+        forked_repo = pagure.lib.query._get_project(self.session, 'test4')
+        req = pagure.lib.query.new_pull_request(
             session=self.session,
             repo_from=forked_repo,
             branch_from='test',
@@ -2287,7 +2287,7 @@ class PagurePrivateRepotest(tests.Modeltests):
         self.session.commit()
 
         # Allow the token to merge PR
-        acls = pagure.lib.get_acls(self.session)
+        acls = pagure.lib.query.get_acls(self.session)
         acl = None
         for acl in acls:
             if acl.name == 'pull_request_merge':
@@ -2525,8 +2525,8 @@ class PagurePrivateRepotest(tests.Modeltests):
             )
 
         # Create private issue
-        repo = pagure.lib._get_project(self.session, 'test4')
-        msg = pagure.lib.new_issue(
+        repo = pagure.lib.query._get_project(self.session, 'test4')
+        msg = pagure.lib.query.new_issue(
             session=self.session,
             repo=repo,
             title='Test issue',
@@ -3078,8 +3078,8 @@ class PagurePrivateRepotest(tests.Modeltests):
         )
 
         # Create normal issue
-        repo = pagure.lib._get_project(self.session, 'test4')
-        msg = pagure.lib.new_issue(
+        repo = pagure.lib.query._get_project(self.session, 'test4')
+        msg = pagure.lib.query.new_issue(
             session=self.session,
             repo=repo,
             title='Test issue #1',
@@ -3091,8 +3091,8 @@ class PagurePrivateRepotest(tests.Modeltests):
         self.assertEqual(msg.title, 'Test issue #1')
 
         # Check status before
-        repo = pagure.lib._get_project(self.session, 'test4')
-        issue = pagure.lib.search_issues(self.session, repo, issueid=1)
+        repo = pagure.lib.query._get_project(self.session, 'test4')
+        issue = pagure.lib.query.search_issues(self.session, repo, issueid=1)
         self.assertEqual(issue.status, 'Open')
 
         data = {
@@ -3116,8 +3116,8 @@ class PagurePrivateRepotest(tests.Modeltests):
             )
 
             # No change
-            repo = pagure.lib._get_project(self.session, 'test4')
-            issue = pagure.lib.search_issues(self.session, repo, issueid=1)
+            repo = pagure.lib.query._get_project(self.session, 'test4')
+            issue = pagure.lib.query.search_issues(self.session, repo, issueid=1)
             self.assertEqual(issue.status, 'Open')
 
             data = {
@@ -3135,8 +3135,8 @@ class PagurePrivateRepotest(tests.Modeltests):
             )
 
             # No change
-            repo = pagure.lib._get_project(self.session, 'test4')
-            issue = pagure.lib.search_issues(self.session, repo, issueid=1)
+            repo = pagure.lib.query._get_project(self.session, 'test4')
+            issue = pagure.lib.query.search_issues(self.session, repo, issueid=1)
             self.assertEqual(issue.status, 'Open')
 
             data = {
@@ -3214,8 +3214,8 @@ class PagurePrivateRepotest(tests.Modeltests):
         )
 
         # Create normal issue
-        repo = pagure.lib._get_project(self.session, 'test4')
-        msg = pagure.lib.new_issue(
+        repo = pagure.lib.query._get_project(self.session, 'test4')
+        msg = pagure.lib.query.new_issue(
             session=self.session,
             repo=repo,
             title='Test issue #1',
@@ -3229,8 +3229,8 @@ class PagurePrivateRepotest(tests.Modeltests):
 
         # Check comments before
         self.session.commit()
-        repo = pagure.lib._get_project(self.session, 'test4')
-        issue = pagure.lib.search_issues(self.session, repo, issueid=1)
+        repo = pagure.lib.query._get_project(self.session, 'test4')
+        issue = pagure.lib.query.search_issues(self.session, repo, issueid=1)
         self.assertEqual(len(issue.comments), 0)
 
         data = {
@@ -3253,8 +3253,8 @@ class PagurePrivateRepotest(tests.Modeltests):
 
         # No change
         self.session.commit()
-        repo = pagure.lib._get_project(self.session, 'test4')
-        issue = pagure.lib.search_issues(self.session, repo, issueid=1)
+        repo = pagure.lib.query._get_project(self.session, 'test4')
+        issue = pagure.lib.query.search_issues(self.session, repo, issueid=1)
         self.assertEqual(issue.status, 'Open')
 
         data = {
@@ -3276,8 +3276,8 @@ class PagurePrivateRepotest(tests.Modeltests):
 
         # One comment added
         self.session.commit()
-        repo = pagure.lib._get_project(self.session, 'test4')
-        issue = pagure.lib.search_issues(self.session, repo, issueid=1)
+        repo = pagure.lib.query._get_project(self.session, 'test4')
+        issue = pagure.lib.query.search_issues(self.session, repo, issueid=1)
         self.assertEqual(len(issue.comments), 1)
 
     @patch('pagure.lib.git.update_git')

+ 48 - 48
tests/test_pagure_flask_api_user.py

@@ -27,8 +27,8 @@ sys.path.insert(0, os.path.join(os.path.dirname(
 
 import pagure.api
 import pagure.config
-import pagure.lib
 import pagure.lib.model as model
+import pagure.lib.query
 import tests
 
 
@@ -262,9 +262,9 @@ class PagureFlaskApiUSertests(tests.Modeltests):
         headers = {'Authorization': 'token aaabbbcccddd'}
 
         # Create a pull-request
-        repo = pagure.lib._get_project(self.session, 'test')
-        forked_repo = pagure.lib._get_project(self.session, 'test')
-        req = pagure.lib.new_pull_request(
+        repo = pagure.lib.query._get_project(self.session, 'test')
+        forked_repo = pagure.lib.query._get_project(self.session, 'test')
+        req = pagure.lib.query.new_pull_request(
             session=self.session,
             repo_from=forked_repo,
             branch_from='master',
@@ -279,7 +279,7 @@ class PagureFlaskApiUSertests(tests.Modeltests):
 
         # Check comments before
         self.session.commit()
-        request = pagure.lib.search_pull_requests(
+        request = pagure.lib.query.search_pull_requests(
             self.session, project_id=1, requestid=1)
         self.assertEqual(len(request.comments), 0)
 
@@ -299,7 +299,7 @@ class PagureFlaskApiUSertests(tests.Modeltests):
 
         # One comment added
         self.session.commit()
-        request = pagure.lib.search_pull_requests(
+        request = pagure.lib.query.search_pull_requests(
             self.session, project_id=1, requestid=1)
         self.assertEqual(len(request.comments), 1)
 
@@ -315,7 +315,7 @@ class PagureFlaskApiUSertests(tests.Modeltests):
 
         # PR closed
         self.session.commit()
-        request = pagure.lib.search_pull_requests(
+        request = pagure.lib.query.search_pull_requests(
             self.session, project_id=1, requestid=1)
         self.assertEqual(request.status, 'Closed')
 
@@ -429,7 +429,7 @@ class PagureFlaskApiUSertests(tests.Modeltests):
         api when the user only did one action. """
 
         tests.create_projects(self.session)
-        repo = pagure.lib._get_project(self.session, 'test')
+        repo = pagure.lib.query._get_project(self.session, 'test')
 
         now = datetime.datetime.utcnow()
         date = now.date().strftime('%Y-%m-%d')
@@ -469,7 +469,7 @@ class PagureFlaskApiUSertests(tests.Modeltests):
         will occur on 2018-02-15 in UTC, but on 2018-02-14 local.
         """
         tests.create_projects(self.session)
-        repo = pagure.lib._get_project(self.session, 'test')
+        repo = pagure.lib.query._get_project(self.session, 'test')
 
         dateobj = datetime.datetime(2018, 2, 15, 3, 30)
         utcdate = '2018-02-15'
@@ -547,7 +547,7 @@ class PagureFlaskApiUSertests(tests.Modeltests):
         occur on 2018-02-15 in UTC, but on 2018-02-16 in local time.
         """
         tests.create_projects(self.session)
-        repo = pagure.lib._get_project(self.session, 'test')
+        repo = pagure.lib.query._get_project(self.session, 'test')
 
         dateobj = datetime.datetime(2018, 2, 15, 22, 30)
         utcdate = '2018-02-15'
@@ -633,9 +633,9 @@ class PagureFlaskApiUsertestrequests(tests.Modeltests):
         tests.create_projects(self.session)
 
         # Create few pull-requests
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        forked_repo = pagure.lib.get_authorized_project(self.session, 'test')
-        pagure.lib.new_pull_request(
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        forked_repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        pagure.lib.query.new_pull_request(
             session=self.session,
             repo_from=forked_repo,
             branch_from='master',
@@ -645,9 +645,9 @@ class PagureFlaskApiUsertestrequests(tests.Modeltests):
             user='foo',
         )
 
-        repo = pagure.lib.get_authorized_project(self.session, 'test2')
-        forked_repo = pagure.lib.get_authorized_project(self.session, 'test2')
-        pagure.lib.new_pull_request(
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test2')
+        forked_repo = pagure.lib.query.get_authorized_project(self.session, 'test2')
+        pagure.lib.query.new_pull_request(
             session=self.session,
             repo_from=forked_repo,
             branch_from='master',
@@ -658,9 +658,9 @@ class PagureFlaskApiUsertestrequests(tests.Modeltests):
         )
         self.session.commit()
 
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        forked_repo = pagure.lib.get_authorized_project(self.session, 'test')
-        pagure.lib.new_pull_request(
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        forked_repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        pagure.lib.query.new_pull_request(
             session=self.session,
             repo_from=forked_repo,
             branch_from='master',
@@ -671,9 +671,9 @@ class PagureFlaskApiUsertestrequests(tests.Modeltests):
             status='Closed',
         )
 
-        repo = pagure.lib.get_authorized_project(self.session, 'test2')
-        forked_repo = pagure.lib.get_authorized_project(self.session, 'test2')
-        pagure.lib.new_pull_request(
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test2')
+        forked_repo = pagure.lib.query.get_authorized_project(self.session, 'test2')
+        pagure.lib.query.new_pull_request(
             session=self.session,
             repo_from=forked_repo,
             branch_from='master',
@@ -685,9 +685,9 @@ class PagureFlaskApiUsertestrequests(tests.Modeltests):
         )
         self.session.commit()
 
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        forked_repo = pagure.lib.get_authorized_project(self.session, 'test')
-        pagure.lib.new_pull_request(
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        forked_repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        pagure.lib.query.new_pull_request(
             session=self.session,
             repo_from=forked_repo,
             branch_from='master',
@@ -698,9 +698,9 @@ class PagureFlaskApiUsertestrequests(tests.Modeltests):
             status='Merged',
         )
 
-        repo = pagure.lib.get_authorized_project(self.session, 'test2')
-        forked_repo = pagure.lib.get_authorized_project(self.session, 'test2')
-        pagure.lib.new_pull_request(
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test2')
+        forked_repo = pagure.lib.query.get_authorized_project(self.session, 'test2')
+        pagure.lib.query.new_pull_request(
             session=self.session,
             repo_from=forked_repo,
             branch_from='master',
@@ -712,9 +712,9 @@ class PagureFlaskApiUsertestrequests(tests.Modeltests):
         )
         self.session.commit()
 
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        forked_repo = pagure.lib.get_authorized_project(self.session, 'test')
-        pagure.lib.new_pull_request(
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        forked_repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        pagure.lib.query.new_pull_request(
             session=self.session,
             repo_from=forked_repo,
             branch_from='master',
@@ -725,9 +725,9 @@ class PagureFlaskApiUsertestrequests(tests.Modeltests):
         )
         self.session.commit()
 
-        repo = pagure.lib.get_authorized_project(self.session, 'test2')
-        forked_repo = pagure.lib.get_authorized_project(self.session, 'test2')
-        pagure.lib.new_pull_request(
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test2')
+        forked_repo = pagure.lib.query.get_authorized_project(self.session, 'test2')
+        pagure.lib.query.new_pull_request(
             session=self.session,
             repo_from=forked_repo,
             branch_from='master',
@@ -738,9 +738,9 @@ class PagureFlaskApiUsertestrequests(tests.Modeltests):
         )
         self.session.commit()
 
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        forked_repo = pagure.lib.get_authorized_project(self.session, 'test')
-        pagure.lib.new_pull_request(
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        forked_repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        pagure.lib.query.new_pull_request(
             session=self.session,
             repo_from=forked_repo,
             branch_from='master',
@@ -752,9 +752,9 @@ class PagureFlaskApiUsertestrequests(tests.Modeltests):
         )
         self.session.commit()
 
-        repo = pagure.lib.get_authorized_project(self.session, 'test2')
-        forked_repo = pagure.lib.get_authorized_project(self.session, 'test2')
-        pagure.lib.new_pull_request(
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test2')
+        forked_repo = pagure.lib.query.get_authorized_project(self.session, 'test2')
+        pagure.lib.query.new_pull_request(
             session=self.session,
             repo_from=forked_repo,
             branch_from='master',
@@ -766,9 +766,9 @@ class PagureFlaskApiUsertestrequests(tests.Modeltests):
         )
         self.session.commit()
 
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        forked_repo = pagure.lib.get_authorized_project(self.session, 'test')
-        pagure.lib.new_pull_request(
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        forked_repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        pagure.lib.query.new_pull_request(
             session=self.session,
             repo_from=forked_repo,
             branch_from='master',
@@ -780,9 +780,9 @@ class PagureFlaskApiUsertestrequests(tests.Modeltests):
         )
         self.session.commit()
 
-        repo = pagure.lib.get_authorized_project(self.session, 'test2')
-        forked_repo = pagure.lib.get_authorized_project(self.session, 'test2')
-        pagure.lib.new_pull_request(
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test2')
+        forked_repo = pagure.lib.query.get_authorized_project(self.session, 'test2')
+        pagure.lib.query.new_pull_request(
             session=self.session,
             repo_from=forked_repo,
             branch_from='master',
@@ -1056,10 +1056,10 @@ class PagureFlaskApiUsertestissues(tests.Modeltests):
 
         tests.create_projects(self.session)
 
-        repo = pagure.lib._get_project(self.session, 'test')
+        repo = pagure.lib.query._get_project(self.session, 'test')
 
         # Create issues to play with
-        msg = pagure.lib.new_issue(
+        msg = pagure.lib.query.new_issue(
             session=self.session,
             repo=repo,
             title='Test issue',

+ 5 - 6
tests/test_pagure_flask_docs.py

@@ -26,9 +26,8 @@ from mock import patch
 sys.path.insert(0, os.path.join(os.path.dirname(
     os.path.abspath(__file__)), '..'))
 
-import pagure
 import pagure.docs_server
-import pagure.lib
+import pagure.lib.query
 import tests
 from pagure.lib.repo import PagureRepo
 
@@ -93,7 +92,7 @@ class PagureFlaskDocstests(tests.SimplePagureTest):
         PagureRepo.push(remote, 'refs/heads/master:refs/heads/master')
 
         # Turn on the docs project since it's off by default
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
         repo.settings = {'project_documentation': True}
         self.session.add(repo)
         self.session.commit()
@@ -111,7 +110,7 @@ class PagureFlaskDocstests(tests.SimplePagureTest):
         tests.create_projects(self.session)
 
         # Turn on the docs project since it's off by default
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
         repo.settings = {'project_documentation': True}
         self.session.add(repo)
         self.session.commit()
@@ -131,7 +130,7 @@ class PagureFlaskDocstests(tests.SimplePagureTest):
         docs.
         """
         tests.create_projects(self.session)
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
         tests.create_projects_git(os.path.join(self.path, 'repos', 'docs'))
 
         output = self.app.get('/test/docs')
@@ -151,7 +150,7 @@ class PagureFlaskDocstests(tests.SimplePagureTest):
             os.path.join(self.path, 'repos', 'docs', 'test.git'), bare=True)
 
         # Turn on the docs project since it's off by default
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
         repo.settings = {'project_documentation': True}
         self.session.add(repo)
         self.session.commit()

+ 16 - 17
tests/test_pagure_flask_dump_load_ticket.py

@@ -27,8 +27,7 @@ from mock import patch
 sys.path.insert(0, os.path.join(os.path.dirname(
     os.path.abspath(__file__)), '..'))
 
-import pagure
-import pagure.lib
+import pagure.lib.query
 import tests
 
 
@@ -52,9 +51,9 @@ class PagureFlaskDumpLoadTicketTests(tests.Modeltests):
         os.makedirs(self.gitrepo)
         repo_obj = pygit2.init_repository(self.gitrepo, bare=True)
 
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
         # Create an issue to play with
-        msg = pagure.lib.new_issue(
+        msg = pagure.lib.query.new_issue(
             session=self.session,
             repo=repo,
             title='Test issue',
@@ -64,7 +63,7 @@ class PagureFlaskDumpLoadTicketTests(tests.Modeltests):
         self.assertEqual(msg.title, 'Test issue')
 
         # Need another two issue to test the dependencie chain
-        msg = pagure.lib.new_issue(
+        msg = pagure.lib.query.new_issue(
             session=self.session,
             repo=repo,
             title='Test issue #2',
@@ -72,7 +71,7 @@ class PagureFlaskDumpLoadTicketTests(tests.Modeltests):
             user='pingou',
         )
         self.assertEqual(msg.title, 'Test issue #2')
-        msg = pagure.lib.new_issue(
+        msg = pagure.lib.query.new_issue(
             session=self.session,
             repo=repo,
             title='Test issue #3',
@@ -81,12 +80,12 @@ class PagureFlaskDumpLoadTicketTests(tests.Modeltests):
         )
         self.assertEqual(msg.title, 'Test issue #3')
 
-        issue = pagure.lib.search_issues(self.session, repo, issueid=1)
-        issue2 = pagure.lib.search_issues(self.session, repo, issueid=2)
-        issue3 = pagure.lib.search_issues(self.session, repo, issueid=3)
+        issue = pagure.lib.query.search_issues(self.session, repo, issueid=1)
+        issue2 = pagure.lib.query.search_issues(self.session, repo, issueid=2)
+        issue3 = pagure.lib.query.search_issues(self.session, repo, issueid=3)
 
         # Add a couple of comment on the ticket
-        msg = pagure.lib.add_issue_comment(
+        msg = pagure.lib.query.add_issue_comment(
             session=self.session,
             issue=issue,
             comment='Hey look a comment!',
@@ -94,7 +93,7 @@ class PagureFlaskDumpLoadTicketTests(tests.Modeltests):
         )
         self.session.commit()
         self.assertEqual(msg, 'Comment added')
-        msg = pagure.lib.add_issue_comment(
+        msg = pagure.lib.query.add_issue_comment(
             session=self.session,
             issue=issue,
             comment='crazy right?',
@@ -103,7 +102,7 @@ class PagureFlaskDumpLoadTicketTests(tests.Modeltests):
         self.session.commit()
         self.assertEqual(msg, 'Comment added')
         # Assign the ticket to someone
-        msg = pagure.lib.add_issue_assignee(
+        msg = pagure.lib.query.add_issue_assignee(
             session=self.session,
             issue=issue,
             assignee='pingou',
@@ -112,7 +111,7 @@ class PagureFlaskDumpLoadTicketTests(tests.Modeltests):
         self.session.commit()
         self.assertEqual(msg, 'Issue assigned to pingou')
         # Add a couple of tags on the ticket
-        msg = pagure.lib.add_tag_obj(
+        msg = pagure.lib.query.add_tag_obj(
             session=self.session,
             obj=issue,
             tags=[' feature ', 'future '],
@@ -121,7 +120,7 @@ class PagureFlaskDumpLoadTicketTests(tests.Modeltests):
         self.session.commit()
         self.assertEqual(msg, 'Issue tagged with: feature, future')
         # Add dependencies
-        msg = pagure.lib.add_issue_dependency(
+        msg = pagure.lib.query.add_issue_dependency(
             session=self.session,
             issue=issue,
             issue_blocked=issue2,
@@ -129,7 +128,7 @@ class PagureFlaskDumpLoadTicketTests(tests.Modeltests):
         )
         self.session.commit()
         self.assertEqual(msg, 'Issue marked as depending on: #2')
-        msg = pagure.lib.add_issue_dependency(
+        msg = pagure.lib.query.add_issue_dependency(
             session=self.session,
             issue=issue3,
             issue_blocked=issue,
@@ -193,9 +192,9 @@ class PagureFlaskDumpLoadTicketTests(tests.Modeltests):
         )
 
         # Post loading
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
         self.assertEqual(len(repo.issues), 1)
-        issue = pagure.lib.search_issues(self.session, repo, issueid=1)
+        issue = pagure.lib.query.search_issues(self.session, repo, issueid=1)
 
         # Check after re-loading
         self.assertEqual(len(issue.comments), 3)

+ 53 - 54
tests/test_pagure_flask_internal.py

@@ -27,8 +27,7 @@ from mock import patch, MagicMock, Mock
 sys.path.insert(0, os.path.join(os.path.dirname(
     os.path.abspath(__file__)), '..'))
 
-import pagure
-import pagure.lib
+import pagure.lib.query
 import tests
 from pagure.lib.repo import PagureRepo
 
@@ -55,9 +54,9 @@ class PagureFlaskInternaltests(tests.Modeltests):
 
         tests.create_projects(self.session)
 
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
 
-        req = pagure.lib.new_pull_request(
+        req = pagure.lib.query.new_pull_request(
             session=self.session,
             repo_from=repo,
             branch_from='feature',
@@ -117,7 +116,7 @@ class PagureFlaskInternaltests(tests.Modeltests):
         self.assertDictEqual(js_data, {'message': 'Comment added'})
 
         self.session.commit()
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
         request = repo.requests[0]
         self.assertEqual(len(request.comments), 1)
         self.assertEqual(len(request.discussion), 1)
@@ -139,8 +138,8 @@ class PagureFlaskInternaltests(tests.Modeltests):
         tests.create_projects(self.session)
 
         # Create issues to play with
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        msg = pagure.lib.new_issue(
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        msg = pagure.lib.query.new_issue(
             session=self.session,
             repo=repo,
             title='Test issue',
@@ -196,7 +195,7 @@ class PagureFlaskInternaltests(tests.Modeltests):
         self.assertDictEqual(js_data, {'message': 'Comment added'})
 
         self.session.commit()
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
         issue = repo.issues[0]
         self.assertEqual(len(issue.comments), 1)
 
@@ -218,8 +217,8 @@ class PagureFlaskInternaltests(tests.Modeltests):
         tests.create_projects(self.session)
 
         # Create issues to play with
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        msg = pagure.lib.new_issue(
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        msg = pagure.lib.query.new_issue(
             session=self.session,
             repo=repo,
             title='Test issue',
@@ -285,7 +284,7 @@ class PagureFlaskInternaltests(tests.Modeltests):
         self.assertDictEqual(js_data, {'message': 'Comment added'})
 
         self.session.commit()
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
         issue = repo.issues[0]
         self.assertEqual(len(issue.comments), 1)
 
@@ -306,8 +305,8 @@ class PagureFlaskInternaltests(tests.Modeltests):
         tests.create_projects(self.session)
 
         # Create issues to play with
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        msg = pagure.lib.new_issue(
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        msg = pagure.lib.query.new_issue(
             session=self.session,
             repo=repo,
             title='Test issue',
@@ -318,7 +317,7 @@ class PagureFlaskInternaltests(tests.Modeltests):
         self.session.commit()
         self.assertEqual(msg.title, 'Test issue')
 
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
         issue = repo.issues[0]
         self.assertEqual(len(issue.comments), 0)
 
@@ -334,10 +333,10 @@ class PagureFlaskInternaltests(tests.Modeltests):
         output = self.app.put('/pv/ticket/comment/', data=data)
         self.assertEqual(output.status_code, 403)
 
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
         # Let's promote him to be a ticketer
         # He shoudn't be able to comment even then though
-        msg = pagure.lib.add_user_to_project(
+        msg = pagure.lib.query.add_user_to_project(
             self.session,
             project=repo,
             new_user='foo',
@@ -346,7 +345,7 @@ class PagureFlaskInternaltests(tests.Modeltests):
         )
         self.session.commit()
         self.assertEqual(msg, 'User added')
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
         self.assertEqual(
             sorted([u.username for u in repo.users]), ['foo'])
         self.assertEqual(
@@ -357,10 +356,10 @@ class PagureFlaskInternaltests(tests.Modeltests):
         output = self.app.put('/pv/ticket/comment/', data=data)
         self.assertEqual(output.status_code, 403)
 
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
         # Let's promote him to be a committer
         # He should be able to comment
-        msg = pagure.lib.add_user_to_project(
+        msg = pagure.lib.query.add_user_to_project(
             self.session,
             project=repo,
             new_user='foo',
@@ -369,7 +368,7 @@ class PagureFlaskInternaltests(tests.Modeltests):
         )
         self.session.commit()
         self.assertEqual(msg, 'User access updated')
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
         self.assertEqual(
             sorted([u.username for u in repo.users]), ['foo'])
         self.assertEqual(
@@ -383,13 +382,13 @@ class PagureFlaskInternaltests(tests.Modeltests):
         js_data = json.loads(output.get_data(as_text=True))
         self.assertDictEqual(js_data, {'message': 'Comment added'})
 
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
         issue = repo.issues[0]
         self.assertEqual(len(issue.comments), 1)
 
         # Let's promote him to be a admin
         # He should be able to comment
-        msg = pagure.lib.add_user_to_project(
+        msg = pagure.lib.query.add_user_to_project(
             self.session,
             project=repo,
             new_user='foo',
@@ -399,7 +398,7 @@ class PagureFlaskInternaltests(tests.Modeltests):
         self.session.commit()
         self.assertEqual(msg, 'User access updated')
 
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
         self.assertEqual(
             sorted([u.username for u in repo.users]), ['foo'])
         self.assertEqual(
@@ -413,7 +412,7 @@ class PagureFlaskInternaltests(tests.Modeltests):
         js_data = json.loads(output.get_data(as_text=True))
         self.assertDictEqual(js_data, {'message': 'Comment added'})
 
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
         issue = repo.issues[0]
         self.assertEqual(len(issue.comments), 2)
 
@@ -502,8 +501,8 @@ class PagureFlaskInternaltests(tests.Modeltests):
 
         # Create a PR for these changes
         tests.create_projects(self.session)
-        project = pagure.lib.get_authorized_project(self.session, 'test')
-        req = pagure.lib.new_pull_request(
+        project = pagure.lib.query.get_authorized_project(self.session, 'test')
+        req = pagure.lib.query.new_pull_request(
             session=self.session,
             repo_from=project,
             branch_from='feature',
@@ -540,7 +539,7 @@ class PagureFlaskInternaltests(tests.Modeltests):
             self.assertEqual(output.status_code, 404)
 
             # With all the desired information
-            project = pagure.lib.get_authorized_project(self.session, 'test')
+            project = pagure.lib.query.get_authorized_project(self.session, 'test')
             data = {
                 'csrf_token': csrf_token,
                 'requestid': project.requests[0].uid,
@@ -623,8 +622,8 @@ class PagureFlaskInternaltests(tests.Modeltests):
 
         # Create a PR for these changes
         tests.create_projects(self.session)
-        project = pagure.lib.get_authorized_project(self.session, 'test')
-        req = pagure.lib.new_pull_request(
+        project = pagure.lib.query.get_authorized_project(self.session, 'test')
+        req = pagure.lib.query.new_pull_request(
             session=self.session,
             repo_from=project,
             branch_from='master',
@@ -661,7 +660,7 @@ class PagureFlaskInternaltests(tests.Modeltests):
             self.assertEqual(output.status_code, 404)
 
             # With all the desired information
-            project = pagure.lib.get_authorized_project(self.session, 'test')
+            project = pagure.lib.query.get_authorized_project(self.session, 'test')
             data = {
                 'csrf_token': csrf_token,
                 'requestid': project.requests[0].uid,
@@ -777,8 +776,8 @@ class PagureFlaskInternaltests(tests.Modeltests):
 
         # Create a PR for these changes
         tests.create_projects(self.session)
-        project = pagure.lib.get_authorized_project(self.session, 'test')
-        req = pagure.lib.new_pull_request(
+        project = pagure.lib.query.get_authorized_project(self.session, 'test')
+        req = pagure.lib.query.new_pull_request(
             session=self.session,
             repo_from=project,
             branch_from='feature',
@@ -813,7 +812,7 @@ class PagureFlaskInternaltests(tests.Modeltests):
             self.assertEqual(output.status_code, 404)
 
             # With all the desired information
-            project = pagure.lib.get_authorized_project(self.session, 'test')
+            project = pagure.lib.query.get_authorized_project(self.session, 'test')
             data = {
                 'csrf_token': csrf_token,
                 'requestid': project.requests[0].uid,
@@ -945,8 +944,8 @@ class PagureFlaskInternaltests(tests.Modeltests):
 
         # Create a PR for these changes
         tests.create_projects(self.session)
-        project = pagure.lib.get_authorized_project(self.session, 'test')
-        req = pagure.lib.new_pull_request(
+        project = pagure.lib.query.get_authorized_project(self.session, 'test')
+        req = pagure.lib.query.new_pull_request(
             session=self.session,
             repo_from=project,
             branch_from='feature',
@@ -981,7 +980,7 @@ class PagureFlaskInternaltests(tests.Modeltests):
             self.assertEqual(output.status_code, 404)
 
             # With all the desired information
-            project = pagure.lib.get_authorized_project(self.session, 'test')
+            project = pagure.lib.query.get_authorized_project(self.session, 'test')
             data = {
                 'csrf_token': csrf_token,
                 'requestid': project.requests[0].uid,
@@ -1097,8 +1096,8 @@ class PagureFlaskInternaltests(tests.Modeltests):
 
         # Create a PR for these changes
         tests.create_projects(self.session)
-        project = pagure.lib.get_authorized_project(self.session, 'test')
-        req = pagure.lib.new_pull_request(
+        project = pagure.lib.query.get_authorized_project(self.session, 'test')
+        req = pagure.lib.query.new_pull_request(
             session=self.session,
             repo_from=project,
             branch_from='feature',
@@ -1124,7 +1123,7 @@ class PagureFlaskInternaltests(tests.Modeltests):
                 'name="csrf_token" type="hidden" value="')[1].split('">')[0]
 
             # With all the desired information
-            project = pagure.lib.get_authorized_project(self.session, 'test')
+            project = pagure.lib.query.get_authorized_project(self.session, 'test')
             data = {
                 'csrf_token': csrf_token,
                 'requestid': project.requests[0].uid,
@@ -1232,8 +1231,8 @@ class PagureFlaskInternaltests(tests.Modeltests):
 
         # Create a PR for these changes
         tests.create_projects(self.session)
-        project = pagure.lib.get_authorized_project(self.session, 'test')
-        req = pagure.lib.new_pull_request(
+        project = pagure.lib.query.get_authorized_project(self.session, 'test')
+        req = pagure.lib.query.new_pull_request(
             session=self.session,
             repo_from=project,
             branch_from='feature',
@@ -1259,7 +1258,7 @@ class PagureFlaskInternaltests(tests.Modeltests):
                 'name="csrf_token" type="hidden" value="')[1].split('">')[0]
 
             # With all the desired information
-            project = pagure.lib.get_authorized_project(self.session, 'test')
+            project = pagure.lib.query.get_authorized_project(self.session, 'test')
             data = {
                 'csrf_token': csrf_token,
                 'requestid': project.requests[0].uid,
@@ -1393,8 +1392,8 @@ class PagureFlaskInternaltests(tests.Modeltests):
 
         # Create a PR for these changes
         tests.create_projects(self.session)
-        project = pagure.lib.get_authorized_project(self.session, 'test')
-        req = pagure.lib.new_pull_request(
+        project = pagure.lib.query.get_authorized_project(self.session, 'test')
+        req = pagure.lib.query.new_pull_request(
             session=self.session,
             repo_from=project,
             branch_from='feature',
@@ -1417,7 +1416,7 @@ class PagureFlaskInternaltests(tests.Modeltests):
             csrf_token = self.get_csrf(output=output)
 
             # With all the desired information
-            project = pagure.lib.get_authorized_project(self.session, 'test')
+            project = pagure.lib.query.get_authorized_project(self.session, 'test')
             data = {
                 'csrf_token': csrf_token,
                 'requestid': project.requests[0].uid,
@@ -1531,8 +1530,8 @@ class PagureFlaskInternaltests(tests.Modeltests):
 
         # Create a PR for these changes
         tests.create_projects(self.session)
-        project = pagure.lib.get_authorized_project(self.session, 'test')
-        req = pagure.lib.new_pull_request(
+        project = pagure.lib.query.get_authorized_project(self.session, 'test')
+        req = pagure.lib.query.new_pull_request(
             session=self.session,
             repo_from=project,
             branch_from='feature',
@@ -1555,7 +1554,7 @@ class PagureFlaskInternaltests(tests.Modeltests):
             csrf_token = self.get_csrf(output=output)
 
             # With all the desired information
-            project = pagure.lib.get_authorized_project(self.session, 'test')
+            project = pagure.lib.query.get_authorized_project(self.session, 'test')
             data = {
                 'csrf_token': csrf_token,
                 'requestid': project.requests[0].uid,
@@ -2611,7 +2610,7 @@ class PagureFlaskInternaltests(tests.Modeltests):
         self.session.commit()
 
         # Delete the parent project
-        project = pagure.lib.get_authorized_project(self.session, 'test')
+        project = pagure.lib.query.get_authorized_project(self.session, 'test')
         self.session.delete(project)
         self.session.commit()
 
@@ -2672,7 +2671,7 @@ class PagureFlaskInternaltests(tests.Modeltests):
         self.session.commit()
 
         # Delete the parent project
-        project = pagure.lib.get_authorized_project(self.session, 'test')
+        project = pagure.lib.query.get_authorized_project(self.session, 'test')
         self.session.delete(project)
         self.session.commit()
 
@@ -2878,22 +2877,22 @@ class PagureFlaskInternaltests(tests.Modeltests):
         """
         tests.create_projects(self.session)
 
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
         project_key = 'ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIC4zmifEL8TLLZUZnjAuVL8495DAkpAAM2eBhwHwawBm'
         project_key_fp = 'SHA256:ZSUQAqpPDWi90Fs6Ow8Epc8F3qiKVfU+H5ssvo7jiI0'
 
-        pingou = pagure.lib.get_user(self.session, 'pingou')
+        pingou = pagure.lib.query.get_user(self.session, 'pingou')
         user_key = 'ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDTsfdTcXw4rlU1aQwOTbLOXqossLwpPIk27S/G17kUz'
         user_key_fp = 'SHA256:jUJHzrq2Ct6Ubf7Y9rnB6tGnbHM9dMVsveyfPojm+i0'
 
-        pagure.lib.add_sshkey_to_project_or_user(
+        pagure.lib.query.add_sshkey_to_project_or_user(
             self.session,
             user_key,
             pushaccess=True,
             creator=pingou,
             user=pingou,
         )
-        pagure.lib.add_sshkey_to_project_or_user(
+        pagure.lib.query.add_sshkey_to_project_or_user(
             self.session,
             project_key,
             pushaccess=True,

+ 46 - 46
tests/test_pagure_flask_ui_app.py

@@ -28,7 +28,7 @@ from mock import patch, MagicMock
 sys.path.insert(0, os.path.join(os.path.dirname(
     os.path.abspath(__file__)), '..'))
 
-import pagure.lib
+import pagure.lib.query
 import tests
 
 
@@ -232,7 +232,7 @@ class PagureFlaskApptests(tests.Modeltests):
         pagure.config.config['ENABLE_NEW_PROJECTS'] = False
 
         # Before
-        projects = pagure.lib.search_projects(self.session)
+        projects = pagure.lib.query.search_projects(self.session)
         self.assertEqual(len(projects), 0)
         self.assertFalse(os.path.exists(
             os.path.join(self.path, 'repos', 'project-1.git')))
@@ -268,7 +268,7 @@ class PagureFlaskApptests(tests.Modeltests):
             self.assertEqual(output.status_code, 404)
 
         #After
-        projects = pagure.lib.search_projects(self.session)
+        projects = pagure.lib.query.search_projects(self.session)
         self.assertEqual(len(projects), 0)
         self.assertFalse(os.path.exists(
             os.path.join(self.path, 'repos', 'project-1.git')))
@@ -284,7 +284,7 @@ class PagureFlaskApptests(tests.Modeltests):
     def test_new_project(self):
         """ Test the new_project endpoint. """
         # Before
-        projects = pagure.lib.search_projects(self.session)
+        projects = pagure.lib.query.search_projects(self.session)
         self.assertEqual(len(projects), 0)
         self.assertFalse(os.path.exists(
             os.path.join(self.path, 'repos', 'project#1.git')))
@@ -353,7 +353,7 @@ class PagureFlaskApptests(tests.Modeltests):
                 '<title>Overview - project-1 - Pagure</title>', output_text)
 
         # After
-        projects = pagure.lib.search_projects(self.session)
+        projects = pagure.lib.query.search_projects(self.session)
         self.assertEqual(len(projects), 1)
         self.assertTrue(os.path.exists(
             os.path.join(self.path, 'repos', 'project-1.git')))
@@ -369,7 +369,7 @@ class PagureFlaskApptests(tests.Modeltests):
     def test_adopt_repos(self):
         """ Test the new_project endpoint with existing git repo. """
         # Before
-        projects = pagure.lib.search_projects(self.session)
+        projects = pagure.lib.query.search_projects(self.session)
         self.assertEqual(len(projects), 0)
         tests.create_projects_git(os.path.join(self.path, 'repos'), bare=True)
         tests.add_content_git_repo(os.path.join(self.path, 'repos', 'test.git'))
@@ -398,7 +398,7 @@ class PagureFlaskApptests(tests.Modeltests):
     def test_adopt_repos_non_admin(self):
         """ Test the new_project endpoint with existing git repo for non-admins. """
         # Before
-        projects = pagure.lib.search_projects(self.session)
+        projects = pagure.lib.query.search_projects(self.session)
         self.assertEqual(len(projects), 0)
         tests.create_projects_git(os.path.join(self.path, 'repos'), bare=True)
         tests.add_content_git_repo(os.path.join(self.path, 'repos', 'test.git'))
@@ -427,7 +427,7 @@ class PagureFlaskApptests(tests.Modeltests):
     def test_adopt_repos_not_allowed(self):
         """ Test the new_project endpoint with existing git repo for no access. """
         # Before
-        projects = pagure.lib.search_projects(self.session)
+        projects = pagure.lib.query.search_projects(self.session)
         self.assertEqual(len(projects), 0)
         tests.create_projects_git(os.path.join(self.path, 'repos'), bare=True)
         tests.add_content_git_repo(os.path.join(self.path, 'repos', 'test.git'))
@@ -455,7 +455,7 @@ class PagureFlaskApptests(tests.Modeltests):
     def test_new_project_diff_regex(self):
         """ Test the new_project endpoint with a different regex. """
         # Before
-        projects = pagure.lib.search_projects(self.session)
+        projects = pagure.lib.query.search_projects(self.session)
         self.assertEqual(len(projects), 0)
 
         user = tests.FakeUser(username='foo')
@@ -489,7 +489,7 @@ class PagureFlaskApptests(tests.Modeltests):
     def test_new_project_private(self):
         """ Test the new_project endpoint for a private project. """
         # Before
-        projects = pagure.lib.search_projects(self.session)
+        projects = pagure.lib.query.search_projects(self.session)
         self.assertEqual(len(projects), 0)
         self.assertFalse(os.path.exists(
             os.path.join(self.path, 'repos', 'foo', 'project#1.git')))
@@ -557,9 +557,9 @@ class PagureFlaskApptests(tests.Modeltests):
                 '<title>Overview - foo/project-1 - Pagure</title>', output_text)
 
         # After
-        projects = pagure.lib.search_projects(self.session)
+        projects = pagure.lib.query.search_projects(self.session)
         self.assertEqual(len(projects), 0)
-        projects = pagure.lib.search_projects(self.session, private=True)
+        projects = pagure.lib.query.search_projects(self.session, private=True)
         self.assertEqual(len(projects), 1)
         self.assertTrue(os.path.exists(
             os.path.join(self.path, 'repos', 'foo', 'project-1.git')))
@@ -573,7 +573,7 @@ class PagureFlaskApptests(tests.Modeltests):
     def test_non_ascii_new_project(self):
         """ Test the new_project endpoint with a non-ascii project. """
         # Before
-        projects = pagure.lib.search_projects(self.session)
+        projects = pagure.lib.query.search_projects(self.session)
         self.assertEqual(len(projects), 0)
         self.assertFalse(os.path.exists(
             os.path.join(self.path, 'repos', 'project-1.git')))
@@ -635,7 +635,7 @@ class PagureFlaskApptests(tests.Modeltests):
             output_text)
 
         # After
-        projects = pagure.lib.search_projects(self.session)
+        projects = pagure.lib.query.search_projects(self.session)
         self.assertEqual(len(projects), 2)
         for project in ['project-1', 'project-2']:
             self.assertTrue(os.path.exists(
@@ -652,7 +652,7 @@ class PagureFlaskApptests(tests.Modeltests):
         """ Test the new_project endpoint for a new project with a template set.
         """
         # Before
-        projects = pagure.lib.search_projects(self.session)
+        projects = pagure.lib.query.search_projects(self.session)
         self.assertEqual(len(projects), 0)
         self.assertFalse(os.path.exists(
             os.path.join(self.path, 'repos', 'project-1.git')))
@@ -713,7 +713,7 @@ class PagureFlaskApptests(tests.Modeltests):
                 template_path='%s/repos/project-1.git' % self.path)
 
         # After
-        projects = pagure.lib.search_projects(self.session)
+        projects = pagure.lib.query.search_projects(self.session)
         self.assertEqual(len(projects), 2)
         for project in ['project-1', 'project-2']:
             self.assertTrue(os.path.exists(
@@ -878,8 +878,8 @@ class PagureFlaskApptests(tests.Modeltests):
             self.assertIn('SSH key does not exist', output_text)
 
         # Add a deploy key to a project
-        pingou = pagure.lib.get_user(self.session, 'pingou')
-        msg = pagure.lib.add_sshkey_to_project_or_user(
+        pingou = pagure.lib.query.get_user(self.session, 'pingou')
+        msg = pagure.lib.query.add_sshkey_to_project_or_user(
             session=self.session,
             ssh_key='ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQDAzBMSIlvPRaEiLOTVInErkRIw9CzQQcnslDekAn1jFnGf+SNa1acvbTiATbCX71AA03giKrPxPH79dxcC7aDXerc6zRcKjJs6MAL9PrCjnbyxCKXRNNZU5U9X/DLaaL1b3caB+WD6OoorhS3LTEtKPX8xyjOzhf3OQSzNjhJp5Q==',
             user=pingou,
@@ -1367,7 +1367,7 @@ class PagureFlaskApptests(tests.Modeltests):
         self.test_new_project()
 
         # Add a pending email to pingou
-        userobj = pagure.lib.search_user(self.session, username='pingou')
+        userobj = pagure.lib.query.search_user(self.session, username='pingou')
 
         self.assertEqual(len(userobj.emails), 2)
 
@@ -1454,7 +1454,7 @@ class PagureFlaskApptests(tests.Modeltests):
         ast.return_value = False
 
         # Add a pending email to pingou
-        userobj = pagure.lib.search_user(self.session, username='pingou')
+        userobj = pagure.lib.query.search_user(self.session, username='pingou')
 
         self.assertEqual(len(userobj.emails), 2)
 
@@ -1491,7 +1491,7 @@ class PagureFlaskApptests(tests.Modeltests):
                 'Email validated',
                 output_text)
 
-        userobj = pagure.lib.search_user(self.session, username='pingou')
+        userobj = pagure.lib.query.search_user(self.session, username='pingou')
         self.assertEqual(len(userobj.emails), 3)
 
         ast.return_value = True
@@ -1512,8 +1512,8 @@ class PagureFlaskApptests(tests.Modeltests):
         """Test the view_user_requests endpoint. """
         # Create the PR
         tests.create_projects(self.session)
-        repo = pagure.lib._get_project(self.session, 'test')
-        req = pagure.lib.new_pull_request(
+        repo = pagure.lib.query._get_project(self.session, 'test')
+        req = pagure.lib.query.new_pull_request(
             session=self.session,
             repo_from=repo,
             branch_from='dev',
@@ -1544,10 +1544,10 @@ class PagureFlaskApptests(tests.Modeltests):
             hook_token='aaabbbttt',
         )
         self.session.add(item)
-        repo = pagure.lib._get_project(
+        repo = pagure.lib.query._get_project(
             self.session, 'test_fork', user='pingou')
 
-        req = pagure.lib.new_pull_request(
+        req = pagure.lib.query.new_pull_request(
             session=self.session,
             repo_from=repo,
             branch_from='dev',
@@ -1578,8 +1578,8 @@ class PagureFlaskApptests(tests.Modeltests):
         in another project. """
         # Pingou creates the PR on test
         tests.create_projects(self.session)
-        repo = pagure.lib._get_project(self.session, 'test')
-        req = pagure.lib.new_pull_request(
+        repo = pagure.lib.query._get_project(self.session, 'test')
+        req = pagure.lib.query.new_pull_request(
             session=self.session,
             repo_from=repo,
             branch_from='dev',
@@ -1593,8 +1593,8 @@ class PagureFlaskApptests(tests.Modeltests):
         self.assertEqual(req.title, 'test pull-request #1')
 
         # foo creates the PR on test
-        repo = pagure.lib._get_project(self.session, 'test')
-        req = pagure.lib.new_pull_request(
+        repo = pagure.lib.query._get_project(self.session, 'test')
+        req = pagure.lib.query.new_pull_request(
             session=self.session,
             repo_from=repo,
             branch_from='dev',
@@ -1636,8 +1636,8 @@ class PagureFlaskApptests(tests.Modeltests):
         by me against a project I do not have rights on. """
         # Create the PR
         tests.create_projects(self.session)
-        repo = pagure.lib._get_project(self.session, 'test')
-        req = pagure.lib.new_pull_request(
+        repo = pagure.lib.query._get_project(self.session, 'test')
+        req = pagure.lib.query.new_pull_request(
             session=self.session,
             repo_from=repo,
             branch_from='dev',
@@ -1671,8 +1671,8 @@ class PagureFlaskApptests(tests.Modeltests):
         """Test the view_user_issues endpoint when the user exists."""
         # Create the issue
         tests.create_projects(self.session)
-        repo = pagure.lib._get_project(self.session, 'test')
-        msg = pagure.lib.new_issue(
+        repo = pagure.lib.query._get_project(self.session, 'test')
+        msg = pagure.lib.query.new_issue(
             session=self.session,
             repo=repo,
             title='Test issue #1',
@@ -1702,9 +1702,9 @@ class PagureFlaskApptests(tests.Modeltests):
             hook_token='aaabbbttt',
         )
         self.session.add(item)
-        repo = pagure.lib._get_project(self.session, 'test_fork', user='foo')
+        repo = pagure.lib.query._get_project(self.session, 'test_fork', user='foo')
 
-        msg = pagure.lib.new_issue(
+        msg = pagure.lib.query.new_issue(
             session=self.session,
             repo=repo,
             title='Test issue #2',
@@ -1716,7 +1716,7 @@ class PagureFlaskApptests(tests.Modeltests):
         self.assertEqual(msg.title, 'Test issue #2')
 
         # Test the assigned issue table.  Create issue then set the assignee
-        msg = pagure.lib.new_issue(
+        msg = pagure.lib.query.new_issue(
             session=self.session,
             repo=repo,
             title='Test issue #3',
@@ -1727,7 +1727,7 @@ class PagureFlaskApptests(tests.Modeltests):
         self.session.commit()
         self.assertEqual(msg.title, 'Test issue #3')
 
-        msg = pagure.lib.add_issue_assignee(
+        msg = pagure.lib.query.add_issue_assignee(
             session=self.session,
             issue=msg,
             assignee='pingou',
@@ -1756,8 +1756,8 @@ class PagureFlaskApptests(tests.Modeltests):
         tracking."""
         # Create the issue
         tests.create_projects(self.session)
-        repo = pagure.lib._get_project(self.session, 'test')
-        msg = pagure.lib.new_issue(
+        repo = pagure.lib.query._get_project(self.session, 'test')
+        msg = pagure.lib.query.new_issue(
             session=self.session,
             repo=repo,
             title='Test issue #1',
@@ -1778,7 +1778,7 @@ class PagureFlaskApptests(tests.Modeltests):
             1)
 
         # Disable issue tracking
-        repo = pagure.lib._get_project(self.session, 'test')
+        repo = pagure.lib.query._get_project(self.session, 'test')
         settings = repo.settings
         settings['issue_tracker'] = False
         repo.settings = settings
@@ -1951,7 +1951,7 @@ class PagureFlaskApptests(tests.Modeltests):
                 output_text.count(
                     '<small class="font-weight-bold text-success input-group-text">Active until'), 0)
 
-            user = pagure.lib.get_user(self.session, key='foo')
+            user = pagure.lib.query.get_user(self.session, key='foo')
             self.assertEqual(len(user.tokens), 1)
             expiration_dt = user.tokens[0].expiration
 
@@ -1968,7 +1968,7 @@ class PagureFlaskApptests(tests.Modeltests):
                     '<small class="font-weight-bold text-success input-group-text">Active until'), 0)
 
             # Ensure the expiration date did not change
-            user = pagure.lib.get_user(self.session, key='foo')
+            user = pagure.lib.query.get_user(self.session, key='foo')
             self.assertEqual(len(user.tokens), 1)
             self.assertEqual(
                 expiration_dt, user.tokens[0].expiration
@@ -2038,7 +2038,7 @@ class PagureFlaskAppNoDocstests(tests.Modeltests):
     def test_new_project_no_docs_folder(self):
         """ Test the new_project endpoint with DOCS_FOLDER is None. """
         # Before
-        projects = pagure.lib.search_projects(self.session)
+        projects = pagure.lib.query.search_projects(self.session)
         self.assertEqual(len(projects), 0)
         self.assertFalse(os.path.exists(
             os.path.join(self.path, 'repos', 'project#1.git')))
@@ -2072,7 +2072,7 @@ class PagureFlaskAppNoDocstests(tests.Modeltests):
                 '<title>Overview - project-1 - Pagure</title>', output_text)
 
         # After
-        projects = pagure.lib.search_projects(self.session)
+        projects = pagure.lib.query.search_projects(self.session)
         self.assertEqual(len(projects), 1)
         self.assertTrue(os.path.exists(
             os.path.join(self.path, 'repos', 'project-1.git')))
@@ -2095,7 +2095,7 @@ class PagureFlaskAppNoTicketstests(tests.Modeltests):
     def test_new_project_no_tickets_folder(self):
         """ Test the new_project endpoint with TICKETS_FOLDER is None. """
         # Before
-        projects = pagure.lib.search_projects(self.session)
+        projects = pagure.lib.query.search_projects(self.session)
         self.assertEqual(len(projects), 0)
         self.assertFalse(os.path.exists(
             os.path.join(self.path, 'repos', 'project#1.git')))
@@ -2129,7 +2129,7 @@ class PagureFlaskAppNoTicketstests(tests.Modeltests):
                 '<title>Overview - project-1 - Pagure</title>', output_text)
 
         # After
-        projects = pagure.lib.search_projects(self.session)
+        projects = pagure.lib.query.search_projects(self.session)
         self.assertEqual(len(projects), 1)
         self.assertTrue(os.path.exists(
             os.path.join(self.path, 'repos', 'project-1.git')))

+ 22 - 22
tests/test_pagure_flask_ui_app_browse.py

@@ -22,7 +22,7 @@ from mock import patch, MagicMock
 sys.path.insert(0, os.path.join(os.path.dirname(
     os.path.abspath(__file__)), '..'))
 
-import pagure.lib
+import pagure.lib.query
 import tests
 
 
@@ -119,8 +119,8 @@ class PagureFlaskAppBrowsetests(tests.Modeltests):
         has no access to the private project. """
 
         # Add user 'pingou' with ticket access on repo
-        repo = pagure.lib._get_project(self.session, 'test3')
-        msg = pagure.lib.add_user_to_project(
+        repo = pagure.lib.query._get_project(self.session, 'test3')
+        msg = pagure.lib.query.add_user_to_project(
             self.session,
             repo,
             new_user='pingou',
@@ -155,8 +155,8 @@ class PagureFlaskAppBrowsetests(tests.Modeltests):
         has no access to the private project. """
 
         # Add user 'pingou' with commit access on repo
-        repo = pagure.lib._get_project(self.session, 'test3')
-        msg = pagure.lib.add_user_to_project(
+        repo = pagure.lib.query._get_project(self.session, 'test3')
+        msg = pagure.lib.query.add_user_to_project(
             self.session,
             repo,
             new_user='pingou',
@@ -190,8 +190,8 @@ class PagureFlaskAppBrowsetests(tests.Modeltests):
         has no access to the private project. """
 
         # Add user 'pingou' with admin access on repo
-        repo = pagure.lib._get_project(self.session, 'test3')
-        msg = pagure.lib.add_user_to_project(
+        repo = pagure.lib.query._get_project(self.session, 'test3')
+        msg = pagure.lib.query.add_user_to_project(
             self.session,
             repo,
             new_user='pingou',
@@ -240,7 +240,7 @@ class PagureFlaskAppBrowseGroupAdmintests(tests.Modeltests):
         self.session.commit()
 
         # Create a group
-        msg = pagure.lib.add_group(
+        msg = pagure.lib.query.add_group(
             self.session,
             group_name='JL',
             display_name='Justice League',
@@ -255,8 +255,8 @@ class PagureFlaskAppBrowseGroupAdmintests(tests.Modeltests):
 
         # Add the group to project we just created, test3
         # Add it with admin ACL
-        project = pagure.lib._get_project(self.session, 'test3')
-        msg = pagure.lib.add_group_to_project(
+        project = pagure.lib.query._get_project(self.session, 'test3')
+        msg = pagure.lib.query.add_group_to_project(
             self.session,
             project=project,
             new_group='JL',
@@ -293,10 +293,10 @@ class PagureFlaskAppBrowseGroupAdmintests(tests.Modeltests):
     def test_browse_project_user_in_group(self):
         """ Test the browse project endpoint when logged in as an user that
         has no access to the private project via a group as admin. """
-        group = pagure.lib.search_groups(
+        group = pagure.lib.query.search_groups(
             self.session, group_name='JL')
 
-        pagure.lib.add_user_to_group(
+        pagure.lib.query.add_user_to_group(
             session=self.session,
             username='pingou',
             group=group,
@@ -345,7 +345,7 @@ class PagureFlaskAppBrowseGroupCommittests(tests.Modeltests):
         self.session.commit()
 
         # Create a group
-        msg = pagure.lib.add_group(
+        msg = pagure.lib.query.add_group(
             self.session,
             group_name='JL',
             display_name='Justice League',
@@ -360,8 +360,8 @@ class PagureFlaskAppBrowseGroupCommittests(tests.Modeltests):
 
         # Add the group to project we just created, test3
         # Add it with commit ACL
-        project = pagure.lib._get_project(self.session, 'test3')
-        msg = pagure.lib.add_group_to_project(
+        project = pagure.lib.query._get_project(self.session, 'test3')
+        msg = pagure.lib.query.add_group_to_project(
             self.session,
             project=project,
             new_group='JL',
@@ -398,10 +398,10 @@ class PagureFlaskAppBrowseGroupCommittests(tests.Modeltests):
     def test_browse_project_user_in_group(self):
         """ Test the browse project endpoint when logged in as an user that
         has no access to the private project via a group as admin. """
-        group = pagure.lib.search_groups(
+        group = pagure.lib.query.search_groups(
             self.session, group_name='JL')
 
-        pagure.lib.add_user_to_group(
+        pagure.lib.query.add_user_to_group(
             session=self.session,
             username='pingou',
             group=group,
@@ -450,7 +450,7 @@ class PagureFlaskAppBrowseGroupTickettests(tests.Modeltests):
         self.session.commit()
 
         # Create a group
-        msg = pagure.lib.add_group(
+        msg = pagure.lib.query.add_group(
             self.session,
             group_name='JL',
             display_name='Justice League',
@@ -465,8 +465,8 @@ class PagureFlaskAppBrowseGroupTickettests(tests.Modeltests):
 
         # Add the group to project we just created, test3
         # Add it with ticket ACL
-        project = pagure.lib._get_project(self.session, 'test3')
-        msg = pagure.lib.add_group_to_project(
+        project = pagure.lib.query._get_project(self.session, 'test3')
+        msg = pagure.lib.query.add_group_to_project(
             self.session,
             project=project,
             new_group='JL',
@@ -503,10 +503,10 @@ class PagureFlaskAppBrowseGroupTickettests(tests.Modeltests):
     def test_browse_project_user_in_group(self):
         """ Test the browse project endpoint when logged in as an user that
         has no access to the private project via a group as admin. """
-        group = pagure.lib.search_groups(
+        group = pagure.lib.query.search_groups(
             self.session, group_name='JL')
 
-        pagure.lib.add_user_to_group(
+        pagure.lib.query.add_user_to_group(
             session=self.session,
             username='pingou',
             group=group,

+ 12 - 12
tests/test_pagure_flask_ui_app_give_project.py

@@ -25,7 +25,7 @@ sys.path.insert(0, os.path.join(os.path.dirname(
     os.path.abspath(__file__)), '..'))
 
 import pagure
-import pagure.lib
+import pagure.lib.query
 import tests
 
 
@@ -47,7 +47,7 @@ class PagureFlaskGiveRepotests(tests.SimplePagureTest):
 
     def _check_user(self, user='pingou'):
         self.session.commit()
-        project = pagure.lib.get_authorized_project(
+        project = pagure.lib.query.get_authorized_project(
             self.session, project_name='test')
         self.assertEqual(project.user.user, user)
 
@@ -180,10 +180,10 @@ class PagureFlaskGiveRepotests(tests.SimplePagureTest):
 
     def test_give_project_not_owner_but_is_admin(self):
         """ Test the give_project endpoint. """
-        project = pagure.lib.get_authorized_project(
+        project = pagure.lib.query.get_authorized_project(
             self.session, project_name='test')
 
-        msg = pagure.lib.add_user_to_project(
+        msg = pagure.lib.query.add_user_to_project(
             self.session,
             project=project,
             new_user='foo',
@@ -276,7 +276,7 @@ class PagureFlaskGiveRepotests(tests.SimplePagureTest):
 
             self._check_user('foo')
             # Make sure that the user giving the project is still an admin
-            project = pagure.lib.get_authorized_project(
+            project = pagure.lib.query.get_authorized_project(
                 self.session, project_name='test')
             self.assertEqual(len(project.users), 1)
             self.assertEqual(project.users[0].user, 'pingou')
@@ -287,8 +287,8 @@ class PagureFlaskGiveRepotests(tests.SimplePagureTest):
         """ Test the give_project endpoint when the new main_admin is already
         a committer on the project. """
 
-        project = pagure.lib._get_project(self.session, 'test')
-        pagure.lib.add_user_to_project(
+        project = pagure.lib.query._get_project(self.session, 'test')
+        pagure.lib.query.add_user_to_project(
             self.session, project,
             new_user='foo',
             user='pingou',
@@ -318,7 +318,7 @@ class PagureFlaskGiveRepotests(tests.SimplePagureTest):
 
             self._check_user('foo')
             # Make sure that the user giving the project is still an admin
-            project = pagure.lib.get_authorized_project(
+            project = pagure.lib.query.get_authorized_project(
                 self.session, project_name='test')
             self.assertEqual(len(project.users), 1)
             self.assertEqual(project.users[0].user, 'pingou')
@@ -359,7 +359,7 @@ class PagureFlaskGiveRepotests(tests.SimplePagureTest):
         """ Test the give_project endpoint. """
 
         # Create the packager group
-        msg = pagure.lib.add_group(
+        msg = pagure.lib.query.add_group(
             self.session,
             group_name='packager',
             display_name='packager group',
@@ -373,8 +373,8 @@ class PagureFlaskGiveRepotests(tests.SimplePagureTest):
         self.assertEqual(msg, 'User `pingou` added to the group `packager`.')
 
         # Add foo to the packager group
-        group = pagure.lib.search_groups(self.session, group_name='packager')
-        msg = pagure.lib.add_user_to_group(
+        group = pagure.lib.query.search_groups(self.session, group_name='packager')
+        msg = pagure.lib.query.add_user_to_group(
             self.session,
             username='foo',
             group=group,
@@ -407,7 +407,7 @@ class PagureFlaskGiveRepotests(tests.SimplePagureTest):
 
             self._check_user('foo')
             # Make sure that the user giving the project is still an admin
-            project = pagure.lib.get_authorized_project(
+            project = pagure.lib.query.get_authorized_project(
                 self.session, project_name='test')
             self.assertEqual(len(project.users), 1)
             self.assertEqual(project.users[0].user, 'pingou')

+ 1 - 1
tests/test_pagure_flask_ui_app_index.py

@@ -27,7 +27,7 @@ from mock import patch, MagicMock
 sys.path.insert(0, os.path.join(os.path.dirname(
     os.path.abspath(__file__)), '..'))
 
-import pagure.lib
+import pagure.lib.query
 import tests
 
 

+ 13 - 13
tests/test_pagure_flask_ui_app_userdash.py

@@ -27,7 +27,7 @@ from mock import patch, MagicMock
 sys.path.insert(0, os.path.join(os.path.dirname(
     os.path.abspath(__file__)), '..'))
 
-import pagure.lib
+import pagure.lib.query
 import tests
 
 
@@ -66,8 +66,8 @@ class PagureFlaskAppUserdashTests(tests.Modeltests):
 
 
             # Add foo to test with admin level
-            project = pagure.lib._get_project(self.session, 'test')
-            msg = pagure.lib.add_user_to_project(
+            project = pagure.lib.query._get_project(self.session, 'test')
+            msg = pagure.lib.query.add_user_to_project(
                 self.session,
                 project=project,
                 new_user='foo',
@@ -113,8 +113,8 @@ class PagureFlaskAppUserdashTests(tests.Modeltests):
                 output_text)
 
             # Add foo to test with commit level
-            project = pagure.lib._get_project(self.session, 'test')
-            msg = pagure.lib.add_user_to_project(
+            project = pagure.lib.query._get_project(self.session, 'test')
+            msg = pagure.lib.query.add_user_to_project(
                 self.session,
                 project=project,
                 new_user='foo',
@@ -161,8 +161,8 @@ class PagureFlaskAppUserdashTests(tests.Modeltests):
                 output_text)
 
             # Add foo to test with ticket level
-            project = pagure.lib._get_project(self.session, 'test')
-            msg = pagure.lib.add_user_to_project(
+            project = pagure.lib.query._get_project(self.session, 'test')
+            msg = pagure.lib.query.add_user_to_project(
                 self.session,
                 project=project,
                 new_user='foo',
@@ -209,8 +209,8 @@ class PagureFlaskAppUserdashTests(tests.Modeltests):
                 output_text)
 
             # Add foo to test with admin level
-            project = pagure.lib._get_project(self.session, 'test')
-            msg = pagure.lib.add_user_to_project(
+            project = pagure.lib.query._get_project(self.session, 'test')
+            msg = pagure.lib.query.add_user_to_project(
                 self.session,
                 project=project,
                 new_user='foo',
@@ -257,8 +257,8 @@ class PagureFlaskAppUserdashTests(tests.Modeltests):
                 output_text)
 
             # Add foo to test with commit level
-            project = pagure.lib._get_project(self.session, 'test')
-            msg = pagure.lib.add_user_to_project(
+            project = pagure.lib.query._get_project(self.session, 'test')
+            msg = pagure.lib.query.add_user_to_project(
                 self.session,
                 project=project,
                 new_user='foo',
@@ -306,8 +306,8 @@ class PagureFlaskAppUserdashTests(tests.Modeltests):
                 output_text)
 
             # Add foo to test with commit level
-            project = pagure.lib._get_project(self.session, 'test')
-            msg = pagure.lib.add_user_to_project(
+            project = pagure.lib.query._get_project(self.session, 'test')
+            msg = pagure.lib.query.add_user_to_project(
                 self.session,
                 project=project,
                 new_user='foo',

+ 3 - 3
tests/test_pagure_flask_ui_clone.py

@@ -28,7 +28,7 @@ from mock import patch, MagicMock
 sys.path.insert(0, os.path.join(os.path.dirname(
     os.path.abspath(__file__)), '..'))
 
-import pagure.lib
+import pagure.lib.query
 import tests
 
 
@@ -99,7 +99,7 @@ class PagureFlaskAppClonetests(tests.Modeltests):
     @patch.dict('pagure.config.config', {'ALLOW_HTTP_PULL_PUSH': True})
     def test_http_clone_private_project_unauthed(self):
         """ Test that the HTTP endpoint enforced project.private. """
-        project = pagure.lib._get_project(self.session, 'clonetest')
+        project = pagure.lib.query._get_project(self.session, 'clonetest')
         project.private = True
         self.session.add(project)
         self.session.commit()
@@ -141,7 +141,7 @@ class PagureFlaskAppClonetests(tests.Modeltests):
         """ Test that HTTP cloning gives reasonable output with project.private. """
         # Unfortunately, actually testing a git clone would need the app to
         # run on a TCP port, which the test environment doesn't do.
-        project = pagure.lib._get_project(self.session, 'clonetest')
+        project = pagure.lib.query._get_project(self.session, 'clonetest')
         project.private = True
         self.session.add(project)
         self.session.commit()

+ 72 - 73
tests/test_pagure_flask_ui_fork.py

@@ -31,8 +31,7 @@ from datetime import datetime, timedelta
 sys.path.insert(0, os.path.join(os.path.dirname(
     os.path.abspath(__file__)), '..'))
 
-import pagure
-import pagure.lib
+import pagure.lib.query
 import pagure.lib.tasks
 import tests
 from pagure.lib.repo import PagureRepo
@@ -206,8 +205,8 @@ class PagureFlaskForktests(tests.Modeltests):
             PagureRepo.push(ori_remote, refname)
 
         # Create a PR for these changes
-        project = pagure.lib.get_authorized_project(self.session, 'test')
-        req = pagure.lib.new_pull_request(
+        project = pagure.lib.query.get_authorized_project(self.session, 'test')
+        req = pagure.lib.query.new_pull_request(
             session=self.session,
             repo_from=project,
             branch_from=branch_from,
@@ -231,7 +230,7 @@ class PagureFlaskForktests(tests.Modeltests):
 
         self.set_up_git_repo(new_project=None, branch_from='feature')
 
-        project = pagure.lib.get_authorized_project(self.session, 'test')
+        project = pagure.lib.query.get_authorized_project(self.session, 'test')
         self.assertEqual(len(project.requests), 1)
 
         # View the pull-request
@@ -267,7 +266,7 @@ class PagureFlaskForktests(tests.Modeltests):
 
         self.set_up_git_repo(new_project=None, branch_from='feature')
 
-        project = pagure.lib.get_authorized_project(self.session, 'test')
+        project = pagure.lib.query.get_authorized_project(self.session, 'test')
         self.assertEqual(len(project.requests), 1)
 
         # View the pull-request
@@ -305,8 +304,8 @@ class PagureFlaskForktests(tests.Modeltests):
 
         self.set_up_git_repo(new_project=None, branch_from='feature')
 
-        self.session = pagure.lib.create_session(self.dbpath)
-        project = pagure.lib.get_authorized_project(self.session, 'test')
+        self.session = pagure.lib.query.create_session(self.dbpath)
+        project = pagure.lib.query.get_authorized_project(self.session, 'test')
         self.assertEqual(len(project.requests), 1)
 
         request = project.requests[0]
@@ -368,8 +367,8 @@ class PagureFlaskForktests(tests.Modeltests):
 
         pagure.lib.tasks.update_pull_request(request.uid)
 
-        self.session = pagure.lib.create_session(self.dbpath)
-        project = pagure.lib.get_authorized_project(self.session, 'test')
+        self.session = pagure.lib.query.create_session(self.dbpath)
+        project = pagure.lib.query.get_authorized_project(self.session, 'test')
         self.assertEqual(len(project.requests), 1)
         request = project.requests[0]
         self.assertEqual(len(request.comments), 1)
@@ -436,7 +435,7 @@ class PagureFlaskForktests(tests.Modeltests):
 
             # Project w/o pull-request
             self.session.commit()
-            repo = pagure.lib.get_authorized_project(self.session, 'test')
+            repo = pagure.lib.query.get_authorized_project(self.session, 'test')
             settings = repo.settings
             settings['pull_requests'] = False
             repo.settings = settings
@@ -450,7 +449,7 @@ class PagureFlaskForktests(tests.Modeltests):
 
             # Project w pull-request but only assignee can merge
             self.session.commit()
-            repo = pagure.lib.get_authorized_project(self.session, 'test')
+            repo = pagure.lib.query.get_authorized_project(self.session, 'test')
             settings['pull_requests'] = True
             settings['Only_assignee_can_merge_pull-request'] = True
             repo.settings = settings
@@ -478,7 +477,7 @@ class PagureFlaskForktests(tests.Modeltests):
 
             # PR assigned but not to this user
             self.session.commit()
-            repo = pagure.lib.get_authorized_project(self.session, 'test')
+            repo = pagure.lib.query.get_authorized_project(self.session, 'test')
             req = repo.requests[0]
             req.assignee_id = 2
             self.session.add(req)
@@ -502,7 +501,7 @@ class PagureFlaskForktests(tests.Modeltests):
 
             # Project w/ minimal PR score
             self.session.commit()
-            repo = pagure.lib.get_authorized_project(self.session, 'test')
+            repo = pagure.lib.query.get_authorized_project(self.session, 'test')
             settings['Only_assignee_can_merge_pull-request'] = False
             settings['Minimum_score_to_merge_pull-request'] = 2
             repo.settings = settings
@@ -528,7 +527,7 @@ class PagureFlaskForktests(tests.Modeltests):
 
             # Merge
             self.session.commit()
-            repo = pagure.lib.get_authorized_project(self.session, 'test')
+            repo = pagure.lib.query.get_authorized_project(self.session, 'test')
             settings['Minimum_score_to_merge_pull-request'] = -1
             repo.settings = settings
             self.session.add(repo)
@@ -769,7 +768,7 @@ class PagureFlaskForktests(tests.Modeltests):
         self.set_up_git_repo(new_project=None, branch_from='feature')
 
         # Project w/o pull-request
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
         settings = repo.settings
         settings['pull_requests'] = False
         repo.settings = settings
@@ -840,8 +839,8 @@ class PagureFlaskForktests(tests.Modeltests):
         PagureRepo.push(ori_remote, refname)
 
         # Create a PR for these changes
-        project = pagure.lib.get_authorized_project(self.session, 'test')
-        req = pagure.lib.new_pull_request(
+        project = pagure.lib.query.get_authorized_project(self.session, 'test')
+        req = pagure.lib.query.new_pull_request(
             session=self.session,
             repo_from=item,
             branch_from='feature',
@@ -907,8 +906,8 @@ class PagureFlaskForktests(tests.Modeltests):
 
         # Create a PR for these "changes" (there are none, both repos are
         # empty)
-        project = pagure.lib.get_authorized_project(self.session, 'test')
-        req = pagure.lib.new_pull_request(
+        project = pagure.lib.query.get_authorized_project(self.session, 'test')
+        req = pagure.lib.query.new_pull_request(
             session=self.session,
             repo_from=item,
             branch_from='feature',
@@ -950,7 +949,7 @@ class PagureFlaskForktests(tests.Modeltests):
         tests.create_projects_git(
             os.path.join(self.path, 'repos'), bare=True)
 
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
         item = pagure.lib.model.Project(
             user_id=2,
             name='test',
@@ -964,7 +963,7 @@ class PagureFlaskForktests(tests.Modeltests):
 
         # create PR's to play with
         # PR-1
-        req = pagure.lib.new_pull_request(
+        req = pagure.lib.query.new_pull_request(
             session=self.session,
             repo_to=repo,
             repo_from=item,
@@ -979,7 +978,7 @@ class PagureFlaskForktests(tests.Modeltests):
         self.assertEqual(req.title, 'PR from the feature branch')
 
         # PR-2
-        req = pagure.lib.new_pull_request(
+        req = pagure.lib.query.new_pull_request(
             session=self.session,
             repo_to=repo,
             branch_to='master',
@@ -993,7 +992,7 @@ class PagureFlaskForktests(tests.Modeltests):
         self.assertEqual(req.title, 'test PR')
 
         # PR-3
-        req = pagure.lib.new_pull_request(
+        req = pagure.lib.query.new_pull_request(
             session=self.session,
             repo_to=repo,
             branch_from='feature',
@@ -1007,7 +1006,7 @@ class PagureFlaskForktests(tests.Modeltests):
         self.assertEqual(req.title, 'test Invalid PR')
 
         # PR-4
-        req = pagure.lib.new_pull_request(
+        req = pagure.lib.query.new_pull_request(
             session=self.session,
             repo_to=repo,
             branch_from='feature',
@@ -1030,7 +1029,7 @@ class PagureFlaskForktests(tests.Modeltests):
         self.assertIn('href="/test/pull-request/2"', tr_elements[1])
         self.assertIn('href="/test/pull-request/1"', tr_elements[2])
 
-        pr_one = pagure.lib.search_pull_requests(
+        pr_one = pagure.lib.query.search_pull_requests(
             self.session, project_id=1, requestid=1)
         pr_one.last_updated = datetime.utcnow() + timedelta(seconds=2)
         self.session.add(pr_one)
@@ -1145,7 +1144,7 @@ class PagureFlaskForktests(tests.Modeltests):
 
 
         # Project w/o pull-request
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
         settings = repo.settings
         settings['pull_requests'] = False
         repo.settings = settings
@@ -1219,7 +1218,7 @@ index 9f44358..2a552bb 100644
         self.assertEqual(patch, exp)
 
         # Project w/o pull-request
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
         settings = repo.settings
         settings['pull_requests'] = False
         repo.settings = settings
@@ -1274,7 +1273,7 @@ index 9f44358..2a552bb 100644
         self.assertEqual(output.get_data(as_text=True), exp)
 
         # Project w/o pull-request
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
         settings = repo.settings
         settings['pull_requests'] = False
         repo.settings = settings
@@ -1392,8 +1391,8 @@ index 9f44358..2a552bb 100644
 
         # Create a PR for these "changes" (there are none, both repos are
         # empty)
-        project = pagure.lib.get_authorized_project(self.session, 'test')
-        req = pagure.lib.new_pull_request(
+        project = pagure.lib.query.get_authorized_project(self.session, 'test')
+        req = pagure.lib.query.new_pull_request(
             session=self.session,
             repo_from=item,
             branch_from='feature',
@@ -1482,8 +1481,8 @@ index 0000000..2a552bb
 
         # Create a PR for these "changes" (there are none, both repos are
         # empty)
-        project = pagure.lib.get_authorized_project(self.session, 'test')
-        req = pagure.lib.new_pull_request(
+        project = pagure.lib.query.get_authorized_project(self.session, 'test')
+        req = pagure.lib.query.new_pull_request(
             session=self.session,
             repo_from=item,
             branch_from='feature',
@@ -1567,7 +1566,7 @@ index 0000000..2a552bb
         user.username = 'pingou'
         with tests.user_set(self.app.application, user):
             # Project w/o pull-request
-            repo = pagure.lib.get_authorized_project(self.session, 'test')
+            repo = pagure.lib.query.get_authorized_project(self.session, 'test')
             settings = repo.settings
             settings['pull_requests'] = False
             repo.settings = settings
@@ -1580,7 +1579,7 @@ index 0000000..2a552bb
             self.assertEqual(output.status_code, 404)
 
             # Project w/ pull-request
-            repo = pagure.lib.get_authorized_project(self.session, 'test')
+            repo = pagure.lib.query.get_authorized_project(self.session, 'test')
             settings = repo.settings
             settings['pull_requests'] = True
             repo.settings = settings
@@ -1655,7 +1654,7 @@ index 0000000..2a552bb
         user.username = 'pingou'
         with tests.user_set(self.app.application, user):
             # Project w/o pull-request
-            repo = pagure.lib.get_authorized_project(self.session, 'test')
+            repo = pagure.lib.query.get_authorized_project(self.session, 'test')
             settings = repo.settings
             settings['pull_requests'] = False
             repo.settings = settings
@@ -1668,7 +1667,7 @@ index 0000000..2a552bb
             self.assertEqual(output.status_code, 404)
 
             # Project w/ pull-request
-            repo = pagure.lib.get_authorized_project(self.session, 'test')
+            repo = pagure.lib.query.get_authorized_project(self.session, 'test')
             settings = repo.settings
             settings['pull_requests'] = True
             repo.settings = settings
@@ -1818,7 +1817,7 @@ index 0000000..2a552bb
                 output_text)
 
             # Pull-Request closed
-            repo = pagure.lib.get_authorized_project(self.session, 'test')
+            repo = pagure.lib.query.get_authorized_project(self.session, 'test')
             req = repo.requests[0]
             req.status = 'Closed'
             req.closed_by_in = 1
@@ -1831,7 +1830,7 @@ index 0000000..2a552bb
             self.assertEqual(output.status_code, 200)
 
             # Project w/o pull-request
-            repo = pagure.lib.get_authorized_project(self.session, 'test')
+            repo = pagure.lib.query.get_authorized_project(self.session, 'test')
             settings = repo.settings
             settings['pull_requests'] = False
             repo.settings = settings
@@ -1929,7 +1928,7 @@ index 0000000..2a552bb
             self.assertEqual(output.status_code, 403)
 
             # Make the PR be from foo
-            repo = pagure.lib.get_authorized_project(self.session, 'test')
+            repo = pagure.lib.query.get_authorized_project(self.session, 'test')
             req = repo.requests[0]
             req.user_id = 2
             self.session.add(req)
@@ -1958,7 +1957,7 @@ index 0000000..2a552bb
         user.username = 'pingou'
         with tests.user_set(self.app.application, user):
             # Pull-Request closed
-            repo = pagure.lib.get_authorized_project(self.session, 'test')
+            repo = pagure.lib.query.get_authorized_project(self.session, 'test')
             req = repo.requests[0]
             req.status = 'Closed'
             req.closed_by_in = 1
@@ -1971,7 +1970,7 @@ index 0000000..2a552bb
             self.assertEqual(output.status_code, 200)
 
             # Project w/o pull-request
-            repo = pagure.lib.get_authorized_project(self.session, 'test')
+            repo = pagure.lib.query.get_authorized_project(self.session, 'test')
             settings = repo.settings
             settings['pull_requests'] = False
             repo.settings = settings
@@ -2036,8 +2035,8 @@ index 0000000..2a552bb
         tests.create_projects_git(
             os.path.join(self.path, 'requests'), bare=True)
 
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        fork = pagure.lib.get_authorized_project(self.session, 'test', user='foo')
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        fork = pagure.lib.query.get_authorized_project(self.session, 'test', user='foo')
 
         self.set_up_git_repo(
             new_project=fork, branch_from='feature', mtype='FF')
@@ -2060,8 +2059,8 @@ index 0000000..2a552bb
         tests.create_projects_git(
             os.path.join(self.path, 'requests'), bare=True)
 
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        fork = pagure.lib.get_authorized_project(self.session, 'test', user='foo')
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        fork = pagure.lib.query.get_authorized_project(self.session, 'test', user='foo')
 
         self.set_up_git_repo(
             new_project=fork, branch_from='feature', mtype='FF')
@@ -2175,8 +2174,8 @@ More information</textarea>
         tests.create_projects_git(
             os.path.join(self.path, 'requests'), bare=True)
 
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        fork = pagure.lib.get_authorized_project(self.session, 'test', user='foo')
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        fork = pagure.lib.query.get_authorized_project(self.session, 'test', user='foo')
 
         # Enforce Signed-of-by in the repo
         settings = repo.settings
@@ -2218,8 +2217,8 @@ More information</textarea>
         tests.create_projects_git(
             os.path.join(self.path, 'requests'), bare=True)
 
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        fork = pagure.lib.get_authorized_project(self.session, 'test', user='foo')
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        fork = pagure.lib.query.get_authorized_project(self.session, 'test', user='foo')
 
         # Enforce Signed-of-by in the repo
         settings = repo.settings
@@ -2286,8 +2285,8 @@ More information</textarea>
         tests.create_projects_git(
             os.path.join(self.path, 'requests'), bare=True)
 
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        fork = pagure.lib.get_authorized_project(self.session, 'test', user='foo')
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        fork = pagure.lib.query.get_authorized_project(self.session, 'test', user='foo')
 
         self.set_up_git_repo(
             new_project=fork, branch_from='feature', mtype='FF')
@@ -2324,7 +2323,7 @@ More information</textarea>
             self.assertIn('<p>Test Initial Comment</p>', output_text)
 
         # Check if commit start and stop have been set for PR#2
-        request = pagure.lib.search_pull_requests(
+        request = pagure.lib.query.search_pull_requests(
             self.session, project_id=1, requestid=2)
         self.assertIsNotNone(request.commit_start)
         self.assertIsNotNone(request.commit_stop)
@@ -2377,7 +2376,7 @@ More information</textarea>
             tests.create_projects_git(
                 os.path.join(self.path, 'requests'), bare=True)
 
-            fork = pagure.lib.get_authorized_project(
+            fork = pagure.lib.query.get_authorized_project(
                 self.session, 'test', user='ralph')
 
             self.set_up_git_repo(
@@ -2440,7 +2439,7 @@ More information</textarea>
                 os.path.join(self.path, 'requests'), bare=True)
 
             # Turn on pull-request on the fork
-            repo = pagure.lib.get_authorized_project(
+            repo = pagure.lib.query.get_authorized_project(
                 self.session, 'test', user='foo')
             settings = repo.settings
             settings['pull_requests'] = True
@@ -2453,7 +2452,7 @@ More information</textarea>
                 new_project=repo, branch_from='master', mtype='FF',
                 name_from=repo.fullname)
 
-            fork = pagure.lib.get_authorized_project(
+            fork = pagure.lib.query.get_authorized_project(
                 self.session, 'test', user='ralph')
 
             self.set_up_git_repo(
@@ -2533,7 +2532,7 @@ More information</textarea>
                 os.path.join(self.path, 'requests'), bare=True)
 
             # Turn on pull-request on the fork
-            repo = pagure.lib.get_authorized_project(
+            repo = pagure.lib.query.get_authorized_project(
                 self.session, 'test', user='foo')
             settings = repo.settings
             settings['pull_requests'] = True
@@ -2548,7 +2547,7 @@ More information</textarea>
                 new_project=repo, branch_from='master', mtype='FF',
                 name_from=repo.fullname, prid=2)
 
-            fork = pagure.lib.get_authorized_project(
+            fork = pagure.lib.query.get_authorized_project(
                 self.session, 'test', user='ralph')
 
             self.set_up_git_repo(
@@ -2641,7 +2640,7 @@ More information</textarea>
                 os.path.join(self.path, 'requests'), bare=True)
 
             # Turn on pull-request on the fork
-            repo = pagure.lib.get_authorized_project(
+            repo = pagure.lib.query.get_authorized_project(
                 self.session, 'test', user='foo')
             settings = repo.settings
             settings['pull_requests'] = True
@@ -2654,7 +2653,7 @@ More information</textarea>
                 new_project=repo, branch_from='master', mtype='FF',
                 name_from=repo.fullname)
 
-            fork = pagure.lib.get_authorized_project(
+            fork = pagure.lib.query.get_authorized_project(
                 self.session, 'test2', user='ralph')
 
             self.set_up_git_repo(
@@ -2686,8 +2685,8 @@ More information</textarea>
         tests.create_projects_git(
             os.path.join(self.path, 'requests'), bare=True)
 
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        fork = pagure.lib.get_authorized_project(self.session, 'test', user='foo')
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        fork = pagure.lib.query.get_authorized_project(self.session, 'test', user='foo')
 
         # Create a git repo to play with
         gitrepo = os.path.join(self.path, 'repos', 'test.git')
@@ -2736,8 +2735,8 @@ More information</textarea>
         tests.create_projects_git(
             os.path.join(self.path, 'requests'), bare=True)
 
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        fork = pagure.lib.get_authorized_project(self.session, 'test', user='foo')
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        fork = pagure.lib.query.get_authorized_project(self.session, 'test', user='foo')
 
         # Create a git repo to play with
         gitrepo = os.path.join(self.path, 'repos', 'test.git')
@@ -2802,7 +2801,7 @@ More information</textarea>
             self.assertEqual(output_text.count('title="PY C (pingou)"'), 2)
 
             # Project w/o pull-request
-            repo = pagure.lib.get_authorized_project(self.session, 'test')
+            repo = pagure.lib.query.get_authorized_project(self.session, 'test')
             settings = repo.settings
             settings['pull_requests'] = False
             repo.settings = settings
@@ -2821,7 +2820,7 @@ More information</textarea>
 
         self.test_pull_request_add_comment()
         # Project w/ pull-request
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
         settings = repo.settings
         settings['pull_requests'] = True
         repo.settings = settings
@@ -2892,7 +2891,7 @@ More information</textarea>
                 output_text)
 
             # Project w/o pull-request
-            repo = pagure.lib.get_authorized_project(self.session, 'test')
+            repo = pagure.lib.query.get_authorized_project(self.session, 'test')
             settings = repo.settings
             settings['pull_requests'] = False
             repo.settings = settings
@@ -2995,7 +2994,7 @@ More information</textarea>
                 'Comment updated', output_text)
 
             #  Project w/o pull-request
-            repo = pagure.lib.get_authorized_project(self.session, 'test')
+            repo = pagure.lib.query.get_authorized_project(self.session, 'test')
             settings = repo.settings
             settings['pull_requests'] = False
             repo.settings = settings
@@ -3069,7 +3068,7 @@ More information</textarea>
             self.assertEqual(output.status_code, 404)
 
             # Project requiring a merge commit
-            repo = pagure.lib.get_authorized_project(self.session, 'test')
+            repo = pagure.lib.query.get_authorized_project(self.session, 'test')
             settings = repo.settings
             settings['always_merge'] = True
             repo.settings = settings
@@ -3512,7 +3511,7 @@ More information</textarea>
         self.session.commit()
 
         # Get fork project
-        project = pagure.lib._get_project(self.session, 'test', 'foo')
+        project = pagure.lib.query._get_project(self.session, 'test', 'foo')
 
         # Pull-requests and issue-trackers are off for forks
         # lib function is not used here so mannually turning them off
@@ -3572,11 +3571,11 @@ More information</textarea>
         tests.create_projects_git(
             os.path.join(self.path, 'requests'), bare=True)
         self.set_up_git_repo(new_project=None, branch_from='feature')
-        pagure.lib.get_authorized_project(self.session, 'test')
-        request = pagure.lib.search_pull_requests(
+        pagure.lib.query.get_authorized_project(self.session, 'test')
+        request = pagure.lib.query.search_pull_requests(
             self.session, requestid=1, project_id=1,
         )
-        pagure.lib.add_pull_request_comment(
+        pagure.lib.query.add_pull_request_comment(
             self.session,
             request=request,
             commit=None,

+ 1 - 1
tests/test_pagure_flask_ui_groups.py

@@ -24,7 +24,7 @@ from mock import patch
 sys.path.insert(0, os.path.join(os.path.dirname(
     os.path.abspath(__file__)), '..'))
 
-import pagure.lib
+import pagure.config
 import tests
 
 

+ 8 - 8
tests/test_pagure_flask_ui_issue_pr_link.py

@@ -29,8 +29,8 @@ from mock import ANY, patch, MagicMock
 sys.path.insert(0, os.path.join(os.path.dirname(
     os.path.abspath(__file__)), '..'))
 
-import pagure
-import pagure.lib
+import pagure.lib.query
+import pagure.lib.tasks
 import tests
 from pagure.lib.repo import PagureRepo
 
@@ -51,10 +51,10 @@ class PagureFlaskPrIssueLinkTest(tests.Modeltests):
         tests.create_projects_git(os.path.join(
             self.path, 'repos', 'forks', 'foo'), bare=True)
 
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
 
         # Create issues to play with
-        msg = pagure.lib.new_issue(
+        msg = pagure.lib.query.new_issue(
             session=self.session,
             repo=repo,
             title='tést íssüé',
@@ -64,7 +64,7 @@ class PagureFlaskPrIssueLinkTest(tests.Modeltests):
         self.session.commit()
         self.assertEqual(msg.title, 'tést íssüé')
 
-        msg = pagure.lib.new_issue(
+        msg = pagure.lib.query.new_issue(
             session=self.session,
             repo=repo,
             title='tést íssüé #2',
@@ -115,11 +115,11 @@ class PagureFlaskPrIssueLinkTest(tests.Modeltests):
 
         # Create the corresponding PR
 
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        fork_repo = pagure.lib.get_authorized_project(
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        fork_repo = pagure.lib.query.get_authorized_project(
             self.session, 'test', user='foo')
 
-        request = pagure.lib.new_pull_request(
+        request = pagure.lib.query.new_pull_request(
             self.session,
             branch_from='master',
             repo_to=repo,

+ 145 - 146
tests/test_pagure_flask_ui_issues.py

@@ -36,8 +36,7 @@ from mock import patch, MagicMock
 sys.path.insert(0, os.path.join(os.path.dirname(
     os.path.abspath(__file__)), '..'))
 
-import pagure
-import pagure.lib
+import pagure.lib.query
 import tests
 
 
@@ -134,7 +133,7 @@ class PagureFlaskIssuestests(tests.Modeltests):
                 output_text)
 
         # Project w/o issue tracker
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
         repo.settings = {'issue_tracker': False}
         self.session.add(repo)
         self.session.commit()
@@ -213,7 +212,7 @@ class PagureFlaskIssuestests(tests.Modeltests):
             os.path.join(self.path, 'tickets'), bare=True)
 
         # Project w/o issue tracker
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
         repo.settings = {'issue_tracker': False}
         self.session.add(repo)
         self.session.commit()
@@ -496,7 +495,7 @@ class PagureFlaskIssuestests(tests.Modeltests):
             os.path.join(self.path, 'tickets'), bare=True)
 
         # Set some milestone
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
         repo.milestones = {'v1.0': '', 'v2.0': 'Tomorrow!'}
         self.session.add(repo)
         self.session.commit()
@@ -566,7 +565,7 @@ class PagureFlaskIssuestests(tests.Modeltests):
             os.path.join(self.path, 'tickets'), bare=True)
 
         # Set some milestone
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
         repo.milestones = {'v1.0': '', 'v2.0': 'Tomorrow!'}
         self.session.add(repo)
         self.session.commit()
@@ -648,9 +647,9 @@ class PagureFlaskIssuestests(tests.Modeltests):
         self.assertIn(
             '<span class="fa fa-fw fa-exclamation-circle"></span> 0 Open Issues\n', output_text)
 
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
         # Create some custom fields to play with
-        msg = pagure.lib.set_custom_key_fields(
+        msg = pagure.lib.query.set_custom_key_fields(
             session=self.session,
             project=repo,
             fields=['test1'],
@@ -661,13 +660,13 @@ class PagureFlaskIssuestests(tests.Modeltests):
         self.session.commit()
         self.assertEqual(msg, 'List of custom fields updated')
 
-        cfield = pagure.lib.get_custom_key(
+        cfield = pagure.lib.query.get_custom_key(
             session=self.session,
             project=repo,
             keyname='test1')
 
         # Create issues to play with
-        msg = pagure.lib.new_issue(
+        msg = pagure.lib.query.new_issue(
             session=self.session,
             repo=repo,
             title='tést íssüé',
@@ -677,7 +676,7 @@ class PagureFlaskIssuestests(tests.Modeltests):
         self.session.commit()
         self.assertEqual(msg.title, 'tést íssüé')
 
-        msg = pagure.lib.set_custom_key_value(
+        msg = pagure.lib.query.set_custom_key_value(
             session=self.session,
             issue=msg,
             key=cfield,
@@ -685,7 +684,7 @@ class PagureFlaskIssuestests(tests.Modeltests):
         self.session.commit()
         self.assertEqual(msg, 'Custom field test1 adjusted to firstissue')
 
-        msg = pagure.lib.new_issue(
+        msg = pagure.lib.query.new_issue(
             session=self.session,
             repo=repo,
             title='Tést íssüé with milestone',
@@ -696,7 +695,7 @@ class PagureFlaskIssuestests(tests.Modeltests):
         self.session.commit()
         self.assertEqual(msg.title, 'Tést íssüé with milestone')
 
-        msg = pagure.lib.new_issue(
+        msg = pagure.lib.query.new_issue(
             session=self.session,
             repo=repo,
             title='Test invalid issue',
@@ -708,7 +707,7 @@ class PagureFlaskIssuestests(tests.Modeltests):
         self.session.commit()
         self.assertEqual(msg.title, 'Test invalid issue')
 
-        msg = pagure.lib.set_custom_key_value(
+        msg = pagure.lib.query.set_custom_key_value(
             session=self.session,
             issue=msg,
             key=cfield,
@@ -844,7 +843,7 @@ class PagureFlaskIssuestests(tests.Modeltests):
         self.assertIn('<span class="fa fa-fw fa-exclamation-circle"></span> 2 Open Issues\n', output_text)
 
         # Add another issue to test sorting
-        msg = pagure.lib.new_issue(
+        msg = pagure.lib.query.new_issue(
             session=self.session,
             repo=repo,
             title='Big problÈm!',
@@ -867,7 +866,7 @@ class PagureFlaskIssuestests(tests.Modeltests):
         self.assertIn('href="/test/issue/1"', tr_elements[2])
 
         # Modify the date of the first issue and try again
-        issue_one = pagure.lib.search_issues(self.session, repo, 1)
+        issue_one = pagure.lib.query.search_issues(self.session, repo, 1)
         issue_one.last_updated = datetime.utcnow() + timedelta(seconds=2)
         self.session.add(issue_one)
         self.session.commit()
@@ -1003,7 +1002,7 @@ class PagureFlaskIssuestests(tests.Modeltests):
             output.get_data(as_text=True))
 
         # Project w/o issue tracker
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
         repo.settings = {'issue_tracker': False}
         self.session.add(repo)
         self.session.commit()
@@ -1031,10 +1030,10 @@ class PagureFlaskIssuestests(tests.Modeltests):
         tests.create_projects_git(
             os.path.join(self.path, 'repos'), bare=True)
 
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
 
         # Create 2 issues to play with
-        msg = pagure.lib.new_issue(
+        msg = pagure.lib.query.new_issue(
             session=self.session,
             repo=repo,
             title='Test issue ☃',
@@ -1044,7 +1043,7 @@ class PagureFlaskIssuestests(tests.Modeltests):
         self.session.commit()
         self.assertEqual(msg.title, 'Test issue ☃')
 
-        msg = pagure.lib.new_issue(
+        msg = pagure.lib.query.new_issue(
             session=self.session,
             repo=repo,
             title='Test issue with milestone',
@@ -1084,7 +1083,7 @@ class PagureFlaskIssuestests(tests.Modeltests):
             os.path.join(self.path, 'repos'), bare=True)
 
         # Add milestones to the project
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
         milestones = {
             'v1.0': {'date': None, 'active': True},
             'v2.0': {'date': 'in the future', 'active': True},
@@ -1093,8 +1092,8 @@ class PagureFlaskIssuestests(tests.Modeltests):
         repo.milestones_keys = ['', 'v1.0', 'v2.0']
 
         # Create issues to play with
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        msg = pagure.lib.new_issue(
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        msg = pagure.lib.query.new_issue(
             session=self.session,
             repo=repo,
             title='Test issue',
@@ -1134,8 +1133,8 @@ class PagureFlaskIssuestests(tests.Modeltests):
         self.assertEqual(output.status_code, 404)
 
         # Create issues to play with
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        msg = pagure.lib.new_issue(
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        msg = pagure.lib.query.new_issue(
             session=self.session,
             repo=repo,
             title='Test issue',
@@ -1199,8 +1198,8 @@ class PagureFlaskIssuestests(tests.Modeltests):
             csrf_token = self.get_csrf(output=output)
 
         # Create private issue
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        msg = pagure.lib.new_issue(
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        msg = pagure.lib.query.new_issue(
             session=self.session,
             repo=repo,
             title='Test issue',
@@ -1239,7 +1238,7 @@ class PagureFlaskIssuestests(tests.Modeltests):
                 output_text)
 
         # Project w/o issue tracker
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
         repo.settings = {'issue_tracker': False}
         self.session.add(repo)
         self.session.commit()
@@ -1256,8 +1255,8 @@ class PagureFlaskIssuestests(tests.Modeltests):
             os.path.join(self.path, 'repos'), bare=True)
 
         # Create issues to play with
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        msg = pagure.lib.new_issue(
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        msg = pagure.lib.query.new_issue(
             session=self.session,
             repo=repo,
             title='Test issue',
@@ -1334,8 +1333,8 @@ class PagureFlaskIssuestests(tests.Modeltests):
         self.assertEqual(output.status_code, 404)
 
         # Create issues to play with
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        msg = pagure.lib.new_issue(
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        msg = pagure.lib.query.new_issue(
             session=self.session,
             repo=repo,
             title='Test issue',
@@ -1359,10 +1358,10 @@ class PagureFlaskIssuestests(tests.Modeltests):
             in output_text)
 
         # Create issues to play with
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
 
         # Add user 'foo' with ticket access on repo
-        msg = pagure.lib.add_user_to_project(
+        msg = pagure.lib.query.add_user_to_project(
             self.session,
             repo,
             new_user='foo',
@@ -1414,8 +1413,8 @@ class PagureFlaskIssuestests(tests.Modeltests):
         self.assertEqual(output.status_code, 404)
 
         # Create issues to play with
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        msg = pagure.lib.new_issue(
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        msg = pagure.lib.query.new_issue(
             session=self.session,
             repo=repo,
             title='Test issue',
@@ -1426,8 +1425,8 @@ class PagureFlaskIssuestests(tests.Modeltests):
         self.assertEqual(msg.title, 'Test issue')
 
         # Add user 'foo' with ticket access on repo
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        msg = pagure.lib.add_user_to_project(
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        msg = pagure.lib.query.add_user_to_project(
             self.session,
             repo,
             new_user='foo',
@@ -1438,8 +1437,8 @@ class PagureFlaskIssuestests(tests.Modeltests):
         self.session.commit()
 
         # Set some custom fields
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        msg = pagure.lib.set_custom_key_fields(
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        msg = pagure.lib.query.set_custom_key_fields(
             self.session,
             repo,
             ['bugzilla', 'upstream', 'reviewstatus'],
@@ -1538,8 +1537,8 @@ class PagureFlaskIssuestests(tests.Modeltests):
 
         stone = 'käpy'
         # Create issues to play with
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        msg = pagure.lib.new_issue(
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        msg = pagure.lib.query.new_issue(
             session=self.session,
             repo=repo,
             title='Test issue',
@@ -1550,8 +1549,8 @@ class PagureFlaskIssuestests(tests.Modeltests):
         self.assertEqual(msg.title, 'Test issue')
 
         # Add a non-ascii milestone to the issue but project has no milestone
-        issue = pagure.lib.search_issues(self.session, repo, issueid=1)
-        message = pagure.lib.edit_issue(
+        issue = pagure.lib.query.search_issues(self.session, repo, issueid=1)
+        message = pagure.lib.query.edit_issue(
             self.session,
             issue=issue,
             milestone=stone,
@@ -1575,7 +1574,7 @@ class PagureFlaskIssuestests(tests.Modeltests):
         self.assertNotIn(stone, output_text)
 
         # Add a non-ascii milestone to the project
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
         repo.milestones = {'käpy': None}
         self.session.add(repo)
         self.session.commit()
@@ -1601,10 +1600,10 @@ class PagureFlaskIssuestests(tests.Modeltests):
         tests.create_projects_git(
             os.path.join(self.path, 'repos'), bare=True)
 
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
 
         # Add custom fields to the project
-        msg = pagure.lib.set_custom_key_fields(
+        msg = pagure.lib.query.set_custom_key_fields(
             session=self.session,
             project=repo,
             fields=['test1'],
@@ -1616,7 +1615,7 @@ class PagureFlaskIssuestests(tests.Modeltests):
         self.assertEqual(msg, 'List of custom fields updated')
 
         # Create issues to play with
-        msg = pagure.lib.new_issue(
+        msg = pagure.lib.query.new_issue(
             session=self.session,
             repo=repo,
             title='Big problÈm!',
@@ -1627,11 +1626,11 @@ class PagureFlaskIssuestests(tests.Modeltests):
         self.assertEqual(msg.title, 'Big problÈm!')
 
         # Assign a value to the custom key on that ticket
-        cfield = pagure.lib.get_custom_key(
+        cfield = pagure.lib.query.get_custom_key(
             session=self.session,
             project=repo,
             keyname='test1')
-        msg = pagure.lib.set_custom_key_value(
+        msg = pagure.lib.query.set_custom_key_value(
             session=self.session,
             issue=msg,
             key=cfield,
@@ -1664,8 +1663,8 @@ class PagureFlaskIssuestests(tests.Modeltests):
         self.assertEqual(output.status_code, 302)
 
         # Create issues to play with
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        msg = pagure.lib.new_issue(
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        msg = pagure.lib.query.new_issue(
             session=self.session,
             repo=repo,
             title='Test issue',
@@ -1899,8 +1898,8 @@ class PagureFlaskIssuestests(tests.Modeltests):
                 in output_text)
 
         # Create another issue with a dependency
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        msg = pagure.lib.new_issue(
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        msg = pagure.lib.query.new_issue(
             session=self.session,
             repo=repo,
             title='Test issue',
@@ -1911,13 +1910,13 @@ class PagureFlaskIssuestests(tests.Modeltests):
         self.assertEqual(msg.title, 'Test issue')
 
         # Reset the status of the first issue
-        parent_issue = pagure.lib.search_issues(
+        parent_issue = pagure.lib.query.search_issues(
             self.session, repo, issueid=1)
         parent_issue.status = 'Open'
         self.session.add(parent_issue)
         # Add the dependency relationship
         self.session.add(parent_issue)
-        issue = pagure.lib.search_issues(self.session, repo, issueid=2)
+        issue = pagure.lib.query.search_issues(self.session, repo, issueid=2)
         issue.parents.append(parent_issue)
         self.session.add(issue)
         self.session.commit()
@@ -1945,8 +1944,8 @@ class PagureFlaskIssuestests(tests.Modeltests):
                 in output_text)
 
         # Create private issue
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        msg = pagure.lib.new_issue(
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        msg = pagure.lib.query.new_issue(
             session=self.session,
             repo=repo,
             title='Test issue',
@@ -1965,7 +1964,7 @@ class PagureFlaskIssuestests(tests.Modeltests):
             self.assertEqual(output.status_code, 403)
 
         # Project w/o issue tracker
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
         repo.settings = {'issue_tracker': False}
         self.session.add(repo)
         self.session.commit()
@@ -1987,8 +1986,8 @@ class PagureFlaskIssuestests(tests.Modeltests):
             os.path.join(self.path, 'repos'), bare=True)
 
         # Create issues to play with
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        msg = pagure.lib.new_issue(
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        msg = pagure.lib.query.new_issue(
             session=self.session,
             repo=repo,
             title='Test issue',
@@ -2039,8 +2038,8 @@ class PagureFlaskIssuestests(tests.Modeltests):
             self.assertEqual(
                 output_text.count('comment_body">'), 2)
 
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        issue = pagure.lib.search_issues(self.session, repo, issueid=1)
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        issue = pagure.lib.query.search_issues(self.session, repo, issueid=1)
         self.assertEqual(len(issue.comments), 1)
 
         data = {
@@ -2085,8 +2084,8 @@ class PagureFlaskIssuestests(tests.Modeltests):
             self.assertEqual(output.status_code, 404)
 
         self.session.commit()
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        issue = pagure.lib.search_issues(self.session, repo, issueid=1)
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        issue = pagure.lib.query.search_issues(self.session, repo, issueid=1)
         self.assertEqual(len(issue.comments), 0)
 
     @patch('pagure.lib.git.update_git')
@@ -2101,8 +2100,8 @@ class PagureFlaskIssuestests(tests.Modeltests):
             os.path.join(self.path, 'repos'), bare=True)
 
         # Create issues to play with
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        msg = pagure.lib.new_issue(
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        msg = pagure.lib.query.new_issue(
             session=self.session,
             repo=repo,
             title='Test issue',
@@ -2112,8 +2111,8 @@ class PagureFlaskIssuestests(tests.Modeltests):
         self.session.commit()
         self.assertEqual(msg.title, 'Test issue')
 
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        msg = pagure.lib.new_issue(
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        msg = pagure.lib.query.new_issue(
             session=self.session,
             repo=repo,
             title='Test issue #2',
@@ -2177,8 +2176,8 @@ class PagureFlaskIssuestests(tests.Modeltests):
                 'Successfully edited issue #1',
                 output_text)
 
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        issue = pagure.lib.search_issues(self.session, repo, issueid=1)
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        issue = pagure.lib.query.search_issues(self.session, repo, issueid=1)
         self.assertEqual(issue.depending_text, [2])
         self.assertEqual(issue.blocking_text, [])
 
@@ -2194,8 +2193,8 @@ class PagureFlaskIssuestests(tests.Modeltests):
             os.path.join(self.path, 'repos'), bare=True)
 
         # Create issues to play with
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        msg = pagure.lib.new_issue(
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        msg = pagure.lib.query.new_issue(
             session=self.session,
             repo=repo,
             title='Test issue',
@@ -2205,8 +2204,8 @@ class PagureFlaskIssuestests(tests.Modeltests):
         self.session.commit()
         self.assertEqual(msg.title, 'Test issue')
 
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        msg = pagure.lib.new_issue(
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        msg = pagure.lib.query.new_issue(
             session=self.session,
             repo=repo,
             title='Test issue #2',
@@ -2239,8 +2238,8 @@ class PagureFlaskIssuestests(tests.Modeltests):
                 '<title>Issue #1: Test issue - test - Pagure</title>',
                 output.get_data(as_text=True))
 
-            repo = pagure.lib.get_authorized_project(self.session, 'test')
-            issue = pagure.lib.search_issues(self.session, repo, issueid=1)
+            repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+            issue = pagure.lib.query.search_issues(self.session, repo, issueid=1)
             self.assertEqual(issue.depending_text, [])
             self.assertEqual(issue.blocking_text, [])
 
@@ -2299,8 +2298,8 @@ class PagureFlaskIssuestests(tests.Modeltests):
                 output_text)
 
         self.session.commit()
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        issue = pagure.lib.search_issues(self.session, repo, issueid=1)
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        issue = pagure.lib.query.search_issues(self.session, repo, issueid=1)
         self.assertEqual(issue.depending_text, [])
         self.assertEqual(issue.blocking_text, [2])
 
@@ -2318,8 +2317,8 @@ class PagureFlaskIssuestests(tests.Modeltests):
             os.path.join(self.path, 'repos', 'tickets'), bare=True)
 
         # Create issues to play with
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        msg = pagure.lib.new_issue(
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        msg = pagure.lib.query.new_issue(
             session=self.session,
             repo=repo,
             title='Test issue',
@@ -2388,7 +2387,7 @@ class PagureFlaskIssuestests(tests.Modeltests):
             self.assertDictEqual(json_data, exp)
 
         # Project w/o issue tracker
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
         repo.settings = {'issue_tracker': False}
         self.session.add(repo)
         self.session.commit()
@@ -2414,8 +2413,8 @@ class PagureFlaskIssuestests(tests.Modeltests):
             os.path.join(self.path, 'tickets'), bare=True)
 
         # Create issues to play with
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        msg = pagure.lib.new_issue(
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        msg = pagure.lib.query.new_issue(
             session=self.session,
             repo=repo,
             title='Test issue',
@@ -2465,8 +2464,8 @@ class PagureFlaskIssuestests(tests.Modeltests):
             os.path.join(self.path, 'tickets'), bare=True)
 
         # Create issues to play with
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        msg = pagure.lib.new_issue(
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        msg = pagure.lib.query.new_issue(
             session=self.session,
             repo=repo,
             title='Test issue',
@@ -2521,8 +2520,8 @@ class PagureFlaskIssuestests(tests.Modeltests):
             os.path.join(self.path, 'tickets'), bare=True)
 
         # Create issues to play with
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        msg = pagure.lib.new_issue(
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        msg = pagure.lib.query.new_issue(
             session=self.session,
             repo=repo,
             title='Test issue',
@@ -2544,7 +2543,7 @@ class PagureFlaskIssuestests(tests.Modeltests):
         self.assertEqual(output.status_code, 404)
 
         # Project w/o issue tracker
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
         repo.settings = {'issue_tracker': False}
         self.session.add(repo)
         self.session.commit()
@@ -2558,7 +2557,7 @@ class PagureFlaskIssuestests(tests.Modeltests):
         self.test_upload_issue()
 
         # Project w/ issue tracker
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
         repo.settings = {'issue_tracker': True}
         self.session.add(repo)
         self.session.commit()
@@ -2579,7 +2578,7 @@ class PagureFlaskIssuestests(tests.Modeltests):
         self.assertEqual(output.status_code, 200)
 
         # Project w/o issue tracker
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
         repo.settings = {'issue_tracker': False}
         self.session.add(repo)
         self.session.commit()
@@ -2620,8 +2619,8 @@ class PagureFlaskIssuestests(tests.Modeltests):
             self.assertEqual(output.status_code, 404)
 
         # Create issues to play with
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        msg = pagure.lib.new_issue(
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        msg = pagure.lib.query.new_issue(
             session=self.session,
             repo=repo,
             title='Test issue',
@@ -2685,7 +2684,7 @@ class PagureFlaskIssuestests(tests.Modeltests):
                 '<p>We should work on this!</p>'), 1)
 
         # Project w/o issue tracker
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
         repo.settings = {'issue_tracker': False}
         self.session.add(repo)
         self.session.commit()
@@ -2705,8 +2704,8 @@ class PagureFlaskIssuestests(tests.Modeltests):
             os.path.join(self.path, 'repos'), bare=True)
 
         # Create an issue to play with
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        msg = pagure.lib.new_issue(
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        msg = pagure.lib.query.new_issue(
             session=self.session,
             repo=repo,
             title='Test issue',
@@ -2774,8 +2773,8 @@ class PagureFlaskIssuestests(tests.Modeltests):
         self.assertEqual(output.status_code, 302)
 
         # Create issues to play with
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        msg = pagure.lib.new_issue(
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        msg = pagure.lib.query.new_issue(
             session=self.session,
             repo=repo,
             title='Test issue',
@@ -2786,8 +2785,8 @@ class PagureFlaskIssuestests(tests.Modeltests):
         self.assertEqual(msg.title, 'Test issue')
 
         # Add a tag to the issue
-        issue = pagure.lib.search_issues(self.session, repo, issueid=1)
-        msg = pagure.lib.add_tag_obj(
+        issue = pagure.lib.query.search_issues(self.session, repo, issueid=1)
+        msg = pagure.lib.query.add_tag_obj(
             session=self.session,
             obj=issue,
             tags='tag1',
@@ -2797,7 +2796,7 @@ class PagureFlaskIssuestests(tests.Modeltests):
         self.assertEqual(msg, 'Issue tagged with: tag1')
 
         # Before edit, list tags
-        tags = pagure.lib.get_tags_of_project(self.session, repo)
+        tags = pagure.lib.query.get_tags_of_project(self.session, repo)
         self.assertEqual([tag.tag for tag in tags], ['tag1'])
 
         # Edit tag
@@ -2848,7 +2847,7 @@ class PagureFlaskIssuestests(tests.Modeltests):
 
         # After edit, list tags
         self.session.commit()
-        tags = pagure.lib.get_tags_of_project(self.session, repo)
+        tags = pagure.lib.query.get_tags_of_project(self.session, repo)
         self.assertEqual([tag.tag for tag in tags], ['tag2'])
 
     @patch('pagure.lib.git.update_git')
@@ -2878,8 +2877,8 @@ class PagureFlaskIssuestests(tests.Modeltests):
         self.assertEqual(output.status_code, 302)
 
         # Create issues to play with
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        msg = pagure.lib.new_issue(
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        msg = pagure.lib.query.new_issue(
             session=self.session,
             repo=repo,
             title='Test issue',
@@ -2890,8 +2889,8 @@ class PagureFlaskIssuestests(tests.Modeltests):
         self.assertEqual(msg.title, 'Test issue')
 
         # Add a tag to the issue
-        issue = pagure.lib.search_issues(self.session, repo, issueid=1)
-        msg = pagure.lib.add_tag_obj(
+        issue = pagure.lib.query.search_issues(self.session, repo, issueid=1)
+        msg = pagure.lib.query.add_tag_obj(
             session=self.session,
             obj=issue,
             tags='tag1',
@@ -2901,7 +2900,7 @@ class PagureFlaskIssuestests(tests.Modeltests):
         self.assertEqual(msg, 'Issue tagged with: tag1')
 
         # Before edit, list tags
-        tags = pagure.lib.get_tags_of_project(self.session, repo)
+        tags = pagure.lib.query.get_tags_of_project(self.session, repo)
         self.assertEqual([tag.tag for tag in tags], ['tag1'])
 
         # Edit tag
@@ -2953,8 +2952,8 @@ class PagureFlaskIssuestests(tests.Modeltests):
         tests.create_projects_git(os.path.join(self.path, 'tickets'))
 
         # Create issues to play with
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        msg = pagure.lib.new_issue(
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        msg = pagure.lib.query.new_issue(
             session=self.session,
             repo=repo,
             title='Test issue',
@@ -3012,7 +3011,7 @@ class PagureFlaskIssuestests(tests.Modeltests):
                 output_text)
 
         # Project w/o issue tracker
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
         repo.settings = {'issue_tracker': False}
         self.session.add(repo)
         self.session.commit()
@@ -3034,8 +3033,8 @@ class PagureFlaskIssuestests(tests.Modeltests):
             os.path.join(self.path, 'repos'), bare=True)
 
         # Create issues to play with
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        msg = pagure.lib.new_issue(
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        msg = pagure.lib.query.new_issue(
             session=self.session,
             repo=repo,
             title='Test issue',
@@ -3086,8 +3085,8 @@ class PagureFlaskIssuestests(tests.Modeltests):
             self.assertEqual(
                 output_text.count('comment_body">'), 2)
 
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        issue = pagure.lib.search_issues(self.session, repo, issueid=1)
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        issue = pagure.lib.query.search_issues(self.session, repo, issueid=1)
         self.assertEqual(len(issue.comments), 1)
         self.assertEqual(
             issue.comments[0].comment,
@@ -3131,8 +3130,8 @@ class PagureFlaskIssuestests(tests.Modeltests):
                 output_text)
 
         self.session.commit()
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        issue = pagure.lib.search_issues(self.session, repo, issueid=1)
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        issue = pagure.lib.query.search_issues(self.session, repo, issueid=1)
         self.assertEqual(len(issue.comments), 1)
         self.assertEqual(issue.comments[0].comment, 'Updated comment')
 
@@ -3171,14 +3170,14 @@ class PagureFlaskIssuestests(tests.Modeltests):
                 output_text)
 
         self.session.commit()
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        issue = pagure.lib.search_issues(self.session, repo, issueid=1)
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        issue = pagure.lib.query.search_issues(self.session, repo, issueid=1)
         self.assertEqual(len(issue.comments), 1)
         self.assertEqual(issue.comments[0].comment, 'Second update')
 
         # Create another issue from someone else
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        msg = pagure.lib.new_issue(
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        msg = pagure.lib.query.new_issue(
             session=self.session,
             repo=repo,
             title='Test issue',
@@ -3188,11 +3187,11 @@ class PagureFlaskIssuestests(tests.Modeltests):
         self.session.commit()
         self.assertEqual(msg.title, 'Test issue')
 
-        issue = pagure.lib.search_issues(self.session, repo, issueid=1)
+        issue = pagure.lib.query.search_issues(self.session, repo, issueid=1)
         self.assertEqual(len(issue.comments), 1)
         self.assertEqual(issue.status, 'Open')
 
-        issue = pagure.lib.search_issues(self.session, repo, issueid=2)
+        issue = pagure.lib.query.search_issues(self.session, repo, issueid=2)
         self.assertEqual(len(issue.comments), 0)
         self.assertEqual(issue.status, 'Open')
 
@@ -3261,12 +3260,12 @@ class PagureFlaskIssuestests(tests.Modeltests):
 
         # Ticket #1 has one more comment and is still open
         self.session.commit()
-        issue = pagure.lib.search_issues(self.session, repo, issueid=1)
+        issue = pagure.lib.query.search_issues(self.session, repo, issueid=1)
         self.assertEqual(len(issue.comments), 2)
         self.assertEqual(issue.status, 'Open')
 
         # Ticket #2 has one less comment and is closed
-        issue = pagure.lib.search_issues(self.session, repo, issueid=2)
+        issue = pagure.lib.query.search_issues(self.session, repo, issueid=2)
         self.assertEqual(len(issue.comments), 2)
         self.assertEqual(
             issue.comments[0].comment,
@@ -3292,10 +3291,10 @@ class PagureFlaskIssuestests(tests.Modeltests):
         user = tests.FakeUser()
         user.username = 'pingou'
 
-        repo = pagure.lib._get_project(self.session, 'test')
-        pagure.lib.update_read_only_mode(self.session, repo, read_only=False)
-        pingou = pagure.lib.get_user(self.session, 'pingou')
-        pagure.lib.add_sshkey_to_project_or_user(
+        repo = pagure.lib.query._get_project(self.session, 'test')
+        pagure.lib.query.update_read_only_mode(self.session, repo, read_only=False)
+        pingou = pagure.lib.query.get_user(self.session, 'pingou')
+        pagure.lib.query.add_sshkey_to_project_or_user(
             session=self.session,
             user=pingou,
             ssh_key='ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQDAzBMSIlvPRaEiLOTVInErkRIw9CzQQcnslDekAn1jFnGf+SNa1acvbTiATbCX71AA03giKrPxPH79dxcC7aDXerc6zRcKjJs6MAL9PrCjnbyxCKXRNNZU5U9X/DLaaL1b3caB+WD6OoorhS3LTEtKPX8xyjOzhf3OQSzNjhJp5Q==',
@@ -3311,7 +3310,7 @@ class PagureFlaskIssuestests(tests.Modeltests):
                 output.get_data(as_text=True))
 
             # Project w/o issue tracker
-            repo = pagure.lib.get_authorized_project(self.session, 'test')
+            repo = pagure.lib.query.get_authorized_project(self.session, 'test')
             repo.settings = {'issue_tracker': True}
             self.session.add(repo)
             self.session.commit()
@@ -3352,8 +3351,8 @@ class PagureFlaskIssuestests(tests.Modeltests):
         self.assertEqual(output.status_code, 302)
 
         # Create issues to play with
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        msg = pagure.lib.new_issue(
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        msg = pagure.lib.query.new_issue(
             session=self.session,
             repo=repo,
             title='Test issue',
@@ -3364,7 +3363,7 @@ class PagureFlaskIssuestests(tests.Modeltests):
         self.assertEqual(msg.title, 'Test issue')
 
          # Before update, list tags
-        tags = pagure.lib.get_tags_of_project(self.session, repo)
+        tags = pagure.lib.query.get_tags_of_project(self.session, repo)
         self.assertEqual([tag.tag for tag in tags], [])
 
         user.username = 'pingou'
@@ -3618,7 +3617,7 @@ class PagureFlaskIssuestests(tests.Modeltests):
                 output_text)
 
         # After update, list tags
-        tags = pagure.lib.get_tags_of_project(self.session, repo)
+        tags = pagure.lib.query.get_tags_of_project(self.session, repo)
         self.assertEqual(
             sorted([tag.tag for tag in tags]),
             ['blue', 'green', 'red', 'red1', 'red2', 'red3'])
@@ -3634,8 +3633,8 @@ class PagureFlaskIssuestests(tests.Modeltests):
         tests.create_projects_git(os.path.join(self.path, 'repos'))
 
         # Create issues to play with
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        msg = pagure.lib.new_issue(
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        msg = pagure.lib.query.new_issue(
             session=self.session,
             repo=repo,
             title='Test issue',
@@ -3646,7 +3645,7 @@ class PagureFlaskIssuestests(tests.Modeltests):
         self.assertEqual(msg.title, 'Test issue')
 
          # Before update, list tags
-        tags = pagure.lib.get_tags_of_project(self.session, repo)
+        tags = pagure.lib.query.get_tags_of_project(self.session, repo)
         self.assertEqual([tag.tag for tag in tags], [])
 
         user = tests.FakeUser()
@@ -3681,7 +3680,7 @@ class PagureFlaskIssuestests(tests.Modeltests):
                 output_text)
 
         # After update, list tags
-        tags = pagure.lib.get_tags_of_project(self.session, repo)
+        tags = pagure.lib.query.get_tags_of_project(self.session, repo)
         self.assertEqual(sorted([tag.tag for tag in tags]), ['is:red2'])
 
     @patch('pagure.lib.git.update_git')
@@ -3705,7 +3704,7 @@ class PagureFlaskIssuestests(tests.Modeltests):
             bare=True)
 
         # Create 2 issues
-        iss = pagure.lib.new_issue(
+        iss = pagure.lib.query.new_issue(
             issue_id=1,
             session=self.session,
             repo=item,
@@ -3718,7 +3717,7 @@ class PagureFlaskIssuestests(tests.Modeltests):
         self.assertEqual(iss.title, 'test issue')
         self.assertEqual(iss.project.fullname, 'ns/test3')
 
-        iss = pagure.lib.new_issue(
+        iss = pagure.lib.query.new_issue(
             issue_id=2,
             session=self.session,
             repo=item,
@@ -3785,7 +3784,7 @@ class PagureFlaskIssuestests(tests.Modeltests):
             bare=True)
 
         # Create 2 issues
-        iss = pagure.lib.new_issue(
+        iss = pagure.lib.query.new_issue(
             issue_id=1,
             session=self.session,
             repo=item,
@@ -3798,7 +3797,7 @@ class PagureFlaskIssuestests(tests.Modeltests):
         self.assertEqual(iss.title, 'test issue')
         self.assertEqual(iss.project.fullname, 'forks/pingou/ns/test3')
 
-        iss = pagure.lib.new_issue(
+        iss = pagure.lib.query.new_issue(
             issue_id=2,
             session=self.session,
             repo=item,
@@ -3840,8 +3839,8 @@ class PagureFlaskIssuestests(tests.Modeltests):
             os.path.join(self.path, 'repos'), bare=True)
 
         # Create issues to play with
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        msg = pagure.lib.new_issue(
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        msg = pagure.lib.query.new_issue(
             session=self.session,
             repo=repo,
             title='Test issue',
@@ -3906,8 +3905,8 @@ class PagureFlaskIssuestests(tests.Modeltests):
             default_email='jdoe@example.com',
         ))
         self.session.commit()
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        msg = pagure.lib.new_issue(
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        msg = pagure.lib.query.new_issue(
             session=self.session,
             repo=repo,
             title='Test issue',
@@ -3915,7 +3914,7 @@ class PagureFlaskIssuestests(tests.Modeltests):
             user='pingou',
             private=private,
         )
-        pagure.lib.add_issue_comment(
+        pagure.lib.query.add_issue_comment(
             session=self.session,
             issue=msg,
             comment='How about no',

+ 43 - 43
tests/test_pagure_flask_ui_issues_acl_checks.py

@@ -33,7 +33,7 @@ sys.path.insert(0, os.path.join(os.path.dirname(
     os.path.abspath(__file__)), '..'))
 
 import pagure.config
-import pagure.lib
+import pagure.lib.query
 import tests
 
 
@@ -58,8 +58,8 @@ class PagureFlaskIssuesACLtests(tests.Modeltests):
         self.assertEqual(output.status_code, 404)
 
         # Create issues to play with
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        msg = pagure.lib.new_issue(
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        msg = pagure.lib.query.new_issue(
             session=self.session,
             repo=repo,
             title='Test issue',
@@ -73,13 +73,13 @@ class PagureFlaskIssuesACLtests(tests.Modeltests):
         # Add milestone
         repo.milestones = {'77': None}
         self.session.add(repo)
-        issue = pagure.lib.search_issues(
+        issue = pagure.lib.query.search_issues(
             self.session,
             repo=repo,
             issueid=1
         )
 
-        pagure.lib.edit_issue(
+        pagure.lib.query.edit_issue(
             self.session,
             issue,
             user='pingou',
@@ -88,7 +88,7 @@ class PagureFlaskIssuesACLtests(tests.Modeltests):
         self.session.add(repo)
         self.session.add(issue)
 
-        msg = pagure.lib.set_custom_key_fields(
+        msg = pagure.lib.query.set_custom_key_fields(
             self.session,
             project=repo,
             fields=['abc', 'xyz'],
@@ -98,10 +98,10 @@ class PagureFlaskIssuesACLtests(tests.Modeltests):
         self.assertEqual(msg, 'List of custom fields updated')
         self.session.add(repo)
 
-        msg = pagure.lib.set_custom_key_value(
+        msg = pagure.lib.query.set_custom_key_value(
             self.session,
             issue=issue,
-            key=pagure.lib.get_custom_key(self.session, repo, 'abc'),
+            key=pagure.lib.query.get_custom_key(self.session, repo, 'abc'),
             value=1
         )
         self.session.add(issue)
@@ -242,8 +242,8 @@ class PagureFlaskIssuesACLtests(tests.Modeltests):
                 output_text)
 
         # Create private issue
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        msg = pagure.lib.new_issue(
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        msg = pagure.lib.query.new_issue(
             session=self.session,
             repo=repo,
             title='Test issue',
@@ -299,10 +299,10 @@ class PagureFlaskIssuesACLtests(tests.Modeltests):
         self.assertEqual(output.status_code, 404)
 
         # Create issues to play with
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
 
         # Add user 'foo' with ticket access on repo
-        msg = pagure.lib.add_user_to_project(
+        msg = pagure.lib.query.add_user_to_project(
             self.session,
             repo,
             new_user='foo',
@@ -312,8 +312,8 @@ class PagureFlaskIssuesACLtests(tests.Modeltests):
         self.assertEqual(msg, 'User added')
         self.session.commit()
 
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        msg = pagure.lib.new_issue(
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        msg = pagure.lib.query.new_issue(
             session=self.session,
             repo=repo,
             title='Test issue',
@@ -327,13 +327,13 @@ class PagureFlaskIssuesACLtests(tests.Modeltests):
         # Add milestone
         repo.milestones = {'77': None}
         self.session.add(repo)
-        issue = pagure.lib.search_issues(
+        issue = pagure.lib.query.search_issues(
             self.session,
             repo=repo,
             issueid=1
         )
 
-        pagure.lib.edit_issue(
+        pagure.lib.query.edit_issue(
             self.session,
             issue,
             user='pingou',
@@ -342,7 +342,7 @@ class PagureFlaskIssuesACLtests(tests.Modeltests):
         self.session.add(repo)
         self.session.add(issue)
 
-        msg = pagure.lib.set_custom_key_fields(
+        msg = pagure.lib.query.set_custom_key_fields(
             self.session,
             project=repo,
             fields=['abc', 'xyz'],
@@ -352,10 +352,10 @@ class PagureFlaskIssuesACLtests(tests.Modeltests):
         self.assertEqual(msg, 'List of custom fields updated')
         self.session.add(repo)
 
-        msg = pagure.lib.set_custom_key_value(
+        msg = pagure.lib.query.set_custom_key_value(
             self.session,
             issue=issue,
-            key=pagure.lib.get_custom_key(self.session, repo, 'abc'),
+            key=pagure.lib.query.get_custom_key(self.session, repo, 'abc'),
             value=1
         )
         self.session.add(issue)
@@ -497,8 +497,8 @@ class PagureFlaskIssuesACLtests(tests.Modeltests):
                 output_text)
 
         # Create private issue
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        msg = pagure.lib.new_issue(
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        msg = pagure.lib.query.new_issue(
             session=self.session,
             repo=repo,
             title='Test issue',
@@ -554,10 +554,10 @@ class PagureFlaskIssuesACLtests(tests.Modeltests):
         self.assertEqual(output.status_code, 404)
 
         # Create issues to play with
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
 
         # Add user 'foo' with ticket access on repo
-        msg = pagure.lib.add_user_to_project(
+        msg = pagure.lib.query.add_user_to_project(
             self.session,
             repo,
             new_user='foo',
@@ -567,8 +567,8 @@ class PagureFlaskIssuesACLtests(tests.Modeltests):
         self.assertEqual(msg, 'User added')
         self.session.commit()
 
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        msg = pagure.lib.new_issue(
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        msg = pagure.lib.query.new_issue(
             session=self.session,
             repo=repo,
             title='Test issue',
@@ -582,13 +582,13 @@ class PagureFlaskIssuesACLtests(tests.Modeltests):
         # Add milestone
         repo.milestones = {'77': None}
         self.session.add(repo)
-        issue = pagure.lib.search_issues(
+        issue = pagure.lib.query.search_issues(
             self.session,
             repo=repo,
             issueid=1
         )
 
-        pagure.lib.edit_issue(
+        pagure.lib.query.edit_issue(
             self.session,
             issue,
             user='pingou',
@@ -597,7 +597,7 @@ class PagureFlaskIssuesACLtests(tests.Modeltests):
         self.session.add(repo)
         self.session.add(issue)
 
-        msg = pagure.lib.set_custom_key_fields(
+        msg = pagure.lib.query.set_custom_key_fields(
             self.session,
             project=repo,
             fields=['abc', 'xyz'],
@@ -607,10 +607,10 @@ class PagureFlaskIssuesACLtests(tests.Modeltests):
         self.assertEqual(msg, 'List of custom fields updated')
         self.session.add(repo)
 
-        msg = pagure.lib.set_custom_key_value(
+        msg = pagure.lib.query.set_custom_key_value(
             self.session,
             issue=issue,
-            key=pagure.lib.get_custom_key(self.session, repo, 'abc'),
+            key=pagure.lib.query.get_custom_key(self.session, repo, 'abc'),
             value=1
         )
         self.session.add(issue)
@@ -750,8 +750,8 @@ class PagureFlaskIssuesACLtests(tests.Modeltests):
                 output_text)
 
         # Create private issue
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        msg = pagure.lib.new_issue(
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        msg = pagure.lib.query.new_issue(
             session=self.session,
             repo=repo,
             title='Test issue',
@@ -807,10 +807,10 @@ class PagureFlaskIssuesACLtests(tests.Modeltests):
         self.assertEqual(output.status_code, 404)
 
         # Create issues to play with
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
 
         # Add user 'foo' with ticket access on repo
-        msg = pagure.lib.add_user_to_project(
+        msg = pagure.lib.query.add_user_to_project(
             self.session,
             repo,
             new_user='foo',
@@ -820,8 +820,8 @@ class PagureFlaskIssuesACLtests(tests.Modeltests):
         self.assertEqual(msg, 'User added')
         self.session.commit()
 
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        msg = pagure.lib.new_issue(
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        msg = pagure.lib.query.new_issue(
             session=self.session,
             repo=repo,
             title='Test issue',
@@ -835,13 +835,13 @@ class PagureFlaskIssuesACLtests(tests.Modeltests):
         # Add milestone
         repo.milestones = {'77': None}
         self.session.add(repo)
-        issue = pagure.lib.search_issues(
+        issue = pagure.lib.query.search_issues(
             self.session,
             repo=repo,
             issueid=1
         )
 
-        pagure.lib.edit_issue(
+        pagure.lib.query.edit_issue(
             self.session,
             issue,
             user='pingou',
@@ -850,7 +850,7 @@ class PagureFlaskIssuesACLtests(tests.Modeltests):
         self.session.add(repo)
         self.session.add(issue)
 
-        msg = pagure.lib.set_custom_key_fields(
+        msg = pagure.lib.query.set_custom_key_fields(
             self.session,
             project=repo,
             fields=['abc', 'xyz'],
@@ -860,10 +860,10 @@ class PagureFlaskIssuesACLtests(tests.Modeltests):
         self.assertEqual(msg, 'List of custom fields updated')
         self.session.add(repo)
 
-        msg = pagure.lib.set_custom_key_value(
+        msg = pagure.lib.query.set_custom_key_value(
             self.session,
             issue=issue,
-            key=pagure.lib.get_custom_key(self.session, repo, 'abc'),
+            key=pagure.lib.query.get_custom_key(self.session, repo, 'abc'),
             value=1
         )
         self.session.add(issue)
@@ -1001,8 +1001,8 @@ class PagureFlaskIssuesACLtests(tests.Modeltests):
                 output_text)
 
         # Create private issue
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        msg = pagure.lib.new_issue(
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        msg = pagure.lib.query.new_issue(
             session=self.session,
             repo=repo,
             title='Test issue',

+ 65 - 65
tests/test_pagure_flask_ui_issues_open_access.py

@@ -37,7 +37,7 @@ sys.path.insert(0, os.path.join(os.path.dirname(
     os.path.abspath(__file__)), '..'))
 
 import pagure
-import pagure.lib
+import pagure.lib.query
 import tests
 
 
@@ -54,7 +54,7 @@ class PagureFlaskIssuesOpenAccesstests(tests.Modeltests):
         tests.create_projects_git(
             os.path.join(self.path, 'tickets'), bare=True)
 
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
         settings = repo.settings
         settings['open_metadata_access_to_all'] = True
         repo.settings = settings
@@ -180,8 +180,8 @@ class PagureFlaskIssuesOpenAccesstests(tests.Modeltests):
         self.assertEqual(output.status_code, 404)
 
         # Create issues to play with
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        msg = pagure.lib.new_issue(
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        msg = pagure.lib.query.new_issue(
             session=self.session,
             repo=repo,
             title='Test issue',
@@ -231,8 +231,8 @@ class PagureFlaskIssuesOpenAccesstests(tests.Modeltests):
             csrf_token = self.get_csrf(output=output)
 
         # Create private issue
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        msg = pagure.lib.new_issue(
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        msg = pagure.lib.query.new_issue(
             session=self.session,
             repo=repo,
             title='Test issue',
@@ -260,7 +260,7 @@ class PagureFlaskIssuesOpenAccesstests(tests.Modeltests):
             self.assertEqual(output.status_code, 404)
 
         # Project w/o issue tracker
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
         repo.settings = {'issue_tracker': False}
         self.session.add(repo)
         self.session.commit()
@@ -277,8 +277,8 @@ class PagureFlaskIssuesOpenAccesstests(tests.Modeltests):
         self.assertEqual(output.status_code, 404)
 
         # Create issues to play with
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        msg = pagure.lib.new_issue(
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        msg = pagure.lib.query.new_issue(
             session=self.session,
             repo=repo,
             title='Test issue',
@@ -302,10 +302,10 @@ class PagureFlaskIssuesOpenAccesstests(tests.Modeltests):
             in output_text)
 
         # Create issues to play with
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
 
         # Add user 'foo' with ticket access on repo
-        msg = pagure.lib.add_user_to_project(
+        msg = pagure.lib.query.add_user_to_project(
             self.session,
             repo,
             new_user='foo',
@@ -347,8 +347,8 @@ class PagureFlaskIssuesOpenAccesstests(tests.Modeltests):
         self.assertEqual(output.status_code, 404)
 
         # Create issues to play with
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        msg = pagure.lib.new_issue(
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        msg = pagure.lib.query.new_issue(
             session=self.session,
             repo=repo,
             title='Test issue',
@@ -359,8 +359,8 @@ class PagureFlaskIssuesOpenAccesstests(tests.Modeltests):
         self.assertEqual(msg.title, 'Test issue')
 
         # Add user 'foo' with ticket access on repo
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        msg = pagure.lib.add_user_to_project(
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        msg = pagure.lib.query.add_user_to_project(
             self.session,
             repo,
             new_user='foo',
@@ -371,8 +371,8 @@ class PagureFlaskIssuesOpenAccesstests(tests.Modeltests):
         self.session.commit()
 
         # Set some custom fields
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        msg = pagure.lib.set_custom_key_fields(
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        msg = pagure.lib.query.set_custom_key_fields(
             self.session,
             repo,
             ['bugzilla', 'upstream', 'reviewstatus'],
@@ -461,8 +461,8 @@ class PagureFlaskIssuesOpenAccesstests(tests.Modeltests):
 
         stone = 'käpy'
         # Create issues to play with
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        msg = pagure.lib.new_issue(
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        msg = pagure.lib.query.new_issue(
             session=self.session,
             repo=repo,
             title='Test issue',
@@ -473,8 +473,8 @@ class PagureFlaskIssuesOpenAccesstests(tests.Modeltests):
         self.assertEqual(msg.title, 'Test issue')
 
         # Add a non-ascii milestone to the issue but project has no milestone
-        issue = pagure.lib.search_issues(self.session, repo, issueid=1)
-        message = pagure.lib.edit_issue(
+        issue = pagure.lib.query.search_issues(self.session, repo, issueid=1)
+        message = pagure.lib.query.edit_issue(
             self.session,
             issue=issue,
             milestone=stone,
@@ -503,10 +503,10 @@ class PagureFlaskIssuesOpenAccesstests(tests.Modeltests):
     def test_view_issue_list_no_data(self):
         """ Test the view_issue endpoint when the issue has a custom field
         of type list with no data attached. """
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
 
         # Add custom fields to the project
-        msg = pagure.lib.set_custom_key_fields(
+        msg = pagure.lib.query.set_custom_key_fields(
             session=self.session,
             project=repo,
             fields=['test1'],
@@ -518,7 +518,7 @@ class PagureFlaskIssuesOpenAccesstests(tests.Modeltests):
         self.assertEqual(msg, 'List of custom fields updated')
 
         # Create issues to play with
-        msg = pagure.lib.new_issue(
+        msg = pagure.lib.query.new_issue(
             session=self.session,
             repo=repo,
             title='Big problÈm!',
@@ -529,11 +529,11 @@ class PagureFlaskIssuesOpenAccesstests(tests.Modeltests):
         self.assertEqual(msg.title, 'Big problÈm!')
 
         # Assign a value to the custom key on that ticket
-        cfield = pagure.lib.get_custom_key(
+        cfield = pagure.lib.query.get_custom_key(
             session=self.session,
             project=repo,
             keyname='test1')
-        msg = pagure.lib.set_custom_key_value(
+        msg = pagure.lib.query.set_custom_key_value(
             session=self.session,
             issue=msg,
             key=cfield,
@@ -554,8 +554,8 @@ class PagureFlaskIssuesOpenAccesstests(tests.Modeltests):
         self.assertEqual(output.status_code, 302)
 
         # Create issues to play with
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        msg = pagure.lib.new_issue(
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        msg = pagure.lib.query.new_issue(
             session=self.session,
             repo=repo,
             title='Test issue',
@@ -774,8 +774,8 @@ class PagureFlaskIssuesOpenAccesstests(tests.Modeltests):
                 output_text)
 
         # Create another issue with a dependency
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        msg = pagure.lib.new_issue(
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        msg = pagure.lib.query.new_issue(
             session=self.session,
             repo=repo,
             title='Test issue',
@@ -786,13 +786,13 @@ class PagureFlaskIssuesOpenAccesstests(tests.Modeltests):
         self.assertEqual(msg.title, 'Test issue')
 
         # Reset the status of the first issue
-        parent_issue = pagure.lib.search_issues(
+        parent_issue = pagure.lib.query.search_issues(
             self.session, repo, issueid=1)
         parent_issue.status = 'Open'
         self.session.add(parent_issue)
         # Add the dependency relationship
         self.session.add(parent_issue)
-        issue = pagure.lib.search_issues(self.session, repo, issueid=2)
+        issue = pagure.lib.query.search_issues(self.session, repo, issueid=2)
         issue.parents.append(parent_issue)
         self.session.add(issue)
         self.session.commit()
@@ -820,8 +820,8 @@ class PagureFlaskIssuesOpenAccesstests(tests.Modeltests):
                 output_text)
 
         # Create private issue
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        msg = pagure.lib.new_issue(
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        msg = pagure.lib.query.new_issue(
             session=self.session,
             repo=repo,
             title='Test issue',
@@ -840,7 +840,7 @@ class PagureFlaskIssuesOpenAccesstests(tests.Modeltests):
             self.assertEqual(output.status_code, 403)
 
         # Project w/o issue tracker
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
         repo.settings = {'issue_tracker': False}
         self.session.add(repo)
         self.session.commit()
@@ -855,8 +855,8 @@ class PagureFlaskIssuesOpenAccesstests(tests.Modeltests):
     def test_update_issue_depend(self):
         """ Test adding dependency via the update_issue endpoint. """
         # Create issues to play with
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        msg = pagure.lib.new_issue(
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        msg = pagure.lib.query.new_issue(
             session=self.session,
             repo=repo,
             title='Test issue',
@@ -866,8 +866,8 @@ class PagureFlaskIssuesOpenAccesstests(tests.Modeltests):
         self.session.commit()
         self.assertEqual(msg.title, 'Test issue')
 
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        msg = pagure.lib.new_issue(
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        msg = pagure.lib.query.new_issue(
             session=self.session,
             repo=repo,
             title='Test issue #2',
@@ -929,8 +929,8 @@ class PagureFlaskIssuesOpenAccesstests(tests.Modeltests):
                 'Successfully edited issue #1',
                 output_text)
 
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        issue = pagure.lib.search_issues(self.session, repo, issueid=1)
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        issue = pagure.lib.query.search_issues(self.session, repo, issueid=1)
         self.assertEqual(issue.depending_text, [2])
         self.assertEqual(issue.blocking_text, [])
 
@@ -939,8 +939,8 @@ class PagureFlaskIssuesOpenAccesstests(tests.Modeltests):
     def test_update_issue_block(self):
         """ Test adding blocked issue via the update_issue endpoint. """
         # Create issues to play with
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        msg = pagure.lib.new_issue(
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        msg = pagure.lib.query.new_issue(
             session=self.session,
             repo=repo,
             title='Test issue',
@@ -950,8 +950,8 @@ class PagureFlaskIssuesOpenAccesstests(tests.Modeltests):
         self.session.commit()
         self.assertEqual(msg.title, 'Test issue')
 
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        msg = pagure.lib.new_issue(
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        msg = pagure.lib.query.new_issue(
             session=self.session,
             repo=repo,
             title='Test issue #2',
@@ -984,8 +984,8 @@ class PagureFlaskIssuesOpenAccesstests(tests.Modeltests):
                 '<title>Issue #1: Test issue - test - Pagure</title>',
                 output.get_data(as_text=True))
 
-            repo = pagure.lib.get_authorized_project(self.session, 'test')
-            issue = pagure.lib.search_issues(self.session, repo, issueid=1)
+            repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+            issue = pagure.lib.query.search_issues(self.session, repo, issueid=1)
             self.assertEqual(issue.depending_text, [])
             self.assertEqual(issue.blocking_text, [2])
 
@@ -1010,8 +1010,8 @@ class PagureFlaskIssuesOpenAccesstests(tests.Modeltests):
                 output_text)
 
         self.session.commit()
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        issue = pagure.lib.search_issues(self.session, repo, issueid=1)
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        issue = pagure.lib.query.search_issues(self.session, repo, issueid=1)
         self.assertEqual(issue.depending_text, [])
         self.assertEqual(issue.blocking_text, [2])
 
@@ -1020,8 +1020,8 @@ class PagureFlaskIssuesOpenAccesstests(tests.Modeltests):
     def test_update_issue_edit_comment(self):
         """ Test the issues edit comment endpoint """
         # Create issues to play with
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        msg = pagure.lib.new_issue(
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        msg = pagure.lib.query.new_issue(
             session=self.session,
             repo=repo,
             title='Test issue',
@@ -1069,8 +1069,8 @@ class PagureFlaskIssuesOpenAccesstests(tests.Modeltests):
             self.assertEqual(
                 output_text.count('comment_body">'), 2)
 
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        issue = pagure.lib.search_issues(self.session, repo, issueid=1)
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        issue = pagure.lib.query.search_issues(self.session, repo, issueid=1)
         self.assertEqual(len(issue.comments), 1)
         self.assertEqual(
             issue.comments[0].comment,
@@ -1111,8 +1111,8 @@ class PagureFlaskIssuesOpenAccesstests(tests.Modeltests):
             self.assertIn('Comment updated', output_text)
 
         self.session.commit()
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        issue = pagure.lib.search_issues(self.session, repo, issueid=1)
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        issue = pagure.lib.query.search_issues(self.session, repo, issueid=1)
         self.assertEqual(len(issue.comments), 1)
         self.assertEqual(issue.comments[0].comment, 'Updated comment')
 
@@ -1149,14 +1149,14 @@ class PagureFlaskIssuesOpenAccesstests(tests.Modeltests):
             self.assertIn('Comment updated', output_text)
 
         self.session.commit()
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        issue = pagure.lib.search_issues(self.session, repo, issueid=1)
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        issue = pagure.lib.query.search_issues(self.session, repo, issueid=1)
         self.assertEqual(len(issue.comments), 1)
         self.assertEqual(issue.comments[0].comment, 'Second update')
 
         # Create another issue from someone else
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        msg = pagure.lib.new_issue(
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        msg = pagure.lib.query.new_issue(
             session=self.session,
             repo=repo,
             title='Test issue',
@@ -1166,11 +1166,11 @@ class PagureFlaskIssuesOpenAccesstests(tests.Modeltests):
         self.session.commit()
         self.assertEqual(msg.title, 'Test issue')
 
-        issue = pagure.lib.search_issues(self.session, repo, issueid=1)
+        issue = pagure.lib.query.search_issues(self.session, repo, issueid=1)
         self.assertEqual(len(issue.comments), 1)
         self.assertEqual(issue.status, 'Open')
 
-        issue = pagure.lib.search_issues(self.session, repo, issueid=2)
+        issue = pagure.lib.query.search_issues(self.session, repo, issueid=2)
         self.assertEqual(len(issue.comments), 0)
         self.assertEqual(issue.status, 'Open')
 
@@ -1227,12 +1227,12 @@ class PagureFlaskIssuesOpenAccesstests(tests.Modeltests):
 
         # Ticket #1 has one more comment and is still open
         self.session.commit()
-        issue = pagure.lib.search_issues(self.session, repo, issueid=1)
+        issue = pagure.lib.query.search_issues(self.session, repo, issueid=1)
         self.assertEqual(len(issue.comments), 2)
         self.assertEqual(issue.status, 'Open')
 
         # Ticket #2 has one less comment and is closed
-        issue = pagure.lib.search_issues(self.session, repo, issueid=2)
+        issue = pagure.lib.query.search_issues(self.session, repo, issueid=2)
         self.assertEqual(len(issue.comments), 2)
         self.assertEqual(
             issue.comments[0].comment,
@@ -1249,8 +1249,8 @@ class PagureFlaskIssuesOpenAccesstests(tests.Modeltests):
     def test_view_issue_closed(self):
         """ Test viewing a closed issue. """
         # Create issues to play with
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        msg = pagure.lib.new_issue(
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        msg = pagure.lib.query.new_issue(
             session=self.session,
             repo=repo,
             title='Test issue',

+ 16 - 17
tests/test_pagure_flask_ui_issues_private.py

@@ -19,8 +19,7 @@ from mock import patch, MagicMock
 sys.path.insert(0, os.path.join(os.path.dirname(
     os.path.abspath(__file__)), '..'))
 
-import pagure  # noqa
-import pagure.lib  # noqa
+import pagure.lib.query  # noqa
 import tests  # noqa
 
 
@@ -50,8 +49,8 @@ class PagureFlaskIssuesPrivatetests(tests.Modeltests):
         tests.create_projects(self.session)
         tests.create_projects_git(os.path.join(self.path, 'repos'))
 
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
-        msg = pagure.lib.new_issue(
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
+        msg = pagure.lib.query.new_issue(
             session=self.session,
             repo=repo,
             title='Test issue #1',
@@ -63,7 +62,7 @@ class PagureFlaskIssuesPrivatetests(tests.Modeltests):
         self.session.commit()
         self.assertEqual(msg.title, 'Test issue #1')
 
-        msg = pagure.lib.new_issue(
+        msg = pagure.lib.query.new_issue(
             session=self.session,
             repo=repo,
             title='Test issue #2',
@@ -133,8 +132,8 @@ class PagureFlaskIssuesPrivatetests(tests.Modeltests):
         """ Test the list of issues when user is authenticated but has
         ticket level access to the project.
         """
-        repo = pagure.lib._get_project(self.session, 'test')
-        msg = pagure.lib.add_user_to_project(
+        repo = pagure.lib.query._get_project(self.session, 'test')
+        msg = pagure.lib.query.add_user_to_project(
             session=self.session,
             project=repo,
             new_user='random',
@@ -158,8 +157,8 @@ class PagureFlaskIssuesPrivatetests(tests.Modeltests):
         """ Test the list of issues when user is authenticated but has
         commit level access to the project.
         """
-        repo = pagure.lib._get_project(self.session, 'test')
-        msg = pagure.lib.add_user_to_project(
+        repo = pagure.lib.query._get_project(self.session, 'test')
+        msg = pagure.lib.query.add_user_to_project(
             session=self.session,
             project=repo,
             new_user='random',
@@ -184,8 +183,8 @@ class PagureFlaskIssuesPrivatetests(tests.Modeltests):
         assigned to one of the issue.
         """
 
-        repo = pagure.lib._get_project(self.session, 'test')
-        issue = pagure.lib.search_issues(self.session, repo, issueid=1)
+        repo = pagure.lib.query._get_project(self.session, 'test')
+        issue = pagure.lib.query.search_issues(self.session, repo, issueid=1)
         issue.assignee_id = 3  # random
         self.session.add(issue)
         self.session.commit()
@@ -255,8 +254,8 @@ class PagureFlaskIssuesPrivatetests(tests.Modeltests):
         """ Test accessing a private ticket when user is authenticated and
         has ticket level access to the project.
         """
-        repo = pagure.lib._get_project(self.session, 'test')
-        msg = pagure.lib.add_user_to_project(
+        repo = pagure.lib.query._get_project(self.session, 'test')
+        msg = pagure.lib.query.add_user_to_project(
             session=self.session,
             project=repo,
             new_user='random',
@@ -275,8 +274,8 @@ class PagureFlaskIssuesPrivatetests(tests.Modeltests):
         """ Test accessing a private ticket when user is authenticated and
         has commit level access to the project.
         """
-        repo = pagure.lib._get_project(self.session, 'test')
-        msg = pagure.lib.add_user_to_project(
+        repo = pagure.lib.query._get_project(self.session, 'test')
+        msg = pagure.lib.query.add_user_to_project(
             session=self.session,
             project=repo,
             new_user='random',
@@ -304,8 +303,8 @@ class PagureFlaskIssuesPrivatetests(tests.Modeltests):
         is assigned to one of the issue.
         """
 
-        repo = pagure.lib._get_project(self.session, 'test')
-        issue = pagure.lib.search_issues(self.session, repo, issueid=1)
+        repo = pagure.lib.query._get_project(self.session, 'test')
+        issue = pagure.lib.query.search_issues(self.session, repo, issueid=1)
         issue.assignee_id = 3  # random
         self.session.add(issue)
         self.session.commit()

+ 7 - 8
tests/test_pagure_flask_ui_issues_read_only.py

@@ -20,8 +20,7 @@ from mock import patch, MagicMock
 sys.path.insert(0, os.path.join(os.path.dirname(
     os.path.abspath(__file__)), '..'))
 
-import pagure  # noqa
-import pagure.lib  # noqa
+import pagure.lib.query  # noqa
 import tests  # noqa
 
 
@@ -38,7 +37,7 @@ class PagureFlaskIssuesReadOnlytests(tests.Modeltests):
         tests.create_projects_git(os.path.join(self.path, 'repos'))
 
         # Make the project's issue tracker read-only
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
         settings = repo.settings
         settings['issue_tracker_read_only'] = True
         repo.settings = settings
@@ -46,7 +45,7 @@ class PagureFlaskIssuesReadOnlytests(tests.Modeltests):
         self.session.commit()
 
         # Create a couple of issue
-        msg = pagure.lib.new_issue(
+        msg = pagure.lib.query.new_issue(
             session=self.session,
             repo=repo,
             title='Test issue #1',
@@ -58,7 +57,7 @@ class PagureFlaskIssuesReadOnlytests(tests.Modeltests):
         self.session.commit()
         self.assertEqual(msg.title, 'Test issue #1')
 
-        msg = pagure.lib.new_issue(
+        msg = pagure.lib.query.new_issue(
             session=self.session,
             repo=repo,
             title='Test issue #2',
@@ -337,7 +336,7 @@ class PagureFlaskIssuesAndPRDisabledtests(tests.Modeltests):
         tests.create_projects_git(os.path.join(self.path, 'repos'))
 
         # Make the project's issue tracker read-only
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
         settings = repo.settings
         settings['pull_requests'] = False
         settings['issue_tracker_read_only'] = True
@@ -346,7 +345,7 @@ class PagureFlaskIssuesAndPRDisabledtests(tests.Modeltests):
         self.session.commit()
 
         # Create a couple of issue
-        msg = pagure.lib.new_issue(
+        msg = pagure.lib.query.new_issue(
             session=self.session,
             repo=repo,
             title='Test issue #1',
@@ -358,7 +357,7 @@ class PagureFlaskIssuesAndPRDisabledtests(tests.Modeltests):
         self.session.commit()
         self.assertEqual(msg.title, 'Test issue #1')
 
-        msg = pagure.lib.new_issue(
+        msg = pagure.lib.query.new_issue(
             session=self.session,
             repo=repo,
             title='Test issue #2',

+ 2 - 3
tests/test_pagure_flask_ui_issues_templates.py

@@ -24,8 +24,7 @@ from mock import patch, MagicMock
 sys.path.insert(0, os.path.join(os.path.dirname(
     os.path.abspath(__file__)), '..'))
 
-import pagure
-import pagure.lib
+import pagure.lib.query
 import tests
 
 
@@ -269,7 +268,7 @@ class PagureFlaskIssuesTemplatetests(tests.Modeltests):
         """ Test the get_ticket_template endpoint when the project has
         disabled its issue tracker.
         """
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
         settings = repo.settings
         settings['issue_tracker'] = False
         repo.settings = settings

+ 23 - 23
tests/test_pagure_flask_ui_login.py

@@ -31,7 +31,7 @@ from mock import patch, MagicMock
 sys.path.insert(0, os.path.join(os.path.dirname(
     os.path.abspath(__file__)), '..'))
 
-import pagure.lib
+import pagure.lib.query
 import tests
 from pagure.lib.repo import PagureRepo
 
@@ -68,7 +68,7 @@ class PagureFlaskLogintests(tests.SimplePagureTest):
         """ Test the new_user endpoint. """
 
         # Check before:
-        items = pagure.lib.search_user(self.session)
+        items = pagure.lib.query.search_user(self.session)
         self.assertEqual(2, len(items))
 
         # First access the new user page
@@ -125,7 +125,7 @@ class PagureFlaskLogintests(tests.SimplePagureTest):
             output.get_data(as_text=True))
 
         # Check after:
-        items = pagure.lib.search_user(self.session)
+        items = pagure.lib.query.search_user(self.session)
         self.assertEqual(3, len(items))
 
     @patch.dict('pagure.config.config', {'PAGURE_AUTH': 'local'})
@@ -168,7 +168,7 @@ class PagureFlaskLogintests(tests.SimplePagureTest):
         # Create a local user
         self.test_new_user()
 
-        items = pagure.lib.search_user(self.session)
+        items = pagure.lib.query.search_user(self.session)
         self.assertEqual(3, len(items))
 
         # Submit the form with the csrf token  -  but user not confirmed
@@ -204,7 +204,7 @@ class PagureFlaskLogintests(tests.SimplePagureTest):
 
         # Confirm the user so that we can log in
         self.session.commit()
-        item = pagure.lib.search_user(self.session, username='foouser')
+        item = pagure.lib.query.search_user(self.session, username='foouser')
         self.assertEqual(item.user, 'foouser')
         self.assertNotEqual(item.token, None)
 
@@ -214,7 +214,7 @@ class PagureFlaskLogintests(tests.SimplePagureTest):
         self.session.commit()
 
         # Check the user
-        item = pagure.lib.search_user(self.session, username='foouser')
+        item = pagure.lib.query.search_user(self.session, username='foouser')
         self.assertEqual(item.user, 'foouser')
         self.assertEqual(item.token, None)
 
@@ -246,7 +246,7 @@ class PagureFlaskLogintests(tests.SimplePagureTest):
 
         # Make the password invalid
         self.session.commit()
-        item = pagure.lib.search_user(self.session, username='foouser')
+        item = pagure.lib.query.search_user(self.session, username='foouser')
         self.assertEqual(item.user, 'foouser')
         self.assertTrue(item.password.startswith('$2$'))
 
@@ -257,7 +257,7 @@ class PagureFlaskLogintests(tests.SimplePagureTest):
 
         # Check the password
         self.session.commit()
-        item = pagure.lib.search_user(self.session, username='foouser')
+        item = pagure.lib.query.search_user(self.session, username='foouser')
         self.assertEqual(item.user, 'foouser')
         self.assertFalse(item.password.startswith('$2$'))
 
@@ -273,7 +273,7 @@ class PagureFlaskLogintests(tests.SimplePagureTest):
 
         # Check the password is still not of a known version
         self.session.commit()
-        item = pagure.lib.search_user(self.session, username='foouser')
+        item = pagure.lib.query.search_user(self.session, username='foouser')
         self.assertEqual(item.user, 'foouser')
         self.assertFalse(item.password.startswith('$1$'))
         self.assertFalse(item.password.startswith('$2$'))
@@ -290,7 +290,7 @@ class PagureFlaskLogintests(tests.SimplePagureTest):
 
         # Check the password
         self.session.commit()
-        item = pagure.lib.search_user(self.session, username='foouser')
+        item = pagure.lib.query.search_user(self.session, username='foouser')
         self.assertEqual(item.user, 'foouser')
         self.assertTrue(item.password.startswith(b'$1$'))
 
@@ -305,7 +305,7 @@ class PagureFlaskLogintests(tests.SimplePagureTest):
 
         # Check the password got upgraded to version 2
         self.session.commit()
-        item = pagure.lib.search_user(self.session, username='foouser')
+        item = pagure.lib.query.search_user(self.session, username='foouser')
         self.assertEqual(item.user, 'foouser')
         self.assertTrue(item.password.startswith('$2$'))
 
@@ -332,7 +332,7 @@ class PagureFlaskLogintests(tests.SimplePagureTest):
         self.session.commit()
 
         # Confirm the user so that we can log in
-        item = pagure.lib.search_user(self.session, username='foouser')
+        item = pagure.lib.query.search_user(self.session, username='foouser')
         self.assertEqual(item.user, 'foouser')
         self.assertNotEqual(item.token, None)
 
@@ -342,7 +342,7 @@ class PagureFlaskLogintests(tests.SimplePagureTest):
         self.session.commit()
 
         # Check the user
-        item = pagure.lib.search_user(self.session, username='foouser')
+        item = pagure.lib.query.search_user(self.session, username='foouser')
         self.assertEqual(item.user, 'foouser')
         self.assertEqual(item.token, None)
 
@@ -379,13 +379,13 @@ class PagureFlaskLogintests(tests.SimplePagureTest):
         self.session.commit()
 
         # Remove the token
-        item = pagure.lib.search_user(self.session, username='foouser')
+        item = pagure.lib.query.search_user(self.session, username='foouser')
         item.token = None
         self.session.add(item)
         self.session.commit()
 
         # Check the user
-        item = pagure.lib.search_user(self.session, username='foouser')
+        item = pagure.lib.query.search_user(self.session, username='foouser')
         self.assertEqual(item.user, 'foouser')
         self.assertEqual(item.token, None)
 
@@ -418,7 +418,7 @@ class PagureFlaskLogintests(tests.SimplePagureTest):
         """
 
         # Check before:
-        items = pagure.lib.search_user(self.session)
+        items = pagure.lib.query.search_user(self.session)
         self.assertEqual(2, len(items))
 
         # First access the new user page
@@ -480,7 +480,7 @@ class PagureFlaskLogintests(tests.SimplePagureTest):
             output_text)
 
         # Check after:
-        items = pagure.lib.search_user(self.session)
+        items = pagure.lib.query.search_user(self.session)
         self.assertEqual(3, len(items))
 
         # Checking for the /login page
@@ -551,7 +551,7 @@ class PagureFlaskLogintests(tests.SimplePagureTest):
             'provided by email?', output_text)
 
         # Confirm the user so that we can log in
-        item = pagure.lib.search_user(self.session, username='foobar')
+        item = pagure.lib.query.search_user(self.session, username='foobar')
         self.assertEqual(item.user, 'foobar')
         self.assertNotEqual(item.token, None)
 
@@ -587,7 +587,7 @@ class PagureFlaskLogintests(tests.SimplePagureTest):
                     'href="/logout/?next=http://localhost/dashboard/projects">', output_text)
 
         # Check the user
-        item = pagure.lib.search_user(self.session, username='foobar')
+        item = pagure.lib.query.search_user(self.session, username='foobar')
         self.assertEqual(item.user, 'foobar')
         self.assertEqual(item.token, None)
 
@@ -603,9 +603,9 @@ class PagureFlaskLogintests(tests.SimplePagureTest):
         # Create a local user
         self.test_new_user()
 
-        items = pagure.lib.search_user(self.session)
+        items = pagure.lib.query.search_user(self.session)
         self.assertEqual(3, len(items))
-        item = pagure.lib.search_user(self.session, username='foouser')
+        item = pagure.lib.query.search_user(self.session, username='foouser')
         self.assertEqual(item.user, 'foouser')
         self.assertTrue(item.password.startswith('$2$'))
         self.assertNotEqual(item.token, None)
@@ -686,7 +686,7 @@ class PagureFlaskLogintests(tests.SimplePagureTest):
         self.test_new_user()
 
         # Check the password
-        item = pagure.lib.search_user(self.session, username='foouser')
+        item = pagure.lib.query.search_user(self.session, username='foouser')
         self.assertEqual(item.user, 'foouser')
         self.assertNotEqual(item.token, None)
         self.assertTrue(item.password.startswith('$2$'))
@@ -781,7 +781,7 @@ class PagureFlaskLogintests(tests.SimplePagureTest):
         self.test_new_user()
 
         # Remove token of foouser
-        item = pagure.lib.search_user(self.session, username='foouser')
+        item = pagure.lib.query.search_user(self.session, username='foouser')
         self.assertEqual(item.user, 'foouser')
         self.assertNotEqual(item.token, None)
         self.assertTrue(item.password.startswith('$2$'))

+ 1 - 1
tests/test_pagure_flask_ui_no_master_branch.py

@@ -26,7 +26,7 @@ from mock import patch
 sys.path.insert(0, os.path.join(os.path.dirname(
     os.path.abspath(__file__)), '..'))
 
-import pagure.lib
+import pagure.lib.query
 import tests
 from pagure.lib.repo import PagureRepo
 

+ 3 - 2
tests/test_pagure_flask_ui_old_commit.py

@@ -17,12 +17,13 @@ import os
 
 import pygit2
 from mock import patch
-import pagure.lib
-import tests
 
 sys.path.insert(0, os.path.join(os.path.dirname(
     os.path.abspath(__file__)), '..'))
 
+import pagure.lib.query
+import tests
+
 
 class PagureFlaskRepoOldUrltests(tests.SimplePagureTest):
     """ Tests for flask app controller of pagure """

+ 0 - 1
tests/test_pagure_flask_ui_plugins.py

@@ -20,7 +20,6 @@ import wtforms
 sys.path.insert(0, os.path.join(os.path.dirname(
     os.path.abspath(__file__)), '..'))
 
-import pagure.lib
 import pagure.lib.plugins
 import pagure.hooks
 import tests

+ 6 - 6
tests/test_pagure_flask_ui_plugins_default_hook.py

@@ -26,7 +26,7 @@ from mock import patch, MagicMock
 sys.path.insert(0, os.path.join(os.path.dirname(
     os.path.abspath(__file__)), '..'))
 
-import pagure.lib
+import pagure.lib.query
 import tests
 
 
@@ -49,7 +49,7 @@ class PagureFlaskPluginDefaultHooktests(tests.Modeltests):
         project is created.
         """
 
-        task = pagure.lib.new_project(
+        task = pagure.lib.query.new_project(
             self.session,
             user='pingou',
             name='test',
@@ -77,7 +77,7 @@ class PagureFlaskPluginDefaultHooktests(tests.Modeltests):
         somehow managed.
         """
 
-        task = pagure.lib.new_project(
+        task = pagure.lib.query.new_project(
             self.session,
             user='pingou',
             name='test',
@@ -97,7 +97,7 @@ class PagureFlaskPluginDefaultHooktests(tests.Modeltests):
                           'repo': 'test',
                           'namespace': None})
 
-        repo = pagure.lib.get_authorized_project(self.session, 'test')
+        repo = pagure.lib.query.get_authorized_project(self.session, 'test')
         plugin = pagure.lib.plugins.get_plugin('default')
         dbobj = plugin.db_object()
 
@@ -115,7 +115,7 @@ class PagureFlaskPluginDefaultHooktests(tests.Modeltests):
             flask.g.session = self.session
             flask.g.fas_user = tests.FakeUser(username='foo')
 
-            task = pagure.lib.new_project(
+            task = pagure.lib.query.new_project(
                 self.session,
                 user='pingou',
                 name='test',
@@ -135,7 +135,7 @@ class PagureFlaskPluginDefaultHooktests(tests.Modeltests):
                               'repo': 'test',
                               'namespace': None})
 
-            repo = pagure.lib.get_authorized_project(self.session, 'test')
+            repo = pagure.lib.query.get_authorized_project(self.session, 'test')
             plugin = pagure.lib.plugins.get_plugin('default')
             dbobj = plugin.db_object()
             form = plugin.form(obj=dbobj)

+ 1 - 1
tests/test_pagure_flask_ui_plugins_fedmsg.py

@@ -21,8 +21,8 @@ from mock import patch
 sys.path.insert(0, os.path.join(os.path.dirname(
     os.path.abspath(__file__)), '..'))
 
-import pagure.lib
 import tests
+import pagure.config
 
 
 class PagureFlaskPluginFedmsgtests(tests.SimplePagureTest):

+ 0 - 1
tests/test_pagure_flask_ui_plugins_irc.py

@@ -18,7 +18,6 @@ import os
 sys.path.insert(0, os.path.join(os.path.dirname(
     os.path.abspath(__file__)), '..'))
 
-import pagure.lib
 import tests
 
 

+ 0 - 1
tests/test_pagure_flask_ui_plugins_mail.py

@@ -20,7 +20,6 @@ import os
 sys.path.insert(0, os.path.join(os.path.dirname(
     os.path.abspath(__file__)), '..'))
 
-import pagure.lib
 import tests
 
 

+ 0 - 1
tests/test_pagure_flask_ui_plugins_mirror.py

@@ -21,7 +21,6 @@ from mock import patch
 sys.path.insert(0, os.path.join(os.path.dirname(
     os.path.abspath(__file__)), '..'))
 
-import pagure.lib
 import pagure.utils
 import tests
 

+ 0 - 1
tests/test_pagure_flask_ui_plugins_noff.py

@@ -20,7 +20,6 @@ import os
 sys.path.insert(0, os.path.join(os.path.dirname(
     os.path.abspath(__file__)), '..'))
 
-import pagure.lib
 import tests
 
 

+ 0 - 1
tests/test_pagure_flask_ui_plugins_pagure_ci.py

@@ -8,7 +8,6 @@ import unittest
 import sys
 import os
 
-import pagure.lib
 import tests
 
 

+ 1 - 1
tests/test_pagure_flask_ui_plugins_pagure_hook.py

@@ -21,8 +21,8 @@ from mock import patch
 sys.path.insert(0, os.path.join(os.path.dirname(
     os.path.abspath(__file__)), '..'))
 
-import pagure.lib
 import tests
+import pagure.config
 
 
 class PagureFlaskPluginPagureHooktests(tests.SimplePagureTest):

+ 1 - 1
tests/test_pagure_flask_ui_plugins_pagure_no_new_branch.py

@@ -21,8 +21,8 @@ import os
 sys.path.insert(0, os.path.join(os.path.dirname(
     os.path.abspath(__file__)), '..'))
 
-import pagure.lib
 import tests
+import pagure.config
 
 
 class PagureFlaskPluginPagureNoNewBranchHooktests(tests.SimplePagureTest):

+ 0 - 1
tests/test_pagure_flask_ui_plugins_pagure_request_hook.py

@@ -20,7 +20,6 @@ import os
 sys.path.insert(0, os.path.join(os.path.dirname(
     os.path.abspath(__file__)), '..'))
 
-import pagure.lib
 import tests
 
 

+ 7 - 1
tests/test_pagure_flask_ui_plugins_pagure_ticket_hook.py

@@ -21,7 +21,6 @@ import os
 sys.path.insert(0, os.path.join(os.path.dirname(
     os.path.abspath(__file__)), '..'))
 
-import pagure.lib
 import tests
 
 
@@ -98,6 +97,7 @@ class PagureFlaskPluginPagureTicketHooktests(tests.SimplePagureTest):
                 'active': 'y',
             }
 
+            print('    ==== ACTIVATE ')
             output = self.app.post(
                 '/test/settings/Pagure tickets', data=data,
                 follow_redirects=True)
@@ -110,6 +110,7 @@ class PagureFlaskPluginPagureTicketHooktests(tests.SimplePagureTest):
                 'Hook Pagure tickets activated',
                 output_text)
 
+            print('    ==== CHECK ')
             output = self.app.get('/test/settings/Pagure tickets')
             self.assertEqual(output.status_code, 200)
             output_text = output.get_data(as_text=True)
@@ -121,6 +122,7 @@ class PagureFlaskPluginPagureTicketHooktests(tests.SimplePagureTest):
                 'type="checkbox" value="y">', output_text)
 
             # De-Activate hook
+            print('    ==== DEACTIVATE ')
             data = {'csrf_token': csrf_token}
             output = self.app.post(
                 '/test/settings/Pagure tickets', data=data,
@@ -134,6 +136,7 @@ class PagureFlaskPluginPagureTicketHooktests(tests.SimplePagureTest):
                 'Hook Pagure tickets deactivated',
                 output_text)
 
+            print('    ==== CHECK ')
             output = self.app.get('/test/settings/Pagure tickets')
             self.assertEqual(output.status_code, 200)
             output_text = output.get_data(as_text=True)
@@ -155,9 +158,12 @@ class PagureFlaskPluginPagureTicketHooktests(tests.SimplePagureTest):
             }
             shutil.rmtree(os.path.join(self.path, 'repos', 'tickets', 'test.git'))
 
+            print('    ==== NO GIT REPO ')
             output = self.app.post('/test/settings/Pagure tickets', data=data)
             self.assertEqual(output.status_code, 404)
 
+        print('*** DONE ***')
+
 
 if __name__ == '__main__':
     unittest.main(verbosity=2)

Some files were not shown because too many files changed in this diff