diff --git a/warehouse/oidc/views.py b/warehouse/oidc/views.py index fd58e2cee320..4ca3d009f00a 100644 --- a/warehouse/oidc/views.py +++ b/warehouse/oidc/views.py @@ -29,7 +29,6 @@ OIDC_ISSUER_SERVICE_NAMES, lookup_custom_issuer_type, ) -from warehouse.organizations.models import OrganizationProject from warehouse.packaging.interfaces import IProjectService from warehouse.packaging.models import ProjectFactory from warehouse.rate_limiting.interfaces import IRateLimiter @@ -218,32 +217,14 @@ def mint_token( # Try creating the new project project_service = request.find_service(IProjectService) try: - # Check if this pending publisher is for an organization - if pending_publisher.organization_id: - # For organization-owned projects, - # create without making the user an owner - new_project = project_service.create_project( - pending_publisher.project_name, - pending_publisher.added_by, - request, - creator_is_owner=False, - ratelimited=False, - ) - # Add the project to the organization - request.db.add( - OrganizationProject( - organization_id=pending_publisher.organization_id, - project_id=new_project.id, - ) - ) - else: - # For user-owned projects, create normally - new_project = project_service.create_project( - pending_publisher.project_name, - pending_publisher.added_by, - request, - ratelimited=False, - ) + new_project = project_service.create_project( + pending_publisher.project_name, + pending_publisher.added_by, + request, + creator_is_owner=pending_publisher.organization_id is None, + ratelimited=False, + organization_id=pending_publisher.organization_id, + ) except HTTPException as exc: return _invalid( errors=[{"code": "invalid-payload", "description": str(exc)}], diff --git a/warehouse/packaging/interfaces.py b/warehouse/packaging/interfaces.py index 739a3f60e835..a6fd4d21fc1e 100644 --- a/warehouse/packaging/interfaces.py +++ b/warehouse/packaging/interfaces.py @@ -9,6 +9,8 @@ from warehouse.rate_limiting.interfaces import RateLimiterException if typing.TYPE_CHECKING: + from uuid import UUID + from warehouse.packaging.models import Project @@ -76,7 +78,14 @@ def check_project_name(name): Check if a project name is valid and available for use. """ - def create_project(name, creator, request, *, creator_is_owner=True): + def create_project( + name, + creator, + request, + *, + creator_is_owner=True, + organization_id: UUID | None = None, + ): """ Creates a new project, recording a user as its creator. diff --git a/warehouse/packaging/services.py b/warehouse/packaging/services.py index 2fb97d16cb47..cd685c18dfb3 100644 --- a/warehouse/packaging/services.py +++ b/warehouse/packaging/services.py @@ -30,6 +30,7 @@ from warehouse.helpdesk.interfaces import IAdminNotificationService from warehouse.metrics import IMetricsService from warehouse.oidc.models import PendingOIDCPublisher +from warehouse.organizations.models import OrganizationProject from warehouse.packaging.interfaces import ( IDocsStorage, IFileStorage, @@ -494,7 +495,14 @@ def check_project_name(self, name: str) -> None: return None def create_project( - self, name, creator, request, *, creator_is_owner=True, ratelimited=True + self, + name, + creator, + request, + *, + creator_is_owner=True, + ratelimited=True, + organization_id=None, ): if ratelimited: self._check_ratelimits(request, creator) @@ -640,6 +648,7 @@ def create_project( # The project name is valid: create it and add it project = Project(name=name) self.db.add(project) + self.db.flush() # To get the new ID # TODO: This should be handled by some sort of database trigger or a # SQLAlchemy hook or the like instead of doing it inline in this @@ -657,8 +666,15 @@ def create_project( additional={"created_by": creator.username}, ) - # Mark the creator as the newly created project's owner, if configured. - if creator_is_owner: + if organization_id: + # If an organization ID is provided, we never set the creator to owner + self.db.add( + OrganizationProject( + organization_id=organization_id, project_id=project.id + ) + ) + elif creator_is_owner: + # Mark the creator as the newly created project's owner, if configured. self.db.add(Role(user=creator, project=project, role_name="Owner")) # TODO: This should be handled by some sort of database trigger or a # SQLAlchemy hook or the like instead of doing it inline in this