From b130e5c6ef75b227661d0de0759979084ca31616 Mon Sep 17 00:00:00 2001 From: Pierre-Yves Chibon Date: Jan 03 2018 08:32:27 +0000 Subject: Re-architure pagure - Move the session to flask.g instead of importing it everywhere - Move the config to its own module - Move the code from pagure/__init__.py to pagure.lib, pagure.utils.py and pagure.flask_app.py - Add an application factory to instanciate and create the flask app - Move the UI to be a blueprint Adjust the services for these changes. Adjust all the tests to pass with these changes. Signed-off-by: Pierre-Yves Chibon --- diff --git a/alembic/env.py b/alembic/env.py index d00ce8b..f4db868 100644 --- a/alembic/env.py +++ b/alembic/env.py @@ -42,7 +42,7 @@ target_metadata = pagure.lib.model.BASE.metadata DBURL = config.get_main_option("sqlalchemy.url") if not DBURL: - DBURL = pagure.APP.config['DB_URL'] + DBURL = pagure.config.config['DB_URL'] def run_migrations_offline(): diff --git a/createdb.py b/createdb.py index d0ac61f..fdde1c2 100644 --- a/createdb.py +++ b/createdb.py @@ -42,12 +42,11 @@ if args.alembic_cfg: sys.exit(2) -from pagure import APP +import pagure from pagure.lib import model model.create_tables( - APP.config['DB_URL'], - APP.config.get('PATH_ALEMBIC_INI', args.alembic_cfg), - acls=APP.config.get('ACLS', {}), - debug=True -) + pagure.config.config['DB_URL'], + pagure.config.config.get('PATH_ALEMBIC_INI', args.alembic_cfg), + acls=pagure.config.config.get('ACLS', {}), + debug=True) diff --git a/dev-data.py b/dev-data.py index fe3dc3a..0827978 100644 --- a/dev-data.py +++ b/dev-data.py @@ -1,12 +1,15 @@ #!/usr/bin/env python """ Populate the pagure db with some dev data. """ -import sys +import argparse import os +import sys + +from sqlalchemy import create_engine, MetaData + import pagure +import pagure.flask_app import tests -from sqlalchemy import create_engine, MetaData -import argparse ''' Usage: @@ -16,15 +19,16 @@ python dev-data.py --populate python dev-data.py --all ''' +_config = pagure.config.config.reload_config() def init_database(): - DB_URL = pagure.APP.config['DB_URL'] + DB_URL = _config['DB_URL'] # create the table if it doesnt exist pagure.lib.model.create_tables( DB_URL, - pagure.APP.config.get('PATH_ALEMBIC_INI', None), - acls=pagure.APP.config.get('ACLS', {}), + _config.get('PATH_ALEMBIC_INI', None), + acls=_config.get('ACLS', {}), debug=True) engine = create_engine('%s' % DB_URL, echo=True) @@ -37,7 +41,7 @@ def init_database(): def empty_dev_db(metadata, engine): print('') print('') - print('WARNING: Deleting all data from ', pagure.APP.config['DB_URL']) + print('WARNING: Deleting all data from ', _config['DB_URL']) # Dangerous: this will wipe the data from the table but keep the schema print('') response = raw_input('Do you want to continue yes or no? ') @@ -48,8 +52,8 @@ def empty_dev_db(metadata, engine): def insert_data(session, username, user_email): - pagure.APP.config['EMAIL_SEND'] = False - pagure.APP.config['TESTING'] = True + _config['EMAIL_SEND'] = False + _config['TESTING'] = True ###################################### # tags @@ -126,24 +130,24 @@ def insert_data(session, username, user_email): import shutil # delete folder from local instance to start from a clean slate if os.path.exists(pagure.APP.config['GIT_FOLDER']): - shutil.rmtree(pagure.APP.config['GIT_FOLDER']) + shutil.rmtree(_config['GIT_FOLDER']) tests.create_projects(session) - tests.create_projects_git(pagure.APP.config['GIT_FOLDER'], bare=True) + tests.create_projects_git(_config['GIT_FOLDER'], bare=True) tests.add_content_git_repo( - os.path.join(pagure.APP.config['GIT_FOLDER'], 'test.git')) + os.path.join(_config['GIT_FOLDER'], 'test.git')) tests.add_readme_git_repo( - os.path.join(pagure.APP.config['GIT_FOLDER'], 'test.git')) + os.path.join(_config['GIT_FOLDER'], 'test.git')) # Add some content to the git repo tests.add_content_git_repo( - os.path.join(pagure.APP.config['GIT_FOLDER'], 'forks', 'pingou', + os.path.join(_config['GIT_FOLDER'], 'forks', 'pingou', 'test.git')) tests.add_readme_git_repo( - os.path.join(pagure.APP.config['GIT_FOLDER'], 'forks', 'pingou', + os.path.join(_config['GIT_FOLDER'], 'forks', 'pingou', 'test.git')) tests.add_commit_git_repo( - os.path.join(pagure.APP.config['GIT_FOLDER'], 'forks', 'pingou', + os.path.join(_config['GIT_FOLDER'], 'forks', 'pingou', 'test.git'), ncommits=10) ###################################### @@ -257,7 +261,7 @@ def insert_data(session, username, user_email): # projects_groups group = pagure.lib.search_groups(session, pattern=None, group_name="rel-eng", group_type=None) - repo = pagure.get_authorized_project(session, 'test') + repo = pagure.lib.get_authorized_project(session, 'test') item = pagure.lib.model.ProjectGroup( project_id=repo.id, group_id=group.id @@ -267,7 +271,7 @@ def insert_data(session, username, user_email): group = pagure.lib.search_groups(session, pattern=None, group_name="admin", group_type=None) - repo = pagure.get_authorized_project(session, 'test2') + repo = pagure.lib.get_authorized_project(session, 'test2') item = pagure.lib.model.ProjectGroup( project_id=repo.id, group_id=group.id @@ -277,8 +281,8 @@ def insert_data(session, username, user_email): ###################################### # pull_requests - repo = pagure.get_authorized_project(session, 'test') - forked_repo = pagure.get_authorized_project(session, 'test') + repo = pagure.lib.get_authorized_project(session, 'test') + forked_repo = pagure.lib.get_authorized_project(session, 'test') req = pagure.lib.new_pull_request( session=session, repo_from=forked_repo, @@ -298,7 +302,7 @@ def insert_data(session, username, user_email): ###################################### # user_projects user = pagure.lib.search_user(session, username='foo') - repo = pagure.get_authorized_project(session, 'test') + repo = pagure.lib.get_authorized_project(session, 'test') item = pagure.lib.model.ProjectUser( project_id=repo.id, user_id=user.id @@ -307,7 +311,7 @@ def insert_data(session, username, user_email): session.commit() user = pagure.lib.search_user(session, username=username) - repo = pagure.get_authorized_project(session, 'test2') + repo = pagure.lib.get_authorized_project(session, 'test2') item = pagure.lib.model.ProjectUser( project_id=repo.id, user_id=user.id @@ -327,11 +331,11 @@ def insert_data(session, username, user_email): ###################################### # issue_to_issue - repo = pagure.get_authorized_project(session, 'test') + 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], all_issues[1], 'pingou', - pagure.APP.config['GIT_FOLDER']) + _config['GIT_FOLDER']) ###################################### # pull_request_comments @@ -366,7 +370,7 @@ def insert_data(session, username, user_email): ###################################### # tags_issues - repo = pagure.get_authorized_project(session, 'test') + repo = pagure.lib.get_authorized_project(session, 'test') issues = pagure.lib.search_issues(session, repo) item = pagure.lib.model.TagIssue( issue_uid=issues[0].uid, @@ -384,42 +388,42 @@ def insert_data(session, username, user_email): # delete fork data fork_proj_location = "forks/foo/test.git" try: - shutil.rmtree(os.path.join(pagure.APP.config['GIT_FOLDER'], + shutil.rmtree(os.path.join(_config['GIT_FOLDER'], fork_proj_location)) except: print('git folder already deleted') try: - shutil.rmtree(os.path.join(pagure.APP.config['DOCS_FOLDER'], + shutil.rmtree(os.path.join(_config['DOCS_FOLDER'], fork_proj_location)) except: print('docs folder already deleted') try: - shutil.rmtree(os.path.join(pagure.APP.config['TICKETS_FOLDER'], + shutil.rmtree(os.path.join(_config['TICKETS_FOLDER'], fork_proj_location)) except: print('tickets folder already deleted') try: - shutil.rmtree(os.path.join(pagure.APP.config['REQUESTS_FOLDER'], + shutil.rmtree(os.path.join(_config['REQUESTS_FOLDER'], fork_proj_location)) except: print('requests folder already deleted') - repo = pagure.get_authorized_project(session, 'test') + repo = pagure.lib.get_authorized_project(session, 'test') result = pagure.lib.fork_project(session, 'foo', repo, - pagure.APP.config['GIT_FOLDER'], - pagure.APP.config['DOCS_FOLDER'], - pagure.APP.config['TICKETS_FOLDER'], - pagure.APP.config['REQUESTS_FOLDER']) + _config['GIT_FOLDER'], + _config['DOCS_FOLDER'], + _config['TICKETS_FOLDER'], + _config['REQUESTS_FOLDER']) if result == 'Repo "test" cloned to "foo/test"': session.commit() if __name__ == "__main__": desc = "Run the dev database initialization/insertion/deletion " \ - "script for db located " + str(pagure.APP.config['DB_URL']) + "script for db located " + str(_config['DB_URL']) parser = argparse.ArgumentParser(prog="dev-data", description=desc) parser.add_argument('-i', '--init', action="store_true", help="Create the dev db") @@ -443,7 +447,7 @@ if __name__ == "__main__": empty_dev_db(meta, eng) if args.populate or args.all: - session = pagure.SESSION + session = pagure.flask_app.SESSION invalid_option = ['pingou', 'bar@pingou.com', 'foo', 'foo@bar.com'] print("") user_name = raw_input( diff --git a/pagure-ci/pagure_ci_server.py b/pagure-ci/pagure_ci_server.py index 523451b..f124a33 100644 --- a/pagure-ci/pagure_ci_server.py +++ b/pagure-ci/pagure_ci_server.py @@ -25,8 +25,9 @@ import requests import trollius import trollius_redis +import pagure +import pagure.lib -_log = logging.getLogger(__name__) if 'PAGURE_CONFIG' not in os.environ \ and os.path.exists('/etc/pagure/pagure.cfg'): @@ -34,8 +35,8 @@ if 'PAGURE_CONFIG' not in os.environ \ os.environ['PAGURE_CONFIG'] = '/etc/pagure/pagure.cfg' -import pagure -import pagure.lib +_log = logging.getLogger(__name__) +_config = pagure.config.config.reload_config() @trollius.coroutine @@ -45,9 +46,9 @@ def handle_messages(): information provided. ''' - host = pagure.APP.config.get('REDIS_HOST', '0.0.0.0') - port = pagure.APP.config.get('REDIS_PORT', 6379) - dbname = pagure.APP.config.get('REDIS_DB', 0) + host = _config.get('REDIS_HOST', '0.0.0.0') + port = _config.get('REDIS_PORT', 6379) + dbname = _config.get('REDIS_DB', 0) connection = yield trollius.From(trollius_redis.Connection.create( host=host, port=port, db=dbname)) @@ -69,7 +70,7 @@ def handle_messages(): pr_uid = data['pr']['uid'] branch = data['pr']['branch_from'] _log.info('Looking for PR: %s', pr_uid) - session = pagure.lib.create_session(pagure.APP.config['DB_URL']) + session = pagure.lib.create_session(_config['DB_URL']) request = pagure.lib.get_request_by_uid(session, pr_uid) _log.info('PR retrieved: %s', request) @@ -90,7 +91,7 @@ def handle_messages(): if data['ci_type'] == 'jenkins': url = url + '/buildWithParameters' repo = '%s/%s' % ( - pagure.APP.config['GIT_URL_GIT'].rstrip('/'), + _config['GIT_URL_GIT'].rstrip('/'), request.project_from.path) _log.info( 'Triggering the build at: %s, for repo: %s', url, repo) diff --git a/pagure-ev/pagure_stream_server.py b/pagure-ev/pagure_stream_server.py index c7c0a36..688799f 100644 --- a/pagure-ev/pagure_stream_server.py +++ b/pagure-ev/pagure_stream_server.py @@ -40,10 +40,20 @@ import pagure.lib # noqa: E402 from pagure.exceptions import PagureEvException # noqa: E402 SERVER = None +SESSION = None POOL = redis.ConnectionPool( - host=pagure.APP.config['REDIS_HOST'], - port=pagure.APP.config['REDIS_PORT'], - db=pagure.APP.config['REDIS_DB']) + host=pagure.config.config['REDIS_HOST'], + port=pagure.config.config['REDIS_PORT'], + db=pagure.config.config['REDIS_DB']) + + +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']) + + return SESSION def _get_issue(repo, objid): @@ -54,8 +64,8 @@ def _get_issue(repo, objid): if not repo.settings.get('issue_tracker', True): raise PagureEvException("No issue tracker found for this project") - issue = pagure.lib.search_issues( - pagure.SESSION, repo, issueid=objid) + session = _get_session() + issue = pagure.lib.search_issues(session, repo, issueid=objid) if issue is None or issue.project != repo: raise PagureEvException("Issue '%s' not found" % objid) @@ -76,8 +86,9 @@ def _get_pull_request(repo, objid): raise PagureEvException( "No pull-request tracker found for this project") + session = _get_session() request = pagure.lib.search_pull_requests( - pagure.SESSION, project_id=repo.id, requestid=objid) + session, project_id=repo.id, requestid=objid) if request is None or request.project != repo: raise PagureEvException("Pull-Request '%s' not found" % objid) @@ -148,8 +159,9 @@ def get_obj_from_path(path): """ Return the Ticket or Request object based on the path provided. """ (username, namespace, reponame, objtype, objid) = _parse_path(path) - repo = pagure.get_authorized_project( - pagure.SESSION, reponame, user=username, namespace=namespace) + session = _get_session() + repo = pagure.lib.get_authorized_project( + session, reponame, user=username, namespace=namespace) if repo is None: raise PagureEvException("Project '%s' not found" % reponame) @@ -199,7 +211,7 @@ def handle_client(client_reader, client_writer): log.warning(err.message) return - origin = pagure.APP.config.get('APP_URL') + origin = pagure.config.config.get('APP_URL') if origin.endswith('/'): origin = origin[:-1] @@ -271,22 +283,23 @@ def stats(client_reader, client_writer): def main(): global SERVER + _get_session() try: loop = trollius.get_event_loop() coro = trollius.start_server( handle_client, host=None, - port=pagure.APP.config['EVENTSOURCE_PORT'], + port=pagure.config.config['EVENTSOURCE_PORT'], loop=loop) SERVER = loop.run_until_complete(coro) log.info( 'Serving server at {}'.format(SERVER.sockets[0].getsockname())) - if pagure.APP.config.get('EV_STATS_PORT'): + if pagure.config.config.get('EV_STATS_PORT'): stats_coro = trollius.start_server( stats, host=None, - port=pagure.APP.config.get('EV_STATS_PORT'), + port=pagure.config.config.get('EV_STATS_PORT'), loop=loop) stats_server = loop.run_until_complete(stats_coro) log.info('Serving stats at {}'.format( @@ -301,7 +314,7 @@ def main(): finally: # Close the server SERVER.close() - if pagure.APP.config.get('EV_STATS_PORT'): + if pagure.config.config.get('EV_STATS_PORT'): stats_server.close() log.info("End Connection") loop.run_until_complete(SERVER.wait_closed()) diff --git a/pagure-loadjson/pagure_loadjson_server.py b/pagure-loadjson/pagure_loadjson_server.py index 8799c98..94c710a 100644 --- a/pagure-loadjson/pagure_loadjson_server.py +++ b/pagure-loadjson/pagure_loadjson_server.py @@ -29,7 +29,11 @@ import trollius_redis from sqlalchemy.exc import SQLAlchemyError -_log = logging.getLogger(__name__) +import pagure +import pagure.exceptions +import pagure.lib +import pagure.lib.notify + if 'PAGURE_CONFIG' not in os.environ \ and os.path.exists('/etc/pagure/pagure.cfg'): @@ -37,10 +41,8 @@ if 'PAGURE_CONFIG' not in os.environ \ os.environ['PAGURE_CONFIG'] = '/etc/pagure/pagure.cfg' -import pagure -import pagure.exceptions -import pagure.lib -import pagure.lib.notify +_log = logging.getLogger(__name__) +_config = pagure.config.config.reload_config() def format_callstack(): @@ -118,9 +120,9 @@ def handle_messages(): ''' - host = pagure.APP.config.get('REDIS_HOST', '0.0.0.0') - port = pagure.APP.config.get('REDIS_PORT', 6379) - dbname = pagure.APP.config.get('REDIS_DB', 0) + host = _config.get('REDIS_HOST', '0.0.0.0') + port = _config.get('REDIS_PORT', 6379) + dbname = _config.get('REDIS_DB', 0) connection = yield trollius.From(trollius_redis.Connection.create( host=host, port=port, db=dbname)) @@ -153,14 +155,14 @@ def handle_messages(): _log.info('Invalid data_type retrieved: %s', data_type) continue - session = pagure.lib.create_session(pagure.APP.config['DB_URL']) + session = pagure.lib.create_session(_config['DB_URL']) _log.info('Looking for project: %s%s of user: %s', '%s/' % namespace if namespace else '', repo, username) project = pagure.lib._get_project( session, repo, user=username, namespace=namespace, - case=pagure.APP.config.get('CASE_SENSITIVE', False)) + case=_config.get('CASE_SENSITIVE', False)) if not project: _log.info('No project found') diff --git a/pagure-logcom/pagure_logcom_server.py b/pagure-logcom/pagure_logcom_server.py index 864a5be..ce45ef6 100644 --- a/pagure-logcom/pagure_logcom_server.py +++ b/pagure-logcom/pagure_logcom_server.py @@ -2,7 +2,7 @@ # -*- coding: utf-8 -*- """ - (c) 2016 - Copyright Red Hat Inc + (c) 2016-2017 - Copyright Red Hat Inc Authors: Pierre-Yves Chibon @@ -26,17 +26,17 @@ from sqlalchemy.exc import SQLAlchemyError import trollius import trollius_redis +import pagure +import pagure.lib -_log = logging.getLogger(__name__) if 'PAGURE_CONFIG' not in os.environ \ and os.path.exists('/etc/pagure/pagure.cfg'): print('Using configuration file `/etc/pagure/pagure.cfg`') os.environ['PAGURE_CONFIG'] = '/etc/pagure/pagure.cfg' - -import pagure -import pagure.lib +_config = pagure.config.config.reload_config() +_log = logging.getLogger(__name__) @trollius.coroutine @@ -70,9 +70,9 @@ def handle_messages(): ''' - host = pagure.APP.config.get('REDIS_HOST', '0.0.0.0') - port = pagure.APP.config.get('REDIS_PORT', 6379) - dbname = pagure.APP.config.get('REDIS_DB', 0) + host = _config.get('REDIS_HOST', '0.0.0.0') + port = _config.get('REDIS_PORT', 6379) + dbname = _config.get('REDIS_DB', 0) connection = yield trollius.From(trollius_redis.Connection.create( host=host, port=port, db=dbname)) @@ -99,14 +99,14 @@ def handle_messages(): if data['project']['parent'] else None namespace = data['project']['namespace'] - session = pagure.lib.create_session(pagure.APP.config['DB_URL']) + session = pagure.lib.create_session(_config['DB_URL']) _log.info('Looking for project: %s%s of %s', '%s/' % namespace if namespace else '', repo, username) project = pagure.lib._get_project( pagure.SESSION, repo, user=username, namespace=namespace, - case=pagure.APP.config.get('CASE_SENSITIVE', False)) + case=_config.get('CASE_SENSITIVE', False)) if not project: _log.info('No project found') diff --git a/pagure-milters/comment_email_milter.py b/pagure-milters/comment_email_milter.py index 0be8a8d..acb0818 100644 --- a/pagure-milters/comment_email_milter.py +++ b/pagure-milters/comment_email_milter.py @@ -20,7 +20,7 @@ import requests from Milter.utils import parse_addr -logq = Queue(maxsize=4) +import pagure if 'PAGURE_CONFIG' not in os.environ \ @@ -28,7 +28,8 @@ if 'PAGURE_CONFIG' not in os.environ \ os.environ['PAGURE_CONFIG'] = '/etc/pagure/pagure.cfg' -import pagure # noqa +logq = Queue(maxsize=4) +_config = pagure.config.config.reload_config() def get_email_body(emailobj): @@ -150,7 +151,7 @@ class PagureMilter(Milter.Base): # Ensure the user replied to his/her own notification, not that # they are trying to forge their ID into someone else's - salt = pagure.APP.config.get('SALT_EMAIL') + salt = _config.get('SALT_EMAIL') from_email = clean_item(msg['From']) try: user = pagure.lib.get_user(pagure.SESSION, from_email) @@ -172,7 +173,7 @@ class PagureMilter(Milter.Base): self.log('Hash does not correspond to the destination') return Milter.CONTINUE - if msg['From'] and msg['From'] == pagure.APP.config.get('FROM_EMAIL'): + if msg['From'] and msg['From'] == _config.get('FROM_EMAIL'): self.log("Let's not process the email we send") return Milter.CONTINUE @@ -204,7 +205,7 @@ class PagureMilter(Milter.Base): 'comment': get_email_body(emailobj), 'useremail': clean_item(emailobj['From']), } - url = pagure.APP.config.get('APP_URL') + url = _config.get('APP_URL') if url.endswith('/'): url = url[:-1] @@ -235,7 +236,7 @@ class PagureMilter(Milter.Base): 'comment': get_email_body(emailobj), 'useremail': clean_item(emailobj['From']), } - url = pagure.APP.config.get('APP_URL') + url = _config.get('APP_URL') if url.endswith('/'): url = url[:-1] diff --git a/pagure-webhook/pagure-webhook-server.py b/pagure-webhook/pagure-webhook-server.py index 4895481..42b245c 100644 --- a/pagure-webhook/pagure-webhook-server.py +++ b/pagure-webhook/pagure-webhook-server.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ - (c) 2015 - Copyright Red Hat Inc + (c) 2015-2017 - Copyright Red Hat Inc Authors: Pierre-Yves Chibon @@ -32,8 +32,9 @@ import trollius_redis from kitchen.text.converters import to_bytes - -log = logging.getLogger(__name__) +import pagure +import pagure.lib +from pagure.exceptions import PagureEvException if 'PAGURE_CONFIG' not in os.environ \ @@ -41,11 +42,8 @@ if 'PAGURE_CONFIG' not in os.environ \ print('Using configuration file `/etc/pagure/pagure.cfg`') os.environ['PAGURE_CONFIG'] = '/etc/pagure/pagure.cfg' - -import pagure -import pagure.lib -from pagure.exceptions import PagureEvException - +_config = pagure.config.config.reload_config() +log = logging.getLogger(__name__) _i = 0 @@ -61,7 +59,7 @@ def call_web_hooks(project, topic, msg, urls): year = datetime.datetime.now().year if isinstance(topic, six.text_type): topic = to_bytes(topic, encoding='utf8', nonstring="passthru") - msg['pagure_instance'] = pagure.APP.config['APP_URL'] + msg['pagure_instance'] = _config['APP_URL'] msg['project_fullname'] = project.fullname msg = dict( topic=topic.decode('utf-8'), @@ -77,7 +75,7 @@ def call_web_hooks(project, topic, msg, urls): hashhex256 = hmac.new( str(project.hook_token), content, hashlib.sha256).hexdigest() headers = { - 'X-Pagure': pagure.APP.config['APP_URL'], + 'X-Pagure': _config['APP_URL'], 'X-Pagure-project': project.fullname, 'X-Pagure-Signature': hashhex, 'X-Pagure-Signature-256': hashhex256, @@ -106,9 +104,9 @@ def call_web_hooks(project, topic, msg, urls): @trollius.coroutine def handle_messages(): - host = pagure.APP.config.get('REDIS_HOST', '0.0.0.0') - port = pagure.APP.config.get('REDIS_PORT', 6379) - dbname = pagure.APP.config.get('REDIS_DB', 0) + host = _config.get('REDIS_HOST', '0.0.0.0') + port = _config.get('REDIS_PORT', 6379) + dbname = _config.get('REDIS_DB', 0) connection = yield trollius.From(trollius_redis.Connection.create( host=host, port=port, db=dbname)) @@ -137,11 +135,11 @@ def handle_messages(): log.info( 'Searching %s/%s/%s' % (username, namespace, projectname)) - session = pagure.lib.create_session(pagure.APP.config['DB_URL']) + session = pagure.lib.create_session(_config['DB_URL']) project = pagure.lib._get_project( session=session, name=projectname, user=username, namespace=namespace, - case=pagure.APP.config.get('CASE_SENSITIVE', False)) + case=_config.get('CASE_SENSITIVE', False)) if not project: log.info('No project found with these criteria') session.close() diff --git a/pagure/__init__.py b/pagure/__init__.py index ba8fd6b..01c8fbf 100644 --- a/pagure/__init__.py +++ b/pagure/__init__.py @@ -8,886 +8,6 @@ """ -# These two lines are needed to run on EL6 -__requires__ = ['SQLAlchemy >= 0.8', 'jinja2 >= 2.4'] -import pkg_resources # noqa: E402,F401 __version__ = '3.13.2' __api_version__ = '0.22' - - -import datetime # noqa: E402 -import gc # noqa: E402 -import logging # noqa: E402 -import logging.config # noqa: E402 -import os # noqa: E402 -import re # noqa: E402 -import time # noqa: E402 -import urlparse # noqa: E402 - -import flask # noqa: E402 -import munch # noqa: E402 -import pygit2 # noqa: E402 -import werkzeug # noqa: E402 -from functools import wraps # noqa: E402 -from sqlalchemy.exc import SQLAlchemyError # noqa: E402 - -from flask_multistatic import MultiStaticFlask # noqa: E402 - -if os.environ.get('PAGURE_PERFREPO'): - import pagure.perfrepo as perfrepo # noqa: E402 -else: - perfrepo = None - -import pagure.exceptions # noqa: E402 - -logging.basicConfig() - -# Create the application. -APP = MultiStaticFlask('pagure') - -if perfrepo: - # Do this as early as possible. - # We want the perfrepo before_request to be the very first thing to be run, - # so that we can properly setup the stats before the request. - APP.before_request(perfrepo.reset_stats) - -APP.jinja_env.trim_blocks = True -APP.jinja_env.lstrip_blocks = True - -# set up FAS -APP.config.from_object('pagure.default_config') - -if 'PAGURE_CONFIG' in os.environ: - APP.config.from_envvar('PAGURE_CONFIG') - -logging.config.dictConfig(APP.config.get('LOGGING') or {'version': 1}) -logger = logging.getLogger(__name__) - - -if APP.config.get('THEME_TEMPLATE_FOLDER', False): - # Jinja can be told to look for templates in different folders - # That's what we do here - template_folder = APP.config['THEME_TEMPLATE_FOLDER'] - if template_folder[0] != '/': - template_folder = os.path.join( - APP.root_path, APP.template_folder, template_folder) - import jinja2 - # Jinja looks for the template in the order of the folders specified - templ_loaders = [ - jinja2.FileSystemLoader(template_folder), - APP.jinja_loader, - ] - APP.jinja_loader = jinja2.ChoiceLoader(templ_loaders) - - -if APP.config.get('THEME_STATIC_FOLDER', False): - static_folder = APP.config['THEME_STATIC_FOLDER'] - if static_folder[0] != '/': - static_folder = os.path.join( - APP.root_path, 'static', static_folder) - # Unlike templates, to serve static files from multiples folders we - # need flask-multistatic - APP.static_folder = [ - static_folder, - os.path.join(APP.root_path, 'static'), - ] - - -import pagure.doc_utils # noqa: E402 -import pagure.forms # noqa: E402 -import pagure.lib # noqa: E402 -import pagure.lib.git # noqa: E402 -import pagure.login_forms # noqa: E402 -import pagure.mail_logging # noqa: E402 -import pagure.proxy # noqa: E402 - - -def set_user(): - if flask.g.fas_user.username is None: - flask.flash( - 'It looks like your Identity Provider did not provide an ' - 'username we could retrieve, username being needed we cannot ' - 'go further.', 'error') - logout() - return - - flask.session['_new_user'] = False - if not pagure.lib.search_user( - SESSION, username=flask.g.fas_user.username): - flask.session['_new_user'] = True - - try: - pagure.lib.set_up_user( - session=SESSION, - username=flask.g.fas_user.username, - fullname=flask.g.fas_user.fullname, - default_email=flask.g.fas_user.email, - ssh_key=flask.g.fas_user.get('ssh_key'), - keydir=APP.config.get('GITOLITE_KEYDIR', None), - ) - - # If groups are managed outside pagure, set up the user at login - if not APP.config.get('ENABLE_GROUP_MNGT', False): - user = pagure.lib.search_user( - SESSION, username=flask.g.fas_user.username) - old_groups = set(user.groups) - fas_groups = set(flask.g.fas_user.groups) - # Add the new groups - for group in fas_groups - old_groups: - groupobj = None - if group: - groupobj = pagure.lib.search_groups( - SESSION, group_name=group) - if groupobj: - try: - pagure.lib.add_user_to_group( - session=SESSION, - username=flask.g.fas_user.username, - group=groupobj, - user=flask.g.fas_user.username, - is_admin=is_admin(), - from_external=True, - ) - except pagure.exceptions.PagureException as err: - APP.logger.error(err) - # Remove the old groups - for group in old_groups - fas_groups: - if group: - try: - pagure.lib.delete_user_of_group( - session=SESSION, - username=flask.g.fas_user.username, - groupname=group, - user=flask.g.fas_user.username, - is_admin=is_admin(), - force=True, - from_external=True, - ) - except pagure.exceptions.PagureException as err: - APP.logger.error(err) - - SESSION.commit() - except SQLAlchemyError as err: - SESSION.rollback() - APP.logger.exception(err) - flask.flash( - 'Could not set up you as a user properly, please contact ' - 'an admin', 'error') - # Ensure the user is logged out if we cannot set them up - # correctly - logout() - - -# Only import flask_fas_openid if it is needed -if APP.config.get('PAGURE_AUTH', None) in ['fas', 'openid']: - from flask_fas_openid import FAS - FAS = FAS(APP) - - @FAS.postlogin - def set_user_fas(return_url): - ''' After login method. ''' - set_user() - return flask.redirect(return_url) - - -if APP.config.get('PAGURE_AUTH', None) == 'oidc': - from flask_oidc import OpenIDConnect - oidc = OpenIDConnect(APP) - - @APP.before_request - def fas_user_from_oidc(): - if oidc.user_loggedin and 'oidc_logintime' in flask.session: - email_key, fulln_key, usern_key, ssh_key, groups_key = [ - APP.config['OIDC_PAGURE_EMAIL'], - APP.config['OIDC_PAGURE_FULLNAME'], - APP.config['OIDC_PAGURE_USERNAME'], - APP.config['OIDC_PAGURE_SSH_KEY'], - APP.config['OIDC_PAGURE_GROUPS'], - ] - info = oidc.user_getinfo( - [email_key, fulln_key, usern_key, ssh_key, groups_key] - ) - username = info.get(usern_key) - if not username: - fb = APP.config['OIDC_PAGURE_USERNAME_FALLBACK'] - if fb == 'email': - username = info[email_key].split('@')[0] - elif fb == 'sub': - username = flask.g.oidc_id_token['sub'] - flask.g.fas_user = munch.Munch( - username=username, - fullname=info.get(fulln_key, ''), - email=info[email_key], - ssh_key=info.get(ssh_key), - groups=info.get(groups_key, []), - login_time=flask.session['oidc_logintime'], - ) - -SESSION = pagure.lib.create_session(APP.config['DB_URL']) -REDIS = None -if APP.config['EVENTSOURCE_SOURCE'] \ - or APP.config['WEBHOOK'] \ - or APP.config.get('PAGURE_CI_SERVICES'): - pagure.lib.set_redis( - host=APP.config['REDIS_HOST'], - port=APP.config['REDIS_PORT'], - dbname=APP.config['REDIS_DB'] - ) - - -if APP.config.get('PAGURE_CI_SERVICES'): - pagure.lib.set_pagure_ci(APP.config['PAGURE_CI_SERVICES']) - - -if not APP.debug and not APP.config.get('DEBUG', False): - APP.logger.addHandler(pagure.mail_logging.get_mail_handler( - smtp_server=APP.config.get('SMTP_SERVER', '127.0.0.1'), - mail_admin=APP.config.get('MAIL_ADMIN', APP.config['EMAIL_ERROR']), - from_email=APP.config.get('FROM_EMAIL', 'pagure@fedoraproject.org') - )) - - -APP.wsgi_app = pagure.proxy.ReverseProxied(APP.wsgi_app) - -# Back port 'equalto' to older version of jinja2 -APP.jinja_env.tests.setdefault('equalto', lambda value, other: value == other) - - -def authenticated(): - ''' Utility function checking if the current user is logged in or not. - ''' - return hasattr(flask.g, 'fas_user') and flask.g.fas_user is not None - - -def logout(): - auth = APP.config.get('PAGURE_AUTH', None) - if auth in ['fas', 'openid']: - if hasattr(flask.g, 'fas_user') and flask.g.fas_user is not None: - FAS.logout() - elif auth == 'oidc': - oidc.logout() - elif auth == 'local': - import pagure.ui.login as login - login.logout() - - -def api_authenticated(): - ''' Utility function checking if the current user is logged in or not - in the API. - ''' - return hasattr(flask.g, 'fas_user') \ - and flask.g.fas_user is not None \ - and hasattr(flask.g, 'token') \ - and flask.g.token is not None - - -def admin_session_timedout(): - ''' Check if the current user has been authenticated for more than what - is allowed (defaults to 15 minutes). - If it is the case, the user is logged out and the method returns True, - otherwise it returns False. - ''' - timedout = False - if not authenticated(): - return True - login_time = flask.g.fas_user.login_time - # This is because flask_fas_openid will store this as a posix timestamp - if not isinstance(login_time, datetime.datetime): - login_time = datetime.datetime.utcfromtimestamp(login_time) - if (datetime.datetime.utcnow() - login_time) > \ - APP.config.get('ADMIN_SESSION_LIFETIME', - datetime.timedelta(minutes=15)): - timedout = True - logout() - return timedout - - -def is_safe_url(target): # pragma: no cover - """ Checks that the target url is safe and sending to the current - website not some other malicious one. - """ - ref_url = urlparse.urlparse(flask.request.host_url) - test_url = urlparse.urlparse( - urlparse.urljoin(flask.request.host_url, target)) - return test_url.scheme in ('http', 'https') and \ - ref_url.netloc == test_url.netloc - - -def is_admin(): - """ Return whether the user is admin for this application or not. """ - if not authenticated(): - return False - - user = flask.g.fas_user - - auth_method = APP.config.get('PAGURE_AUTH', None) - if auth_method == 'fas': - if not user.cla_done: - return False - - admin_users = APP.config.get('PAGURE_ADMIN_USERS', []) - if not isinstance(admin_users, list): - admin_users = [admin_users] - if user.username in admin_users: - return True - - admins = APP.config['ADMIN_GROUP'] - if not isinstance(admins, list): - admins = [admins] - admins = set(admins or []) - groups = set(flask.g.fas_user.groups) - - return not groups.isdisjoint(admins) - - -def is_repo_admin(repo_obj): - """ Return whether the user is an admin of the provided repo. """ - if not authenticated(): - return False - - user = flask.g.fas_user.username - - if is_admin(): - return True - - usergrps = [ - usr.user - for grp in repo_obj.admin_groups - for usr in grp.users] - - return user == repo_obj.user.user or ( - user in [usr.user for usr in repo_obj.admins] - ) or (user in usergrps) - - -def is_repo_committer(repo_obj): - """ Return whether the user is a committer of the provided repo. """ - if not authenticated(): - return False - - user = flask.g.fas_user.username - - if is_admin(): - return True - - grps = flask.g.fas_user.groups - ext_committer = APP.config.get('EXTERNAL_COMMITTER', None) - if ext_committer: - overlap = set(ext_committer).intersection(grps) - if overlap: - for grp in overlap: - restrict = ext_committer[grp].get('restrict', []) - exclude = ext_committer[grp].get('exclude', []) - if restrict and repo_obj.fullname not in restrict: - return False - elif repo_obj.fullname in exclude: - return False - else: - return True - - usergrps = [ - usr.user - for grp in repo_obj.committer_groups - for usr in grp.users] - - return user == repo_obj.user.user or ( - user in [usr.user for usr in repo_obj.committers] - ) or (user in usergrps) - - -def is_repo_user(repo_obj): - """ Return whether the user has some access in the provided repo. """ - if not authenticated(): - return False - - user = flask.g.fas_user.username - - if is_admin(): - return True - - usergrps = [ - usr.user - for grp in repo_obj.groups - for usr in grp.users] - - return user == repo_obj.user.user or ( - user in [usr.user for usr in repo_obj.users] - ) or (user in usergrps) - - -def get_authorized_project(session, project_name, user=None, namespace=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 - :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, - case=APP.config.get('CASE_SENSITIVE', False) - ) - - if repo and repo.private and not is_repo_admin(repo): - return None - - return repo - - -def generate_user_key_files(): - """ Regenerate the key files used by gitolite. - """ - gitolite_home = APP.config.get('GITOLITE_HOME', None) - if gitolite_home: - users = pagure.lib.search_user(SESSION) - for user in users: - pagure.lib.update_user_ssh( - SESSION, user, user.public_ssh_key, - APP.config.get('GITOLITE_KEYDIR', None)) - pagure.lib.git.generate_gitolite_acls(project=None) - - -def login_required(function): - """ Flask decorator to retrict access to logged in user. - If the auth system is ``fas`` it will also require that the user sign - the FPCA. - """ - auth_method = APP.config.get('PAGURE_AUTH', None) - - @wraps(function) - def decorated_function(*args, **kwargs): - """ Decorated function, actually does the work. """ - if flask.session.get('_justloggedout', False): - return flask.redirect(flask.url_for('.index')) - elif not authenticated(): - return flask.redirect( - flask.url_for('auth_login', next=flask.request.url)) - elif auth_method == 'fas' and not flask.g.fas_user.cla_done: - flask.flash(flask.Markup( - 'You must sign the FPCA (Fedora Project ' - 'Contributor Agreement) to use pagure'), 'errors') - return flask.redirect(flask.url_for('.index')) - return function(*args, **kwargs) - return decorated_function - - -@APP.context_processor -def inject_variables(): - """ With this decorator we can set some variables to all templates. - """ - user_admin = is_admin() - - forkbuttonform = None - if authenticated(): - forkbuttonform = pagure.forms.ConfirmationForm() - - justlogedout = flask.session.get('_justloggedout', False) - if justlogedout: - flask.session['_justloggedout'] = None - - new_user = False - if flask.session.get('_new_user'): - new_user = True - flask.session['_new_user'] = False - - return dict( - version=__version__, - admin=user_admin, - authenticated=authenticated(), - forkbuttonform=forkbuttonform, - new_user=new_user, - ) - - -@APP.before_request -def set_session(): - """ Set the flask session as permanent. """ - flask.session.permanent = True - - -@APP.before_request -def set_variables(): - """ This method retrieves the repo and username set in the URLs and - provides some of the variables that are most often used. - """ - - # The API namespace has its own way of getting repo and username and - # of handling errors - if flask.request.blueprint == 'api_ns': - return - - # Retrieve the variables in the URL - args = flask.request.view_args or {} - # Check if there is a `repo` and an `username` - repo = args.get('repo') - username = args.get('username') - namespace = args.get('namespace') - - # 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.get_authorized_project( - SESSION, repo, user=username, namespace=namespace) - if authenticated(): - flask.g.repo_forked = pagure.get_authorized_project( - SESSION, repo, user=flask.g.fas_user.username, - namespace=namespace) - flask.g.repo_starred = pagure.lib.has_starred( - SESSION, flask.g.repo, user=flask.g.fas_user.username, - ) - - if not flask.g.repo \ - and APP.config.get('OLD_VIEW_COMMIT_ENABLED', False) \ - and len(repo) == 40: - return flask.redirect(flask.url_for( - 'view_commit', repo=namespace, commitid=repo, - username=username, namespace=None)) - - if flask.g.repo is None: - flask.abort(404, 'Project not found') - - flask.g.reponame = get_repo_path(flask.g.repo) - flask.g.repo_obj = pygit2.Repository(flask.g.reponame) - flask.g.repo_admin = is_repo_admin(flask.g.repo) - flask.g.repo_committer = is_repo_committer(flask.g.repo) - flask.g.repo_user = is_repo_user(flask.g.repo) - flask.g.branches = sorted(flask.g.repo_obj.listall_branches()) - - repouser = flask.g.repo.user.user if flask.g.repo.is_fork else None - fas_user = flask.g.fas_user if authenticated() else None - flask.g.repo_watch_levels = pagure.lib.get_watch_level_on_repo( - SESSION, fas_user, flask.g.repo.name, - repouser=repouser, namespace=namespace) - - items_per_page = APP.config['ITEM_PER_PAGE'] - flask.g.offset = 0 - flask.g.page = 1 - flask.g.limit = items_per_page - page = flask.request.args.get('page') - limit = flask.request.args.get('n') - if limit: - try: - limit = int(limit) - except ValueError: - limit = 10 - if limit > 500 or limit <= 0: - limit = items_per_page - - flask.g.limit = limit - - if page: - try: - page = abs(int(page)) - except ValueError: - page = 1 - if page <= 0: - page = 1 - - flask.g.page = page - flask.g.offset = (page - 1) * flask.g.limit - - -@APP.errorhandler(404) -def not_found(error): - """404 Not Found page""" - return flask.render_template('not_found.html', error=error), 404 - - -@APP.errorhandler(500) -def fatal_error(error): # pragma: no cover - """500 Fatal Error page""" - return flask.render_template('fatal_error.html', error=error), 500 - - -@APP.errorhandler(401) -def unauthorized(error): # pragma: no cover - """401 Unauthorized page""" - return flask.render_template('unauthorized.html', error=error), 401 - - -@APP.route('/login/', methods=('GET', 'POST')) -def auth_login(): # pragma: no cover - """ Method to log into the application using FAS OpenID. """ - return_point = flask.url_for('index') - if 'next' in flask.request.args: - if is_safe_url(flask.request.args['next']): - return_point = flask.request.args['next'] - - auth = APP.config.get('PAGURE_AUTH', None) - if not authenticated() and auth == 'oidc': - # If oidc is used and user hits this endpoint, it will redirect - # to IdP with destination=/login?next= - # After confirming user identity, the IdP will redirect user here - # again, but this time oidc.user_loggedin will be True and thus - # execution will go through the else clause, making the Pagure - # authentication machinery pick the user up - if not oidc.user_loggedin: - return oidc.redirect_to_auth_server(flask.request.url) - else: - flask.session['oidc_logintime'] = time.time() - fas_user_from_oidc() - set_user() - if authenticated(): - return flask.redirect(return_point) - - admins = APP.config['ADMIN_GROUP'] - if isinstance(admins, list): - admins = set(admins) - else: # pragma: no cover - admins = set([admins]) - - if auth in ['fas', 'openid']: - groups = set() - if not APP.config.get('ENABLE_GROUP_MNGT', False): - groups = [ - group.group_name - for group in pagure.lib.search_groups( - SESSION, group_type='user') - ] - groups = set(groups).union(admins) - ext_committer = set(APP.config.get('EXTERNAL_COMMITTER', {})) - groups = set(groups).union(ext_committer) - return FAS.login(return_url=return_point, groups=groups) - elif auth == 'local': - form = pagure.login_forms.LoginForm() - return flask.render_template( - 'login/login.html', - next_url=return_point, - form=form, - ) - - -@APP.route('/logout/') -def auth_logout(): # pragma: no cover - """ Method to log out from the application. """ - return_point = flask.url_for('index') - if 'next' in flask.request.args: - if is_safe_url(flask.request.args['next']): - return_point = flask.request.args['next'] - - if not authenticated(): - return flask.redirect(return_point) - - logout() - flask.flash("You have been logged out") - flask.session['_justloggedout'] = True - return flask.redirect(return_point) - - -def __get_file_in_tree(repo_obj, tree, filepath, bail_on_tree=False): - ''' Retrieve the entry corresponding to the provided filename in a - given tree. - ''' - - filename = filepath[0] - if isinstance(tree, pygit2.Blob): - return - for entry in tree: - fname = entry.name.decode('utf-8') - if fname == filename: - if len(filepath) == 1: - blob = repo_obj.get(entry.id) - # If we can't get the content (for example: an empty folder) - if blob is None: - return - # If we get a tree instead of a blob, let's escape - if isinstance(blob, pygit2.Tree) and bail_on_tree: - return blob - content = blob.data - # If it's a (sane) symlink, we try a single-level dereference - if entry.filemode == pygit2.GIT_FILEMODE_LINK \ - and os.path.normpath(content) == content \ - and not os.path.isabs(content): - try: - dereferenced = tree[content] - except KeyError: - pass - else: - if dereferenced.filemode == pygit2.GIT_FILEMODE_BLOB: - blob = repo_obj[dereferenced.oid] - - return blob - else: - try: - nextitem = repo_obj[entry.oid] - except KeyError: - # We could not find the blob/entry in the git repo - # so we bail - return - # If we can't get the content (for example: an empty folder) - if nextitem is None: - return - return __get_file_in_tree( - repo_obj, nextitem, filepath[1:], - bail_on_tree=bail_on_tree) - - -def get_repo_path(repo): - """ Return the path of the git repository corresponding to the provided - Repository object from the DB. - """ - repopath = os.path.join(APP.config['GIT_FOLDER'], repo.path) - if not os.path.exists(repopath): - flask.abort(404, 'No git repo found') - - return repopath - - -def get_remote_repo_path(remote_git, branch_from, ignore_non_exist=False): - """ Return the path of the remote git repository corresponding to the - provided information. - """ - repopath = os.path.join( - APP.config['REMOTE_GIT_FOLDER'], - werkzeug.secure_filename('%s_%s' % (remote_git, branch_from)) - ) - - if not os.path.exists(repopath) and not ignore_non_exist: - return None - else: - return repopath - - -def wait_for_task(taskid, prev=None): - if prev is None: - prev = flask.request.full_path - return flask.redirect(flask.url_for( - 'wait_task', - taskid=taskid, - prev=prev)) - - -def wait_for_task_post(taskid, form, endpoint, initial=False, **kwargs): - form_action = flask.url_for(endpoint, **kwargs) - return flask.render_template( - 'waiting_post.html', - taskid=taskid, - form_action=form_action, - form_data=form.data, - csrf=form.csrf_token, - initial=initial) - - -ip_middle_octet = u"(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5]))" -ip_last_octet = u"(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))" - -""" -regex based on https://github.com/kvesteri/validators/blob/ -master/validators/url.py -LICENSED on Dec 16th 2016 as MIT: - -The MIT License (MIT) - -Copyright (c) 2013-2014 Konsta Vesterinen - -Permission is hereby granted, free of charge, to any person obtaining a -copy of this software and associated documentation files (the "Software"), -to deal in the Software without restriction, including without limitation -the rights to use, copy, modify, merge, publish, distribute, sublicense, -and/or sell copies of the Software, and to permit persons to whom the -Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -IN THE SOFTWARE. - -""" -urlregex = re.compile( - u"^" - # protocol identifier - u"(?:(?:https?|ftp)://)" - # user:pass authentication - u"(?:\S+(?::\S*)?@)?" - u"(?:" - u"(?P" - # IP address exclusion - # private & local networks - u"(?:(?:10|127)" + ip_middle_octet + u"{2}" + ip_last_octet + u")|" - u"(?:(?:169\.254|192\.168)" + ip_middle_octet + ip_last_octet + u")|" - u"(?:172\.(?:1[6-9]|2\d|3[0-1])" + ip_middle_octet + ip_last_octet + u"))" - u"|" - # IP address dotted notation octets - # excludes loopback network 0.0.0.0 - # excludes reserved space >= 224.0.0.0 - # excludes network & broadcast addresses - # (first & last IP address of each class) - u"(?P" - u"(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])" - u"" + ip_middle_octet + u"{2}" - u"" + ip_last_octet + u")" - u"|" - # host name - u"(?:(?:[a-z\u00a1-\uffff0-9]-?)*[a-z\u00a1-\uffff0-9]+)" - # domain name - u"(?:\.(?:[a-z\u00a1-\uffff0-9]-?)*[a-z\u00a1-\uffff0-9]+)*" - # TLD identifier - u"(?:\.(?:[a-z\u00a1-\uffff]{2,}))" - u")" - # port number - u"(?::\d{2,5})?" - # resource path - u"(?:/\S*)?" - u"$", - re.UNICODE | re.IGNORECASE -) -urlpattern = re.compile(urlregex) - -# Import the application -import pagure.ui.app # noqa: E402 -import pagure.ui.fork # noqa: E402 -import pagure.ui.groups # noqa: E402 -if APP.config.get('ENABLE_TICKETS', True): - import pagure.ui.issues # noqa: E402 -import pagure.ui.plugins # noqa: E402 -import pagure.ui.repo # noqa: E402 - -from pagure.api import API # noqa: E402 -APP.register_blueprint(API) - -import pagure.internal # noqa: E402 -APP.register_blueprint(pagure.internal.PV) - - -# Only import the login controller if the app is set up for local login -if APP.config.get('PAGURE_AUTH', None) == 'local': - import pagure.ui.login as login - APP.before_request_funcs[None].insert(0, login._check_session_cookie) - APP.after_request(login._send_session_cookie) - - -# pylint: disable=unused-argument -@APP.teardown_request -def shutdown_session(exception=None): - """ Remove the DB session at the end of each request. """ - SESSION.remove() - - -# pylint: disable=unused-argument -@APP.teardown_request -def gcollect(exception=None): - """ Runs a garbage collection to get rid of any open pygit2 handles. - - Details: https://pagure.io/pagure/issue/2302""" - gc.collect() - - -if perfrepo: - # Do this at the very end, so that the after_request comes last. - APP.after_request(perfrepo.print_stats) diff --git a/pagure/api/__init__.py b/pagure/api/__init__.py index 793b6f6..67e8b4e 100644 --- a/pagure/api/__init__.py +++ b/pagure/api/__init__.py @@ -16,6 +16,7 @@ API namespace version 0. import codecs import functools +import logging import os import docutils @@ -26,12 +27,15 @@ import markupsafe API = flask.Blueprint('api_ns', __name__, url_prefix='/api/0') -import pagure # noqa: E402 import pagure.lib # noqa: E402 import pagure.lib.tasks # noqa: E402 -from pagure import __api_version__, APP, SESSION, authenticated # 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 from pagure.exceptions import APIError # noqa: E402 +from pagure.utils import authenticated # noqa: E402 + + +_log = logging.getLogger(__name__) def preload_docs(endpoint): @@ -63,7 +67,7 @@ class APIERROR(enum.Enum): 'action from reaching completion' EINVALIDREQ = 'Invalid or incomplete input submitted' EINVALIDTOK = 'Invalid or expired token. Please visit %s to get or '\ - 'renew your API token.' % APP.config['APP_URL'] + 'renew your API token.' % pagure_config['APP_URL'] ENOISSUE = 'Issue not found' EISSUENOTALLOWED = 'You are not allowed to view this issue' EPULLREQUESTSDISABLED = 'Pull-Request have been deactivated for this '\ @@ -93,10 +97,10 @@ class APIERROR(enum.Enum): ENOCOMMIT = 'No such commit found in this repository' -def get_authorized_api_project(SESSION, repo, user=None, namespace=None): +def get_authorized_api_project(session, repo, user=None, namespace=None): ''' Helper function to get an authorized_project with optional lock. ''' - repo = pagure.get_authorized_project( - SESSION, repo, user=user, namespace=namespace) + repo = pagure.lib.get_authorized_project( + flask.g.session, repo, user=user, namespace=namespace) flask.g.repo = repo return repo @@ -120,7 +124,7 @@ def check_api_acls(acls, optional=False): token_auth = False if token_str: - token = pagure.lib.get_api_token(SESSION, token_str) + token = pagure.lib.get_api_token(flask.g.session, token_str) if token and not token.expired: if acls and set(token.acls_list).intersection(set(acls)): token_auth = True @@ -203,7 +207,7 @@ def api_method(function): result = function(*args, **kwargs) except APIError as err: if err.error_code in [APIERROR.EDBERROR]: - APP.logger.exception(err) + _log.exception(err) if err.error_code in [APIERROR.ENOCODE]: output = { @@ -228,14 +232,14 @@ def api_method(function): return wrapper -if pagure.APP.config.get('ENABLE_TICKETS', True): +if pagure_config.get('ENABLE_TICKETS', True): from pagure.api import issue # noqa: E402 from pagure.api import fork # noqa: E402 from pagure.api import project # noqa: E402 from pagure.api import user # noqa: E402 from pagure.api import group # noqa: E402 -if pagure.APP.config.get('PAGURE_CI_SERVICES', False): +if pagure_config.get('PAGURE_CI_SERVICES', False): from pagure.api.ci import jenkins # noqa: E402 @@ -261,7 +265,7 @@ def api_version(): } ''' - return flask.jsonify({'version': __api_version__}) + return flask.jsonify({'version': pagure.__api_version__}) @API.route('/users/') @@ -302,7 +306,7 @@ def api_users(): if pattern is not None and not pattern.endswith('*'): pattern += '*' - users = pagure.lib.search_user(SESSION, pattern=pattern) + users = pagure.lib.search_user(flask.g.session, pattern=pattern) return flask.jsonify( { @@ -375,11 +379,12 @@ def api_project_tags(repo, username=None): } ''' + pattern = flask.request.args.get('pattern', None) if pattern is not None and not pattern.endswith('*'): pattern += '*' - project_obj = get_authorized_api_project(SESSION, repo, username) + project_obj = get_authorized_api_project(flask.g.session, repo, username) if not project_obj: output = {'output': 'notok', 'error': 'Project not found'} jsonout = flask.jsonify(output) @@ -387,7 +392,7 @@ def api_project_tags(repo, username=None): return jsonout tags = pagure.lib.get_tags_of_project( - SESSION, project_obj, pattern=pattern) + flask.g.session, project_obj, pattern=pattern) return flask.jsonify( { @@ -445,7 +450,7 @@ def api(): api_commit_add_flag_doc = load_doc(project.api_commit_add_flag) issues = [] - if pagure.APP.config.get('ENABLE_TICKETS', True): + if pagure_config.get('ENABLE_TICKETS', True): issues.append(load_doc(issue.api_new_issue)) issues.append(load_doc(issue.api_view_issues)) issues.append(load_doc(issue.api_view_issue)) @@ -460,8 +465,8 @@ def api(): issues.append(load_doc(user.api_view_user_issues)) ci_doc = [] - if pagure.APP.config.get('PAGURE_CI_SERVICES', True): - if 'jenkins' in pagure.APP.config['PAGURE_CI_SERVICES']: + if pagure_config.get('PAGURE_CI_SERVICES', True): + if 'jenkins' in pagure_config['PAGURE_CI_SERVICES']: ci_doc.append(load_doc(jenkins.jenkins_ci_notification)) api_pull_request_views_doc = load_doc(fork.api_pull_request_views) @@ -487,7 +492,7 @@ def api(): api_view_group_doc = load_doc(group.api_view_group) api_groups_doc = load_doc(group.api_groups) - if pagure.APP.config.get('ENABLE_TICKETS', True): + if pagure_config.get('ENABLE_TICKETS', True): api_project_tags_doc = load_doc(api_project_tags) api_error_codes_doc = load_doc(api_error_codes) @@ -496,12 +501,12 @@ def api(): api_error_codes_doc, ] - if pagure.APP.config.get('ENABLE_TICKETS', True): + if pagure_config.get('ENABLE_TICKETS', True): extras.append(api_project_tags_doc) return flask.render_template( 'api.html', - version=__api_version__, + version=pagure.__api_version__, api_doc=APIDOC, projects=[ api_new_project_doc, @@ -541,12 +546,3 @@ def api(): ci=ci_doc, extras=extras, ) - - -@APP.route('/api/') -@APP.route('/api') -def api_redirect(): - ''' Redirects the user to the API documentation page. - - ''' - return flask.redirect(flask.url_for('api_ns.api')) diff --git a/pagure/api/ci/jenkins.py b/pagure/api/ci/jenkins.py index 2c53d2a..280bf11 100644 --- a/pagure/api/ci/jenkins.py +++ b/pagure/api/ci/jenkins.py @@ -8,6 +8,8 @@ """ +import logging + import flask from cryptography.hazmat.primitives import constant_time @@ -17,10 +19,12 @@ import pagure import pagure.exceptions import pagure.lib import pagure.lib.lib_ci as lib_ci -from pagure import APP, SESSION from pagure.api import API, APIERROR, api_method +_log = logging.getLogger(__name__) + + @API.route('/ci/jenkins///build-finished', methods=['POST']) @API.route('/ci/jenkins////build-finished', @@ -45,8 +49,8 @@ def jenkins_ci_notification( """ project = pagure.lib._get_project( - SESSION, repo, user=username, namespace=namespace, - case=APP.config.get('CASE_SENSITIVE', False)) + flask.g.session, repo, user=username, namespace=namespace, + case=pagure.config.config.get('CASE_SENSITIVE', False)) flask.g.repo_locked = True flask.g.repo = project if not project: @@ -59,28 +63,28 @@ def jenkins_ci_notification( data = flask.request.get_json() if not data: - APP.logger.debug("Bad Request: No JSON retrieved") + _log.debug("Bad Request: No JSON retrieved") raise pagure.exceptions.APIError(400, error_code=APIERROR.EINVALIDREQ) build_id = data.get('build', {}).get('number') if not build_id: - APP.logger.debug("Bad Request: No build ID retrieved") + _log.debug("Bad Request: No build ID retrieved") raise pagure.exceptions.APIError(400, error_code=APIERROR.EINVALIDREQ) try: lib_ci.process_jenkins_build( - SESSION, + flask.g.session, project, build_id, - requestfolder=APP.config['REQUESTS_FOLDER'] + requestfolder=pagure.config.config['REQUESTS_FOLDER'] ) except pagure.exceptions.NoCorrespondingPR as err: raise pagure.exceptions.APIError( 400, error_code=APIERROR.ENOCODE, error=str(err)) except pagure.exceptions.PagureException as err: - APP.logger.error('Error processing jenkins notification', exc_info=err) + _log.error('Error processing jenkins notification', exc_info=err) raise pagure.exceptions.APIError( 400, error_code=APIERROR.ENOCODE, error=str(err)) - APP.logger.info('Successfully proccessed jenkins notification') + _log.info('Successfully proccessed jenkins notification') return ('', 204) diff --git a/pagure/api/fork.py b/pagure/api/fork.py index 73b5f30..0d81fa6 100644 --- a/pagure/api/fork.py +++ b/pagure/api/fork.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- """ - (c) 2015 - Copyright Red Hat Inc + (c) 2015-2017 - Copyright Red Hat Inc Authors: Pierre-Yves Chibon @@ -9,6 +9,7 @@ """ import flask +import logging from sqlalchemy.exc import SQLAlchemyError @@ -16,9 +17,13 @@ import pagure import pagure.exceptions import pagure.lib import pagure.lib.tasks -from pagure import APP, SESSION, is_repo_committer, api_authenticated from pagure.api import (API, api_method, api_login_required, APIERROR, get_authorized_api_project) +from pagure.config import config as pagure_config +from pagure.utils import is_repo_committer, api_authenticated + + +_log = logging.getLogger(__name__) @API.route('//pull-requests') @@ -126,7 +131,7 @@ def api_pull_request_views(repo, username=None, namespace=None): """ repo = get_authorized_api_project( - SESSION, repo, user=username, namespace=namespace) + flask.g.session, repo, user=username, namespace=namespace) if repo is None: raise pagure.exceptions.APIError(404, error_code=APIERROR.ENOPROJECT) @@ -142,7 +147,7 @@ def api_pull_request_views(repo, username=None, namespace=None): requests = [] if str(status).lower() in ['0', 'false', 'closed']: requests = pagure.lib.search_pull_requests( - SESSION, + flask.g.session, project_id=repo.id, status=False, assignee=assignee, @@ -150,7 +155,7 @@ def api_pull_request_views(repo, username=None, namespace=None): elif str(status).lower() == 'all': requests = pagure.lib.search_pull_requests( - SESSION, + flask.g.session, project_id=repo.id, status=None, assignee=assignee, @@ -158,7 +163,7 @@ def api_pull_request_views(repo, username=None, namespace=None): else: requests = pagure.lib.search_pull_requests( - SESSION, + flask.g.session, project_id=repo.id, assignee=assignee, author=author, @@ -252,7 +257,7 @@ def api_pull_request_view(repo, requestid, username=None, namespace=None): """ repo = get_authorized_api_project( - SESSION, repo, user=username, namespace=namespace) + flask.g.session, repo, user=username, namespace=namespace) if repo is None: raise pagure.exceptions.APIError(404, error_code=APIERROR.ENOPROJECT) @@ -262,7 +267,7 @@ def api_pull_request_view(repo, requestid, username=None, namespace=None): 404, error_code=APIERROR.EPULLREQUESTSDISABLED) request = pagure.lib.search_pull_requests( - SESSION, project_id=repo.id, requestid=requestid) + flask.g.session, project_id=repo.id, requestid=requestid) if not request: raise pagure.exceptions.APIError(404, error_code=APIERROR.ENOREQ) @@ -320,7 +325,7 @@ def api_pull_request_merge(repo, requestid, username=None, namespace=None): output = {} repo = get_authorized_api_project( - SESSION, repo, user=username, namespace=namespace) + flask.g.session, repo, user=username, namespace=namespace) if repo is None: raise pagure.exceptions.APIError(404, error_code=APIERROR.ENOPROJECT) @@ -333,7 +338,7 @@ def api_pull_request_merge(repo, requestid, username=None, namespace=None): raise pagure.exceptions.APIError(401, error_code=APIERROR.EINVALIDTOK) request = pagure.lib.search_pull_requests( - SESSION, project_id=repo.id, requestid=requestid) + flask.g.session, project_id=repo.id, requestid=requestid) if not request: raise pagure.exceptions.APIError(404, error_code=APIERROR.ENOREQ) @@ -412,7 +417,7 @@ def api_pull_request_close(repo, requestid, username=None, namespace=None): output = {} repo = get_authorized_api_project( - SESSION, repo, user=username, namespace=namespace) + flask.g.session, repo, user=username, namespace=namespace) if repo is None: raise pagure.exceptions.APIError(404, error_code=APIERROR.ENOPROJECT) @@ -425,7 +430,7 @@ def api_pull_request_close(repo, requestid, username=None, namespace=None): raise pagure.exceptions.APIError(401, error_code=APIERROR.EINVALIDTOK) request = pagure.lib.search_pull_requests( - SESSION, project_id=repo.id, requestid=requestid) + flask.g.session, project_id=repo.id, requestid=requestid) if not request: raise pagure.exceptions.APIError(404, error_code=APIERROR.ENOREQ) @@ -435,14 +440,14 @@ def api_pull_request_close(repo, requestid, username=None, namespace=None): try: pagure.lib.close_pull_request( - SESSION, request, flask.g.fas_user.username, - requestfolder=APP.config['REQUESTS_FOLDER'], + flask.g.session, request, flask.g.fas_user.username, + requestfolder=pagure_config['REQUESTS_FOLDER'], merged=False) - SESSION.commit() + flask.g.session.commit() output['message'] = 'Pull-request closed!' except SQLAlchemyError as err: # pragma: no cover - SESSION.rollback() - APP.logger.exception(err) + flask.g.session.rollback() + _log.exception(err) raise pagure.exceptions.APIError(400, error_code=APIERROR.EDBERROR) jsonout = flask.jsonify(output) @@ -515,7 +520,7 @@ def api_pull_request_add_comment( """ # noqa repo = get_authorized_api_project( - SESSION, repo, user=username, namespace=namespace) + flask.g.session, repo, user=username, namespace=namespace) output = {} @@ -530,7 +535,7 @@ def api_pull_request_add_comment( raise pagure.exceptions.APIError(401, error_code=APIERROR.EINVALIDTOK) request = pagure.lib.search_pull_requests( - SESSION, project_id=repo.id, requestid=requestid) + flask.g.session, project_id=repo.id, requestid=requestid) if not request: raise pagure.exceptions.APIError(404, error_code=APIERROR.ENOREQ) @@ -545,7 +550,7 @@ def api_pull_request_add_comment( try: # New comment message = pagure.lib.add_pull_request_comment( - SESSION, + flask.g.session, request=request, commit=commit, tree_id=tree_id, @@ -553,16 +558,16 @@ def api_pull_request_add_comment( row=row, comment=comment, user=flask.g.fas_user.username, - requestfolder=APP.config['REQUESTS_FOLDER'], + requestfolder=pagure_config['REQUESTS_FOLDER'], ) - SESSION.commit() + flask.g.session.commit() output['message'] = message except pagure.exceptions.PagureException as err: raise pagure.exceptions.APIError( 400, error_code=APIERROR.ENOCODE, error=str(err)) except SQLAlchemyError as err: # pragma: no cover - APP.logger.exception(err) - SESSION.rollback() + _log.exception(err) + flask.g.session.rollback() raise pagure.exceptions.APIError(400, error_code=APIERROR.EDBERROR) else: @@ -695,7 +700,7 @@ def api_pull_request_add_flag(repo, requestid, username=None, namespace=None): """ # noqa repo = get_authorized_api_project( - SESSION, repo, user=username, namespace=namespace) + flask.g.session, repo, user=username, namespace=namespace) output = {} @@ -712,7 +717,7 @@ def api_pull_request_add_flag(repo, requestid, username=None, namespace=None): 401, error_code=APIERROR.EINVALIDTOK) request = pagure.lib.search_pull_requests( - SESSION, project_id=repo.id, requestid=requestid) + flask.g.session, project_id=repo.id, requestid=requestid) if not request: raise pagure.exceptions.APIError(404, error_code=APIERROR.ENOREQ) @@ -737,7 +742,7 @@ def api_pull_request_add_flag(repo, requestid, username=None, namespace=None): try: # New Flag message, uid = pagure.lib.add_pull_request_flag( - SESSION, + flask.g.session, request=request, username=username, status=status, @@ -747,11 +752,11 @@ def api_pull_request_add_flag(repo, requestid, username=None, namespace=None): uid=uid, user=flask.g.fas_user.username, token=flask.g.token.id, - requestfolder=APP.config['REQUESTS_FOLDER'], + requestfolder=pagure_config['REQUESTS_FOLDER'], ) - SESSION.commit() + flask.g.session.commit() pr_flag = pagure.lib.get_pull_request_flag_by_uid( - SESSION, request, uid) + flask.g.session, request, uid) output['message'] = message output['uid'] = uid output['flag'] = pr_flag.to_json() @@ -759,8 +764,8 @@ def api_pull_request_add_flag(repo, requestid, username=None, namespace=None): raise pagure.exceptions.APIError( 400, error_code=APIERROR.ENOCODE, error=str(err)) except SQLAlchemyError as err: # pragma: no cover - APP.logger.exception(err) - SESSION.rollback() + _log.exception(err) + flask.g.session.rollback() raise pagure.exceptions.APIError(400, error_code=APIERROR.EDBERROR) else: @@ -827,7 +832,7 @@ def api_subscribe_pull_request( """ # noqa repo = get_authorized_api_project( - SESSION, repo, user=username, namespace=namespace) + flask.g.session, repo, user=username, namespace=namespace) output = {} @@ -845,7 +850,7 @@ def api_subscribe_pull_request( 401, error_code=APIERROR.EINVALIDTOK) request = pagure.lib.search_pull_requests( - SESSION, project_id=repo.id, requestid=requestid) + flask.g.session, project_id=repo.id, requestid=requestid) if not request: raise pagure.exceptions.APIError(404, error_code=APIERROR.ENOREQ) @@ -856,16 +861,16 @@ def api_subscribe_pull_request( try: # Toggle subscribtion message = pagure.lib.set_watch_obj( - SESSION, + flask.g.session, user=flask.g.fas_user.username, obj=request, watch_status=status ) - SESSION.commit() + flask.g.session.commit() output['message'] = message except SQLAlchemyError as err: # pragma: no cover - SESSION.rollback() - APP.logger.exception(err) + flask.g.session.rollback() + _log.logger.exception(err) raise pagure.exceptions.APIError(400, error_code=APIERROR.EDBERROR) else: diff --git a/pagure/api/group.py b/pagure/api/group.py index 58edcf9..6af56a7 100644 --- a/pagure/api/group.py +++ b/pagure/api/group.py @@ -14,7 +14,6 @@ import flask import pagure import pagure.exceptions import pagure.lib -from pagure import SESSION from pagure.api import API, APIERROR, api_method, api_login_optional @@ -63,7 +62,7 @@ def api_groups(): if pattern is not None and not pattern.endswith('*'): pattern += '*' - groups = pagure.lib.search_groups(SESSION, pattern=pattern) + groups = pagure.lib.search_groups(flask.g.session, pattern=pattern) if extended: groups = [ @@ -187,11 +186,11 @@ def api_view_group(group): elif acl: acl = [acl] - group = pagure.lib.search_groups(SESSION, group_name=group) + group = pagure.lib.search_groups(flask.g.session, group_name=group) if not group: raise pagure.exceptions.APIError(404, error_code=APIERROR.ENOGROUP) - output = group.to_json(public=(not pagure.api_authenticated())) + output = group.to_json(public=(not pagure.utils.api_authenticated())) if projects and not acl: output['projects'] = [ project.to_json(public=True) diff --git a/pagure/api/issue.py b/pagure/api/issue.py index 3eba96e..10e2eb1 100644 --- a/pagure/api/issue.py +++ b/pagure/api/issue.py @@ -12,21 +12,26 @@ from __future__ import print_function import flask import datetime +import logging from sqlalchemy.exc import SQLAlchemyError -import pagure import pagure.exceptions import pagure.lib - -from pagure import ( - APP, SESSION, is_repo_committer, api_authenticated, - urlpattern, is_repo_user -) from pagure.api import ( API, api_method, api_login_required, api_login_optional, APIERROR, get_authorized_api_project ) +from pagure.config import config as pagure_config +from pagure.utils import ( + api_authenticated, + is_repo_committer, + is_repo_user, + urlpattern, +) + + +_log = logging.getLogger(__name__) def _get_repo(repo_name, username=None, namespace=None): @@ -39,7 +44,7 @@ def _get_repo(repo_name, username=None, namespace=None): :return: repository name """ repo = get_authorized_api_project( - SESSION, repo_name, user=username, namespace=namespace) + flask.g.session, repo_name, user=username, namespace=namespace) if repo is None: raise pagure.exceptions.APIError( @@ -84,7 +89,7 @@ def _get_issue(repo, issueid, issueuid=None): :return: issue """ issue = pagure.lib.search_issues( - SESSION, repo, issueid=issueid, issueuid=issueuid) + flask.g.session, repo, issueid=issueid, issueuid=issueuid) if issue is None or issue.project != repo: raise pagure.exceptions.APIError(404, error_code=APIERROR.ENOISSUE) @@ -243,7 +248,7 @@ def api_new_issue(repo, username=None, namespace=None): _check_token(repo, project_token=False) user_obj = pagure.lib.get_user( - SESSION, flask.g.fas_user.username) + flask.g.session, flask.g.fas_user.username) if not user_obj: raise pagure.exceptions.APIError(404, error_code=APIERROR.ENOUSER) @@ -267,7 +272,7 @@ def api_new_issue(repo, username=None, namespace=None): try: issue = pagure.lib.new_issue( - SESSION, + flask.g.session, repo=repo, title=title, content=content, @@ -277,16 +282,16 @@ def api_new_issue(repo, username=None, namespace=None): priority=priority, tags=tags, user=flask.g.fas_user.username, - ticketfolder=APP.config['TICKETS_FOLDER'], + ticketfolder=pagure_config['TICKETS_FOLDER'], ) - SESSION.flush() + flask.g.session.flush() # If there is a file attached, attach it. filestream = flask.request.files.get('filestream') if filestream and '' in issue.content: new_filename = pagure.lib.add_attachment( repo=repo, issue=issue, - attachmentfolder=APP.config['ATTACHMENTS_FOLDER'], + attachmentfolder=pagure_config['ATTACHMENTS_FOLDER'], user=user_obj, filename=filestream.filename, filestream=filestream.stream, @@ -303,15 +308,15 @@ def api_new_issue(repo, username=None, namespace=None): url = '[![%s](%s)](%s)' % ( new_filename, filelocation, filelocation) issue.content = issue.content.replace('', url) - SESSION.add(issue) - SESSION.flush() + flask.g.session.add(issue) + flask.g.session.flush() - SESSION.commit() + flask.g.session.commit() output['message'] = 'Issue created' output['issue'] = issue.to_json(public=True) except SQLAlchemyError as err: # pragma: no cover - SESSION.rollback() - APP.logger.exception(err) + flask.g.session.rollback() + _log.exception(err) raise pagure.exceptions.APIError(400, error_code=APIERROR.EDBERROR) else: @@ -485,7 +490,7 @@ def api_view_issues(repo, username=None, namespace=None): private = None params = { - 'session': SESSION, + 'session': flask.g.session, 'repo': repo, 'tags': tags, 'assignee': assignee, @@ -679,7 +684,8 @@ 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(SESSION, issue.uid, commentid) + comment = pagure.lib.get_issue_comment( + flask.g.session, issue.uid, commentid) if not comment: raise pagure.exceptions.APIError( 404, error_code=APIERROR.ENOCOMMENT) @@ -751,13 +757,13 @@ def api_change_status_issue(repo, issueid, username=None, namespace=None): issue = _get_issue(repo, issueid) _check_ticket_access(issue) - status = pagure.lib.get_issue_statuses(SESSION) + status = pagure.lib.get_issue_statuses(flask.g.session) form = pagure.forms.StatusForm( status=status, close_status=repo.close_status, csrf_enabled=False) - if not pagure.is_repo_user(repo) \ + if not pagure.utils.is_repo_user(repo) \ and flask.g.fas_user.username != issue.user.user: raise pagure.exceptions.APIError( 403, error_code=APIERROR.EISSUENOTALLOWED) @@ -775,14 +781,14 @@ def api_change_status_issue(repo, issueid, username=None, namespace=None): try: # Update status message = pagure.lib.edit_issue( - SESSION, + flask.g.session, issue=issue, status=new_status, close_status=close_status, user=flask.g.fas_user.username, - ticketfolder=APP.config['TICKETS_FOLDER'], + ticketfolder=pagure_config['TICKETS_FOLDER'], ) - SESSION.commit() + flask.g.session.commit() if message: output['message'] = message else: @@ -790,17 +796,17 @@ def api_change_status_issue(repo, issueid, username=None, namespace=None): if message: pagure.lib.add_metadata_update_notif( - session=SESSION, + session=flask.g.session, obj=issue, messages=message, user=flask.g.fas_user.username, - gitfolder=APP.config['TICKETS_FOLDER'] + gitfolder=pagure_config['TICKETS_FOLDER'] ) except pagure.exceptions.PagureException as err: raise pagure.exceptions.APIError( 400, error_code=APIERROR.ENOCODE, error=str(err)) except SQLAlchemyError as err: # pragma: no cover - SESSION.rollback() + flask.g.session.rollback() raise pagure.exceptions.APIError(400, error_code=APIERROR.EDBERROR) else: @@ -880,13 +886,13 @@ def api_change_milestone_issue(repo, issueid, username=None, namespace=None): try: # Update status message = pagure.lib.edit_issue( - SESSION, + flask.g.session, issue=issue, milestone=new_milestone, user=flask.g.fas_user.username, - ticketfolder=APP.config['TICKETS_FOLDER'], + ticketfolder=pagure_config['TICKETS_FOLDER'], ) - SESSION.commit() + flask.g.session.commit() if message: output['message'] = message else: @@ -894,17 +900,17 @@ def api_change_milestone_issue(repo, issueid, username=None, namespace=None): if message: pagure.lib.add_metadata_update_notif( - session=SESSION, + session=flask.g.session, obj=issue, messages=message, user=flask.g.fas_user.username, - gitfolder=APP.config['TICKETS_FOLDER'] + gitfolder=pagure_config['TICKETS_FOLDER'] ) except pagure.exceptions.PagureException as err: raise pagure.exceptions.APIError( 400, error_code=APIERROR.ENOCODE, error=str(err)) except SQLAlchemyError as err: # pragma: no cover - SESSION.rollback() + flask.g.session.rollback() raise pagure.exceptions.APIError(400, error_code=APIERROR.EDBERROR) else: @@ -974,17 +980,17 @@ def api_comment_issue(repo, issueid, username=None, namespace=None): try: # New comment message = pagure.lib.add_issue_comment( - SESSION, + flask.g.session, issue=issue, comment=comment, user=flask.g.fas_user.username, - ticketfolder=APP.config['TICKETS_FOLDER'], + ticketfolder=pagure_config['TICKETS_FOLDER'], ) - SESSION.commit() + flask.g.session.commit() output['message'] = message except SQLAlchemyError as err: # pragma: no cover - SESSION.rollback() - APP.logger.exception(err) + flask.g.session.rollback() + _log.exception(err) raise pagure.exceptions.APIError(400, error_code=APIERROR.EDBERROR) else: @@ -1055,20 +1061,20 @@ def api_assign_issue(repo, issueid, username=None, namespace=None): try: # New comment message = pagure.lib.add_issue_assignee( - SESSION, + flask.g.session, issue=issue, assignee=assignee, user=flask.g.fas_user.username, - ticketfolder=APP.config['TICKETS_FOLDER'], + ticketfolder=pagure_config['TICKETS_FOLDER'], ) - SESSION.commit() + flask.g.session.commit() if message: pagure.lib.add_metadata_update_notif( - session=SESSION, + session=flask.g.session, obj=issue, messages=message, user=flask.g.fas_user.username, - gitfolder=APP.config['TICKETS_FOLDER'] + gitfolder=pagure_config['TICKETS_FOLDER'] ) output['message'] = message else: @@ -1077,8 +1083,8 @@ def api_assign_issue(repo, issueid, username=None, namespace=None): raise pagure.exceptions.APIError( 400, error_code=APIERROR.ENOCODE, error=str(err)) except SQLAlchemyError as err: # pragma: no cover - SESSION.rollback() - APP.logger.exception(err) + flask.g.session.rollback() + _log.exception(err) raise pagure.exceptions.APIError(400, error_code=APIERROR.EDBERROR) else: @@ -1152,16 +1158,16 @@ def api_subscribe_issue(repo, issueid, username=None, namespace=None): try: # Toggle subscribtion message = pagure.lib.set_watch_obj( - SESSION, + flask.g.session, user=flask.g.fas_user.username, obj=issue, watch_status=status ) - SESSION.commit() + flask.g.session.commit() output['message'] = message except SQLAlchemyError as err: # pragma: no cover - SESSION.rollback() - APP.logger.exception(err) + flask.g.session.rollback() + _log.exception(err) raise pagure.exceptions.APIError(400, error_code=APIERROR.EDBERROR) else: @@ -1240,17 +1246,17 @@ def api_update_custom_field( _check_link_custom_field(key, value) try: message = pagure.lib.set_custom_key_value( - SESSION, issue, key, value) + flask.g.session, issue, key, value) - SESSION.commit() + flask.g.session.commit() if message: output['message'] = message pagure.lib.add_metadata_update_notif( - session=SESSION, + session=flask.g.session, obj=issue, messages=message, user=flask.g.fas_user.username, - gitfolder=APP.config['TICKETS_FOLDER'] + gitfolder=pagure_config['TICKETS_FOLDER'] ) else: output['message'] = 'No changes' @@ -1259,7 +1265,7 @@ def api_update_custom_field( 400, error_code=APIERROR.ENOCODE, error=str(err)) except SQLAlchemyError as err: # pragma: no cover print(err) - SESSION.rollback() + flask.g.session.rollback() raise pagure.exceptions.APIError(400, error_code=APIERROR.EDBERROR) jsonout = flask.jsonify(output) @@ -1364,17 +1370,17 @@ def api_update_custom_fields( _check_link_custom_field(key, value) try: message = pagure.lib.set_custom_key_value( - SESSION, issue, key, value) + flask.g.session, issue, key, value) - SESSION.commit() + flask.g.session.commit() if message: output['messages'].append({key.name: message}) pagure.lib.add_metadata_update_notif( - session=SESSION, + session=flask.g.session, obj=issue, messages=message, user=flask.g.fas_user.username, - gitfolder=APP.config['TICKETS_FOLDER'] + gitfolder=pagure_config['TICKETS_FOLDER'] ) else: output['messages'].append({key.name: 'No changes'}) @@ -1383,7 +1389,7 @@ def api_update_custom_fields( 400, error_code=APIERROR.ENOCODE, error=str(err)) except SQLAlchemyError as err: # pragma: no cover print(err) - SESSION.rollback() + flask.g.session.rollback() raise pagure.exceptions.APIError(400, error_code=APIERROR.EDBERROR) jsonout = flask.jsonify(output) @@ -1433,6 +1439,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(SESSION, repo) + stats = pagure.lib.issues_history_stats(flask.g.session, repo) jsonout = flask.jsonify({'stats': stats}) return jsonout diff --git a/pagure/api/project.py b/pagure/api/project.py index 406fc49..0f72ab0 100644 --- a/pagure/api/project.py +++ b/pagure/api/project.py @@ -9,6 +9,7 @@ """ import flask +import logging from sqlalchemy.exc import SQLAlchemyError from six import string_types @@ -19,9 +20,13 @@ import pagure.forms import pagure.exceptions import pagure.lib import pagure.lib.git -from pagure import SESSION, APP, authenticated +import pagure.utils from pagure.api import (API, api_method, APIERROR, api_login_required, get_authorized_api_project, api_login_optional) +from pagure.config import config as pagure_config + + +_log = logging.getLogger(__name__) @API.route('//git/tags') @@ -57,7 +62,7 @@ def api_git_tags(repo, username=None, namespace=None): """ repo = get_authorized_api_project( - SESSION, repo, user=username, namespace=namespace) + flask.g.session, repo, user=username, namespace=namespace) if repo is None: raise pagure.exceptions.APIError(404, error_code=APIERROR.ENOPROJECT) @@ -107,7 +112,7 @@ def api_project_watchers(repo, username=None, namespace=None): } ''' repo = get_authorized_api_project( - SESSION, repo, user=username, namespace=namespace) + flask.g.session, repo, user=username, namespace=namespace) if repo is None: raise pagure.exceptions.APIError(404, error_code=APIERROR.ENOPROJECT) @@ -120,7 +125,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( - SESSION, implicit_watch_user, repo) + flask.g.session, implicit_watch_user, repo) watching_users_to_watch_level[implicit_watch_user] = user_watch_level for access_type in repo.access_groups.keys(): @@ -139,7 +144,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( - SESSION, watcher.user.username, repo) + flask.g.session, watcher.user.username, repo) else: if watcher.user.username in watching_users_to_watch_level: watching_users_to_watch_level.pop(watcher.user.username, None) @@ -186,13 +191,13 @@ def api_project_git_urls(repo, username=None, namespace=None): } ''' repo = get_authorized_api_project( - SESSION, repo, user=username, namespace=namespace) + flask.g.session, repo, user=username, namespace=namespace) if repo is None: raise pagure.exceptions.APIError(404, error_code=APIERROR.ENOPROJECT) git_urls = {} - git_url_ssh = APP.config.get('GIT_URL_SSH') - if authenticated() and git_url_ssh: + git_url_ssh = pagure_config.get('GIT_URL_SSH') + if pagure.utils.authenticated() and git_url_ssh: try: git_url_ssh = git_url_ssh.format( username=flask.g.fas_user.username) @@ -201,9 +206,9 @@ def api_project_git_urls(repo, username=None, namespace=None): if git_url_ssh: git_urls['ssh'] = '{0}{1}.git'.format(git_url_ssh, repo.fullname) - if pagure.APP.config.get('GIT_URL_GIT'): + if pagure_config.get('GIT_URL_GIT'): git_urls['git'] = '{0}{1}.git'.format( - pagure.APP.config['GIT_URL_GIT'], repo.fullname) + pagure_config['GIT_URL_GIT'], repo.fullname) return flask.jsonify({ 'total_urls': len(git_urls), @@ -244,7 +249,7 @@ def api_git_branches(repo, username=None, namespace=None): ''' repo = get_authorized_api_project( - SESSION, repo, user=username, namespace=namespace) + flask.g.session, repo, user=username, namespace=namespace) if repo is None: raise pagure.exceptions.APIError(404, error_code=APIERROR.ENOPROJECT) @@ -520,12 +525,14 @@ def api_projects(): short = False private = False - if authenticated() and username == flask.g.fas_user.username: + if pagure.utils.authenticated() \ + and username == flask.g.fas_user.username: private = flask.g.fas_user.username project_count = pagure.lib.search_projects( - SESSION, username=username, fork=fork, tags=tags, pattern=pattern, - private=private, namespace=namespace, owner=owner, count=True) + flask.g.session, username=username, fork=fork, tags=tags, + pattern=pattern, private=private, namespace=namespace, owner=owner, + count=True) # Pagination code inspired by Flask-SQLAlchemy pagination_metadata = None query_start = None @@ -560,9 +567,9 @@ def api_projects(): query_limit = per_page projects = pagure.lib.search_projects( - SESSION, username=username, fork=fork, tags=tags, pattern=pattern, - private=private, namespace=namespace, owner=owner, limit=query_limit, - start=query_start) + flask.g.session, username=username, fork=fork, tags=tags, + pattern=pattern, private=private, namespace=namespace, owner=owner, + limit=query_limit, start=query_start) # prepare the output json jsonout = { @@ -681,7 +688,7 @@ def api_project(repo, username=None, namespace=None): """ repo = get_authorized_api_project( - SESSION, repo, user=username, namespace=namespace) + flask.g.session, repo, user=username, namespace=namespace) expand_group = str( flask.request.values.get('expand_group', None) @@ -779,14 +786,15 @@ def api_new_project(): } """ - user = pagure.lib.search_user(SESSION, username=flask.g.fas_user.username) + user = pagure.lib.search_user( + flask.g.session, username=flask.g.fas_user.username) output = {} - if not pagure.APP.config.get('ENABLE_NEW_PROJECTS', True): + if not pagure_config.get('ENABLE_NEW_PROJECTS', True): raise pagure.exceptions.APIError( 404, error_code=APIERROR.ENEWPROJECTDISABLED) - namespaces = APP.config['ALLOWED_PREFIX'][:] + namespaces = pagure_config['ALLOWED_PREFIX'][:] if user: namespaces.extend([grp for grp in user.groups]) @@ -804,12 +812,12 @@ def api_new_project(): namespace = namespace.strip() private = False - if pagure.APP.config.get('PRIVATE_PROJECTS', False): + if pagure_config.get('PRIVATE_PROJECTS', False): private = form.private.data try: taskid = pagure.lib.new_project( - SESSION, + flask.g.session, name=name, namespace=namespace, description=description, @@ -817,35 +825,35 @@ def api_new_project(): url=url, avatar_email=avatar_email, user=flask.g.fas_user.username, - blacklist=APP.config['BLACKLISTED_PROJECTS'], - allowed_prefix=APP.config['ALLOWED_PREFIX'], - gitfolder=APP.config['GIT_FOLDER'], - docfolder=APP.config['DOCS_FOLDER'], - ticketfolder=APP.config['TICKETS_FOLDER'], - requestfolder=APP.config['REQUESTS_FOLDER'], + blacklist=pagure_config['BLACKLISTED_PROJECTS'], + allowed_prefix=pagure_config['ALLOWED_PREFIX'], + gitfolder=pagure_config['GIT_FOLDER'], + docfolder=pagure_config['DOCS_FOLDER'], + ticketfolder=pagure_config['TICKETS_FOLDER'], + requestfolder=pagure_config['REQUESTS_FOLDER'], add_readme=create_readme, userobj=user, - prevent_40_chars=APP.config.get( + prevent_40_chars=pagure_config.get( 'OLD_VIEW_COMMIT_ENABLED', False), - user_ns=APP.config.get('USER_NAMESPACE', False), + user_ns=pagure_config.get('USER_NAMESPACE', False), ) - SESSION.commit() + flask.g.session.commit() output = {'message': 'Project creation queued', 'taskid': taskid} if flask.request.form.get('wait', True): result = pagure.lib.tasks.get_result(taskid).get() project = pagure.lib._get_project( - SESSION, name=result['repo'], + flask.g.session, name=result['repo'], namespace=result['namespace'], - case=APP.config.get('CASE_SENSITIVE', False)) + case=pagure_config.get('CASE_SENSITIVE', False)) output = {'message': 'Project "%s" created' % project.fullname} except pagure.exceptions.PagureException as err: raise pagure.exceptions.APIError( 400, error_code=APIERROR.ENOCODE, error=str(err)) except SQLAlchemyError as err: # pragma: no cover - APP.logger.exception(err) - SESSION.rollback() + _log.exception(err) + flask.g.session.rollback() raise pagure.exceptions.APIError(400, error_code=APIERROR.EDBERROR) else: raise pagure.exceptions.APIError( @@ -927,17 +935,18 @@ def api_modify_project(repo, namespace=None): """ project = get_authorized_api_project( - SESSION, repo, namespace=namespace) + flask.g.session, repo, namespace=namespace) if not project: raise pagure.exceptions.APIError( 404, error_code=APIERROR.ENOPROJECT) - is_site_admin = pagure.is_admin() - admins = project.get_project_users('admin') + is_site_admin = pagure.utils.is_admin() + admins = [u.username for u in project.get_project_users('admin')] # Only allow the main admin, the admins of the project, and Pagure site # admins to modify projects, even if the user has the right ACLs on their # token - if flask.g.fas_user not in admins and flask.g.fas_user != project.user \ + if flask.g.fas_user.username not in admins \ + and flask.g.fas_user.username != project.user.username \ and not is_site_admin: raise pagure.exceptions.APIError( 401, error_code=APIERROR.EMODIFYPROJECTNOTALLOWED) @@ -963,7 +972,8 @@ def api_modify_project(repo, namespace=None): 400, error_code=APIERROR.EINVALIDREQ) if 'main_admin' in args: - if flask.g.fas_user != project.user and not is_site_admin: + if flask.g.fas_user.username != project.user.username \ + and not is_site_admin: raise pagure.exceptions.APIError( 401, error_code=APIERROR.ENOTMAINADMIN) # If the main_admin is already set correctly, don't do anything @@ -971,21 +981,23 @@ 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(SESSION, args['main_admin']) + new_main_admin = pagure.lib.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(SESSION, project, new_main_admin) + pagure.lib.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( - SESSION, project, new_user=flask.g.fas_user.username, + flask.g.session, project, new_user=flask.g.fas_user.username, user=flask.g.fas_user.username) try: - SESSION.commit() + flask.g.session.commit() except SQLAlchemyError: # pragma: no cover - SESSION.rollback() + flask.g.session.rollback() raise pagure.exceptions.APIError( 400, error_code=APIERROR.EDBERROR) @@ -1060,22 +1072,22 @@ def api_fork_project(): namespace = form.namespace.data.strip() or None repo = get_authorized_api_project( - SESSION, repo, user=username, namespace=namespace) + flask.g.session, repo, user=username, namespace=namespace) if repo is None: raise pagure.exceptions.APIError( 404, error_code=APIERROR.ENOPROJECT) try: taskid = pagure.lib.fork_project( - SESSION, + flask.g.session, user=flask.g.fas_user.username, repo=repo, - gitfolder=APP.config['GIT_FOLDER'], - docfolder=APP.config['DOCS_FOLDER'], - ticketfolder=APP.config['TICKETS_FOLDER'], - requestfolder=APP.config['REQUESTS_FOLDER'], + gitfolder=pagure_config['GIT_FOLDER'], + docfolder=pagure_config['DOCS_FOLDER'], + ticketfolder=pagure_config['TICKETS_FOLDER'], + requestfolder=pagure_config['REQUESTS_FOLDER'], ) - SESSION.commit() + flask.g.session.commit() output = {'message': 'Project forking queued', 'taskid': taskid} @@ -1088,8 +1100,8 @@ def api_fork_project(): raise pagure.exceptions.APIError( 400, error_code=APIERROR.ENOCODE, error=str(err)) except SQLAlchemyError as err: # pragma: no cover - APP.logger.exception(err) - SESSION.rollback() + _log.exception(err) + flask.g.session.rollback() raise pagure.exceptions.APIError( 400, error_code=APIERROR.EDBERROR) else: @@ -1151,7 +1163,8 @@ def api_generate_acls(repo, username=None, namespace=None): } """ - project = get_authorized_api_project(SESSION, repo, namespace=namespace) + project = get_authorized_api_project( + flask.g.session, repo, namespace=namespace) if not project: raise pagure.exceptions.APIError(404, error_code=APIERROR.ENOPROJECT) @@ -1231,7 +1244,8 @@ def api_new_branch(repo, username=None, namespace=None): } """ - project = get_authorized_api_project(SESSION, repo, namespace=namespace) + project = get_authorized_api_project( + flask.g.session, repo, namespace=namespace) if not project: raise pagure.exceptions.APIError(404, error_code=APIERROR.ENOPROJECT) @@ -1385,7 +1399,7 @@ def api_commit_add_flag(repo, commit_hash, username=None, namespace=None): """ # noqa repo = get_authorized_api_project( - SESSION, repo, user=username, namespace=namespace) + flask.g.session, repo, user=username, namespace=namespace) output = {} @@ -1397,7 +1411,7 @@ def api_commit_add_flag(repo, commit_hash, username=None, namespace=None): raise pagure.exceptions.APIError( 401, error_code=APIERROR.EINVALIDTOK) - reponame = pagure.get_repo_path(repo) + reponame = pagure.utils.get_repo_path(repo) repo_obj = Repository(reponame) try: repo_obj.get(commit_hash) @@ -1416,7 +1430,7 @@ def api_commit_add_flag(repo, commit_hash, username=None, namespace=None): try: # New Flag message, uid = pagure.lib.add_commit_flag( - session=SESSION, + session=flask.g.session, repo=repo, commit_hash=commit_hash, username=username, @@ -1428,9 +1442,9 @@ def api_commit_add_flag(repo, commit_hash, username=None, namespace=None): user=flask.g.fas_user.username, token=flask.g.token.id, ) - SESSION.commit() + flask.g.session.commit() c_flag = pagure.lib.get_commit_flag_by_uid( - SESSION, commit_hash, uid) + flask.g.session, commit_hash, uid) output['message'] = message output['uid'] = uid output['flag'] = c_flag.to_json() @@ -1438,8 +1452,8 @@ def api_commit_add_flag(repo, commit_hash, username=None, namespace=None): raise pagure.exceptions.APIError( 400, error_code=APIERROR.ENOCODE, error=str(err)) except SQLAlchemyError as err: # pragma: no cover - APP.logger.exception(err) - SESSION.rollback() + flask.g.session.rollback() + _log.logger.exception(err) raise pagure.exceptions.APIError( 400, error_code=APIERROR.EDBERROR) else: diff --git a/pagure/api/user.py b/pagure/api/user.py index e796c39..8256719 100644 --- a/pagure/api/user.py +++ b/pagure/api/user.py @@ -18,7 +18,6 @@ import flask import pagure import pagure.exceptions import pagure.lib -from pagure import SESSION from pagure.api import API, api_method, APIERROR @@ -26,7 +25,7 @@ def _get_user(username): """ Check user is valid or not """ try: - return pagure.lib.get_user(SESSION, username) + return pagure.lib.get_user(flask.g.session, username) except pagure.exceptions.PagureException: raise pagure.exceptions.APIError(404, error_code=APIERROR.ENOUSER) @@ -115,12 +114,12 @@ def api_view_user(username): forkpage = 1 repos = pagure.lib.search_projects( - SESSION, + flask.g.session, username=username, fork=False) forks = pagure.lib.search_projects( - SESSION, + flask.g.session, username=username, fork=True) @@ -316,7 +315,7 @@ def api_view_user_issues(username): limit = page * 50 params = { - 'session': SESSION, + 'session': flask.g.session, 'tags': tags, 'milestones': milestone, 'order': order, @@ -486,7 +485,7 @@ def api_view_user_activity_stats(username): user = _get_user(username=username) stats = pagure.lib.get_yearly_stats_user( - SESSION, + flask.g.session, user, datetime.datetime.utcnow().date() + datetime.timedelta(days=1) ) @@ -587,7 +586,7 @@ def api_view_user_activity_date(username, date): user = _get_user(username=username) - activities = pagure.lib.get_user_activity_day(SESSION, user, date) + activities = pagure.lib.get_user_activity_day(flask.g.session, user, date) js_act = [] if grouped: commits = collections.defaultdict(list) @@ -832,7 +831,7 @@ def api_view_user_requests_filed(username): status = status.capitalize() pullrequests = pagure.lib.get_pull_request_of_user( - SESSION, + flask.g.session, username=username, status=status, offset=offset, @@ -1060,7 +1059,7 @@ def api_view_user_requests_actionable(username): status = status.capitalize() pullrequests = pagure.lib.get_pull_request_of_user( - SESSION, + flask.g.session, username=username, status=status, offset=offset, diff --git a/pagure/cli/admin.py b/pagure/cli/admin.py index ad4ccfb..c4eea5c 100644 --- a/pagure/cli/admin.py +++ b/pagure/cli/admin.py @@ -22,13 +22,16 @@ if 'PAGURE_CONFIG' not in os.environ \ print('Using configuration file `/etc/pagure/pagure.cfg`') os.environ['PAGURE_CONFIG'] = '/etc/pagure/pagure.cfg' +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 -from pagure import (SESSION, APP, generate_user_key_files) # 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']) _log = logging.getLogger(__name__) @@ -265,6 +268,10 @@ def parse_arguments(): description='The admin CLI for this pagure instance') parser.add_argument( + '-c', '--config', default=None, + help='Specify a configuration to use') + + parser.add_argument( '--debug', default=False, action='store_true', help='Increase the verbosity of the information displayed') @@ -320,7 +327,7 @@ def _get_project(arg_project, user=None): name = arg_project return pagure.lib._get_project( - SESSION, namespace=namespace, name=name, user=user) + session, namespace=namespace, name=name, user=user) def do_generate_acl(args): @@ -352,12 +359,12 @@ def do_generate_acl(args): return helper = pagure.lib.git_auth.get_git_auth_helper( - APP.config['GITOLITE_BACKEND']) + pagure.config.config['GITOLITE_BACKEND']) _log.debug('Got helper: %s', helper) group_obj = None if args.group: - group_obj = pagure.lib.search_groups(SESSION, group_name=args.group) + group_obj = pagure.lib.search_groups(session, group_name=args.group) _log.debug( 'Calling helper: %s with arg: project=%s, group=%s', helper, project, group_obj) @@ -400,7 +407,7 @@ def do_generate_hook_token(_): 'the database? This will break every web-hook set-up on this ' 'instance. You should only ever run this for a security issue') if _ask_confirmation(): - pagure.lib.generate_hook_token(SESSION) + pagure.lib.generate_hook_token(session) print('Hook token all re-generated') @@ -415,9 +422,9 @@ def do_list_admin_token(args): _log.debug('active: %s', args.active) _log.debug('expire: %s', args.expired) - acls = APP.config['ADMIN_API_ACLS'] + acls = pagure.config.config['ADMIN_API_ACLS'] tokens = pagure.lib.search_token( - SESSION, acls, + session, acls, user=args.user, active=args.active, expired=args.expired) @@ -437,8 +444,8 @@ def do_info_admin_token(args): """ _log.debug('token: %s', args.token) - acls = APP.config['ADMIN_API_ACLS'] - token = pagure.lib.search_token(SESSION, acls, token=args.token) + acls = pagure.config.config['ADMIN_API_ACLS'] + token = pagure.lib.search_token(session, acls, token=args.token) if not token: raise pagure.exceptions.PagureException('No such admin token found') @@ -457,8 +464,8 @@ def do_expire_admin_token(args): """ _log.debug('token: %s', args.token) - acls = APP.config['ADMIN_API_ACLS'] - token = pagure.lib.search_token(SESSION, acls, token=args.token) + acls = pagure.config.config['ADMIN_API_ACLS'] + token = pagure.lib.search_token(session, acls, token=args.token) if not token: raise pagure.exceptions.PagureException('No such admin token found') @@ -471,8 +478,8 @@ def do_expire_admin_token(args): print('Do you really want to expire this API token?') if _ask_confirmation(): token.expiration = datetime.datetime.utcnow() - SESSION.add(token) - SESSION.commit() + session.add(token) + session.commit() print('Token expired') @@ -485,8 +492,8 @@ def do_update_admin_token(args): _log.debug('token: %s', args.token) _log.debug('new date: %s', args.date) - acls = APP.config['ADMIN_API_ACLS'] - token = pagure.lib.search_token(SESSION, acls, token=args.token) + acls = pagure.config.config['ADMIN_API_ACLS'] + token = pagure.lib.search_token(session, acls, token=args.token) if not token: raise pagure.exceptions.PagureException('No such admin token found') @@ -516,8 +523,8 @@ def do_update_admin_token(args): args.date) if _ask_confirmation(): token.expiration = date.naive - SESSION.add(token) - SESSION.commit() + session.add(token) + session.commit() print('Token updated') @@ -529,9 +536,9 @@ def do_create_admin_token(args): """ _log.debug('user: %s', args.user) # Validate user first - pagure.lib.get_user(SESSION, args.user) + pagure.lib.get_user(session, args.user) - acls_list = APP.config['ADMIN_API_ACLS'] + acls_list = pagure.config.config['ADMIN_API_ACLS'] for idx, acl in enumerate(acls_list): print('%s. %s' % (idx, acl)) @@ -546,7 +553,7 @@ 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.add_token_to_user(session, None, acls, args.user)) def do_get_watch_status(args): @@ -558,7 +565,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.get_user(session, args.user) # Get the project project = _get_project(args.project) @@ -568,7 +575,7 @@ def do_get_watch_status(args): 'No project found with: %s' % args.project) level = pagure.lib.get_watch_level_on_repo( - session=SESSION, + session=session, user=args.user, repo=project.name, repouser=None, @@ -594,7 +601,7 @@ def do_update_watch_status(args): _log.debug('project: %s', args.project) # Validate user - pagure.lib.get_user(SESSION, args.user) + pagure.lib.get_user(session, args.user) # Ask the status if none were given if args.status is None: @@ -620,11 +627,11 @@ def do_update_watch_status(args): args.user, args.status, WATCH[args.status], args.project)) pagure.lib.update_watch_status( - session=SESSION, + session=session, project=project, user=args.user, watch=args.status) - SESSION.commit() + session.commit() def do_read_only(args): @@ -639,7 +646,7 @@ def do_read_only(args): _log.debug('read-only: %s', args.ro) # Validate user - pagure.lib.get_user(SESSION, args.user) + pagure.lib.get_user(session, args.user) # Get the project project = _get_project(args.project) @@ -660,9 +667,9 @@ def do_read_only(args): project.fullname, project.read_only)) else: pagure.lib.update_read_only_mode( - SESSION, project, read_only=(args.ro.lower() == 'true') + session, project, read_only=(args.ro.lower() == 'true') ) - SESSION.commit() + session.commit() print( 'The read-only flag of the project %s has been set to %s' % ( project.fullname, args.ro.lower() == 'true')) @@ -674,6 +681,16 @@ def main(): # Parse the arguments args = parse_arguments() + if args.config: + config = args.config + if not config.startswith('/'): + config = os.path.join(os.getcwd(), config) + os.environ['PAGURE_CONFIG'] = config + + global session, _config + _config = pagure.config.reload_config() + session = pagure.lib.create_session(_config['DB_URL']) + logging.basicConfig() if args.debug: _log.setLevel(logging.DEBUG) @@ -692,6 +709,8 @@ def main(): print('Error: {0}'.format(err)) logging.exception("Generic error catched:") return_code = 2 + finally: + session.remove() return return_code diff --git a/pagure/config.py b/pagure/config.py new file mode 100644 index 0000000..da043ce --- /dev/null +++ b/pagure/config.py @@ -0,0 +1,30 @@ +# -*- coding: utf-8 -*- + +""" + (c) 2017 - Copyright Red Hat Inc + + Authors: + Pierre-Yves Chibon + +""" + +import os # noqa: E402 +import flask # noqa: E402 + + +def reload_config(): + """ Reload the configuration. """ + config = flask.config.Config( + os.path.dirname(os.path.abspath(__file__)), + flask.Flask.default_config + ) + + config.from_object('pagure.default_config') + + if 'PAGURE_CONFIG' in os.environ: + config.from_envvar('PAGURE_CONFIG') + + return config + + +config = reload_config() diff --git a/pagure/docs_server.py b/pagure/docs_server.py index 3a8b89a..e3ea53b 100644 --- a/pagure/docs_server.py +++ b/pagure/docs_server.py @@ -16,7 +16,7 @@ import pygit2 from binaryornot.helpers import is_binary_string -import pagure +import pagure.config import pagure.doc_utils import pagure.exceptions import pagure.lib @@ -27,10 +27,7 @@ import pagure.forms APP = flask.Flask(__name__) # set up FAS -APP.config.from_object('pagure.default_config') - -if 'PAGURE_CONFIG' in os.environ: - APP.config.from_envvar('PAGURE_CONFIG') +APP.config = pagure.config.reload_config() SESSION = pagure.lib.create_session(APP.config['DB_URL']) @@ -142,7 +139,7 @@ def view_docs(repo, username=None, namespace=None, filename=None): if '.' in repo: namespace, repo = repo.split('.', 1) - repo = pagure.get_authorized_project( + repo = pagure.lib.get_authorized_project( SESSION, repo, user=username, namespace=namespace) if not repo: diff --git a/pagure/flask_app.py b/pagure/flask_app.py new file mode 100644 index 0000000..14e00a4 --- /dev/null +++ b/pagure/flask_app.py @@ -0,0 +1,402 @@ +# -*- coding: utf-8 -*- + +""" + (c) 2014-2017 - Copyright Red Hat Inc + + Authors: + Pierre-Yves Chibon + +""" + +import datetime +import gc +import logging +import logging.config +import time +import os + +import flask +import pygit2 + +from flask_multistatic import MultiStaticFlask + +import pagure.doc_utils +import pagure.exceptions +import pagure.forms +import pagure.lib +import pagure.lib.git +import pagure.login_forms +import pagure.mail_logging +import pagure.proxy +import pagure.utils +from pagure.config import config as pagure_config +from pagure.utils import get_repo_path + +if os.environ.get('PAGURE_PERFREPO'): + import pagure.perfrepo as perfrepo +else: + perfrepo = None + + +logging.basicConfig() +logging.config.dictConfig(pagure_config.get('LOGGING') or {'version': 1}) +logger = logging.getLogger(__name__) + +REDIS = None +if pagure_config['EVENTSOURCE_SOURCE'] \ + or pagure_config['WEBHOOK'] \ + or pagure_config.get('PAGURE_CI_SERVICES'): + pagure.lib.set_redis( + host=pagure_config['REDIS_HOST'], + port=pagure_config['REDIS_PORT'], + dbname=pagure_config['REDIS_DB'] + ) + + +if pagure_config.get('PAGURE_CI_SERVICES'): + pagure.lib.set_pagure_ci(pagure_config['PAGURE_CI_SERVICES']) + + +def create_app(config=None): + """ Create the flask application. """ + app = MultiStaticFlask(__name__) + app.config = pagure_config + + if config: + app.config.update(config) + + logging.basicConfig() + logging.config.dictConfig(app.config.get('LOGGING') or {'version': 1}) + + app.jinja_env.trim_blocks = True + app.jinja_env.lstrip_blocks = True + + if perfrepo: + # Do this as early as possible. + # We want the perfrepo before_request to be the very first thing + # to be run, so that we can properly setup the stats before the + # request. + app.before_request(perfrepo.reset_stats) + + if pagure_config.get('THEME_TEMPLATE_FOLDER', False): + # Jinja can be told to look for templates in different folders + # That's what we do here + template_folder = pagure_config['THEME_TEMPLATE_FOLDER'] + if template_folder[0] != '/': + template_folder = os.path.join( + app.root_path, app.template_folder, template_folder) + import jinja2 + # Jinja looks for the template in the order of the folders specified + templ_loaders = [ + jinja2.FileSystemLoader(template_folder), + app.jinja_loader, + ] + app.jinja_loader = jinja2.ChoiceLoader(templ_loaders) + + if pagure_config.get('THEME_STATIC_FOLDER', False): + static_folder = pagure_config['THEME_STATIC_FOLDER'] + if static_folder[0] != '/': + static_folder = os.path.join( + app.root_path, 'static', static_folder) + # Unlike templates, to serve static files from multiples folders we + # need flask-multistatic + app.static_folder = [ + static_folder, + os.path.join(app.root_path, 'static'), + ] + + auth = pagure_config.get('PAGURE_AUTH', None) + if auth in ['fas', 'openid']: + # Only import and set flask_fas_openid if it is needed + from pagure.ui.fas_login import FAS + FAS.init_app(app) + elif auth == 'oidc': + # Only import and set flask_fas_openid if it is needed + from pagure.ui.oidc_login import oidc, fas_user_from_oidc + oidc.init_app(app) + app.before_request(fas_user_from_oidc) + + # Report error by email + if not app.debug and not pagure_config.get('DEBUG', False): + app.logger.addHandler(pagure.mail_logging.get_mail_handler( + smtp_server=pagure_config.get('SMTP_SERVER', '127.0.0.1'), + mail_admin=pagure_config.get( + 'MAIL_ADMIN', pagure_config['EMAIL_ERROR']), + from_email=pagure_config.get( + 'FROM_EMAIL', 'pagure@fedoraproject.org') + )) + + # Support proxy + app.wsgi_app = pagure.proxy.ReverseProxied(app.wsgi_app) + + # Back port 'equalto' to older version of jinja2 + app.jinja_env.tests.setdefault( + 'equalto', lambda value, other: value == other) + + # Import the application + + from pagure.api import API # noqa: E402 + app.register_blueprint(API) + + from pagure.ui import UI_NS # noqa: E402 + app.register_blueprint(UI_NS) + + from pagure.internal import PV # noqa: E402 + app.register_blueprint(PV) + + app.before_request(set_request) + + # Only import the login controller if the app is set up for local login + if pagure_config.get('PAGURE_AUTH', None) == 'local': + import pagure.ui.login as login + app.before_request_funcs[None].insert(0, login._check_session_cookie) + app.after_request(login._send_session_cookie) + + if perfrepo: + # Do this at the very end, so that this after_request comes last. + app.after_request(perfrepo.print_stats) + app.after_request(end_request) + + app.add_url_rule('/login/', view_func=auth_login, methods=['GET', 'POST']) + app.add_url_rule('/logout/', view_func=auth_logout) + + return app + + +def generate_user_key_files(): + """ Regenerate the key files used by gitolite. + """ + gitolite_home = pagure_config.get('GITOLITE_HOME', None) + if gitolite_home: + users = pagure.lib.search_user(flask.g.session) + for user in users: + pagure.lib.update_user_ssh( + flask.g.session, user, user.public_ssh_key, + pagure_config.get('GITOLITE_KEYDIR', None)) + pagure.lib.git.generate_gitolite_acls(project=None) + + +def admin_session_timedout(): + """ Check if the current user has been authenticated for more than what + is allowed (defaults to 15 minutes). + If it is the case, the user is logged out and the method returns True, + otherwise it returns False. + """ + timedout = False + if not pagure.utils.authenticated(): + return True + login_time = flask.g.fas_user.login_time + # This is because flask_fas_openid will store this as a posix timestamp + if not isinstance(login_time, datetime.datetime): + login_time = datetime.datetime.utcfromtimestamp(login_time) + if (datetime.datetime.utcnow() - login_time) > \ + pagure_config.get( + 'ADMIN_SESSION_LIFETIME', + datetime.timedelta(minutes=15)): + timedout = True + logout() + return timedout + + +def logout(): + """ Log out the user currently logged in in the application + """ + auth = pagure_config.get('PAGURE_AUTH', None) + if auth in ['fas', 'openid']: + if hasattr(flask.g, 'fas_user') and flask.g.fas_user is not None: + from pagure.ui.fas_login import FAS + FAS.logout() + elif auth == 'oidc': + from pagure.ui.oidc_login import oidc + oidc.logout() + elif auth == 'local': + import pagure.ui.login as login + login.logout() + + +def set_request(): + """ Prepare every request. """ + flask.session.permanent = True + flask.g.session = pagure.lib.create_session( + flask.current_app.config['DB_URL']) + + flask.g.version = pagure.__version__ + + # The API namespace has its own way of getting repo and username and + # of handling errors + if flask.request.blueprint == 'api_ns': + return + + flask.g.forkbuttonform = None + if pagure.utils.authenticated(): + flask.g.forkbuttonform = pagure.forms.ConfirmationForm() + + flask.g.justlogedout = flask.session.get('_justloggedout', False) + if flask.g.justlogedout: + flask.session['_justloggedout'] = None + + flask.g.new_user = False + if flask.session.get('_new_user'): + flask.g.new_user = True + flask.session['_new_user'] = False + + flask.g.admin = pagure.utils.is_admin() + + flask.g.authenticated = pagure.utils.authenticated() + # Retrieve the variables in the URL + args = flask.request.view_args or {} + # Check if there is a `repo` and an `username` + repo = args.get('repo') + username = args.get('username') + namespace = args.get('namespace') + + # 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.session, repo, user=username, namespace=namespace) + if pagure.utils.authenticated(): + flask.g.repo_forked = pagure.lib.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.session, flask.g.repo, + user=flask.g.fas_user.username, + ) + + if not flask.g.repo \ + and pagure_config.get('OLD_VIEW_COMMIT_ENABLED', False) \ + and len(repo) == 40: + return flask.redirect(flask.url_for( + 'ui_ns.view_commit', repo=namespace, commitid=repo, + username=username, namespace=None)) + + if flask.g.repo is None: + flask.abort(404, 'Project not found') + + flask.g.reponame = get_repo_path(flask.g.repo) + flask.g.repo_obj = pygit2.Repository(flask.g.reponame) + flask.g.repo_admin = pagure.utils.is_repo_admin(flask.g.repo) + flask.g.repo_committer = pagure.utils.is_repo_committer(flask.g.repo) + flask.g.repo_user = pagure.utils.is_repo_user(flask.g.repo) + flask.g.branches = sorted(flask.g.repo_obj.listall_branches()) + + 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.session, fas_user, flask.g.repo.name, + repouser=repouser, namespace=namespace) + + items_per_page = pagure_config['ITEM_PER_PAGE'] + flask.g.offset = 0 + flask.g.page = 1 + flask.g.limit = items_per_page + page = flask.request.args.get('page') + limit = flask.request.args.get('n') + if limit: + try: + limit = int(limit) + except ValueError: + limit = 10 + if limit > 500 or limit <= 0: + limit = items_per_page + + flask.g.limit = limit + + if page: + try: + page = abs(int(page)) + except ValueError: + page = 1 + if page <= 0: + page = 1 + + flask.g.page = page + flask.g.offset = (page - 1) * flask.g.limit + + +def auth_login(): # pragma: no cover + """ Method to log into the application using FAS OpenID. """ + return_point = flask.url_for('ui_ns.index') + if 'next' in flask.request.args: + if pagure.utils.is_safe_url(flask.request.args['next']): + return_point = flask.request.args['next'] + + authenticated = pagure.utils.authenticated() + auth = pagure_config.get('PAGURE_AUTH', None) + + if not authenticated and auth == 'oidc': + from pagure.ui.oidc_login import oidc, fas_user_from_oidc, set_user + # If oidc is used and user hits this endpoint, it will redirect + # to IdP with destination=/login?next= + # After confirming user identity, the IdP will redirect user here + # again, but this time oidc.user_loggedin will be True and thus + # execution will go through the else clause, making the Pagure + # authentication machinery pick the user up + if not oidc.user_loggedin: + return oidc.redirect_to_auth_server(flask.request.url) + else: + flask.session['oidc_logintime'] = time.time() + fas_user_from_oidc() + authenticated = pagure.utils.authenticated() + set_user() + + if authenticated: + return flask.redirect(return_point) + + admins = pagure_config['ADMIN_GROUP'] + if isinstance(admins, list): + admins = set(admins) + else: # pragma: no cover + admins = set([admins]) + + if auth in ['fas', 'openid']: + from pagure.ui.fas_login import FAS + groups = set() + if not pagure_config.get('ENABLE_GROUP_MNGT', False): + groups = [ + group.group_name + for group in pagure.lib.search_groups( + flask.g.session, group_type='user') + ] + groups = set(groups).union(admins) + ext_committer = set(pagure_config.get('EXTERNAL_COMMITTER', {})) + groups = set(groups).union(ext_committer) + return FAS.login(return_url=return_point, groups=groups) + elif auth == 'local': + form = pagure.login_forms.LoginForm() + return flask.render_template( + 'login/login.html', + next_url=return_point, + form=form, + ) + + +def auth_logout(): # pragma: no cover + """ Method to log out from the application. """ + return_point = flask.url_for('ui_ns.index') + if 'next' in flask.request.args: + if pagure.utils.is_safe_url(flask.request.args['next']): + return_point = flask.request.args['next'] + + if not pagure.utils.authenticated(): + return flask.redirect(return_point) + + logout() + flask.flash("You have been logged out") + flask.session['_justloggedout'] = True + return flask.redirect(return_point) + + +def end_request(response): + """ This method is called at the end of each request. + + Remove the DB session at the end of each request. + Runs a garbage collection to get rid of any open pygit2 handles. + Details: https://pagure.io/pagure/issue/2302 + + """ + flask.g.session.remove() + gc.collect() + + return response diff --git a/pagure/forms.py b/pagure/forms.py index 3f7fd3e..c0a68fd 100644 --- a/pagure/forms.py +++ b/pagure/forms.py @@ -25,8 +25,8 @@ except ImportError: import six import wtforms -import pagure import pagure.lib +from pagure.config import config as pagure_config STRICT_REGEX = '^[a-zA-Z0-9-_]+$' @@ -38,7 +38,7 @@ class PagureForm(FlaskForm): """ Local form allowing us to form set the time limit. """ def __init__(self, *args, **kwargs): - delta = pagure.APP.config.get('WTF_CSRF_TIME_LIMIT', 3600) + delta = pagure_config.get('WTF_CSRF_TIME_LIMIT', 3600) if delta \ and ( not hasattr(wtf, '__version__') @@ -84,7 +84,7 @@ def file_virus_validator(form, field): ''' Checks for virus in the file from flask request object, raises wtf.ValidationError if virus is found else None. ''' - if not pagure.APP.config['VIRUS_SCAN_ATTACHMENTS']: + if not pagure_config['VIRUS_SCAN_ATTACHMENTS']: return from pyclamd import ClamdUnixSocket @@ -168,7 +168,7 @@ class ProjectForm(ProjectFormSimplified): """ super(ProjectForm, self).__init__(*args, **kwargs) # set the name validator - regex = pagure.APP.config.get( + regex = pagure_config.get( 'PROJECT_NAME_REGEX', '^[a-zA-z0-9_][a-zA-Z0-9-_]*$') self.name.validators = [ wtforms.validators.Required(), @@ -179,7 +179,7 @@ class ProjectForm(ProjectFormSimplified): self.namespace.choices = [ (namespace, namespace) for namespace in kwargs['namespaces'] ] - if not pagure.APP.config.get('USER_NAMESPACE', False): + if not pagure_config.get('USER_NAMESPACE', False): self.namespace.choices.insert(0, ('', '')) diff --git a/pagure/hooks/__init__.py b/pagure/hooks/__init__.py index 540441a..d397b51 100644 --- a/pagure/hooks/__init__.py +++ b/pagure/hooks/__init__.py @@ -11,8 +11,9 @@ import os import wtforms +from pagure.config import config as pagure_config from pagure.exceptions import FileNotFoundException -from pagure import APP, get_repo_path +from pagure.utils import get_repo_path class RequiredIf(wtforms.validators.Required): @@ -51,8 +52,8 @@ class BaseHook(object): ''' repopaths = [get_repo_path(project)] for folder in [ - APP.config.get('DOCS_FOLDER'), - APP.config.get('REQUESTS_FOLDER')]: + pagure_config.get('DOCS_FOLDER'), + pagure_config.get('REQUESTS_FOLDER')]: if folder: repopaths.append( os.path.join(folder, project.path) diff --git a/pagure/hooks/default.py b/pagure/hooks/default.py index 184820b..6d78cdf 100644 --- a/pagure/hooks/default.py +++ b/pagure/hooks/default.py @@ -19,7 +19,7 @@ from sqlalchemy.orm import backref from pagure.hooks import BaseHook from pagure.lib.model import BASE, Project -from pagure import get_repo_path +from pagure.utils import get_repo_path class DefaultTable(BASE): diff --git a/pagure/hooks/fedmsg.py b/pagure/hooks/fedmsg.py index 3778179..6c9890f 100644 --- a/pagure/hooks/fedmsg.py +++ b/pagure/hooks/fedmsg.py @@ -19,7 +19,7 @@ from sqlalchemy.orm import backref from pagure.hooks import BaseHook from pagure.lib.model import BASE, Project -from pagure import get_repo_path +from pagure.utils import get_repo_path class FedmsgTable(BASE): diff --git a/pagure/hooks/files/default_hook.py b/pagure/hooks/files/default_hook.py index 79754a1..8c70e26 100755 --- a/pagure/hooks/files/default_hook.py +++ b/pagure/hooks/files/default_hook.py @@ -11,12 +11,8 @@ import sys import pygit2 -if 'PAGURE_CONFIG' not in os.environ \ - and os.path.exists('/etc/pagure/pagure.cfg'): - os.environ['PAGURE_CONFIG'] = '/etc/pagure/pagure.cfg' - - import pagure # noqa: E402 +import pagure.flask_app # noqa: E402 import pagure.exceptions # noqa: E402 import pagure.lib.link # noqa: E402 import pagure.lib.tasks # noqa: E402 @@ -24,6 +20,12 @@ import pagure.lib.tasks # noqa: E402 from pagure.lib import REDIS # noqa: E402 +if 'PAGURE_CONFIG' not in os.environ \ + and os.path.exists('/etc/pagure/pagure.cfg'): + os.environ['PAGURE_CONFIG'] = '/etc/pagure/pagure.cfg' + + +_config = pagure.config.config.reload_config() abspath = os.path.abspath(os.environ['GIT_DIR']) @@ -32,21 +34,21 @@ def run_as_post_receive_hook(): repo = pagure.lib.git.get_repo_name(abspath) username = pagure.lib.git.get_username(abspath) namespace = pagure.lib.git.get_repo_namespace(abspath) - if pagure.APP.config.get('HOOK_DEBUG', False): + if _config.get('HOOK_DEBUG', False): print('repo:', repo) print('user:', username) print('namespace:', namespace) project = pagure.lib._get_project( pagure.SESSION, repo, user=username, namespace=namespace, - case=pagure.APP.config.get('CASE_SENSITIVE', False)) + case=_config.get('CASE_SENSITIVE', False)) for line in sys.stdin: - if pagure.APP.config.get('HOOK_DEBUG', False): + if _config.get('HOOK_DEBUG', False): print(line) (oldrev, newrev, refname) = line.strip().split(' ', 2) - if pagure.APP.config.get('HOOK_DEBUG', False): + if _config.get('HOOK_DEBUG', False): print(' -- Old rev') print(oldrev) print(' -- New rev') @@ -100,7 +102,7 @@ def run_as_post_receive_hook(): and target_repo.settings.get('pull_requests', True): print() prs = pagure.lib.search_pull_requests( - pagure.SESSION, + pagure.flask_app.SESSION, project_id_from=project.id, status='Open', branch_from=refname, @@ -110,7 +112,7 @@ def run_as_post_receive_hook(): for pr in prs: print('View pull-request for %s' % refname) print(' %s/%s/pull-request/%s' % ( - pagure.APP.config['APP_URL'].rstrip('/'), + _config['APP_URL'].rstrip('/'), project.url_path, pr.id) ) @@ -118,7 +120,7 @@ def run_as_post_receive_hook(): if not seen: print('Create a pull-request for %s' % refname) print(' %s/%s/diff/%s..%s' % ( - pagure.APP.config['APP_URL'].rstrip('/'), + _config['APP_URL'].rstrip('/'), project.url_path, default_branch, refname) diff --git a/pagure/hooks/files/fedmsg_hook.py b/pagure/hooks/files/fedmsg_hook.py index 0ebffa1..a7fb01b 100755 --- a/pagure/hooks/files/fedmsg_hook.py +++ b/pagure/hooks/files/fedmsg_hook.py @@ -26,6 +26,7 @@ config['active'] = True config['endpoints']['relay_inbound'] = config['relay_inbound'] fedmsg.init(name='relay_inbound', **config) +_config = pagure.config.config.reload_config() seen = [] @@ -55,7 +56,7 @@ for line in sys.stdin.readlines(): namespace = pagure.lib.git.get_repo_namespace(abspath) project = pagure.lib._get_project( pagure.SESSION, project_name, username, namespace=namespace, - case=pagure.APP.config.get('CASE_SENSITIVE', False)) + case=_config.get('CASE_SENSITIVE', False)) if not project: project = project_name diff --git a/pagure/hooks/files/pagure_block_unsigned.py b/pagure/hooks/files/pagure_block_unsigned.py index 85ae56c..f89e980 100755 --- a/pagure/hooks/files/pagure_block_unsigned.py +++ b/pagure/hooks/files/pagure_block_unsigned.py @@ -21,18 +21,18 @@ import pagure.exceptions # noqa: E402 import pagure.lib.link # noqa: E402 import pagure.ui.plugins # noqa: E402 - +_config = pagure.config.config.reload_config() abspath = os.path.abspath(os.environ['GIT_DIR']) def run_as_pre_receive_hook(): for line in sys.stdin: - if pagure.APP.config.get('HOOK_DEBUG', False): + if _config.get('HOOK_DEBUG', False): print(line) (oldrev, newrev, refname) = line.strip().split(' ', 2) - if pagure.APP.config.get('HOOK_DEBUG', False): + if _config.get('HOOK_DEBUG', False): print(' -- Old rev') print(oldrev) print(' -- New rev') @@ -48,7 +48,7 @@ def run_as_pre_receive_hook(): commits = pagure.lib.git.get_revs_between( oldrev, newrev, abspath, refname) for commit in commits: - if pagure.APP.config.get('HOOK_DEBUG', False): + if _config.get('HOOK_DEBUG', False): print('Processing commit: %s' % commit) signed = False for line in pagure.lib.git.read_git_lines( @@ -56,7 +56,7 @@ def run_as_pre_receive_hook(): if line.lower().strip().startswith('signed-off-by'): signed = True break - if pagure.APP.config.get('HOOK_DEBUG', False): + if _config.get('HOOK_DEBUG', False): print(' - Commit: %s is signed: %s' % (commit, signed)) if not signed: print("Commit %s is not signed" % commit) diff --git a/pagure/hooks/files/pagure_force_commit_hook.py b/pagure/hooks/files/pagure_force_commit_hook.py index d496cfc..5b1b18c 100755 --- a/pagure/hooks/files/pagure_force_commit_hook.py +++ b/pagure/hooks/files/pagure_force_commit_hook.py @@ -21,6 +21,7 @@ import pagure.lib.link # noqa: E402 import pagure.lib.plugins # noqa: E402 +_config = pagure.config.config.reload_config() abspath = os.path.abspath(os.environ['GIT_DIR']) @@ -28,14 +29,14 @@ def run_as_pre_receive_hook(): reponame = pagure.lib.git.get_repo_name(abspath) namespace = pagure.lib.git.get_repo_namespace(abspath) username = pagure.lib.git.get_username(abspath) - if pagure.APP.config.get('HOOK_DEBUG', False): + if _config.get('HOOK_DEBUG', False): print('repo: ', reponame) print('user: ', username) print('namspaces:', namespace) repo = pagure.lib._get_project( pagure.SESSION, reponame, user=username, namespace=namespace, - case=pagure.APP.config.get('CASE_SENSITIVE', False)) + case=_config.get('CASE_SENSITIVE', False)) if not repo: print('Unknown repo %s of username: %s in namespace %s' % ( @@ -57,13 +58,13 @@ def run_as_pre_receive_hook(): if branch] for line in sys.stdin: - if pagure.APP.config.get('HOOK_DEBUG', False): + if _config.get('HOOK_DEBUG', False): print(line) (oldrev, newrev, refname) = line.strip().split(' ', 2) refname = refname.replace('refs/heads/', '') if refname in branches: - if pagure.APP.config.get('HOOK_DEBUG', False): + if _config.get('HOOK_DEBUG', False): print(' -- Old rev') print(oldrev) print(' -- New rev') diff --git a/pagure/hooks/files/pagure_hook.py b/pagure/hooks/files/pagure_hook.py index 020a9d5..1487606 100755 --- a/pagure/hooks/files/pagure_hook.py +++ b/pagure/hooks/files/pagure_hook.py @@ -26,6 +26,7 @@ import pagure.lib.link # noqa: E402 _log = logging.getLogger(__name__) +_config = pagure.config.config.reload_config() abspath = os.path.abspath(os.environ['GIT_DIR']) @@ -51,7 +52,7 @@ def generate_revision_change_log(new_commits_list): 'fixes', include_prs=True): fixes_relation(commitid, relation, - pagure.APP.config.get('APP_URL')) + _config.get('APP_URL')) for issue in pagure.lib.link.get_relation( pagure.SESSION, @@ -60,7 +61,7 @@ def generate_revision_change_log(new_commits_list): pagure.lib.git.get_repo_namespace(abspath), line, 'relates'): - relates_commit(commitid, issue, pagure.APP.config.get('APP_URL')) + relates_commit(commitid, issue, _config.get('APP_URL')) def relates_commit(commitid, issue, app_url=None): @@ -87,7 +88,7 @@ def relates_commit(commitid, issue, app_url=None): issue=issue, comment=comment, user=user, - ticketfolder=pagure.APP.config['TICKETS_FOLDER'], + ticketfolder=_config['TICKETS_FOLDER'], ) pagure.SESSION.commit() except pagure.exceptions.PagureException as err: @@ -123,7 +124,7 @@ def fixes_relation(commitid, relation, app_url=None): issue=relation, comment=comment, user=user, - ticketfolder=pagure.APP.config['TICKETS_FOLDER'], + ticketfolder=_config['TICKETS_FOLDER'], ) elif relation.isa == 'pull-request': pagure.lib.add_pull_request_comment( @@ -135,7 +136,7 @@ def fixes_relation(commitid, relation, app_url=None): row=None, comment=comment, user=user, - requestfolder=pagure.APP.config['REQUESTS_FOLDER'], + requestfolder=_config['REQUESTS_FOLDER'], ) pagure.SESSION.commit() except pagure.exceptions.PagureException as err: @@ -149,14 +150,14 @@ def fixes_relation(commitid, relation, app_url=None): pagure.lib.edit_issue( pagure.SESSION, relation, - ticketfolder=pagure.APP.config['TICKETS_FOLDER'], + ticketfolder=_config['TICKETS_FOLDER'], user=user, status='Closed', close_status='Fixed') elif relation.isa == 'pull-request': pagure.lib.close_pull_request( pagure.SESSION, relation, - requestfolder=pagure.APP.config['REQUESTS_FOLDER'], + requestfolder=_config['REQUESTS_FOLDER'], user=user, merged=True) pagure.SESSION.commit() @@ -171,11 +172,11 @@ def fixes_relation(commitid, relation, app_url=None): def run_as_post_receive_hook(): for line in sys.stdin: - if pagure.APP.config.get('HOOK_DEBUG', False): + if _config.get('HOOK_DEBUG', False): print(line) (oldrev, newrev, refname) = line.strip().split(' ', 2) - if pagure.APP.config.get('HOOK_DEBUG', False): + if _config.get('HOOK_DEBUG', False): print(' -- Old rev') print(oldrev) print(' -- New rev') @@ -202,7 +203,7 @@ def run_as_post_receive_hook(): generate_revision_change_log( pagure.lib.git.get_revs_between(oldrev, newrev, abspath, refname)) - if pagure.APP.config.get('HOOK_DEBUG', False): + if _config.get('HOOK_DEBUG', False): print('ns :', pagure.lib.git.get_repo_namespace(abspath)) print('repo:', pagure.lib.git.get_repo_name(abspath)) print('user:', pagure.lib.git.get_username(abspath)) diff --git a/pagure/hooks/files/pagure_hook_requests.py b/pagure/hooks/files/pagure_hook_requests.py index 260e4f9..8c25587 100755 --- a/pagure/hooks/files/pagure_hook_requests.py +++ b/pagure/hooks/files/pagure_hook_requests.py @@ -21,6 +21,7 @@ if 'PAGURE_CONFIG' not in os.environ \ import pagure.lib.git # noqa: E402 +_config = pagure.config.config.reload_config() abspath = os.path.abspath(os.environ['GIT_DIR']) @@ -44,11 +45,11 @@ def run_as_post_receive_hook(): file_list = set() for line in sys.stdin: - if pagure.APP.config.get('HOOK_DEBUG', False): + if _config.get('HOOK_DEBUG', False): print(line) (oldrev, newrev, refname) = line.strip().split(' ', 2) - if pagure.APP.config.get('HOOK_DEBUG', False): + if _config.get('HOOK_DEBUG', False): print(' -- Old rev') print(oldrev) print(' -- New rev') @@ -68,7 +69,7 @@ def run_as_post_receive_hook(): reponame = pagure.lib.git.get_repo_name(abspath) username = pagure.lib.git.get_username(abspath) namespace = pagure.lib.git.get_repo_namespace( - abspath, gitfolder=pagure.APP.config['REQUESTS_FOLDER']) + abspath, gitfolder=_config['REQUESTS_FOLDER']) print('repo:', reponame, username, namespace) for filename in file_list: @@ -90,10 +91,10 @@ def run_as_post_receive_hook(): username=username, request_uid=filename, json_data=json_data, - gitfolder=pagure.APP.config['GIT_FOLDER'], - docfolder=pagure.APP.config['DOCS_FOLDER'], - ticketfolder=pagure.APP.config['TICKETS_FOLDER'], - requestfolder=pagure.APP.config['REQUESTS_FOLDER'], + gitfolder=_config['GIT_FOLDER'], + docfolder=_config['DOCS_FOLDER'], + ticketfolder=_config['TICKETS_FOLDER'], + requestfolder=_config['REQUESTS_FOLDER'], ) diff --git a/pagure/hooks/files/pagure_hook_tickets.py b/pagure/hooks/files/pagure_hook_tickets.py index ce5bdef..93d57cd 100755 --- a/pagure/hooks/files/pagure_hook_tickets.py +++ b/pagure/hooks/files/pagure_hook_tickets.py @@ -22,6 +22,7 @@ import pagure.lib.git # noqa: E402 from pagure.lib import REDIS # noqa: E402 +_config = pagure.config.config.reload_config() abspath = os.path.abspath(os.environ['GIT_DIR']) @@ -30,22 +31,22 @@ def run_as_post_receive_hook(): repo = pagure.lib.git.get_repo_name(abspath) username = pagure.lib.git.get_username(abspath) namespace = pagure.lib.git.get_repo_namespace( - abspath, gitfolder=pagure.APP.config['TICKETS_FOLDER']) - if pagure.APP.config.get('HOOK_DEBUG', False): + abspath, gitfolder=_config['TICKETS_FOLDER']) + if _config.get('HOOK_DEBUG', False): print('repo:', repo) print('user:', username) print('namespace:', namespace) project = pagure.lib._get_project( pagure.SESSION, repo, user=username, namespace=namespace, - case=pagure.APP.config.get('CASE_SENSITIVE', False)) + case=_config.get('CASE_SENSITIVE', False)) for line in sys.stdin: - if pagure.APP.config.get('HOOK_DEBUG', False): + if _config.get('HOOK_DEBUG', False): print(line) (oldrev, newrev, refname) = line.strip().split(' ', 2) - if pagure.APP.config.get('HOOK_DEBUG', False): + if _config.get('HOOK_DEBUG', False): print(' -- Old rev') print(oldrev) print(' -- New rev') diff --git a/pagure/hooks/files/rtd_hook.py b/pagure/hooks/files/rtd_hook.py index dad93d9..3addc3a 100755 --- a/pagure/hooks/files/rtd_hook.py +++ b/pagure/hooks/files/rtd_hook.py @@ -23,6 +23,7 @@ import pagure.lib.link # noqa: E402 import pagure.lib.plugins # noqa: E402 +_config = pagure.config.config.reload_config() abspath = os.path.abspath(os.environ['GIT_DIR']) @@ -30,12 +31,12 @@ def run_as_post_receive_hook(): reponame = pagure.lib.git.get_repo_name(abspath) username = pagure.lib.git.get_username(abspath) namespace = pagure.lib.git.get_repo_namespace(abspath) - if pagure.APP.config.get('HOOK_DEBUG', False): + if _config.get('HOOK_DEBUG', False): print('repo: ', reponame) print('user: ', username) print('namespace:', namespace) - repo = pagure.get_authorized_project( + repo = pagure.lib.get_authorized_project( pagure.SESSION, reponame, user=username, namespace=namespace) if not repo: print('Unknown repo %s of username: %s' % (reponame, username)) @@ -59,7 +60,7 @@ def run_as_post_receive_hook(): ) for line in sys.stdin: - if pagure.APP.config.get('HOOK_DEBUG', False): + if _config.get('HOOK_DEBUG', False): print(line) (oldrev, newrev, refname) = line.strip().split(' ', 2) diff --git a/pagure/hooks/irc.py b/pagure/hooks/irc.py index 5871875..fb101ff 100644 --- a/pagure/hooks/irc.py +++ b/pagure/hooks/irc.py @@ -20,7 +20,7 @@ from sqlalchemy.orm import backref from pagure.hooks import BaseHook, RequiredIf from pagure.lib.model import BASE, Project -from pagure import get_repo_path +from pagure.utils import get_repo_path class IrcTable(BASE): diff --git a/pagure/hooks/mail.py b/pagure/hooks/mail.py index f411316..c29283e 100644 --- a/pagure/hooks/mail.py +++ b/pagure/hooks/mail.py @@ -20,7 +20,7 @@ from sqlalchemy.orm import backref from pagure.hooks import BaseHook, RequiredIf from pagure.lib.model import BASE, Project -from pagure import get_repo_path +from pagure.utils import get_repo_path class MailTable(BASE): diff --git a/pagure/hooks/pagure_ci.py b/pagure/hooks/pagure_ci.py index 7f9ea7d..6b62bfc 100644 --- a/pagure/hooks/pagure_ci.py +++ b/pagure/hooks/pagure_ci.py @@ -8,6 +8,7 @@ """ +import flask import sqlalchemy as sa import wtforms try: @@ -20,7 +21,6 @@ from sqlalchemy.orm import backref import pagure.lib from pagure.hooks import BaseHook, RequiredIf from pagure.lib.model import BASE, Project -from pagure import SESSION, APP class PagureCITable(BASE): @@ -108,7 +108,7 @@ class PagureCiForm(FlaskForm): """ super(PagureCiForm, self).__init__(*args, **kwargs) - types = APP.config.get('PAGURE_CI_SERVICES', []) + types = pagure.config.config.get('PAGURE_CI_SERVICES', []) self.ci_type.choices = [ (ci_type, ci_type) for ci_type in types ] @@ -144,7 +144,7 @@ class PagureCi(BaseHook): ''' if not dbobj.pagure_ci_token: dbobj.pagure_ci_token = pagure.lib.login.id_generator(32) - SESSION.commit() + flask.g.session.commit() @classmethod def remove(cls, project): @@ -156,4 +156,4 @@ class PagureCi(BaseHook): ''' if project.ci_hook is not None: project.ci_hook.pagure_ci_token = None - SESSION.commit() + flask.g.session.commit() diff --git a/pagure/hooks/pagure_force_commit.py b/pagure/hooks/pagure_force_commit.py index 1152458..5ec8fe1 100644 --- a/pagure/hooks/pagure_force_commit.py +++ b/pagure/hooks/pagure_force_commit.py @@ -20,7 +20,7 @@ from sqlalchemy.orm import backref from pagure.hooks import BaseHook, RequiredIf from pagure.lib.model import BASE, Project -from pagure import get_repo_path +from pagure.utils import get_repo_path class PagureForceCommitTable(BASE): diff --git a/pagure/hooks/pagure_hook.py b/pagure/hooks/pagure_hook.py index 2d655cb..c07f1ba 100644 --- a/pagure/hooks/pagure_hook.py +++ b/pagure/hooks/pagure_hook.py @@ -19,9 +19,10 @@ except ImportError: from sqlalchemy.orm import relation from sqlalchemy.orm import backref +from pagure.config import config as pagure_config from pagure.hooks import BaseHook from pagure.lib.model import BASE, Project -from pagure import APP, get_repo_path +from pagure.utils import get_repo_path class PagureTable(BASE): @@ -114,8 +115,8 @@ class PagureHook(BaseHook): ''' repopaths = [get_repo_path(project)] for folder in [ - APP.config.get('DOCS_FOLDER'), - APP.config.get('REQUESTS_FOLDER')]: + pagure_config.get('DOCS_FOLDER'), + pagure_config.get('REQUESTS_FOLDER')]: if folder: repopaths.append( os.path.join(folder, project.path) @@ -133,8 +134,8 @@ class PagureHook(BaseHook): ''' repopaths = [get_repo_path(project)] for folder in [ - APP.config.get('DOCS_FOLDER'), - APP.config.get('REQUESTS_FOLDER')]: + pagure_config.get('DOCS_FOLDER'), + pagure_config.get('REQUESTS_FOLDER')]: if folder: repopaths.append( os.path.join(folder, project.path) diff --git a/pagure/hooks/pagure_request_hook.py b/pagure/hooks/pagure_request_hook.py index 3aa049f..650bf47 100644 --- a/pagure/hooks/pagure_request_hook.py +++ b/pagure/hooks/pagure_request_hook.py @@ -20,9 +20,9 @@ except ImportError: from sqlalchemy.orm import relation from sqlalchemy.orm import backref +from pagure.config import config as pagure_config from pagure.hooks import BaseHook from pagure.lib.model import BASE, Project -from pagure import APP class PagureRequestsTable(BASE): @@ -78,7 +78,7 @@ class PagureRequestHook(BaseHook): ''' Install the generic post-receive hook that allow us to call multiple post-receive hooks as set per plugin. ''' - repopath = os.path.join(APP.config['REQUESTS_FOLDER'], project.path) + repopath = os.path.join(pagure_config['REQUESTS_FOLDER'], project.path) if not os.path.exists(repopath): flask.abort(404, 'No git repo found') @@ -104,7 +104,8 @@ class PagureRequestHook(BaseHook): should be installed ''' - repopaths = [os.path.join(APP.config['REQUESTS_FOLDER'], project.path)] + repopaths = [os.path.join( + pagure_config['REQUESTS_FOLDER'], project.path)] cls.base_install(repopaths, dbobj, 'pagure-requests', 'pagure_hook_requests.py') @@ -117,6 +118,7 @@ class PagureRequestHook(BaseHook): should be installed ''' - repopaths = [os.path.join(APP.config['REQUESTS_FOLDER'], project.path)] + repopaths = [os.path.join( + pagure_config['REQUESTS_FOLDER'], project.path)] cls.base_remove(repopaths, 'pagure-requests') diff --git a/pagure/hooks/pagure_ticket_hook.py b/pagure/hooks/pagure_ticket_hook.py index 00bd8d3..b5f5896 100644 --- a/pagure/hooks/pagure_ticket_hook.py +++ b/pagure/hooks/pagure_ticket_hook.py @@ -20,9 +20,9 @@ except ImportError: from sqlalchemy.orm import relation from sqlalchemy.orm import backref +from pagure.config import config as pagure_config from pagure.hooks import BaseHook from pagure.lib.model import BASE, Project -from pagure import APP class PagureTicketsTable(BASE): @@ -77,7 +77,7 @@ class PagureTicketHook(BaseHook): ''' Install the generic post-receive hook that allow us to call multiple post-receive hooks as set per plugin. ''' - repopath = os.path.join(APP.config['TICKETS_FOLDER'], project.path) + repopath = os.path.join(pagure_config['TICKETS_FOLDER'], project.path) if not os.path.exists(repopath): flask.abort(404, 'No git repo found') @@ -103,7 +103,8 @@ class PagureTicketHook(BaseHook): should be installed ''' - repopaths = [os.path.join(APP.config['TICKETS_FOLDER'], project.path)] + repopaths = [os.path.join( + pagure_config['TICKETS_FOLDER'], project.path)] cls.base_install(repopaths, dbobj, 'pagure-ticket', 'pagure_hook_tickets.py') @@ -116,6 +117,7 @@ class PagureTicketHook(BaseHook): should be installed ''' - repopaths = [os.path.join(APP.config['TICKETS_FOLDER'], project.path)] + repopaths = [os.path.join( + pagure_config['TICKETS_FOLDER'], project.path)] cls.base_remove(repopaths, 'pagure-ticket') diff --git a/pagure/hooks/pagure_unsigned_commits.py b/pagure/hooks/pagure_unsigned_commits.py index fbb6448..3b983aa 100644 --- a/pagure/hooks/pagure_unsigned_commits.py +++ b/pagure/hooks/pagure_unsigned_commits.py @@ -19,7 +19,7 @@ from sqlalchemy.orm import backref from pagure.hooks import BaseHook from pagure.lib.model import BASE, Project -from pagure import get_repo_path +from pagure.utils import get_repo_path class PagureUnsignedCommitTable(BASE): diff --git a/pagure/hooks/rtd.py b/pagure/hooks/rtd.py index 8d8ad19..b3b25ee 100644 --- a/pagure/hooks/rtd.py +++ b/pagure/hooks/rtd.py @@ -21,7 +21,7 @@ from sqlalchemy.orm import backref from pagure.hooks import BaseHook, RequiredIf from pagure.lib.model import BASE, Project -from pagure import get_repo_path +from pagure.utils import get_repo_path class RtdTable(BASE): diff --git a/pagure/internal/__init__.py b/pagure/internal/__init__.py index 35dacc0..f336a7b 100644 --- a/pagure/internal/__init__.py +++ b/pagure/internal/__init__.py @@ -28,6 +28,7 @@ import pagure.forms # noqa: E402 import pagure.lib # noqa: E402 import pagure.lib.git # noqa: E402 import pagure.lib.tasks # noqa: E402 +import pagure.utils # noqa: E402 import pagure.ui.fork # noqa: E402 @@ -61,7 +62,7 @@ def localonly(function): def decorated_function(*args, **kwargs): ''' Wrapped function actually checking if the request is local. ''' - ip_allowed = pagure.APP.config.get( + ip_allowed = pagure.config.config.get( 'IP_ALLOWED_INTERNAL', ['127.0.0.1', 'localhost', '::1']) if flask.request.remote_addr not in ip_allowed: _log.debug('IP: %s is not in the list of allowed IPs: %s' % ( @@ -85,7 +86,7 @@ def pull_request_add_comment(): useremail = pform.useremail.data request = pagure.lib.get_request_by_uid( - pagure.SESSION, + flask.g.session, request_uid=objid, ) @@ -105,7 +106,7 @@ def pull_request_add_comment(): try: message = pagure.lib.add_pull_request_comment( - pagure.SESSION, + flask.g.session, request=request, commit=commit, tree_id=tree_id, @@ -113,12 +114,12 @@ def pull_request_add_comment(): row=row, comment=comment, user=useremail, - requestfolder=pagure.APP.config['REQUESTS_FOLDER'], + requestfolder=pagure.config.config['REQUESTS_FOLDER'], ) - pagure.SESSION.commit() + flask.g.session.commit() except SQLAlchemyError as err: # pragma: no cover - pagure.SESSION.rollback() - pagure.APP.logger.exception(err) + flask.g.session.rollback() + _log.exception(err) flask.abort(500, 'Error when saving the request to the database') return flask.jsonify({'message': message}) @@ -137,14 +138,14 @@ def ticket_add_comment(): useremail = pform.useremail.data issue = pagure.lib.get_issue_by_uid( - pagure.SESSION, + flask.g.session, issue_uid=objid ) if issue is None: flask.abort(404, 'Issue not found') - user_obj = pagure.lib.search_user(pagure.SESSION, email=useremail) + user_obj = pagure.lib.search_user(flask.g.session, email=useremail) admin = False if user_obj: admin = user_obj.user == issue.project.user.user or ( @@ -164,16 +165,16 @@ def ticket_add_comment(): try: message = pagure.lib.add_issue_comment( - pagure.SESSION, + flask.g.session, issue=issue, comment=comment, user=useremail, - ticketfolder=pagure.APP.config['TICKETS_FOLDER'], + ticketfolder=pagure.config.config['TICKETS_FOLDER'], notify=True) - pagure.SESSION.commit() + flask.g.session.commit() except SQLAlchemyError as err: # pragma: no cover - pagure.SESSION.rollback() - pagure.APP.logger.exception(err) + flask.g.session.rollback() + _log.exception(err) flask.abort(500, 'Error when saving the request to the database') return flask.jsonify({'message': message}) @@ -199,7 +200,7 @@ def mergeable_request_pull(): requestid = flask.request.form.get('requestid') request = pagure.lib.get_request_by_uid( - pagure.SESSION, request_uid=requestid) + flask.g.session, request_uid=requestid) if not request: response = flask.jsonify({ @@ -217,7 +218,7 @@ def mergeable_request_pull(): try: merge_status = pagure.lib.git.merge_pull_request( - session=pagure.SESSION, + session=flask.g.session, request=request, username=None, request_folder=None, @@ -254,8 +255,8 @@ def get_pull_request_ready_branch(): response.status_code = 400 return response - repo = pagure.get_authorized_project( - pagure.SESSION, + repo = pagure.lib.get_authorized_project( + flask.g.session, flask.request.form.get('repo', '').strip() or None, namespace=flask.request.form.get('namespace', '').strip() or None, user=flask.request.form.get('repouser', '').strip() or None) @@ -268,7 +269,7 @@ def get_pull_request_ready_branch(): response.status_code = 404 return response - reponame = pagure.get_repo_path(repo) + reponame = pagure.utils.get_repo_path(repo) repo_obj = pygit2.Repository(reponame) if repo.is_fork: if not repo.parent.settings.get('pull_requests', True): @@ -279,7 +280,7 @@ def get_pull_request_ready_branch(): response.status_code = 400 return response - parentreponame = pagure.get_repo_path(repo.parent) + parentreponame = pagure.utils.get_repo_path(repo.parent) parent_repo_obj = pygit2.Repository(parentreponame) else: if not repo.settings.get('pull_requests', True): @@ -322,7 +323,7 @@ def get_pull_request_ready_branch(): branches[branchname] = [c.oid.hex for c in diff_commits] prs = pagure.lib.search_pull_requests( - pagure.SESSION, + flask.g.session, project_id_from=repo.id, status='Open' ) @@ -370,8 +371,8 @@ def get_ticket_template(repo, namespace=None, username=None): response.status_code = 400 return response - repo = pagure.get_authorized_project( - pagure.SESSION, repo, user=username, namespace=namespace) + repo = pagure.lib.get_authorized_project( + flask.g.session, repo, user=username, namespace=namespace) if repo is None: response = flask.jsonify({ @@ -390,14 +391,14 @@ def get_ticket_template(repo, namespace=None, username=None): return response ticketrepopath = os.path.join( - pagure.APP.config['TICKETS_FOLDER'], repo.path) + pagure.config.config['TICKETS_FOLDER'], repo.path) content = None if os.path.exists(ticketrepopath): ticketrepo = pygit2.Repository(ticketrepopath) if not ticketrepo.is_empty and not ticketrepo.head_is_unborn: commit = ticketrepo[ticketrepo.head.target] # Get the asked template - content_file = pagure.__get_file_in_tree( + content_file = pagure.utils.__get_file_in_tree( ticketrepo, commit.tree, ['templates', '%s.md' % template], bail_on_tree=True) if content_file: @@ -439,8 +440,8 @@ def get_branches_of_commit(): response.status_code = 400 return response - repo = pagure.get_authorized_project( - pagure.SESSION, + repo = pagure.lib.get_authorized_project( + flask.g.session, flask.request.form.get('repo', '').strip() or None, user=flask.request.form.get('repouser', '').strip() or None, namespace=flask.request.form.get('namespace', '').strip() or None,) @@ -453,7 +454,7 @@ def get_branches_of_commit(): response.status_code = 404 return response - repopath = os.path.join(pagure.APP.config['GIT_FOLDER'], repo.path) + repopath = os.path.join(pagure.config.config['GIT_FOLDER'], repo.path) if not os.path.exists(repopath): response = flask.jsonify({ @@ -543,8 +544,8 @@ def get_branches_head(): response.status_code = 400 return response - repo = pagure.get_authorized_project( - pagure.SESSION, + repo = pagure.lib.get_authorized_project( + flask.g.session, flask.request.form.get('repo', '').strip() or None, namespace=flask.request.form.get('namespace', '').strip() or None, user=flask.request.form.get('repouser', '').strip() or None) @@ -557,7 +558,7 @@ def get_branches_head(): response.status_code = 404 return response - repopath = os.path.join(pagure.APP.config['GIT_FOLDER'], repo.path) + repopath = os.path.join(pagure.config.config['GIT_FOLDER'], repo.path) if not os.path.exists(repopath): response = flask.jsonify({ @@ -619,8 +620,8 @@ def get_stats_commits(): response.status_code = 400 return response - repo = pagure.get_authorized_project( - pagure.SESSION, + repo = pagure.lib.get_authorized_project( + flask.g.session, flask.request.form.get('repo', '').strip() or None, namespace=flask.request.form.get('namespace', '').strip() or None, user=flask.request.form.get('repouser', '').strip() or None) @@ -633,7 +634,7 @@ def get_stats_commits(): response.status_code = 404 return response - repopath = os.path.join(pagure.APP.config['GIT_FOLDER'], repo.path) + repopath = os.path.join(pagure.config.config['GIT_FOLDER'], repo.path) task = pagure.lib.tasks.commits_author_stats.delay(repopath) @@ -661,8 +662,8 @@ def get_stats_commits_trend(): response.status_code = 400 return response - repo = pagure.get_authorized_project( - pagure.SESSION, + repo = pagure.lib.get_authorized_project( + flask.g.session, flask.request.form.get('repo', '').strip() or None, namespace=flask.request.form.get('namespace', '').strip() or None, user=flask.request.form.get('repouser', '').strip() or None) @@ -675,7 +676,7 @@ def get_stats_commits_trend(): response.status_code = 404 return response - repopath = os.path.join(pagure.APP.config['GIT_FOLDER'], repo.path) + repopath = os.path.join(pagure.config.config['GIT_FOLDER'], repo.path) task = pagure.lib.tasks.commits_history_stats.delay(repopath) diff --git a/pagure/lib/__init__.py b/pagure/lib/__init__.py index dfb8133..b7bdbdf 100644 --- a/pagure/lib/__init__.py +++ b/pagure/lib/__init__.py @@ -47,13 +47,14 @@ from sqlalchemy.orm import sessionmaker from sqlalchemy.orm import scoped_session from flask import url_for -import pagure import pagure.exceptions import pagure.lib.git 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 @@ -115,7 +116,8 @@ def create_session(db_url=None, debug=False, pool_recycle=3600): ''' global SESSIONMAKER - if SESSIONMAKER is None: + if SESSIONMAKER is None or ( + db_url and db_url != str(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 @@ -125,6 +127,14 @@ def create_session(db_url=None, debug=False, pool_recycle=3600): 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) @@ -1509,11 +1519,12 @@ def new_project(session, user, name, blacklist, allowed_prefix, ) # Repo exists in the DB - repo = pagure.get_authorized_project(session, name, namespace=namespace) + 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( - 'The project repo "%s" already exists in the database' % ( - path) + 'It is not possible to create the repo "%s"' % (path) ) project = model.Project( @@ -3698,7 +3709,7 @@ def text2markdown(text, extended=True, readme=False): if text: try: text = _convert_markdown(md_processor, text) - except Exception: + except Exception as err: _log.debug( 'A markdown error occured while processing: ``%s``', str(text)) @@ -3714,7 +3725,7 @@ def filter_img_src(name, value): if name == 'src': parsed = urlparse.urlparse(value) return (not parsed.netloc) or parsed.netloc == urlparse.urlparse( - pagure.APP.config['APP_URL']).netloc + pagure_config['APP_URL']).netloc return False @@ -3956,18 +3967,18 @@ def get_watch_level_on_repo(session, user, repo, repouser=None, 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 we can't find the user in the database, we can't determine their + # watch level if not user_obj: return [] - # If the user passed in a Project for the repo parameter, then we don't - # need to query for it + # 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 user passed in a string, then assume it is a project name + # If the project passed in a string, then assume it is a project name elif isinstance(repo, six.string_types): - project = pagure.get_authorized_project( + project = _get_project( session, repo, user=repouser, namespace=namespace) else: raise RuntimeError('The passed in repo is an invalid type of "{0}"' @@ -3997,8 +4008,8 @@ def get_watch_level_on_repo(session, user, repo, repouser=None, 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 + # 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 @@ -4016,9 +4027,9 @@ def get_watch_level_on_repo(session, user, repo, repouser=None, 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 a - # default watch level + # 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 [] @@ -4879,3 +4890,31 @@ def issues_history_stats(session, project): output[start.isoformat()] = cnt return output + + +def get_authorized_project( + session, project_name, user=None, namespace=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 + :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, + case=pagure_config.get('CASE_SENSITIVE', False) + ) + + if repo and repo.private and not pagure.utils.is_repo_admin(repo): + return None + + return repo diff --git a/pagure/lib/git.py b/pagure/lib/git.py index 4751b60..0cdf849 100644 --- a/pagure/lib/git.py +++ b/pagure/lib/git.py @@ -28,10 +28,11 @@ import pygit2 from sqlalchemy.exc import SQLAlchemyError from pygit2.remote import RemoteCollection -import pagure +import pagure.utils import pagure.exceptions import pagure.lib import pagure.lib.notify +from pagure.config import config as pagure_config from pagure.lib import model from pagure.lib.repo import PagureRepo from pagure.lib import tasks @@ -365,7 +366,7 @@ def get_user_from_json(session, jsondata, key='user'): fullname=fullname or username, default_email=default_email, emails=useremails, - keydir=pagure.APP.config.get('GITOLITE_KEYDIR', None), + keydir=pagure_config.get('GITOLITE_KEYDIR', None), ) session.commit() @@ -389,7 +390,7 @@ def get_project_from_json( project = pagure.lib._get_project( session, name, user=project_user, namespace=namespace, - case=pagure.APP.config.get('CASE_SENSITIVE', False)) + case=pagure_config.get('CASE_SENSITIVE', False)) if not project: parent = None @@ -401,10 +402,10 @@ def get_project_from_json( pagure.lib.fork_project( session=session, repo=parent, - gitfolder=pagure.APP.config['GIT_FOLDER'], - docfolder=pagure.APP.config['DOCS_FOLDER'], - ticketfolder=pagure.APP.config['TICKETS_FOLDER'], - requestfolder=pagure.APP.config['REQUESTS_FOLDER'], + gitfolder=pagure_config['GIT_FOLDER'], + docfolder=pagure_config['DOCS_FOLDER'], + ticketfolder=pagure_config['TICKETS_FOLDER'], + requestfolder=pagure_config['REQUESTS_FOLDER'], user=user.username) else: @@ -417,20 +418,20 @@ def get_project_from_json( namespace=namespace, description=jsondata.get('description'), parent_id=parent.id if parent else None, - blacklist=pagure.APP.config.get('BLACKLISTED_PROJECTS', []), - allowed_prefix=pagure.APP.config.get('ALLOWED_PREFIX', []), + blacklist=pagure_config.get('BLACKLISTED_PROJECTS', []), + allowed_prefix=pagure_config.get('ALLOWED_PREFIX', []), gitfolder=gitfolder, docfolder=docfolder, ticketfolder=ticketfolder, requestfolder=requestfolder, - prevent_40_chars=pagure.APP.config.get( + prevent_40_chars=pagure_config.get( 'OLD_VIEW_COMMIT_ENABLED', False), ) session.commit() project = pagure.lib._get_project( session, name, user=user.username, namespace=namespace, - case=pagure.APP.config.get('CASE_SENSITIVE', False)) + case=pagure_config.get('CASE_SENSITIVE', False)) tags = jsondata.get('tags', None) if tags: @@ -514,7 +515,7 @@ def update_ticket_from_git( repo = pagure.lib._get_project( session, reponame, user=username, namespace=namespace, - case=pagure.APP.config.get('CASE_SENSITIVE', False)) + case=pagure_config.get('CASE_SENSITIVE', False)) if not repo: raise pagure.exceptions.PagureException( @@ -697,7 +698,7 @@ def update_request_from_git( repo = pagure.lib._get_project( session, reponame, user=username, namespace=namespace, - case=pagure.APP.config.get('CASE_SENSITIVE', False)) + case=pagure_config.get('CASE_SENSITIVE', False)) if not repo: raise pagure.exceptions.PagureException( @@ -889,7 +890,7 @@ def _update_file_in_git( _log.info('Updating file: %s in the repo: %s', filename, repo.path) # Get the fork - repopath = pagure.get_repo_path(repo) + repopath = pagure.utils.get_repo_path(repo) # Clone the repo into a temp folder newpath = tempfile.mkdtemp(prefix='pagure-') @@ -1107,7 +1108,7 @@ def get_repo_namespace(abspath, gitfolder=None): ''' namespace = None if not gitfolder: - gitfolder = pagure.APP.config['GIT_FOLDER'] + gitfolder = pagure_config['GIT_FOLDER'] short_path = os.path.realpath(abspath).replace( os.path.realpath(gitfolder), '').strip('/') @@ -1161,16 +1162,16 @@ def merge_pull_request( if request.remote: # Get the fork - repopath = pagure.get_remote_repo_path( + repopath = pagure.utils.get_remote_repo_path( request.remote_git, request.branch_from) else: # Get the fork - repopath = pagure.get_repo_path(request.project_from) + repopath = pagure.utils.get_repo_path(request.project_from) fork_obj = PagureRepo(repopath) # Get the original repo - parentpath = pagure.get_repo_path(request.project) + parentpath = pagure.utils.get_repo_path(request.project) # Clone the original repo into a temp folder newpath = tempfile.mkdtemp(prefix='pagure-pr-merge') @@ -1178,7 +1179,7 @@ def merge_pull_request( new_repo = pygit2.clone_repository(parentpath, newpath) # Main repo, bare version - mainrepopath = pagure.get_repo_path(request.project) + mainrepopath = pagure.utils.get_repo_path(request.project) bare_main_repo = PagureRepo(mainrepopath) # Update the start and stop commits in the DB, one last time @@ -1266,7 +1267,6 @@ def merge_pull_request( except SQLAlchemyError as err: # pragma: no cover session.rollback() _log.exception(' Could not merge the PR in the DB') - pagure.APP.logger.exception(err) raise pagure.exceptions.PagureException( 'Could not close this pull-request') raise pagure.exceptions.PagureException( @@ -1327,6 +1327,7 @@ def merge_pull_request( except pygit2.GitError as err: _log.debug( ' Could not write down the new tree: merge conflicts') + _log.debug(err) shutil.rmtree(newpath) if domerge: _log.info(' Merge conflict: Bailing') @@ -1592,7 +1593,7 @@ def update_pull_ref(request, repo): """ Create or update the refs/pull/ reference in the git repo. """ - repopath = pagure.get_repo_path(request.project) + repopath = pagure.utils.get_repo_path(request.project) reponame = '%s_%s' % (request.user.user, request.uid) _log.info( @@ -1614,7 +1615,7 @@ def get_git_tags(project): """ Returns the list of tags created in the git repositorie of the specified project. """ - repopath = pagure.get_repo_path(project) + repopath = pagure.utils.get_repo_path(project) repo_obj = PagureRepo(repopath) tags = [ @@ -1630,7 +1631,7 @@ def get_git_tags_objects(project): """ Returns the list of references of the tags created in the git repositorie the specified project. The list is sorted using the time of the commit associated to the tag """ - repopath = pagure.get_repo_path(project) + repopath = pagure.utils.get_repo_path(project) repo_obj = PagureRepo(repopath) tags = {} for tag in repo_obj.listall_references(): @@ -1727,7 +1728,7 @@ def get_git_branches(project): ''' Return a list of branches for the project :arg project: The Project instance to get the branches for ''' - repo_path = pagure.get_repo_path(project) + repo_path = pagure.utils.get_repo_path(project) repo_obj = pygit2.Repository(repo_path) return repo_obj.listall_branches() @@ -1739,7 +1740,7 @@ def new_git_branch(project, branch, from_branch=None, from_commit=None): ''' if not from_branch and not from_commit: from_branch = 'master' - repo_path = pagure.get_repo_path(project) + repo_path = pagure.utils.get_repo_path(project) repo_obj = pygit2.Repository(repo_path) branches = repo_obj.listall_branches() diff --git a/pagure/lib/git_auth.py b/pagure/lib/git_auth.py index a5470fd..fe44a28 100644 --- a/pagure/lib/git_auth.py +++ b/pagure/lib/git_auth.py @@ -17,12 +17,12 @@ import subprocess import werkzeug -import pagure import pagure.exceptions -from pagure import APP +from pagure.config import config as pagure_config from pagure.lib import model -logging.config.dictConfig(APP.config.get('LOGGING') or {'version': 1}) + +# logging.config.dictConfig(pagure_config.get('LOGGING') or {'version': 1}) _log = logging.getLogger(__name__) @@ -372,7 +372,7 @@ class Gitolite2Auth(GitAuthHelper): 'Loading the file to include at the end of the generated one') postconfig = _read_file(postconf) - global_pr_only = pagure.APP.config.get('PR_ONLY', False) + global_pr_only = pagure_config.get('PR_ONLY', False) config = [] groups = {} if group is None: @@ -453,9 +453,9 @@ class Gitolite2Auth(GitAuthHelper): if not project: raise RuntimeError('Project undefined') - configfile = pagure.APP.config['GITOLITE_CONFIG'] - preconf = pagure.APP.config.get('GITOLITE_PRE_CONFIG') or None - postconf = pagure.APP.config.get('GITOLITE_POST_CONFIG') or None + configfile = pagure_config['GITOLITE_CONFIG'] + preconf = pagure_config.get('GITOLITE_PRE_CONFIG') or None + postconf = pagure_config.get('GITOLITE_POST_CONFIG') or None if not os.path.exists(configfile): _log.info( @@ -533,11 +533,11 @@ class Gitolite2Auth(GitAuthHelper): configuration file. """ _log.info('Compiling the gitolite configuration') - gitolite_folder = pagure.APP.config.get('GITOLITE_HOME', None) + gitolite_folder = pagure_config.get('GITOLITE_HOME', None) if gitolite_folder: cmd = 'GL_RC=%s GL_BINDIR=%s gl-compile-conf' % ( - pagure.APP.config.get('GL_RC'), - pagure.APP.config.get('GL_BINDIR') + pagure_config.get('GL_RC'), + pagure_config.get('GL_BINDIR') ) _log.debug('Command: %s', cmd) return cmd @@ -562,14 +562,16 @@ 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']) cls.write_gitolite_acls( - pagure.SESSION, + session, project=project, - configfile=pagure.APP.config['GITOLITE_CONFIG'], - preconf=pagure.APP.config.get('GITOLITE_PRE_CONFIG') or None, - postconf=pagure.APP.config.get('GITOLITE_POST_CONFIG') or None, + configfile=pagure_config['GITOLITE_CONFIG'], + preconf=pagure_config.get('GITOLITE_PRE_CONFIG') or None, + postconf=pagure_config.get('GITOLITE_POST_CONFIG') or None, group=group, ) + session.remove() cmd = cls._get_gitolite_command() if cmd: @@ -578,7 +580,7 @@ class Gitolite2Auth(GitAuthHelper): shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, - cwd=pagure.APP.config['GITOLITE_HOME'] + cwd=pagure_config['GITOLITE_HOME'] ) stdout, stderr = proc.communicate() if proc.returncode != 0: @@ -598,7 +600,7 @@ class Gitolite3Auth(Gitolite2Auth): configuration file. """ _log.info('Compiling the gitolite configuration') - gitolite_folder = pagure.APP.config.get('GITOLITE_HOME', None) + gitolite_folder = pagure_config.get('GITOLITE_HOME', None) if gitolite_folder: cmd = 'HOME=%s gitolite compile && HOME=%s gitolite trigger '\ 'POST_COMPILE' % (gitolite_folder, gitolite_folder) diff --git a/pagure/lib/link.py b/pagure/lib/link.py index dc2c246..a8afc12 100644 --- a/pagure/lib/link.py +++ b/pagure/lib/link.py @@ -57,7 +57,7 @@ def get_relation(session, reponame, username, namespace, text, ''' - repo = pagure.get_authorized_project( + repo = pagure.lib.get_authorized_project( session, reponame, user=username, namespace=namespace) if not repo: return [] diff --git a/pagure/lib/notify.py b/pagure/lib/notify.py index c054e79..6165436 100644 --- a/pagure/lib/notify.py +++ b/pagure/lib/notify.py @@ -22,19 +22,19 @@ import urlparse import re import smtplib import time - -import flask -import pagure - from email.header import Header from email.mime.text import MIMEText +import flask +import pagure.lib +from pagure.config import config as pagure_config + _log = logging.getLogger(__name__) REPLY_MSG = 'To reply, visit the link below' -if pagure.APP.config['EVENTSOURCE_SOURCE']: +if pagure_config['EVENTSOURCE_SOURCE']: REPLY_MSG += ' or just reply to this email' @@ -80,7 +80,8 @@ def _add_mentioned_users(emails, comment): ''' mentio_re = r'@(\w+)' for username in re.findall(mentio_re, comment): - user = pagure.lib.search_user(pagure.SESSION, username=username) + user = pagure.lib.search_user( + flask.g.session, username=username) if user: emails.add(user.default_email) return emails @@ -165,7 +166,7 @@ def _get_emails_for_obj(obj): # Drop the email used by pagure when sending emails = _clean_emails( - emails, pagure.APP.config.get(pagure.APP.config.get( + emails, pagure_config.get(pagure_config.get( 'FROM_EMAIL', 'pagure@fedoraproject.org')) ) @@ -180,7 +181,7 @@ def _get_emails_for_commit_notification(project): # Drop the email used by pagure when sending emails = _clean_emails( - emails, pagure.APP.config.get(pagure.APP.config.get( + emails, pagure_config.get(pagure_config.get( 'FROM_EMAIL', 'pagure@fedoraproject.org')) ) @@ -228,7 +229,7 @@ def send_email(text, subject, to_mail, if not to_mail: return - from_email = pagure.APP.config.get( + from_email = pagure_config.get( 'FROM_EMAIL', 'pagure@fedoraproject.org') if user_from: header = Header(user_from, 'utf-8') @@ -240,10 +241,10 @@ def send_email(text, subject, to_mail, subject_tag = 'Pagure' if mail_id: mail_id = mail_id + "@%s" %\ - pagure.APP.config['DOMAIN_EMAIL_NOTIFICATIONS'] + pagure_config['DOMAIN_EMAIL_NOTIFICATIONS'] if in_reply_to: in_reply_to = in_reply_to + "@%s" %\ - pagure.APP.config['DOMAIN_EMAIL_NOTIFICATIONS'] + pagure_config['DOMAIN_EMAIL_NOTIFICATIONS'] smtp = None for mailto in to_mail.split(','): @@ -260,12 +261,12 @@ def send_email(text, subject, to_mail, msg['In-Reply-To'] = '<%s>' % in_reply_to msg['X-Auto-Response-Suppress'] = 'All' - msg['X-pagure'] = pagure.APP.config['APP_URL'] + msg['X-pagure'] = pagure_config['APP_URL'] if project_name is not None: msg['X-pagure-project'] = project_name msg['List-ID'] = project_name msg['List-Archive'] = _build_url( - pagure.APP.config['APP_URL'], + pagure_config['APP_URL'], _fullname_to_url(project_name)) # Send the message via our own SMTP server, but don't include the @@ -273,15 +274,15 @@ def send_email(text, subject, to_mail, if isinstance(mailto, unicode): mailto = mailto.encode('utf-8') msg['To'] = mailto - salt = pagure.APP.config.get('SALT_EMAIL') + salt = pagure_config.get('SALT_EMAIL') if isinstance(mail_id, unicode): mail_id = mail_id.encode('utf-8') mhash = hashlib.sha512('<%s>%s%s' % (mail_id, salt, mailto)) msg['Reply-To'] = 'reply+%s@%s' % ( mhash.hexdigest(), - pagure.APP.config['DOMAIN_EMAIL_NOTIFICATIONS']) + pagure_config['DOMAIN_EMAIL_NOTIFICATIONS']) msg['Mail-Followup-To'] = msg['Reply-To'] - if not pagure.APP.config.get('EMAIL_SEND', True): + if not pagure_config.get('EMAIL_SEND', True): print('******EMAIL******') print('From: %s' % from_email) print('To: %s' % to_mail) @@ -296,19 +297,19 @@ def send_email(text, subject, to_mail, continue try: if smtp is None: - if pagure.APP.config['SMTP_SSL']: + if pagure_config['SMTP_SSL']: smtp = smtplib.SMTP_SSL( - pagure.APP.config['SMTP_SERVER'], - pagure.APP.config['SMTP_PORT']) + pagure_config['SMTP_SERVER'], + pagure_config['SMTP_PORT']) else: smtp = smtplib.SMTP( - pagure.APP.config['SMTP_SERVER'], - pagure.APP.config['SMTP_PORT']) - if pagure.APP.config['SMTP_USERNAME'] \ - and pagure.APP.config['SMTP_PASSWORD']: + pagure_config['SMTP_SERVER'], + pagure_config['SMTP_PORT']) + if pagure_config['SMTP_USERNAME'] \ + and pagure_config['SMTP_PASSWORD']: smtp.login( - pagure.APP.config['SMTP_USERNAME'], - pagure.APP.config['SMTP_PASSWORD'] + pagure_config['SMTP_USERNAME'], + pagure_config['SMTP_PASSWORD'] ) smtp.sendmail( @@ -339,7 +340,7 @@ def notify_new_comment(comment, user=None): comment.comment, REPLY_MSG, _build_url( - pagure.APP.config['APP_URL'], + pagure_config['APP_URL'], _fullname_to_url(comment.issue.project.fullname), 'issue', comment.issue.id)) @@ -378,7 +379,7 @@ def notify_new_issue(issue, user=None): issue.content, REPLY_MSG, _build_url( - pagure.APP.config['APP_URL'], + pagure_config['APP_URL'], _fullname_to_url(issue.project.fullname), 'issue', issue.id)) @@ -411,7 +412,7 @@ The issue: `%s` of project: `%s` has been %s by %s. action, user.username, _build_url( - pagure.APP.config['APP_URL'], + pagure_config['APP_URL'], _fullname_to_url(issue.project.fullname), 'issue', issue.id)) @@ -448,7 +449,7 @@ The status of the issue: `%s` of project: `%s` has been updated to: %s by %s. status, user.username, _build_url( - pagure.APP.config['APP_URL'], + pagure_config['APP_URL'], _fullname_to_url(issue.project.fullname), 'issue', issue.id)) @@ -478,7 +479,7 @@ def notify_meta_change_issue(issue, user, msg): """ % (user.username, msg, _build_url( - pagure.APP.config['APP_URL'], + pagure_config['APP_URL'], _fullname_to_url(issue.project.fullname), 'issue', issue.id)) @@ -510,7 +511,7 @@ The pull-request: `%s` of project: `%s` has been %s by %s. action, user.username, _build_url( - pagure.APP.config['APP_URL'], + pagure_config['APP_URL'], _fullname_to_url(request.project.fullname), 'pull-request', request.id)) @@ -549,7 +550,7 @@ def notify_new_pull_request(request): request.title, REPLY_MSG, _build_url( - pagure.APP.config['APP_URL'], + pagure_config['APP_URL'], _fullname_to_url(request.project.fullname), 'pull-request', request.id)) @@ -583,7 +584,7 @@ Merged pull-request: request.project.name, request.title, _build_url( - pagure.APP.config['APP_URL'], + pagure_config['APP_URL'], _fullname_to_url(request.project.fullname), 'pull-request', request.id)) @@ -619,7 +620,7 @@ Cancelled pull-request: request.project.name, request.title, _build_url( - pagure.APP.config['APP_URL'], + pagure_config['APP_URL'], _fullname_to_url(request.project.fullname), 'pull-request', request.id)) @@ -654,7 +655,7 @@ def notify_pull_request_comment(comment, user): comment.comment, REPLY_MSG, _build_url( - pagure.APP.config['APP_URL'], + pagure_config['APP_URL'], _fullname_to_url(comment.pull_request.project.fullname), 'pull-request', comment.pull_request.id)) @@ -677,11 +678,11 @@ def notify_new_email(email, user): ''' Ask the user to confirm to the email belong to them. ''' - root_url = pagure.APP.config.get('APP_URL', flask.request.url_root) + root_url = pagure_config.get('APP_URL', flask.request.url_root) url = urlparse.urljoin( root_url or flask.request.url_root, - flask.url_for('confirm_email', token=email.token), + flask.url_for('ui_ns.confirm_email', token=email.token), ) text = u"""Dear %(username)s, @@ -722,7 +723,7 @@ def notify_new_commits(abspath, project, branch, commits): commit_info['commit'], commit_info['author'], commit_info['subject']) for commit_info in commits_info) commit_url = _build_url( - pagure.APP.config['APP_URL'], _fullname_to_url(project.fullname), + pagure_config['APP_URL'], _fullname_to_url(project.fullname), 'commits', branch) email_body = ''' diff --git a/pagure/lib/tasks.py b/pagure/lib/tasks.py index 3488453..11d1333 100644 --- a/pagure/lib/tasks.py +++ b/pagure/lib/tasks.py @@ -29,26 +29,26 @@ from celery import Celery from celery.result import AsyncResult from sqlalchemy.exc import SQLAlchemyError -import pagure -from pagure import APP import pagure.lib import pagure.lib.git import pagure.lib.git_auth import pagure.lib.repo +import pagure.utils +from pagure.config import config as pagure_config -logging.config.dictConfig(APP.config.get('LOGGING') or {'version': 1}) +# logging.config.dictConfig(pagure_config.get('LOGGING') or {'version': 1}) _log = logging.getLogger(__name__) if os.environ.get('PAGURE_BROKER_URL'): broker_url = os.environ['PAGURE_BROKER_URL'] -elif APP.config.get('BROKER_URL'): - broker_url = APP.config['BROKER_URL'] +elif pagure_config.get('BROKER_URL'): + broker_url = pagure_config['BROKER_URL'] else: - broker_url = 'redis://%s' % APP.config['REDIS_HOST'] + broker_url = 'redis://%s' % pagure_config['REDIS_HOST'] conn = Celery('tasks', broker=broker_url, backend=broker_url) -conn.conf.update(APP.config['CELERY_CONFIG']) +conn.conf.update(pagure_config['CELERY_CONFIG']) def set_status(function): @@ -87,7 +87,7 @@ def gc_clean(): gc.collect() -@conn.task(queue=APP.config.get('GITOLITE_CELERY_QUEUE', None), bind=True) +@conn.task(queue=pagure_config.get('GITOLITE_CELERY_QUEUE', None), bind=True) @set_status def generate_gitolite_acls( self, namespace=None, name=None, user=None, group=None): @@ -104,18 +104,17 @@ def generate_gitolite_acls( :type group: None or str """ - - session = pagure.lib.create_session() + session = pagure.lib.create_session(pagure_config['DB_URL']) project = None if name and name != -1: project = pagure.lib._get_project( session, namespace=namespace, name=name, user=user, - case=APP.config.get('CASE_SENSITIVE', False)) + case=pagure_config.get('CASE_SENSITIVE', False)) elif name == -1: project = name helper = pagure.lib.git_auth.get_git_auth_helper( - APP.config['GITOLITE_BACKEND']) + pagure_config['GITOLITE_BACKEND']) _log.debug('Got helper: %s', helper) group_obj = None @@ -138,7 +137,7 @@ def generate_gitolite_acls( gc_clean() -@conn.task(queue=APP.config.get('GITOLITE_CELERY_QUEUE', None), bind=True) +@conn.task(queue=pagure_config.get('GITOLITE_CELERY_QUEUE', None), bind=True) @set_status def delete_project( self, namespace=None, name=None, user=None, action_user=None): @@ -159,11 +158,10 @@ def delete_project( :type action_user: None or str """ - - session = pagure.lib.create_session() + session = pagure.lib.create_session(pagure_config['DB_URL']) project = pagure.lib._get_project( session, namespace=namespace, name=name, user=user, - case=APP.config.get('CASE_SENSITIVE', False)) + case=pagure_config.get('CASE_SENSITIVE', False)) if not project: raise RuntimeError( @@ -172,7 +170,7 @@ def delete_project( # Remove the project from gitolite.conf helper = pagure.lib.git_auth.get_git_auth_helper( - APP.config['GITOLITE_BACKEND']) + pagure_config['GITOLITE_BACKEND']) _log.debug('Got helper: %s', helper) _log.debug( @@ -184,8 +182,8 @@ def delete_project( for key in [ 'GIT_FOLDER', 'DOCS_FOLDER', 'TICKETS_FOLDER', 'REQUESTS_FOLDER']: - if APP.config[key]: - path = os.path.join(APP.config[key], project.path) + if pagure_config[key]: + path = os.path.join(pagure_config[key], project.path) if os.path.exists(path): paths.append(path) @@ -223,7 +221,7 @@ def delete_project( gc_clean() - return ret('view_user', username=username) + return ret('ui_ns.view_user', username=username) @conn.task(bind=True) @@ -246,16 +244,15 @@ def create_project(self, username, namespace, name, add_readme, :type ignore_existing_repo: bool """ - - session = pagure.lib.create_session() + session = pagure.lib.create_session(pagure_config['DB_URL']) project = pagure.lib._get_project( session, namespace=namespace, name=name, - case=APP.config.get('CASE_SENSITIVE', False)) + case=pagure_config.get('CASE_SENSITIVE', False)) with project.lock('WORKER'): userobj = pagure.lib.search_user(session, username=username) - gitrepo = os.path.join(APP.config['GIT_FOLDER'], project.path) + gitrepo = os.path.join(pagure_config['GIT_FOLDER'], project.path) # Add the readme file if it was asked if not add_readme: @@ -288,24 +285,27 @@ def create_project(self, username, namespace, name, add_readme, with open(http_clone_file, 'w') as stream: pass - if APP.config['DOCS_FOLDER']: - docrepo = os.path.join(APP.config['DOCS_FOLDER'], project.path) + if pagure_config['DOCS_FOLDER']: + docrepo = os.path.join( + pagure_config['DOCS_FOLDER'], project.path) if os.path.exists(docrepo): if not ignore_existing_repo: shutil.rmtree(gitrepo) + session.remove() raise pagure.exceptions.RepoExistsException( 'The docs repo "%s" already exists' % project.path ) else: pygit2.init_repository(docrepo, bare=True) - if APP.config['TICKETS_FOLDER']: + if pagure_config['TICKETS_FOLDER']: ticketrepo = os.path.join( - APP.config['TICKETS_FOLDER'], project.path) + pagure_config['TICKETS_FOLDER'], project.path) if os.path.exists(ticketrepo): if not ignore_existing_repo: shutil.rmtree(gitrepo) shutil.rmtree(docrepo) + session.remove() raise pagure.exceptions.RepoExistsException( 'The tickets repo "%s" already exists' % project.path @@ -316,12 +316,13 @@ def create_project(self, username, namespace, name, add_readme, mode=pygit2.C.GIT_REPOSITORY_INIT_SHARED_GROUP) requestrepo = os.path.join( - APP.config['REQUESTS_FOLDER'], project.path) + pagure_config['REQUESTS_FOLDER'], project.path) if os.path.exists(requestrepo): if not ignore_existing_repo: shutil.rmtree(gitrepo) shutil.rmtree(docrepo) shutil.rmtree(ticketrepo) + session.remove() raise pagure.exceptions.RepoExistsException( 'The requests repo "%s" already exists' % project.path @@ -351,7 +352,7 @@ def create_project(self, username, namespace, name, add_readme, session.remove() gc_clean() - return ret('view_repo', repo=name, namespace=namespace) + return ret('ui_ns.view_repo', repo=name, namespace=namespace) @conn.task(bind=True) @@ -360,20 +361,19 @@ def update_git(self, name, namespace, user, ticketuid=None, requestuid=None): """ Update the JSON representation of either a ticket or a pull-request depending on the argument specified. """ - - session = pagure.lib.create_session() + session = pagure.lib.create_session(pagure_config['DB_URL']) project = pagure.lib._get_project( session, namespace=namespace, name=name, user=user, - case=APP.config.get('CASE_SENSITIVE', False)) + case=pagure_config.get('CASE_SENSITIVE', False)) with project.lock('WORKER'): if ticketuid is not None: obj = pagure.lib.get_issue_by_uid(session, ticketuid) - folder = APP.config['TICKETS_FOLDER'] + folder = pagure_config['TICKETS_FOLDER'] elif requestuid is not None: obj = pagure.lib.get_request_by_uid(session, requestuid) - folder = APP.config['REQUESTS_FOLDER'] + folder = pagure_config['REQUESTS_FOLDER'] else: raise NotImplementedError('No ticket ID or request ID provided') @@ -393,16 +393,15 @@ def clean_git(self, name, namespace, user, ticketuid): """ Remove the JSON representation of a ticket on the git repository for tickets. """ - - session = pagure.lib.create_session() + session = pagure.lib.create_session(pagure_config['DB_URL']) project = pagure.lib._get_project( session, namespace=namespace, name=name, user=user, - case=APP.config.get('CASE_SENSITIVE', False)) + case=pagure_config.get('CASE_SENSITIVE', False)) with project.lock('WORKER'): obj = pagure.lib.get_issue_by_uid(session, ticketuid) - folder = APP.config['TICKETS_FOLDER'] + folder = pagure_config['TICKETS_FOLDER'] if obj is None: raise Exception('Unable to find object') @@ -420,13 +419,12 @@ def update_file_in_git(self, name, namespace, user, branch, branchto, runhook=False): """ Update a file in the specified git repo. """ - - session = pagure.lib.create_session() + session = pagure.lib.create_session(pagure_config['DB_URL']) userobj = pagure.lib.search_user(session, username=username) project = pagure.lib._get_project( session, namespace=namespace, name=name, user=user, - case=APP.config.get('CASE_SENSITIVE', False)) + case=pagure_config.get('CASE_SENSITIVE', False)) with project.lock('WORKER'): pagure.lib.git._update_file_in_git( @@ -434,7 +432,7 @@ def update_file_in_git(self, name, namespace, user, branch, branchto, content, message, userobj, email, runhook=runhook) session.remove() - return ret('view_commits', repo=project.name, username=user, + return ret('ui_ns.view_commits', repo=project.name, username=user, namespace=namespace, branchname=branchto) @@ -443,15 +441,15 @@ def update_file_in_git(self, name, namespace, user, branch, branchto, def delete_branch(self, name, namespace, user, branchname): """ Delete a branch from a git repo. """ - - session = pagure.lib.create_session() + session = pagure.lib.create_session(pagure_config['DB_URL']) project = pagure.lib._get_project( session, namespace=namespace, name=name, user=user, - case=APP.config.get('CASE_SENSITIVE', False)) + case=pagure_config.get('CASE_SENSITIVE', False)) with project.lock('WORKER'): - repo_obj = pygit2.Repository(pagure.get_repo_path(project)) + repo_obj = pygit2.Repository( + pagure.utils.get_repo_path(project)) try: branch = repo_obj.lookup_branch(branchname) @@ -460,7 +458,8 @@ def delete_branch(self, name, namespace, user, branchname): _log.exception(err) session.remove() - return ret('view_repo', repo=name, namespace=namespace, username=user) + return ret( + 'ui_ns.view_repo', repo=name, namespace=namespace, username=user) @conn.task(bind=True) @@ -484,20 +483,19 @@ def fork(self, name, namespace, user_owner, user_forker, editbranch, editfile): :type editfile: str """ - - session = pagure.lib.create_session() + session = pagure.lib.create_session(pagure_config['DB_URL']) repo_from = pagure.lib._get_project( session, namespace=namespace, name=name, user=user_owner, - case=APP.config.get('CASE_SENSITIVE', False)) + case=pagure_config.get('CASE_SENSITIVE', False)) repo_to = pagure.lib._get_project( session, namespace=namespace, name=name, user=user_forker, - case=APP.config.get('CASE_SENSITIVE', False)) + case=pagure_config.get('CASE_SENSITIVE', False)) with repo_to.lock('WORKER'): - reponame = os.path.join(APP.config['GIT_FOLDER'], repo_from.path) - forkreponame = os.path.join(APP.config['GIT_FOLDER'], repo_to.path) + reponame = os.path.join(pagure_config['GIT_FOLDER'], repo_from.path) + forkreponame = os.path.join(pagure_config['GIT_FOLDER'], repo_to.path) frepo = pygit2.clone_repository(reponame, forkreponame, bare=True) # Clone all the branches as well @@ -517,8 +515,9 @@ def fork(self, name, namespace, user_owner, user_forker, editbranch, editfile): # Only fork the doc folder if the pagure instance supports the doc # service/server. - if APP.config.get('DOCS_FOLDER'): - docrepo = os.path.join(APP.config['DOCS_FOLDER'], repo_to.path) + if pagure_config.get('DOCS_FOLDER'): + docrepo = os.path.join( + pagure_config['DOCS_FOLDER'], repo_to.path) if os.path.exists(docrepo): shutil.rmtree(forkreponame) raise pagure.exceptions.RepoExistsException( @@ -526,9 +525,9 @@ def fork(self, name, namespace, user_owner, user_forker, editbranch, editfile): ) pygit2.init_repository(docrepo, bare=True) - if APP.config.get('TICKETS_FOLDER'): + if pagure_config.get('TICKETS_FOLDER'): ticketrepo = os.path.join( - APP.config['TICKETS_FOLDER'], repo_to.path) + pagure_config['TICKETS_FOLDER'], repo_to.path) if os.path.exists(ticketrepo): shutil.rmtree(forkreponame) shutil.rmtree(docrepo) @@ -539,7 +538,8 @@ def fork(self, name, namespace, user_owner, user_forker, editbranch, editfile): ticketrepo, bare=True, mode=pygit2.C.GIT_REPOSITORY_INIT_SHARED_GROUP) - requestrepo = os.path.join(APP.config['REQUESTS_FOLDER'], repo_to.path) + requestrepo = os.path.join( + pagure_config['REQUESTS_FOLDER'], repo_to.path) if os.path.exists(requestrepo): shutil.rmtree(forkreponame) shutil.rmtree(docrepo) @@ -572,10 +572,10 @@ def fork(self, name, namespace, user_owner, user_forker, editbranch, editfile): gc_clean() if editfile is None: - return ret('view_repo', repo=name, namespace=namespace, + return ret('ui_ns.view_repo', repo=name, namespace=namespace, username=user_forker) else: - return ret('edit_file', repo=name, namespace=namespace, + return ret('ui_ns.edit_file', repo=name, namespace=namespace, username=user_forker, branchname=editbranch, filename=editfile) @@ -602,12 +602,11 @@ def refresh_remote_pr(self, name, namespace, user, requestid): """ Refresh the local clone of a git repository used in a remote pull-request. """ - - session = pagure.lib.create_session() + session = pagure.lib.create_session(pagure_config['DB_URL']) project = pagure.lib._get_project( session, namespace=namespace, name=name, user=user, - case=APP.config.get('CASE_SENSITIVE', False)) + case=pagure_config.get('CASE_SENSITIVE', False)) request = pagure.lib.search_pull_requests( session, project_id=project.id, requestid=requestid) @@ -625,8 +624,9 @@ def refresh_remote_pr(self, name, namespace, user, requestid): session.remove() del repo gc_clean() - return ret('request_pull', username=user, namespace=namespace, repo=name, - requestid=requestid) + return ret( + 'ui_ns.request_pull', username=user, namespace=namespace, + repo=name, requestid=requestid) @conn.task(bind=True) @@ -634,12 +634,11 @@ def refresh_remote_pr(self, name, namespace, user, requestid): def refresh_pr_cache(self, name, namespace, user): """ Refresh the merge status cached of pull-requests. """ - - session = pagure.lib.create_session() + session = pagure.lib.create_session(pagure_config['DB_URL']) project = pagure.lib._get_project( session, namespace=namespace, name=name, user=user, - case=APP.config.get('CASE_SENSITIVE', False)) + case=pagure_config.get('CASE_SENSITIVE', False)) pagure.lib.reset_status_pull_request(session, project) @@ -652,12 +651,11 @@ def refresh_pr_cache(self, name, namespace, user): def merge_pull_request(self, name, namespace, user, requestid, user_merger): """ Merge pull-request. """ - - session = pagure.lib.create_session() + session = pagure.lib.create_session(pagure_config['DB_URL']) project = pagure.lib._get_project( session, namespace=namespace, name=name, user=user, - case=APP.config.get('CASE_SENSITIVE', False)) + case=pagure_config.get('CASE_SENSITIVE', False)) with project.lock('WORKER'): request = pagure.lib.search_pull_requests( @@ -666,12 +664,13 @@ def merge_pull_request(self, name, namespace, user, requestid, user_merger): 'Merging pull-request: %s/#%s', request.project.fullname, request.id) pagure.lib.git.merge_pull_request( - session, request, user_merger, APP.config['REQUESTS_FOLDER']) + session, request, user_merger, pagure_config['REQUESTS_FOLDER']) refresh_pr_cache.delay(name, namespace, user) session.remove() gc_clean() - return ret('view_repo', repo=name, username=user, namespace=namespace) + return ret( + 'ui_ns.view_repo', repo=name, username=user, namespace=namespace) @conn.task(bind=True) @@ -680,19 +679,18 @@ def add_file_to_git( self, name, namespace, user, user_attacher, issueuid, filename): """ Add a file to the specified git repo. """ - - session = pagure.lib.create_session() + session = pagure.lib.create_session(pagure_config['DB_URL']) project = pagure.lib._get_project( session, namespace=namespace, name=name, user=user, - case=APP.config.get('CASE_SENSITIVE', False)) + case=pagure_config.get('CASE_SENSITIVE', False)) with project.lock('WORKER'): issue = pagure.lib.get_issue_by_uid(session, issueuid) user_attacher = pagure.lib.search_user(session, username=user_attacher) - from_folder = APP.config['ATTACHMENTS_FOLDER'] - to_folder = APP.config['TICKETS_FOLDER'] + from_folder = pagure_config['ATTACHMENTS_FOLDER'] + to_folder = pagure_config['TICKETS_FOLDER'] _log.info( 'Adding file %s from %s to %s', filename, from_folder, to_folder) pagure.lib.git._add_file_to_git( @@ -714,14 +712,13 @@ def project_dowait(self, name, namespace, user): It should never be allowed to be called in production instances, since that would allow an attacker to basically DOS a project by calling this repeatedly. """ + assert pagure_config.get('ALLOW_PROJECT_DOWAIT', False) - assert APP.config.get('ALLOW_PROJECT_DOWAIT', False) - - session = pagure.lib.create_session() + session = pagure.lib.create_session(pagure_config['DB_URL']) project = pagure.lib._get_project( session, namespace=namespace, name=name, user=user, - case=APP.config.get('CASE_SENSITIVE', False)) + case=pagure_config.get('CASE_SENSITIVE', False)) with project.lock('WORKER'): time.sleep(10) @@ -729,7 +726,8 @@ def project_dowait(self, name, namespace, user): session.remove() gc_clean() - return ret('view_repo', repo=name, username=user, namespace=namespace) + return ret( + 'ui_ns.view_repo', repo=name, username=user, namespace=namespace) @conn.task(bind=True) @@ -738,12 +736,11 @@ def sync_pull_ref(self, name, namespace, user, requestid): """ Synchronize a pull/ reference from the content in the forked repo, allowing local checkout of the pull-request. """ - - session = pagure.lib.create_session() + session = pagure.lib.create_session(pagure_config['DB_URL']) project = pagure.lib._get_project( session, namespace=namespace, name=name, user=user, - case=APP.config.get('CASE_SENSITIVE', False)) + case=pagure_config.get('CASE_SENSITIVE', False)) with project.lock('WORKER'): request = pagure.lib.search_pull_requests( @@ -758,7 +755,7 @@ def sync_pull_ref(self, name, namespace, user, requestid): request.remote_git, request.branch_from) else: # Get the fork - repopath = pagure.get_repo_path(request.project_from) + repopath = pagure.utils.get_repo_path(request.project_from) _log.debug(' working on the repo in: %s', repopath) repo_obj = pygit2.Repository(repopath) diff --git a/pagure/pfmarkdown.py b/pagure/pfmarkdown.py index e4cd654..1f139f1 100644 --- a/pagure/pfmarkdown.py +++ b/pagure/pfmarkdown.py @@ -25,8 +25,8 @@ import markdown.inlinepatterns import markdown.util import pygit2 -import pagure import pagure.lib +from pagure.config import config as pagure_config MENTION_RE = r'@(\w+)' @@ -64,12 +64,12 @@ 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(pagure.SESSION, username=name) + user = pagure.lib.search_user(flask.g.session, username=name) if not user: return text element = markdown.util.etree.Element("a") - base_url = pagure.APP.config['APP_URL'] + base_url = pagure_config['APP_URL'] if base_url.endswith('/'): base_url = base_url[:-1] url = '%s/user/%s' % (base_url, user.username) @@ -141,7 +141,7 @@ class CommitLinkPattern(markdown.inlinepatterns.Pattern): text = '%s/%s' % (user.rstrip('/'), text) if pagure.lib.search_projects( - pagure.SESSION, + flask.g.session, username=user, fork=is_fork, namespace=namespace, @@ -222,7 +222,7 @@ class ImplicitCommitPattern(markdown.inlinepatterns.Pattern): return text if pagure.lib.search_projects( - pagure.SESSION, + flask.g.session, username=user, namespace=namespace, pattern=repo) \ @@ -262,7 +262,7 @@ class PagureExtension(markdown.extensions.Extension): md.inlinePatterns['commit_links'] = CommitLinkPattern( COMMIT_LINK_RE) - if pagure.APP.config.get('ENABLE_TICKETS', True): + if pagure_config.get('ENABLE_TICKETS', True): md.inlinePatterns['implicit_pr'] = \ ImplicitPRPattern(IMPLICIT_PR_RE) md.inlinePatterns['explicit_fork_issue'] = \ @@ -283,14 +283,14 @@ def makeExtension(*arg, **kwargs): def _issue_exists(user, namespace, repo, idx): """ Utility method checking if a given issue exists. """ - repo_obj = pagure.get_authorized_project( - pagure.SESSION, project_name=repo, user=user, namespace=namespace) + repo_obj = pagure.lib.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( - pagure.SESSION, repo=repo_obj, issueid=idx) + flask.g.session, repo=repo_obj, issueid=idx) if not issue_obj: return False @@ -299,14 +299,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.get_authorized_project( - pagure.SESSION, project_name=repo, user=user, namespace=namespace) + repo_obj = pagure.lib.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( - pagure.SESSION, project_id=repo_obj.id, requestid=idx) + flask.g.session, project_id=repo_obj.id, requestid=idx) if not pr_obj: return False @@ -315,12 +315,12 @@ 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.get_authorized_project( - pagure.SESSION, project_name=repo, user=user, namespace=namespace) + repo_obj = pagure.lib.get_authorized_project( + flask.g.session, project_name=repo, user=user, namespace=namespace) if not repo_obj: return False - reponame = pagure.get_repo_path(repo_obj) + reponame = pagure.utils.get_repo_path(repo_obj) git_repo = pygit2.Repository(reponame) return githash in git_repo @@ -334,13 +334,13 @@ def _obj_anchor_tag(user, namespace, repo, obj, text): """ if isinstance(obj, basestring): url = flask.url_for( - 'view_commit', username=user, namespace=namespace, repo=repo, - commitid=obj) + 'ui_ns.view_commit', username=user, namespace=namespace, + repo=repo, commitid=obj) title = 'Commit %s' % obj elif obj.isa == 'issue': url = flask.url_for( - 'view_issue', username=user, namespace=namespace, repo=repo, - issueid=obj.id) + 'ui_ns.view_issue', username=user, namespace=namespace, + repo=repo, issueid=obj.id) if obj.private: title = 'Private issue' else: @@ -350,8 +350,8 @@ def _obj_anchor_tag(user, namespace, repo, obj, text): title = obj.title else: url = flask.url_for( - 'request_pull', username=user, namespace=namespace, repo=repo, - requestid=obj.id) + 'ui_ns.request_pull', username=user, namespace=namespace, + repo=repo, requestid=obj.id) if obj.status: title = '[%s] %s' % (obj.status, obj.title) else: diff --git a/pagure/templates/_browseheader.html b/pagure/templates/_browseheader.html index c9c2271..f50becb 100644 --- a/pagure/templates/_browseheader.html +++ b/pagure/templates/_browseheader.html @@ -1,7 +1,7 @@ {% macro browse_header(select) -%}
-
+ {% if repo %} - Cancel {% else %} - Cancel {% endif %} diff --git a/pagure/templates/add_user.html b/pagure/templates/add_user.html index aacb1e5..107f7bb 100644 --- a/pagure/templates/add_user.html +++ b/pagure/templates/add_user.html @@ -18,7 +18,7 @@ Add user to the {{repo.name}} project
- diff --git a/pagure/templates/blame.html b/pagure/templates/blame.html index 52a61d0..4eba4ea 100644 --- a/pagure/templates/blame.html +++ b/pagure/templates/blame.html @@ -34,7 +34,7 @@ {% for branch in g.branches %} {% if origin == 'view_tree' %}