예제 #1
0
    def dispatch(
        self,
        path: str,
        method: str,
        data: dict = None,
        files: Mapping[str, BinaryIO] = None,
        json: dict = None,
        params: dict = None,
        request=None,
        tenant=True,
    ) -> Response:
        if request:
            assert not json
            assert not data
            assert not files
            data = request.data
            files = request.files
            json = None
            params = request.args

        if tenant is True:
            tenant = auth.get_current_tenant()

        if json:
            assert not data
            data = dumps(json)
            content_type = 'application/json'
        elif files:
            if not data:
                data = {}
            for key, value in request.form.items():
                data[key] = value
            for key, value in files.items():
                data[key] = value
            content_type = 'multipart/form-data'
        else:
            content_type = None

        with current_app.test_client() as client:
            response = client.open(path='/api/{}'.format(path.lstrip('/')),
                                   query_string=params,
                                   method=method,
                                   content_type=content_type,
                                   data=data,
                                   environ_overrides={
                                       'zeus.tenant': tenant,
                                   })
        if not (200 <= response.status_code < 300):
            raise ApiError(
                text=response.get_data(as_text=True),
                code=response.status_code,
            )
        if response.headers['Content-Type'] != 'application/json':
            raise ApiError(
                text='Request returned invalid content type: {}'.format(
                    response.headers['Content-Type']),
                code=response.status_code,
            )
        return response
예제 #2
0
    def get(self):
        """
        Return a list of repositories.
        """
        tenant = auth.get_current_tenant()
        if not tenant.repository_ids:
            return self.respond([])

        query = (Repository.query.filter(
            Repository.id.in_(tenant.repository_ids)).order_by(
                Repository.owner_name.asc(), Repository.name.asc()).limit(100))
        schema = RepositorySchema(many=True,
                                  context={"user": auth.get_current_user()})
        return self.paginate_with_schema(schema, query)
예제 #3
0
    def dispatch_request(self, hook_id: str, *args, **kwargs) -> Response:
        queryset = Hook.query.filter(Hook.id == hook_id)
        if self.select_resource_for_update():
            queryset = queryset.with_for_update()
        hook = queryset.first()
        if not hook:
            return self.not_found()

        tenant = auth.get_current_tenant()
        required_permission = self.permission_overrides.get(
            request.method, PERMISSION_MAP[request.method])
        if not tenant.has_permission(hook.repository_id, required_permission):
            return self.error("permission denied", 400)

        return Resource.dispatch_request(self, hook, *args, **kwargs)
예제 #4
0
    def constrained(self):
        from zeus.auth import get_current_tenant

        if not self.current_constrained:
            return self

        mzero = self._mapper_zero()
        if mzero is not None:
            tenant = get_current_tenant()
            if tenant.repository_ids:
                return self.enable_assertions(False).filter(
                    mzero.class_.id.in_(tenant.repository_ids))
            else:
                return self.enable_assertions(False).filter(
                    sqlalchemy.sql.false())
        return self
예제 #5
0
    def get(self):
        """
        Return a list of builds.
        """
        # tenants automatically restrict this query but we dont want
        # to include public repos
        tenant = auth.get_current_tenant()
        if not tenant.repository_ids:
            return self.respond([])

        query = (
            Build.query.options(
                joinedload("repository"),
                joinedload("revision"),
                subqueryload_all("revision.authors"),
                subqueryload_all("stats"),
                subqueryload_all("authors"),
            )
            .filter(Build.repository_id.in_(tenant.repository_ids))
            .order_by(Build.date_created.desc())
        )
        user = request.args.get("user")
        if user:
            if user == "me":
                user = auth.get_current_user()
            else:
                user = User.query.get(user)
            if not user:
                return self.respond([])

            query = query.filter(
                Build.authors.any(
                    Author.email.in_(
                        db.session.query(Email.email).filter(
                            Email.user_id == user.id, Email.verified == True  # NOQA
                        )
                    )
                )
            )

        repository = request.args.get("repository")
        if repository:
            repo = Repository.from_full_name(repository)
            if not repo:
                return self.respond([])
            query = query.filter(Build.repository_id == repo.id)
        return self.paginate_with_schema(builds_schema, query)
예제 #6
0
    def dispatch(
        self,
        path: str,
        method: str,
        data: dict = None,
        files: Mapping[str, BinaryIO] = None,
        json: dict = None,
        request=None,
        tenant=True,
    ) -> Response:
        if request:
            assert not json
            assert not data
            assert not files
            data = request.data
            files = request.files
            json = None

        if tenant is True:
            tenant = auth.get_current_tenant()

        if json:
            assert not data
            data = dumps(json)
        elif files:
            if not data:
                data = {}
            for key, value in files.items():
                data[key] = value

        with current_app.test_client() as client:
            response = client.open(
                path='/api/{}'.format(path.lstrip('/')),
                method=method,
                content_type=(request.content_type if request else
                              ('application/json' if json else None)),
                data=data,
                environ_overrides={
                    'zeus.tenant': tenant,
                })
        if not (200 <= response.status_code < 300):
            raise APIError.from_response(response)
        if response.headers['Content-Type'] != 'application/json':
            raise APIError('Request returned invalid content type: %s' %
                           (response.headers['Content-Type'], ))
        return response
예제 #7
0
    def constrained(self):
        from zeus.auth import get_current_tenant

        if not self.current_constrained:
            return self

        mzero = self._mapper_zero()
        if mzero is not None:
            cls = mzero.class_
            tenant = get_current_tenant()
            if tenant.repository_ids:
                return self.enable_assertions(False).filter(
                    or_(cls.id.in_(tenant.repository_ids), cls.public == True)  # NOQA
                )

            else:
                return self.enable_assertions(False).filter(cls.public == True)  # NOQA

        return self
예제 #8
0
    def get(self):
        """
        Return a list of builds.
        """
        # tenants automatically restrict this query but we dont want
        # to include public repos
        tenant = auth.get_current_tenant()
        if not tenant.repository_ids:
            return self.respond([])

        query = (Build.query.options(
            joinedload("repository"),
            joinedload("source"),
            joinedload("source").joinedload("author"),
            joinedload("source").joinedload("revision"),
            subqueryload_all("stats"),
        ).filter(Build.repository_id.in_(tenant.repository_ids)).order_by(
            Build.date_created.desc()))
        return self.paginate_with_schema(builds_schema, query)
예제 #9
0
    def get(self):
        """
        Return a list of change requests.
        """
        tenant = auth.get_current_tenant()
        if not tenant.repository_ids:
            return self.respond([])

        query = (ChangeRequest.query.options(
            joinedload("head_revision"),
            joinedload("parent_revision", innerjoin=True),
            joinedload("author"),
        ).filter(ChangeRequest.repository_id.in_(
            tenant.repository_ids)).order_by(
                ChangeRequest.date_created.desc()))
        user = request.args.get("user")
        if user:
            if user == "me":
                user = auth.get_current_user()
            else:
                user = User.query.get(user)
            if not user:
                return self.respond([])

            query = query.filter(
                ChangeRequest.author_id.in_(
                    db.session.query(Author.id).filter(
                        Author.email.in_(
                            db.session.query(Email.email).filter(
                                Email.user_id == user.id,
                                Email.verified == True  # NOQA
                            )))))
        repository = request.args.get("repository")
        if repository:
            repo = Repository.from_full_name(repository)
            if not repo:
                return self.respond([])
            query = query.filter(ChangeRequest.repository_id == repo.id)

        schema = ChangeRequestWithBuildSchema(many=True, strict=True)
        return self.paginate_with_schema(schema, query)
예제 #10
0
    def dispatch_request(self, provider, owner_name: str, repo_name: str,
                         *args, **kwargs) -> Response:
        queryset = Repository.query.filter(
            Repository.provider == RepositoryProvider(provider),
            Repository.owner_name == owner_name,
            Repository.name == repo_name,
        )
        if self.select_resource_for_update():
            queryset = queryset.with_for_update()
        repo = queryset.first()
        if not repo:
            return self.not_found()

        tenant = auth.get_current_tenant()
        required_permission = self.permission_overrides.get(
            request.method, PERMISSION_MAP[request.method])

        if not tenant.has_permission(repo.id, required_permission):
            return self.error("permission denied", 400)

        return Resource.dispatch_request(self, repo, *args, **kwargs)
예제 #11
0
    def dispatch_request(self, provider, owner_name: str, repo_name: str,
                         revision_sha: str, *args, **kwargs) -> Response:
        queryset = Revision.query.join(
            Repository, Repository.id == Revision.repository_id).filter(
                Repository.provider == RepositoryProvider(provider),
                Repository.owner_name == owner_name,
                Repository.name == repo_name,
                Revision.sha == revision_sha,
            )
        if self.select_resource_for_update():
            queryset = queryset.with_for_update()
        revision = queryset.first()
        if not revision:
            return self.not_found()

        tenant = auth.get_current_tenant()
        if not tenant.has_permission(revision.repository_id,
                                     PERMISSION_MAP[request.method]):
            return self.error("permission denied", 400)

        return Resource.dispatch_request(self, revision, *args, **kwargs)
예제 #12
0
    def dispatch(
        self,
        path: str,
        method: str,
        data: dict = None,
        files: Mapping[str, BinaryIO] = None,
        json: dict = None,
        params: dict = None,
        request=None,
        tenant=True,
        raise_errors=True,
    ) -> Response:
        if request:
            assert not json
            assert not data
            assert not files
            data = request.data
            files = request.files
            json = None
            params = request.args

        if tenant is True:
            tenant = auth.get_current_tenant()

        if json:
            assert not data
            data = dumps(json, default=json_encoder)
            content_type = "application/json"
        elif files:
            if not data:
                data = {}
            for key, value in request.form.items():
                data[key] = value
            for key, value in files.items():
                data[key] = value
            content_type = "multipart/form-data"
        else:
            content_type = None

        path = "/api/{}".format(path.lstrip("/"))

        from sentry_sdk import Hub

        hub = Hub.current
        with hub.start_span(op="api", description=f"{method} {path}"
                            ), current_app.test_client() as client:
            response = client.open(
                path=path,
                query_string=params,
                method=method,
                content_type=content_type,
                data=data,
                environ_overrides={"zeus.tenant": tenant},
            )
        if raise_errors and not (200 <= response.status_code < 300):
            raise ApiError(text=response.get_data(as_text=True),
                           code=response.status_code)

        if raise_errors and response.headers[
                "Content-Type"] != "application/json":
            raise ApiError(
                text="Request returned invalid content type: {}".format(
                    response.headers["Content-Type"]),
                code=response.status_code,
            )

        return response
예제 #13
0
 def get_constraints(self, mzero):
     from zeus import auth
     tenant = auth.get_current_tenant()
     if tenant.repository_ids:
         return mzero.class_.id.in_(tenant.repository_ids)
     return sqlalchemy.sql.false()