def delete_distro(distro_name): """ Delete a distro """ distro = models.Distro.by_name(Session, distro_name) if not distro: flask.abort(404) if not is_admin(): flask.abort(401) form = anitya.forms.ConfirmationForm() if form.validate_on_submit(): utilities.log( Session, distro=distro.__json__(), topic="distro.remove", message=dict(agent=flask.g.user.username, distro=distro.name), ) Session.delete(distro) Session.commit() flask.flash("Distro %s has been removed" % distro_name) return flask.redirect(flask.url_for("anitya_ui.distros")) return flask.render_template( "distro_delete.html", current="distros", distro=distro, form=form )
def delete_distro(distro_name): """ Delete a distro """ distro = models.Distro.by_name(Session, distro_name) if not distro: flask.abort(404) if not is_admin(): flask.abort(401) form = anitya.forms.ConfirmationForm() if form.validate_on_submit(): utilities.log( Session, distro=distro.__json__(), topic="distro.remove", message=dict(agent=flask.g.user.username, distro=distro.name), ) Session.delete(distro) Session.commit() flask.flash("Distro %s has been removed" % distro_name) return flask.redirect(flask.url_for("anitya_ui.distros")) return flask.render_template("distro_delete.html", current="distros", distro=distro, form=form)
def setUp(self): super(EditDistroTests, self).setUp() # Add a regular user and an admin user session = Session() self.user = models.User( email='*****@*****.**', username='******', ) user_social_auth = social_models.UserSocialAuth( user_id=self.user.id, user=self.user ) session.add(self.user) session.add(user_social_auth) self.admin = models.User(email='*****@*****.**', username='******') admin_social_auth = social_models.UserSocialAuth( user_id=self.admin.id, user=self.admin ) # Add distributions to edit self.fedora = models.Distro(name='Fedora') self.centos = models.Distro(name='CentOS') session.add_all([admin_social_auth, self.admin, self.fedora, self.centos]) session.commit() mock_config = mock.patch.dict( models.anitya_config, {'ANITYA_WEB_ADMINS': [six.text_type(self.admin.id)]}) mock_config.start() self.addCleanup(mock_config.stop) self.client = self.flask_app.test_client()
def tearDown(self): """Roll back all the changes from the test and clean up the session.""" self.session.close() self.transaction.rollback() self.connection.close() Session.remove() super(DatabaseTestCase, self).tearDown()
def setUp(self): super(DatabaseTestCase, self).setUp() # We don't want our SQLAlchemy session thrown away post-request because that rolls # back the transaction and no database assertions can be made. self.flask_app.teardown_request_funcs = {} if engine is None: # In the future we could provide a postgres URI to test against various # databases! _configure_db() self.connection = engine.connect() Base.metadata.create_all(bind=self.connection) PSABase.metadata.create_all(bind=self.connection) self.transaction = self.connection.begin() Session.remove() Session.configure(bind=self.connection, autoflush=False) self.session = Session() # Start a transaction after creating the schema, but before anything is # placed into the database. We'll roll back to the start of this # transaction at the end of every test, and code under test will start # nested transactions self.session.begin_nested()
def test_list_packages_items_per_page_with_page(self): """Assert retrieving other pages works.""" project = models.Project(name="requests", homepage="https://pypi.io/project/requests", backend="PyPI") fedora_package = models.Packages(distro_name="Fedora", project=project, package_name="python-requests") debian_package = models.Packages(distro_name="Debian", project=project, package_name="python-requests") Session.add_all([project, fedora_package, debian_package]) Session.commit() output = self.app.get("/api/v2/packages/?items_per_page=1&page=2") self.assertEqual(output.status_code, 200) data = _read_json(output) exp = { "page": 2, "items_per_page": 1, "total_items": 2, "items": [{ "distribution": "Debian", "name": "python-requests", "project": "requests", "ecosystem": "pypi", }], } self.assertEqual(data, exp)
def test_list_packages_items_per_page_with_page(self): """Assert retrieving other pages works.""" project = models.Project( name="requests", homepage="https://pypi.io/project/requests", backend="PyPI" ) fedora_package = models.Packages( distro_name="Fedora", project=project, package_name="python-requests" ) debian_package = models.Packages( distro_name="Debian", project=project, package_name="python-requests" ) Session.add_all([project, fedora_package, debian_package]) Session.commit() output = self.app.get("/api/v2/packages/?items_per_page=1&page=2") self.assertEqual(output.status_code, 200) data = _read_json(output) exp = { "page": 2, "items_per_page": 1, "total_items": 2, "items": [ { "distribution": "Debian", "name": "python-requests", "project": "requests", "ecosystem": "pypi", } ], } self.assertEqual(data, exp)
def integrity_error_handler(error): """ Flask error handler for unhandled IntegrityErrors. Args: error (IntegrityError): The exception to be handled. Returns: tuple: A tuple of (message, HTTP error code). """ # Because social auth provides the route and raises the exception, this is # the simplest way to turn the error into a nicely formatted error message # for the user. if 'email' in error.params: Session.rollback() if 'social_auth' in error.params: msg = ( "Error: Authentication with authentication provider failed. " "Please try again later...") return msg, 500 else: other_user = models.User.query.filter_by( email=error.params['email']).one() social_auth_user = other_user.social_auth.filter_by( user_id=other_user.id).one() msg = ( "Error: There's already an account associated with your email, " "authenticate with {}.".format(social_auth_user.provider)) return msg, 400 return 'The server encountered an unexpected error', 500
def setUp(self): super(IsAdminTests, self).setUp() # Add a regular user and an admin user session = Session() self.user = models.User( email='*****@*****.**', username='******', ) user_social_auth = social_models.UserSocialAuth( user_id=self.user.id, user=self.user ) session.add(self.user) session.add(user_social_auth) self.admin = models.User(email='*****@*****.**', username='******') admin_social_auth = social_models.UserSocialAuth( user_id=self.admin.id, user=self.admin ) session.add_all([admin_social_auth, self.admin]) session.commit() mock_config = mock.patch.dict( models.anitya_config, {'ANITYA_WEB_ADMINS': [six.text_type(self.admin.id)]}) mock_config.start() self.addCleanup(mock_config.stop)
def test_session_removed_post_request(self): """Assert that the session is cleaned up after a request.""" session = Session() self.assertTrue(session is Session()) app = self.flask_app.test_client() app.get('/about', follow_redirects=False) self.assertFalse(session is Session())
def test_list_projects_with_same_name(self): """Assert two projects with the same name are sorted by the ecosystem.""" self.maxDiff = None session = Session() project1 = models.Project( name="zlib", homepage="https://hackage.haskell.org/package/zlib", backend="GitHub", ecosystem_name="https://hackage.haskell.org/package/zlib", ) project2 = models.Project( name="zlib", homepage="http://www.zlib.net/", backend="custom", regex="DEFAULT", ecosystem_name="http://www.zlib.net/", ) session.add_all([project1, project2]) session.commit() output = self.app.get("/api/v2/projects/") self.assertEqual(output.status_code, 200) data = _read_json(output) for item in data["items"]: del item["created_on"] del item["updated_on"] exp = { "page": 1, "items_per_page": 25, "total_items": 2, "items": [ { "id": 2, "backend": "custom", "homepage": "http://www.zlib.net/", "name": "zlib", "regex": "DEFAULT", "version": None, "version_url": None, "versions": [], "ecosystem": "http://www.zlib.net/", }, { "id": 1, "backend": "GitHub", "homepage": "https://hackage.haskell.org/package/zlib", "name": "zlib", "regex": None, "version": None, "version_url": None, "versions": [], "ecosystem": "https://hackage.haskell.org/package/zlib", }, ], } self.assertEqual(data, exp)
def test_filter_distribution(self): """Assert retrieving other pages works.""" project = models.Project( name='requests', homepage='https://pypi.io/project/requests', backend='PyPI', ) fedora_package = models.Packages(distro_name='Fedora', project=project, package_name='python-requests') debian_package = models.Packages(distro_name='Debian', project=project, package_name='python-requests') Session.add_all([project, fedora_package, debian_package]) Session.commit() fedora = self.app.get('/api/v2/packages/?distribution=Fedora') debian = self.app.get('/api/v2/packages/?distribution=Debian') self.assertEqual(fedora.status_code, 200) self.assertEqual(debian.status_code, 200) fedora_data = _read_json(fedora) debian_data = _read_json(debian) fedora_exp = { 'page': 1, 'items_per_page': 25, 'total_items': 1, 'items': [ { "distribution": "Fedora", "name": "python-requests", "project": "requests", "ecosystem": "pypi" }, ] } debian_exp = { 'page': 1, 'items_per_page': 25, 'total_items': 1, 'items': [ { "distribution": "Debian", "name": "python-requests", "project": "requests", "ecosystem": "pypi" }, ] } self.assertEqual(fedora_data, fedora_exp) self.assertEqual(debian_data, debian_exp)
def new_token(): """Create a new API token for the current user.""" form = anitya.forms.TokenForm() if form.validate_on_submit(): token = models.ApiToken(user=flask.g.user, description=form.description.data) Session.add(token) Session.commit() return flask.redirect(flask.url_for("anitya_ui.settings")) else: flask.abort(400)
def test_db_config(self): """Assert creating the application configures the scoped session.""" # Assert the scoped session is not bound. self.assertRaises(UnboundExecutionError, Session.get_bind) Session.remove() app.create( {"DB_URL": "sqlite://", "SOCIAL_AUTH_USER_MODEL": "anitya.db.models.User"} ) self.assertEqual("sqlite://", str(Session().get_bind().url))
def test_invalid(self): """Assert invalid ecosystems raise an exception.""" project = models.Project( name="requests", homepage="https://pypi.org/requests", backend="PyPI", ecosystem_name="invalid_ecosystem", ) Session.add(project) self.assertRaises(ValueError, Session.commit)
def test_set_automatically(self): """Assert the ecosystem gets set automatically based on the backend.""" project = models.Project( name="requests", homepage="https://pypi.org/requests", backend="PyPI" ) Session.add(project) Session.commit() project = models.Project.query.all()[0] self.assertEqual("pypi", project.ecosystem_name)
def test_invalid(self): """Assert invalid ecosystems raise an exception.""" project = models.Project( name='requests', homepage='https://pypi.org/requests', backend='PyPI', ecosystem_name='invalid_ecosystem', ) Session.add(project) self.assertRaises(ValueError, Session.commit)
def test_packages(self): """Assert packages are returned when they exist.""" project = models.Project( name='requests', homepage='https://pypi.io/project/requests', backend='PyPI', ) fedora_package = models.Packages(distro_name='Fedora', project=project, package_name='python-requests') debian_package = models.Packages(distro_name='Debian', project=project, package_name='python-requests') jcline_package = models.Packages(distro_name='jcline linux', project=project, package_name='requests') Session.add_all( [project, fedora_package, debian_package, jcline_package]) Session.commit() output = self.app.get('/api/v2/packages/') self.assertEqual(output.status_code, 200) data = _read_json(output) exp = { 'page': 1, 'items_per_page': 25, 'total_items': 3, 'items': [ { "distribution": "Fedora", "name": "python-requests", "project": "requests", "ecosystem": "pypi" }, { "distribution": "Debian", "name": "python-requests", "project": "requests", "ecosystem": "pypi" }, { "distribution": "jcline linux", "name": "requests", "project": "requests", "ecosystem": "pypi" }, ] } self.assertEqual(data, exp)
def test_db_config(self): """Assert creating the application configures the scoped session.""" # Assert the scoped session is not bound. self.assertRaises(UnboundExecutionError, Session.get_bind) Session.remove() app.create({ 'DB_URL': 'sqlite://', 'SOCIAL_AUTH_USER_MODEL': 'anitya.db.models.User', }) self.assertEqual('sqlite://', str(Session().get_bind().url))
def delete_token(token): """Delete the API token provided for current user.""" form = anitya.forms.TokenForm() if form.validate_on_submit(): t = models.ApiToken.query.filter_by(user=flask.g.user, token=token).first() if t is None: flask.abort(404) Session.delete(t) Session.commit() return flask.redirect(flask.url_for("anitya_ui.settings")) else: flask.abort(400)
def test_packages(self): """Assert packages are returned when they exist.""" project = models.Project(name="requests", homepage="https://pypi.io/project/requests", backend="PyPI") fedora_package = models.Packages(distro_name="Fedora", project=project, package_name="python-requests") debian_package = models.Packages(distro_name="Debian", project=project, package_name="python-requests") jcline_package = models.Packages(distro_name="jcline linux", project=project, package_name="requests") Session.add_all( [project, fedora_package, debian_package, jcline_package]) Session.commit() output = self.app.get("/api/v2/packages/") self.assertEqual(output.status_code, 200) data = _read_json(output) exp = { "page": 1, "items_per_page": 25, "total_items": 3, "items": [ { "distribution": "Fedora", "name": "python-requests", "project": "requests", "ecosystem": "pypi", }, { "distribution": "Debian", "name": "python-requests", "project": "requests", "ecosystem": "pypi", }, { "distribution": "jcline linux", "name": "requests", "project": "requests", "ecosystem": "pypi", }, ], } self.assertEqual(data, exp)
def edit_project_mapping(project_id, pkg_id): project = models.Project.get(Session, project_id) if not project: flask.abort(404) package = models.Packages.by_id(Session, pkg_id) if not package: flask.abort(404) # Get all available distros name distros = models.Distro.all(Session) distro_names = [] for distro in distros: distro_names.append(distro.name) form = anitya.forms.MappingForm( package_name=package.package_name, distro=package.distro_name, distros=distro_names, ) if form.validate_on_submit(): try: utilities.map_project( Session, project=project, package_name=form.package_name.data, distribution=form.distro.data, user_id=flask.g.user.username, old_package_name=package.package_name, old_distro_name=package.distro_name, ) Session.commit() flask.flash("Mapping edited") except exceptions.AnityaInvalidMappingException as err: err.link = flask.url_for("anitya_ui.project", project_id=err.project_id) flask.flash(err.message, "error") except exceptions.AnityaException as err: flask.flash(str(err), "error") return flask.redirect( flask.url_for("anitya_ui.project", project_id=project_id)) return flask.render_template("mapping.html", current="projects", project=project, package=package, form=form)
def test_filter_distribution(self): """Assert retrieving other pages works.""" project = models.Project(name="requests", homepage="https://pypi.io/project/requests", backend="PyPI") fedora_package = models.Packages(distro_name="Fedora", project=project, package_name="python-requests") debian_package = models.Packages(distro_name="Debian", project=project, package_name="python-requests") Session.add_all([project, fedora_package, debian_package]) Session.commit() fedora = self.app.get("/api/v2/packages/?distribution=Fedora") debian = self.app.get("/api/v2/packages/?distribution=Debian") self.assertEqual(fedora.status_code, 200) self.assertEqual(debian.status_code, 200) fedora_data = _read_json(fedora) debian_data = _read_json(debian) fedora_exp = { "page": 1, "items_per_page": 25, "total_items": 1, "items": [{ "distribution": "Fedora", "name": "python-requests", "project": "requests", "ecosystem": "pypi", }], } debian_exp = { "page": 1, "items_per_page": 25, "total_items": 1, "items": [{ "distribution": "Debian", "name": "python-requests", "project": "requests", "ecosystem": "pypi", }], } self.assertEqual(fedora_data, fedora_exp) self.assertEqual(debian_data, debian_exp)
def setUp(self): super(ProjectsResourceGetTests, self).setUp() self.app = self.flask_app.test_client() session = Session() self.user = models.User(email="*****@*****.**", username="******") user_social_auth = social_models.UserSocialAuth(user_id=self.user.id, user=self.user) session.add(self.user) session.add(user_social_auth) self.api_token = models.ApiToken(user=self.user) session.add(self.api_token) session.commit()
def test_set_manually(self): """Assert the ecosystem can be set manually.""" project = models.Project( name="requests", homepage="https://pypi.org/requests", ecosystem_name="crates.io", backend="PyPI", ) Session.add(project) Session.commit() project = models.Project.query.all()[0] self.assertEqual("crates.io", project.ecosystem_name)
def test_set_manually(self): """Assert the ecosystem can be set manually.""" project = models.Project( name='requests', homepage='https://pypi.org/requests', ecosystem_name='crates.io', backend='PyPI', ) Session.add(project) Session.commit() project = models.Project.query.all()[0] self.assertEqual('crates.io', project.ecosystem_name)
def test_filter_distribution(self): """Assert retrieving other pages works.""" project = models.Project( name="requests", homepage="https://pypi.io/project/requests", backend="PyPI" ) fedora_package = models.Packages( distro_name="Fedora", project=project, package_name="python-requests" ) debian_package = models.Packages( distro_name="Debian", project=project, package_name="python-requests" ) Session.add_all([project, fedora_package, debian_package]) Session.commit() fedora = self.app.get("/api/v2/packages/?distribution=Fedora") debian = self.app.get("/api/v2/packages/?distribution=Debian") self.assertEqual(fedora.status_code, 200) self.assertEqual(debian.status_code, 200) fedora_data = _read_json(fedora) debian_data = _read_json(debian) fedora_exp = { "page": 1, "items_per_page": 25, "total_items": 1, "items": [ { "distribution": "Fedora", "name": "python-requests", "project": "requests", "ecosystem": "pypi", } ], } debian_exp = { "page": 1, "items_per_page": 25, "total_items": 1, "items": [ { "distribution": "Debian", "name": "python-requests", "project": "requests", "ecosystem": "pypi", } ], } self.assertEqual(fedora_data, fedora_exp) self.assertEqual(debian_data, debian_exp)
def test_packages(self): """Assert packages are returned when they exist.""" project = models.Project( name="requests", homepage="https://pypi.io/project/requests", backend="PyPI" ) fedora_package = models.Packages( distro_name="Fedora", project=project, package_name="python-requests" ) debian_package = models.Packages( distro_name="Debian", project=project, package_name="python-requests" ) jcline_package = models.Packages( distro_name="jcline linux", project=project, package_name="requests" ) Session.add_all([project, fedora_package, debian_package, jcline_package]) Session.commit() output = self.app.get("/api/v2/packages/") self.assertEqual(output.status_code, 200) data = _read_json(output) exp = { "page": 1, "items_per_page": 25, "total_items": 3, "items": [ { "distribution": "Fedora", "name": "python-requests", "project": "requests", "ecosystem": "pypi", }, { "distribution": "Debian", "name": "python-requests", "project": "requests", "ecosystem": "pypi", }, { "distribution": "jcline linux", "name": "requests", "project": "requests", "ecosystem": "pypi", }, ], } self.assertEqual(data, exp)
def delete_project_version(project_id, version): project = models.Project.get(Session, project_id) if not project: flask.abort(404) version_obj = None for vers in project.versions_obj: if version == vers.version: version_obj = vers break if version_obj is None: flask.abort( 404, "Version %s not found for project %s" % (version, project.name)) if not is_admin(): flask.abort(401) form = anitya.forms.ConfirmationForm() confirm = flask.request.form.get("confirm", False) if form.validate_on_submit(): if confirm: utilities.log( Session, project=project.__json__(), topic="project.version.remove", message=dict(agent=flask.g.user.username, project=project.name, version=version), ) # Delete the record of the version for this project Session.delete(version_obj) # Adjust the latest_version if needed sorted_versions = project.get_sorted_version_objects() if len(sorted_versions ) > 1 and sorted_versions[0].version == version: project.latest_version = sorted_versions[1].parse() Session.add(project) elif len(sorted_versions) == 1: project.latest_version = None Session.add(project) Session.commit() flask.flash("Version for %s has been removed" % version) return flask.redirect( flask.url_for("anitya_ui.project", project_id=project.id)) return flask.render_template( "version_delete.html", current="projects", project=project, version=version, form=form, )
def setUp(self): super(RequireTokenTests, self).setUp() self.app = self.flask_app.test_client() session = Session() self.user = models.User( email='*****@*****.**', username='******', ) user_social_auth = social_models.UserSocialAuth(user_id=self.user.id, user=self.user) session.add(self.user) session.add(user_social_auth) self.api_token = ApiToken(user=self.user) session.add(self.api_token) session.commit()
def setUp(self): super(IntegrityErrorHandlerTests, self).setUp() session = Session() user = models.User(email='*****@*****.**', username='******') social_auth_user = social_models.UserSocialAuth( provider='Demo Provider', user=user) session.add(social_auth_user) session.add(user) session.commit()
def delete_project_mapping(project_id, distro_name, pkg_name): project = models.Project.get(Session, project_id) if not project: flask.abort(404) distro = models.Distro.get(Session, distro_name) if not distro: flask.abort(404) package = models.Packages.get(Session, project.id, distro.name, pkg_name) if not package: flask.abort(404) if not is_admin(): flask.abort(401) form = anitya.forms.ConfirmationForm() confirm = flask.request.form.get("confirm", False) if form.validate_on_submit(): if confirm: utilities.log( Session, project=project.__json__(), topic="project.map.remove", message=dict( agent=flask.g.user.username, project=project.name, distro=distro.name, ), ) Session.delete(package) Session.commit() flask.flash("Mapping for %s has been removed" % project.name) return flask.redirect( flask.url_for("anitya_ui.project", project_id=project.id)) return flask.render_template( "regex_delete.html", current="projects", project=project, package=package, form=form, )
def map_project(project_id): project = models.Project.get(Session, project_id) if not project: flask.abort(404) # Get all available distros name distros = models.Distro.all(Session) distro_names = [] for distro in distros: distro_names.append(distro.name) form = anitya.forms.MappingForm(distros=distro_names) if flask.request.method == 'GET': form.package_name.data = flask.request.args.get( 'package_name', project.name) form.distro.data = flask.request.args.get('distro', '') if form.validate_on_submit(): try: utilities.map_project( Session, project=project, package_name=form.package_name.data.strip(), distribution=form.distro.data.strip(), user_id=flask.g.user.username, ) Session.commit() flask.flash('Mapping added') except exceptions.AnityaInvalidMappingException as err: err.link = flask.url_for('anitya_ui.project', project_id=err.project_id) flask.flash(err.message, 'error') except exceptions.AnityaException as err: flask.flash(str(err), 'error') return flask.redirect( flask.url_for('anitya_ui.project', project_id=project.id)) return flask.render_template( 'mapping.html', current='projects', project=project, form=form, )
def setUp(self): super(PackagesResourceGetTests, self).setUp() self.app = self.flask_app.test_client() session = Session() self.user = models.User(email="*****@*****.**", username="******") user_social_auth = social_models.UserSocialAuth(user_id=self.user.id, user=self.user) session.add(self.user) session.add(user_social_auth) self.api_token = models.ApiToken(user=self.user) fedora = models.Distro("Fedora") debian = models.Distro("Debian") jcline_linux = models.Distro("jcline linux") session.add_all([self.api_token, fedora, debian, jcline_linux]) session.commit()
def delete_project_mapping(project_id, distro_name, pkg_name): project = models.Project.get(Session, project_id) if not project: flask.abort(404) distro = models.Distro.get(Session, distro_name) if not distro: flask.abort(404) package = models.Packages.get(Session, project.id, distro.name, pkg_name) if not package: flask.abort(404) if not is_admin(): flask.abort(401) form = anitya.forms.ConfirmationForm() confirm = flask.request.form.get("confirm", False) if form.validate_on_submit(): if confirm: utilities.log( Session, project=project.__json__(), topic="project.map.remove", message=dict( agent=flask.g.user.username, project=project.name, distro=distro.name, ), ) Session.delete(package) Session.commit() flask.flash("Mapping for %s has been removed" % project.name) return flask.redirect(flask.url_for("anitya_ui.project", project_id=project.id)) return flask.render_template( "regex_delete.html", current="projects", project=project, package=package, form=form, )
def test_username_unique(self): """Assert User usernames have a uniqueness constraint on them.""" session = Session() user = models.User(email='*****@*****.**', username='******') session.add(user) session.commit() user2 = models.User(email='*****@*****.**', username='******') session.add(user2) self.assertRaises(IntegrityError, session.commit)
def setUp(self): super(RequireTokenTests, self).setUp() self.app = self.flask_app.test_client() session = Session() self.user = models.User(email="*****@*****.**", username="******") user_social_auth = social_models.UserSocialAuth( user_id=self.user.id, user=self.user ) session.add(self.user) session.add(user_social_auth) self.api_token = ApiToken(user=self.user) session.add(self.api_token) session.commit()
def setUp(self): super(ProjectsResourcePostTests, self).setUp() self.app = self.flask_app.test_client() session = Session() self.user = models.User( email='*****@*****.**', username='******', ) user_social_auth = social_models.UserSocialAuth(user_id=self.user.id, user=self.user) session.add(self.user) session.add(user_social_auth) self.api_token = models.ApiToken(user=self.user) session.add(self.api_token) session.commit() self.auth = {'Authorization': 'Token ' + self.api_token.token}
def setUp(self): super(BrowseLogsTests, self).setUp() session = Session() # Add a regular user and an admin user self.user = models.User( email='*****@*****.**', username='******', ) user_social_auth = social_models.UserSocialAuth( user_id=self.user.id, user=self.user ) session.add(self.user) session.add(user_social_auth) self.admin = models.User(email='*****@*****.**', username='******') admin_social_auth = social_models.UserSocialAuth( user_id=self.admin.id, user=self.admin ) self.user_log = models.Log( user='******', project='relational_db', distro='Fedora', description='This is a log', ) self.admin_log = models.Log( user='******', project='best_project', distro='CentOS', description='This is also a log', ) session.add_all([admin_social_auth, self.admin, self.user_log, self.admin_log]) session.commit() mock_config = mock.patch.dict( models.anitya_config, {'ANITYA_WEB_ADMINS': [six.text_type(self.admin.id)]}) mock_config.start() self.addCleanup(mock_config.stop) self.client = self.flask_app.test_client()
def edit_project_mapping(project_id, pkg_id): project = models.Project.get(Session, project_id) if not project: flask.abort(404) package = models.Packages.by_id(Session, pkg_id) if not package: flask.abort(404) form = anitya.forms.MappingForm(obj=package) if form.validate_on_submit(): try: utilities.map_project( Session, project=project, package_name=form.package_name.data, distribution=form.distro.data, user_id=flask.g.user.username, old_package_name=package.package_name, old_distro_name=package.distro, ) Session.commit() flask.flash('Mapping edited') except exceptions.AnityaInvalidMappingException as err: err.link = flask.url_for('anitya_ui.project', project_id=err.project_id) flask.flash(err.message, 'error') except exceptions.AnityaException as err: flask.flash(str(err), 'error') return flask.redirect( flask.url_for('anitya_ui.project', project_id=project_id)) return flask.render_template( 'mapping.html', current='projects', project=project, package=package, form=form, )
def setUp(self): super(LoadUserFromSessionTests, self).setUp() session = Session() self.user = models.User(email="*****@*****.**", username="******") user_social_auth = social_models.UserSocialAuth(user_id=self.user.id, user=self.user) session.add(self.user) session.add(user_social_auth) session.commit()
def setUp(self): super(ProjectsResourcePostTests, self).setUp() self.app = self.flask_app.test_client() session = Session() self.user = models.User(email="*****@*****.**", username="******") user_social_auth = social_models.UserSocialAuth( user_id=self.user.id, user=self.user ) session.add(self.user) session.add(user_social_auth) self.api_token = models.ApiToken(user=self.user) session.add(self.api_token) session.commit() self.auth = {"Authorization": "Token " + self.api_token.token}
def setUp(self): super(PackagesResourceGetTests, self).setUp() self.app = self.flask_app.test_client() session = Session() self.user = models.User(email="*****@*****.**", username="******") user_social_auth = social_models.UserSocialAuth( user_id=self.user.id, user=self.user ) session.add(self.user) session.add(user_social_auth) self.api_token = models.ApiToken(user=self.user) fedora = models.Distro("Fedora") debian = models.Distro("Debian") jcline_linux = models.Distro("jcline linux") session.add_all([self.api_token, fedora, debian, jcline_linux]) session.commit()
def test_same_package_two_distros(self): """Assert packages can be created.""" Session.add(models.Distro("Debian")) Session.commit() request_data = { "project_ecosystem": "pypi", "project_name": "requests", "package_name": "python-requests", "distribution": "Fedora", } output = self.app.post( "/api/v2/packages/", headers=self.auth, data=request_data ) self.assertEqual(output.status_code, 201) request_data["distribution"] = "Debian" output = self.app.post( "/api/v2/packages/", headers=self.auth, data=request_data ) self.assertEqual(output.status_code, 201)
def setUp(self): super(LoadUserFromSessionTests, self).setUp() session = Session() self.user = models.User(email="*****@*****.**", username="******") user_social_auth = social_models.UserSocialAuth( user_id=self.user.id, user=self.user ) session.add(self.user) session.add(user_social_auth) session.commit()
def edit_distro(distro_name): distro = models.Distro.by_name(Session, distro_name) if not distro: flask.abort(404) if not is_admin(): flask.abort(401) form = anitya.forms.DistroForm(obj=distro) if form.validate_on_submit(): name = form.name.data if name != distro.name: utilities.log( Session, distro=distro.__json__(), topic="distro.edit", message=dict(agent=flask.g.user.username, old=distro.name, new=name), ) distro.name = name Session.add(distro) Session.commit() message = "Distribution edited" flask.flash(message) return flask.redirect(flask.url_for("anitya_ui.distros")) return flask.render_template( "distro_add_edit.html", context="Edit", current="distros", distro=distro, form=form, )
def setUp(self): super(PackagesResourcePostTests, self).setUp() self.app = self.flask_app.test_client() session = Session() self.user = models.User(email="*****@*****.**", username="******") user_social_auth = social_models.UserSocialAuth( user_id=self.user.id, user=self.user ) session.add(self.user) session.add(user_social_auth) self.api_token = models.ApiToken(user=self.user) self.project = models.Project( name="requests", homepage="https://pypi.io/project/requests", backend="PyPI" ) self.fedora = models.Distro("Fedora") session.add_all([self.api_token, self.project, self.fedora]) session.commit() self.auth = {"Authorization": "Token " + self.api_token.token}
def delete_project_version(project_id, version): project = models.Project.get(Session, project_id) if not project: flask.abort(404) version_obj = None for vers in project.versions_obj: if version == vers.version: version_obj = vers break if version_obj is None: flask.abort( 404, "Version %s not found for project %s" % (version, project.name) ) if not is_admin(): flask.abort(401) form = anitya.forms.ConfirmationForm() confirm = flask.request.form.get("confirm", False) if form.validate_on_submit(): if confirm: utilities.log( Session, project=project.__json__(), topic="project.version.remove", message=dict( agent=flask.g.user.username, project=project.name, version=version ), ) # Delete the record of the version for this project Session.delete(version_obj) # Adjust the latest_version if needed if project.latest_version == version: project.latest_version = None Session.add(project) Session.commit() flask.flash("Version for %s has been removed" % version) return flask.redirect(flask.url_for("anitya_ui.project", project_id=project.id)) return flask.render_template( "version_delete.html", current="projects", project=project, version=version, form=form, )
def set_user_active_state(user_id, state): if not is_admin(): flask.abort(401) if state.upper() == "TRUE": state = True elif state.upper() == "FALSE": state = False else: flask.abort(422) try: user = Session.query(models.User).filter(models.User.id == user_id).one() except Exception as err: _log.exception(err) user = None if not user: flask.abort(404) form = anitya.forms.ConfirmationForm() if form.validate_on_submit(): try: user.active = state Session.add(user) Session.commit() if state: flask.flash("User {0} is no longer banned".format(user.username)) else: flask.flash("User {0} is banned".format(user.username)) except Exception as err: _log.exception(err) flask.flash(str(err), "errors") Session.rollback() return flask.redirect(flask.url_for("anitya_ui.browse_users"))
def delete_project(project_id): project = models.Project.get(Session, project_id) if not project: flask.abort(404) if not is_admin(): flask.abort(401) project_name = project.name form = anitya.forms.ConfirmationForm() confirm = flask.request.form.get("confirm", False) if form.validate_on_submit(): if confirm: utilities.log( Session, project=project.__json__(), topic="project.remove", message=dict(agent=flask.g.user.username, project=project.name), ) for version in project.versions_obj: Session.delete(version) Session.delete(project) Session.commit() flask.flash("Project %s has been removed" % project_name) return flask.redirect(flask.url_for("anitya_ui.projects")) else: return flask.redirect( flask.url_for("anitya_ui.project", project_id=project.id) ) return flask.render_template( "project_delete.html", current="projects", project=project, form=form )
def integrity_error_handler(error): """ Flask error handler for unhandled IntegrityErrors. Args: error (IntegrityError): The exception to be handled. Returns: tuple: A tuple of (message, HTTP error code). """ # Because social auth provides the route and raises the exception, this is # the simplest way to turn the error into a nicely formatted error message # for the user. if "email" in error.params: Session.rollback() other_user = models.User.query.filter_by(email=error.params["email"]).one() try: social_auth_user = other_user.social_auth.filter_by( user_id=other_user.id ).one() msg = ( "Error: There's already an account associated with your email, " "authenticate with {}.".format(social_auth_user.provider) ) return msg, 400 # This error happens only if there is account without provider info except NoResultFound: Session.delete(other_user) Session.commit() msg = ( "Error: There was already an existing account with missing provider. " "So we removed it. " "Please try to log in again." ) return msg, 500 return "The server encountered an unexpected error", 500
def post(self): """ Create a new package associated with an existing project and distribution. **Example request**: .. sourcecode:: http POST /api/v2/packages/ HTTP/1.1 Accept: application/json Accept-Encoding: gzip, deflate Authorization: Token gAOFi2wQPzUJFIfDkscAKjbJfXELCz0r44m57Ur2 Connection: keep-alive Content-Length: 120 Content-Type: application/json Host: localhost:5000 User-Agent: HTTPie/0.9.4 { "distribution": "Fedora", "package_name": "python-requests", "project_ecosystem": "pypi", "project_name": "requests" } .. sourcecode:: http HTTP/1.0 201 CREATED Content-Length: 69 Content-Type: application/json Date: Mon, 15 Jan 2018 21:49:01 GMT Server: Werkzeug/0.14.1 Python/2.7.14 { "distribution": "Fedora", "name": "python-requests" } :reqheader Authorization: API token to use for authentication :reqjson string distribution: The name of the distribution that contains this package. :reqjson string package_name: The name of the package in the distribution repository. :reqjson string project_name: The project name in Anitya. :reqjson string project_ecosystem: The ecosystem the project is a part of. If it's not part of an ecosystem, use the homepage used in the Anitya project. :statuscode 201: When the package was successfully created. :statuscode 400: When required arguments are missing or malformed. :statuscode 401: When your access token is missing or invalid :statuscode 409: When the package already exists. """ distribution_help = _( "The name of the distribution that contains this package." ) package_name_help = _("The name of the package in the distribution repository.") project_name_help = _("The project name in Anitya.") project_ecosystem_help = _( "The ecosystem the project is a part of. If it's not part of an ecosystem," " use the homepage used in the Anitya project." ) parser = _BASE_ARG_PARSER.copy() parser.add_argument( "distribution", type=str, help=distribution_help, required=True ) parser.add_argument( "package_name", type=str, help=package_name_help, required=True ) parser.add_argument( "project_name", type=str, help=project_name_help, required=True ) parser.add_argument( "project_ecosystem", type=str, help=project_ecosystem_help, required=True ) args = parser.parse_args(strict=True) try: project = models.Project.query.filter_by( name=args.project_name, ecosystem_name=args.project_ecosystem ).one() except NoResultFound: return ( { "error": 'Project "{}" in ecosystem "{}" not found'.format( args.project_name, args.project_ecosystem ) }, 400, ) try: distro = models.Distro.query.filter_by(name=args.distribution).one() except NoResultFound: return ( {"error": 'Distribution "{}" not found'.format(args.distribution)}, 400, ) try: package = models.Packages( distro_name=distro.name, project=project, package_name=args.package_name ) Session.add(package) Session.commit() message = dict( agent=flask_login.current_user.email, project=project.name, distro=distro.name, new=package.package_name, ) utilities.log( Session, project=project.__json__(), distro=distro.__json__(), topic="project.map.new", message=message, ) return {u"distribution": distro.name, u"name": package.package_name}, 201 except IntegrityError: Session.rollback() return {"error": "package already exists in distribution"}, 409
def shutdown_session(exception=None): """ Remove the DB session at the end of each request. """ Session.remove()
def consume(self, message): """ This method is called when a message with a topic this consumer subscribes to arrives. If the project is unknown to Anitya, a new :class:`Project` is created, but only if the 'create_librariesio_projects' configuration key is set. If it's an existing project, this will call Anitya's ``check_project_release`` API to update the latest version information. This is because we are subscribed to libraries.io over HTTP and therefore have no authentication. Checking the version ourselves serves two purposes. Firstly, we connect to libraries.io over HTTP so we don't have any authentication. Secondly, we might map the libraries.io project to the wrong Anitya project, so this is a good opportunity to catch those problems. Args: message (dict): The fedmsg to process. """ librariesio_msg = message["body"]["msg"]["data"] name = librariesio_msg["name"] platform = librariesio_msg["platform"].lower() version = librariesio_msg["version"] homepage = librariesio_msg["package_manager_url"] for ecosystem in plugins.ECOSYSTEM_PLUGINS.get_plugins(): if platform == ecosystem.name or platform in ecosystem.aliases: break else: _log.debug( "Dropped librariesio update to %s for %s (%s) since it is on the " "unsupported %s platform", version, name, homepage, platform, ) return session = Session() project = models.Project.by_name_and_ecosystem(session, name, ecosystem.name) if ( project is None and platform in config.config["LIBRARIESIO_PLATFORM_WHITELIST"] ): try: project = utilities.create_project( session, name, homepage, "anitya", backend=ecosystem.default_backend, check_release=True, ) _log.info( "Discovered new project at version %s via libraries.io: %r", version, project, ) except exceptions.AnityaException as e: _log.error( "A new project was discovered via libraries.io, %r, " 'but we failed with "%s"', project, str(e), ) elif project is None: _log.info( "Discovered new project, %s, on the %s platform, but anitya is " "configured to not create the project", name, platform, ) else: _log.info( "libraries.io has found an update (version %s) for project %r", version, project, ) # This will fetch the version, emit fedmsgs, add log entries, and # commit the transaction. try: utilities.check_project_release(project, session) except exceptions.AnityaPluginException as e: _log.warning( "libraries.io found an update for %r, but we failed with %s", project, str(e), ) # Refresh the project object that was committed by either # ``create_project`` or ``check_project_release`` above project = models.Project.by_name_and_ecosystem(session, name, ecosystem.name) if project and project.latest_version != version: _log.info( "libraries.io found %r had a latest version of %s, but Anitya found %s", project, version, project.latest_version, ) Session.remove()
def post(self): """ Create a new project. **Example Request**: .. sourcecode:: http POST /api/v2/projects/ HTTP/1.1 Authorization: token hxPpKow7nnT6UTAEKMtQwl310P6GtyqV8DDbexnk Accept: application/json Accept-Encoding: gzip, deflate Connection: keep-alive Content-Length: 114 Content-Type: application/json Host: localhost:5000 User-Agent: HTTPie/0.9.4 { "backend": "custom", "homepage": "https://example.com/test", "name": "test_project", "version_prefix": "release-" } **Example Response**: .. sourcecode:: http HTTP/1.0 201 CREATED Content-Length: 276 Content-Type: application/json Date: Sun, 26 Mar 2017 15:56:30 GMT Server: Werkzeug/0.12.1 Python/2.7.13 { "backend": "PyPI", "created_on": 1490543790.0, "homepage": "http://python-requests.org", "id": 13857, "name": "requests", "regex": null, "updated_on": 1490543790.0, "version": null, "version_url": null, "versions": [] } :query string access_token: Your API access token. :reqjson string name: The project name :reqjson string homepage: The project homepage URL :reqjson string backend: The project backend (github, folder, etc.). :reqjson string version_url: The URL to fetch when determining the project version (defaults to null). :reqjson string version_prefix: The project version prefix, if any. For example, some projects prefix with "v". :reqjson string regex: The regex to use when searching the ``version_url`` page. :reqjson bool insecure: When retrieving the versions via HTTPS, do not validate the certificate (defaults to false). :reqjson bool check_release: Check the release immediately after creating the project. :statuscode 201: When the project was successfully created. :statuscode 400: When required arguments are missing or malformed. :statuscode 401: When your access token is missing or invalid, or when the server is not configured for OpenID Connect. The response will include a JSON body describing the exact problem. :statuscode 409: When the project already exists. """ name_help = _("The project name") homepage_help = _("The project homepage URL") backend_help = _("The project backend (github, folder, etc.)") version_url_help = _( "The URL to fetch when determining the project " "version (defaults to null)" ) version_prefix_help = _( "The project version prefix, if any. For " 'example, some projects prefix with "v"' ) regex_help = _("The regex to use when searching the version_url page") insecure_help = _( "When retrieving the versions via HTTPS, do not " "validate the certificate (defaults to false)" ) check_release_help = _( "Check the release immediately after creating " "the project." ) parser = _BASE_ARG_PARSER.copy() parser.add_argument("name", type=str, help=name_help, required=True) parser.add_argument("homepage", type=str, help=homepage_help, required=True) parser.add_argument("backend", type=str, help=backend_help, required=True) parser.add_argument( "version_url", type=str, help=version_url_help, default=None ) parser.add_argument( "version_prefix", type=str, help=version_prefix_help, default=None ) parser.add_argument("regex", type=str, help=regex_help, default=None) parser.add_argument("insecure", type=bool, help=insecure_help, default=False) parser.add_argument("check_release", type=bool, help=check_release_help) args = parser.parse_args(strict=True) try: project = utilities.create_project( Session, user_id=flask_login.current_user.email, **args ) Session.commit() return project.__json__(), 201 except ProjectExists as e: response = jsonify(e.to_dict()) response.status_code = 409 return response
def setUp(self): super(IntegrityErrorHandlerTests, self).setUp() session = Session() self.user = models.User(email="*****@*****.**", username="******") session.add(self.user) session.commit()
def browse_users(): if not is_admin(): flask.abort(401) user_id = flask.request.args.get("user_id", None) username = flask.request.args.get("username", None) email = flask.request.args.get("email", None) admin = flask.request.args.get("admin", None) active = flask.request.args.get("active", None) limit = flask.request.args.get("limit", 50) page = flask.request.args.get("page", 1) try: page = int(page) except ValueError: page = 1 if admin: if admin.upper() == "TRUE": admin = True elif admin.upper() == "FALSE": admin = False else: admin = None if active: if active.upper() == "TRUE": active = True elif active.upper() == "FALSE": active = False else: active = None try: limit = int(limit) except ValueError: limit = 50 flask.flash("Incorrect limit provided, using default", "errors") offset = 0 if page is not None and limit is not None and limit > 0: offset = (page - 1) * limit users = [] cnt_users = 0 try: users_query = Session.query(models.User) if user_id: users_query = users_query.filter_by(id=user_id) if username: users_query = users_query.filter_by(username=username) if email: users_query = users_query.filter_by(email=email) if admin is not None: users_query = users_query.filter_by(admin=admin) if active is not None: users_query = users_query.filter_by(active=active) if offset > 0: users_query = users_query.offset(offset) if limit > 0: users_query = users_query.limit(limit) users = users_query.all() cnt_users = users_query.count() except Exception as err: _log.exception(err) flask.flash(err, "errors") try: total_page = int(ceil(cnt_users / float(limit))) except ZeroDivisionError: total_page = 1 form = anitya.forms.ConfirmationForm() return flask.render_template( "users.html", current="users", users=users, cnt_users=cnt_users, total_page=total_page, form=form, page=page, username=username or "", email=email or "", user_id=user_id or "", admin=admin, active=active, )
def setUp(self): # Make sure each test starts with a clean session Session.remove() Session.configure(bind=None)