diff --git a/tests/common/db/packaging.py b/tests/common/db/packaging.py index cd72f6d557e0..dab5fd972dcd 100644 --- a/tests/common/db/packaging.py +++ b/tests/common/db/packaging.py @@ -12,6 +12,7 @@ import datetime import hashlib +import uuid import factory import factory.fuzzy @@ -36,6 +37,7 @@ class ProjectFactory(WarehouseFactory): class Meta: model = Project + id = factory.LazyFunction(uuid.uuid4) name = factory.fuzzy.FuzzyText(length=12) @@ -43,7 +45,7 @@ class ReleaseFactory(WarehouseFactory): class Meta: model = Release - name = factory.LazyAttribute(lambda o: o.project.name) + id = factory.LazyFunction(uuid.uuid4) project = factory.SubFactory(ProjectFactory) version = factory.Sequence(lambda n: str(n) + ".0") canonical_version = factory.LazyAttribute( @@ -58,7 +60,6 @@ class FileFactory(WarehouseFactory): class Meta: model = File - name = factory.LazyAttribute(lambda o: o.release.name) release = factory.SubFactory(ReleaseFactory) python_version = "source" md5_digest = factory.LazyAttribute( @@ -96,8 +97,7 @@ class DependencyFactory(WarehouseFactory): class Meta: model = Dependency - name = factory.fuzzy.FuzzyText(length=12) - version = factory.Sequence(lambda n: str(n) + ".0") + release = factory.SubFactory(ReleaseFactory) kind = factory.fuzzy.FuzzyChoice(int(kind) for kind in DependencyKind) specifier = factory.fuzzy.FuzzyText(length=12) diff --git a/tests/unit/admin/views/test_blacklist.py b/tests/unit/admin/views/test_blacklist.py index b96d70643d93..60d066c74f0f 100644 --- a/tests/unit/admin/views/test_blacklist.py +++ b/tests/unit/admin/views/test_blacklist.py @@ -211,9 +211,7 @@ def test_adds_blacklist_with_deletes(self, db_request): project = ProjectFactory.create(name="foo") release = ReleaseFactory.create(project=project) - FileFactory.create( - name=project.name, version=release.version, filename="who cares" - ) + FileFactory.create(release=release, filename="who cares") RoleFactory.create(project=project, user=db_request.user) views.add_blacklist(db_request) diff --git a/tests/unit/admin/views/test_projects.py b/tests/unit/admin/views/test_projects.py index d3617f685a59..5279ac8d4dce 100644 --- a/tests/unit/admin/views/test_projects.py +++ b/tests/unit/admin/views/test_projects.py @@ -567,7 +567,8 @@ def test_delete_role(self, db_request): assert db_request.session.flash.calls == [ pretend.call( - f"Removed '{role.user_name}' as '{role.role_name}' on '{project.name}'", + f"Removed '{role.user.username}' as '{role.role_name}' " + f"on '{project.name}'", queue="success", ) ] diff --git a/tests/unit/legacy/api/test_json.py b/tests/unit/legacy/api/test_json.py index 0acd678c2c0f..1dea89554f3b 100644 --- a/tests/unit/legacy/api/test_json.py +++ b/tests/unit/legacy/api/test_json.py @@ -194,8 +194,7 @@ def test_detail_renders(self, pyramid_config, db_request, db_session): for urlspec in project_urls: db_session.add( Dependency( - name=releases[3].project.name, - version="3.0", + release=releases[3], kind=DependencyKind.project_url.value, specifier=urlspec, ) @@ -460,7 +459,9 @@ def test_normalizing_redirects(self, db_request): assert isinstance(resp, HTTPMovedPermanently) assert db_request.route_path.calls == [ pretend.call( - "legacy.api.json.release", name=release.name, version=release.version + "legacy.api.json.release", + name=release.project.name, + version=release.version, ) ] assert resp.headers["Location"] == "/project/the-redirect" diff --git a/tests/unit/legacy/api/xmlrpc/test_xmlrpc.py b/tests/unit/legacy/api/xmlrpc/test_xmlrpc.py index 705890aa073d..21c3141c40be 100644 --- a/tests/unit/legacy/api/xmlrpc/test_xmlrpc.py +++ b/tests/unit/legacy/api/xmlrpc/test_xmlrpc.py @@ -785,7 +785,7 @@ def test_browse(db_request): expected_release._classifiers = classifiers assert set(xmlrpc.browse(db_request, ["Environment :: Other Environment"])) == { - (r.name, r.version) for r in releases + (r.project.name, r.version) for r in releases } assert set( xmlrpc.browse( @@ -795,7 +795,7 @@ def test_browse(db_request): "Development Status :: 5 - Production/Stable", ], ) - ) == {(expected_release.name, expected_release.version)} + ) == {(expected_release.project.name, expected_release.version)} assert set( xmlrpc.browse( db_request, @@ -805,7 +805,7 @@ def test_browse(db_request): "Programming Language :: Python", ], ) - ) == {(expected_release.name, expected_release.version)} + ) == {(expected_release.project.name, expected_release.version)} assert set( xmlrpc.browse( db_request, @@ -814,7 +814,7 @@ def test_browse(db_request): "Programming Language :: Python", ], ) - ) == {(expected_release.name, expected_release.version)} + ) == {(expected_release.project.name, expected_release.version)} def test_multicall(pyramid_request): diff --git a/tests/unit/manage/test_views.py b/tests/unit/manage/test_views.py index a3575c8ef5df..385518815a3b 100644 --- a/tests/unit/manage/test_views.py +++ b/tests/unit/manage/test_views.py @@ -22,7 +22,7 @@ from warehouse.manage import views from warehouse.accounts.interfaces import IUserService, IPasswordBreachedService -from warehouse.packaging.models import JournalEntry, Project, Role, User +from warehouse.packaging.models import JournalEntry, Project, File, Role, User from warehouse.utils.project import remove_documentation from ...common.db.accounts import EmailFactory @@ -30,6 +30,7 @@ JournalEntryFactory, ProjectFactory, ReleaseFactory, + FileFactory, RoleFactory, UserFactory, ) @@ -977,53 +978,51 @@ def test_delete_project_release_bad_confirm(self): ) ] - def test_delete_project_release_file(self, monkeypatch): - release_file = pretend.stub(filename="foo-bar.tar.gz", id=str(uuid.uuid4())) - release = pretend.stub(version="1.2.3", project=pretend.stub(name="foobar")) - request = pretend.stub( - POST={ - "confirm_project_name": release.project.name, - "file_id": release_file.id, - }, - method="POST", - db=pretend.stub( - delete=pretend.call_recorder(lambda a: None), - add=pretend.call_recorder(lambda a: None), - query=lambda a: pretend.stub( - filter=lambda *a: pretend.stub(one=lambda: release_file) - ), - ), - route_path=pretend.call_recorder(lambda *a, **kw: "/the-redirect"), - session=pretend.stub(flash=pretend.call_recorder(lambda *a, **kw: None)), - user=pretend.stub(), - remote_addr=pretend.stub(), + def test_delete_project_release_file(self, db_request): + user = UserFactory.create() + + project = ProjectFactory.create(name="foobar") + release = ReleaseFactory.create(project=project) + release_file = FileFactory.create( + release=release, filename=f"foobar-{release.version}.tar.gz" ) - journal_obj = pretend.stub() - journal_cls = pretend.call_recorder(lambda **kw: journal_obj) - monkeypatch.setattr(views, "JournalEntry", journal_cls) - view = views.ManageProjectRelease(release, request) + db_request.POST = { + "confirm_project_name": release.project.name, + "file_id": release_file.id, + } + db_request.method = ("POST",) + db_request.route_path = pretend.call_recorder(lambda *a, **kw: "/the-redirect") + db_request.session = pretend.stub( + flash=pretend.call_recorder(lambda *a, **kw: None) + ) + db_request.user = user + db_request.remote_addr = "1.2.3.4" + + view = views.ManageProjectRelease(release, db_request) result = view.delete_project_release_file() assert isinstance(result, HTTPSeeOther) assert result.headers["Location"] == "/the-redirect" - assert request.session.flash.calls == [ + assert db_request.session.flash.calls == [ pretend.call(f"Deleted file {release_file.filename!r}", queue="success") ] - assert request.db.delete.calls == [pretend.call(release_file)] - assert request.db.add.calls == [pretend.call(journal_obj)] - assert journal_cls.calls == [ - pretend.call( - name=release.project.name, - action=f"remove file {release_file.filename}", + + assert db_request.db.query(File).filter_by(id=release_file.id).first() is None + assert ( + db_request.db.query(JournalEntry) + .filter_by( + name=project.name, version=release.version, - submitted_by=request.user, - submitted_from=request.remote_addr, + action=f"remove file {release_file.filename}", + submitted_by=user, + submitted_from="1.2.3.4", ) - ] - assert request.route_path.calls == [ + .one() + ) + assert db_request.route_path.calls == [ pretend.call( "manage.project.release", project_name=release.project.name, @@ -1059,36 +1058,38 @@ def test_delete_project_release_file_no_confirm(self): ) ] - def test_delete_project_release_file_not_found(self): - release = pretend.stub(version="1.2.3", project=pretend.stub(name="foobar")) + def test_delete_project_release_file_not_found(self, db_request): + project = ProjectFactory.create(name="foobar") + release = ReleaseFactory.create(project=project) def no_result_found(): raise NoResultFound - request = pretend.stub( - POST={"confirm_project_name": "whatever"}, - method="POST", - db=pretend.stub( - delete=pretend.call_recorder(lambda a: None), - query=lambda a: pretend.stub( - filter=lambda *a: pretend.stub(one=no_result_found) - ), + db_request.POST = {"confirm_project_name": "whatever"} + db_request.method = "POST" + db_request.db = pretend.stub( + delete=pretend.call_recorder(lambda a: None), + query=lambda a: pretend.stub( + filter=lambda *a: pretend.stub(one=no_result_found) ), - route_path=pretend.call_recorder(lambda *a, **kw: "/the-redirect"), - session=pretend.stub(flash=pretend.call_recorder(lambda *a, **kw: None)), ) - view = views.ManageProjectRelease(release, request) + db_request.route_path = pretend.call_recorder(lambda *a, **kw: "/the-redirect") + db_request.session = pretend.stub( + flash=pretend.call_recorder(lambda *a, **kw: None) + ) + + view = views.ManageProjectRelease(release, db_request) result = view.delete_project_release_file() assert isinstance(result, HTTPSeeOther) assert result.headers["Location"] == "/the-redirect" - assert request.db.delete.calls == [] - assert request.session.flash.calls == [ + assert db_request.db.delete.calls == [] + assert db_request.session.flash.calls == [ pretend.call("Could not find file", queue="error") ] - assert request.route_path.calls == [ + assert db_request.route_path.calls == [ pretend.call( "manage.project.release", project_name=release.project.name, @@ -1096,37 +1097,38 @@ def no_result_found(): ) ] - def test_delete_project_release_file_bad_confirm(self): - release_file = pretend.stub(filename="foo-bar.tar.gz", id=str(uuid.uuid4())) - release = pretend.stub(version="1.2.3", project=pretend.stub(name="foobar")) - request = pretend.stub( - POST={"confirm_project_name": "invalid"}, - method="POST", - db=pretend.stub( - delete=pretend.call_recorder(lambda a: None), - query=lambda a: pretend.stub( - filter=lambda *a: pretend.stub(one=lambda: release_file) - ), - ), - route_path=pretend.call_recorder(lambda *a, **kw: "/the-redirect"), - session=pretend.stub(flash=pretend.call_recorder(lambda *a, **kw: None)), + def test_delete_project_release_file_bad_confirm(self, db_request): + project = ProjectFactory.create(name="foobar") + release = ReleaseFactory.create(project=project, version="1.2.3") + release_file = FileFactory.create( + release=release, filename="foobar-1.2.3.tar.gz" ) - view = views.ManageProjectRelease(release, request) + + db_request.POST = { + "confirm_project_name": "invalid", + "file_id": str(release_file.id), + } + db_request.method = "POST" + db_request.route_path = pretend.call_recorder(lambda *a, **kw: "/the-redirect") + db_request.session = pretend.stub( + flash=pretend.call_recorder(lambda *a, **kw: None) + ) + + view = views.ManageProjectRelease(release, db_request) result = view.delete_project_release_file() assert isinstance(result, HTTPSeeOther) assert result.headers["Location"] == "/the-redirect" - - assert request.db.delete.calls == [] - assert request.session.flash.calls == [ + assert db_request.db.query(File).filter_by(id=release_file.id).one() + assert db_request.session.flash.calls == [ pretend.call( "Could not delete file - " + f"'invalid' is not the same as {release.project.name!r}", queue="error", ) ] - assert request.route_path.calls == [ + assert db_request.route_path.calls == [ pretend.call( "manage.project.release", project_name=release.project.name, diff --git a/tests/unit/packaging/test_models.py b/tests/unit/packaging/test_models.py index c3a275fac6a5..601169f57056 100644 --- a/tests/unit/packaging/test_models.py +++ b/tests/unit/packaging/test_models.py @@ -260,8 +260,7 @@ def test_urls(self, db_session, home_page, download_url, project_urls, expected) for urlspec in project_urls: db_session.add( Dependency( - name=release.project.name, - version=release.version, + release=release, kind=DependencyKind.project_url.value, specifier=urlspec, ) diff --git a/tests/unit/search/test_tasks.py b/tests/unit/search/test_tasks.py index 6cc76a4ee5d6..b89365799dc5 100644 --- a/tests/unit/search/test_tasks.py +++ b/tests/unit/search/test_tasks.py @@ -57,7 +57,7 @@ def test_project_docs(db_session): "latest_version": first(prs, key=lambda r: not r.is_prerelease).version, }, } - for p, prs in sorted(releases.items(), key=lambda x: x[0].name.lower()) + for p, prs in sorted(releases.items(), key=lambda x: x[0].id) ] diff --git a/tests/unit/utils/test_project.py b/tests/unit/utils/test_project.py index 354dc4dd6737..b81872964597 100644 --- a/tests/unit/utils/test_project.py +++ b/tests/unit/utils/test_project.py @@ -95,9 +95,9 @@ def test_remove_project(db_request, flash): user = UserFactory.create() project = ProjectFactory.create(name="foo") release = ReleaseFactory.create(project=project) - FileFactory.create(name=project.name, version=release.version, filename="who cares") + FileFactory.create(release=release, filename="who cares") RoleFactory.create(user=user, project=project) - DependencyFactory.create(name=project.name, version=release.version) + DependencyFactory.create(release=release) db_request.user = user db_request.remote_addr = "192.168.1.1" @@ -113,13 +113,20 @@ def test_remove_project(db_request, flash): assert db_request.session.flash.calls == [] assert not (db_request.db.query(Role).filter(Role.project == project).count()) - assert not (db_request.db.query(File).filter(File.name == project.name).count()) assert not ( - db_request.db.query(Dependency).filter(Dependency.name == project.name).count() + db_request.db.query(File) + .join(Release) + .join(Project) + .filter(Release.project == project) + .count() ) assert not ( - db_request.db.query(Release).filter(Release.name == project.name).count() + db_request.db.query(Dependency) + .join(Release) + .filter(Release.project == project) + .count() ) + assert not (db_request.db.query(Release).filter(Release.project == project).count()) assert not ( db_request.db.query(Project).filter(Project.name == project.name).count() ) diff --git a/warehouse/accounts/models.py b/warehouse/accounts/models.py index 8fb2badf9719..5d27caf80207 100644 --- a/warehouse/accounts/models.py +++ b/warehouse/accounts/models.py @@ -53,12 +53,12 @@ class DisableReason(enum.Enum): class User(SitemapMixin, db.Model): - __tablename__ = "accounts_user" + __tablename__ = "users" __table_args__ = ( - CheckConstraint("length(username) <= 50", name="packages_valid_name"), + CheckConstraint("length(username) <= 50", name="users_valid_username_length"), CheckConstraint( "username ~* '^([A-Z0-9]|[A-Z0-9][A-Z0-9._-]*[A-Z0-9])$'", - name="accounts_user_valid_username", + name="users_valid_username", ), ) @@ -110,16 +110,16 @@ class UnverifyReasons(enum.Enum): class Email(db.ModelBase): - __tablename__ = "accounts_email" + __tablename__ = "user_emails" __table_args__ = ( - UniqueConstraint("email", name="accounts_email_email_key"), - Index("accounts_email_user_id", "user_id"), + UniqueConstraint("email", name="user_emails_email_key"), + Index("user_emails_user_id", "user_id"), ) id = Column(Integer, primary_key=True, nullable=False) user_id = Column( UUID(as_uuid=True), - ForeignKey("accounts_user.id", deferrable=True, initially="DEFERRED"), + ForeignKey("users.id", deferrable=True, initially="DEFERRED"), nullable=False, ) email = Column(String(length=254), nullable=False) diff --git a/warehouse/admin/flags.py b/warehouse/admin/flags.py index ae74b79bce51..7b01a5159c06 100644 --- a/warehouse/admin/flags.py +++ b/warehouse/admin/flags.py @@ -17,7 +17,7 @@ class AdminFlag(db.ModelBase): - __tablename__ = "warehouse_admin_flag" + __tablename__ = "admin_flags" id = Column(Text, primary_key=True, nullable=False) description = Column(Text, nullable=False) diff --git a/warehouse/admin/squats.py b/warehouse/admin/squats.py index 6df274a5d32f..ccb1d68562f4 100644 --- a/warehouse/admin/squats.py +++ b/warehouse/admin/squats.py @@ -10,7 +10,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -from sqlalchemy import Boolean, Column, DateTime, ForeignKey, Integer, Text +from sqlalchemy import Boolean, Column, DateTime, ForeignKey, Integer from sqlalchemy import orm, sql from warehouse import db @@ -18,18 +18,20 @@ class Squat(db.ModelBase): - __tablename__ = "warehouse_admin_squat" + __tablename__ = "admin_squats" id = Column(Integer, primary_key=True, nullable=False) created = Column( DateTime(timezone=False), nullable=False, server_default=sql.func.now() ) - squatter_name = Column( - Text, ForeignKey("packages.name", onupdate="CASCADE", ondelete="CASCADE") + squatter_id = Column( + ForeignKey("projects.id", onupdate="CASCADE", ondelete="CASCADE"), + nullable=False, ) - squattee_name = Column( - Text, ForeignKey("packages.name", onupdate="CASCADE", ondelete="CASCADE") + squattee_id = Column( + ForeignKey("projects.id", onupdate="CASCADE", ondelete="CASCADE"), + nullable=False, ) - squatter = orm.relationship("Project", foreign_keys=[squatter_name], lazy=False) - squattee = orm.relationship("Project", foreign_keys=[squattee_name], lazy=False) + squatter = orm.relationship("Project", foreign_keys=[squatter_id], lazy=False) + squattee = orm.relationship("Project", foreign_keys=[squattee_id], lazy=False) reviewed = Column(Boolean, nullable=False, server_default=sql.false()) diff --git a/warehouse/admin/templates/admin/projects/detail.html b/warehouse/admin/templates/admin/projects/detail.html index cb765714b6aa..387c24c61b00 100644 --- a/warehouse/admin/templates/admin/projects/detail.html +++ b/warehouse/admin/templates/admin/projects/detail.html @@ -86,7 +86,7 @@

Maintainers: