Exemple #1
0
class Role(db.Model):

    __tablename__ = "roles"
    __table_args__ = (
        Index("roles_user_id_idx", "user_id"),
        Index("roles_project_id_idx", "project_id"),
        UniqueConstraint("user_id",
                         "project_id",
                         name="_roles_user_project_uc"),
    )

    __repr__ = make_repr("role_name")

    role_name = Column(Text, nullable=False)
    user_id = Column(ForeignKey("users.id",
                                onupdate="CASCADE",
                                ondelete="CASCADE"),
                     nullable=False)
    project_id = Column(
        ForeignKey("projects.id", onupdate="CASCADE", ondelete="CASCADE"),
        nullable=False,
    )

    user = orm.relationship(User, lazy=False)
    project = orm.relationship("Project", lazy=False)
Exemple #2
0
 def __repr__(self):
     inst = inspect(self)
     self.__repr__ = make_repr(
         *[c_attr.key for c_attr in inst.mapper.column_attrs],
         _self=self,
     )
     return self.__repr__()
Exemple #3
0
class RoleInvitation(db.Model):

    __tablename__ = "role_invitations"
    __table_args__ = (
        Index("role_invitations_user_id_idx", "user_id"),
        UniqueConstraint("user_id",
                         "project_id",
                         name="_role_invitations_user_project_uc"),
    )

    __repr__ = make_repr("invite_status", "user", "project")

    invite_status = Column(
        Enum(RoleInvitationStatus,
             values_callable=lambda x: [e.value for e in x]),
        nullable=False,
    )
    token = Column(Text, nullable=False)
    user_id = Column(ForeignKey("users.id",
                                onupdate="CASCADE",
                                ondelete="CASCADE"),
                     nullable=False)
    project_id = Column(
        ForeignKey("projects.id", onupdate="CASCADE", ondelete="CASCADE"),
        nullable=False,
    )

    user = orm.relationship(User, lazy=False)
    project = orm.relationship("Project", lazy=False)
Exemple #4
0
class OrganizationInvitation(db.Model):

    __tablename__ = "organization_invitations"
    __table_args__ = (
        Index("organization_invitations_user_id_idx", "user_id"),
        UniqueConstraint(
            "user_id",
            "organization_id",
            name="_organization_invitations_user_organization_uc",
        ),
    )

    __repr__ = make_repr("invite_status", "user", "organization")

    invite_status = Column(
        Enum(OrganizationInvitationStatus,
             values_callable=lambda x: [e.value for e in x]),
        nullable=False,
    )
    token = Column(Text, nullable=False)
    user_id = Column(
        ForeignKey("users.id", onupdate="CASCADE", ondelete="CASCADE"),
        nullable=False,
        index=True,
    )
    organization_id = Column(
        ForeignKey("organizations.id", onupdate="CASCADE", ondelete="CASCADE"),
        nullable=False,
        index=True,
    )

    user = orm.relationship(User, lazy=False)
    organization = orm.relationship("Organization", lazy=False)
Exemple #5
0
class User(SitemapMixin, db.Model):

    __tablename__ = "users"
    __table_args__ = (
        CheckConstraint("length(username) <= 50", name="users_valid_username_length"),
        CheckConstraint(
            "username ~* '^([A-Z0-9]|[A-Z0-9][A-Z0-9._-]*[A-Z0-9])$'",
            name="users_valid_username",
        ),
    )

    __repr__ = make_repr("username")

    username = Column(CIText, nullable=False, unique=True)
    name = Column(String(length=100), nullable=False)
    password = Column(String(length=128), nullable=False)
    password_date = Column(DateTime, nullable=True, server_default=sql.func.now())
    is_active = Column(Boolean, nullable=False, server_default=sql.false())
    is_superuser = Column(Boolean, nullable=False, server_default=sql.false())
    is_moderator = Column(Boolean, nullable=False, server_default=sql.false())
    date_joined = Column(DateTime, server_default=sql.func.now())
    last_login = Column(DateTime, nullable=False, server_default=sql.func.now())
    disabled_for = Column(
        Enum(DisableReason, values_callable=lambda x: [e.value for e in x]),
        nullable=True,
    )
    totp_secret = Column(Binary(length=20), nullable=True)

    emails = orm.relationship(
        "Email", backref="user", cascade="all, delete-orphan", lazy=False
    )

    @property
    def primary_email(self):
        primaries = [x for x in self.emails if x.primary]
        if primaries:
            return primaries[0]

    @hybrid_property
    def email(self):
        primary_email = self.primary_email
        return primary_email.email if primary_email else None

    @email.expression
    def email(self):
        return (
            select([Email.email])
            .where((Email.user_id == self.id) & (Email.primary.is_(True)))
            .as_scalar()
        )

    @property
    def has_two_factor(self):
        # TODO: This is where user.u2f_provisioned et al.
        # will also go.
        return self.totp_secret is not None

    @property
    def two_factor_provisioning_allowed(self):
        return self.primary_email is not None and self.primary_email.verified
Exemple #6
0
class OrganizationRole(db.Model):

    __tablename__ = "organization_roles"
    __table_args__ = (
        Index("organization_roles_user_id_idx", "user_id"),
        Index("organization_roles_organization_id_idx", "organization_id"),
        UniqueConstraint(
            "user_id",
            "organization_id",
            name="_organization_roles_user_organization_uc",
        ),
    )

    __repr__ = make_repr("role_name")

    role_name = Column(
        Enum(OrganizationRoleType,
             values_callable=lambda x: [e.value for e in x]),
        nullable=False,
    )
    user_id = Column(ForeignKey("users.id",
                                onupdate="CASCADE",
                                ondelete="CASCADE"),
                     nullable=False)
    organization_id = Column(
        ForeignKey("organizations.id", onupdate="CASCADE", ondelete="CASCADE"),
        nullable=False,
    )

    user = orm.relationship(User, lazy=False)
    organization = orm.relationship("Organization", lazy=False)
Exemple #7
0
 def __repr__(self):
     inst = inspect(self)
     self.__repr__ = make_repr(
         *[c_attr.key for c_attr in inst.mapper.column_attrs],
         _self=self,
     )
     return self.__repr__()
Exemple #8
0
class OrganizationProject(db.Model):

    __tablename__ = "organization_project"
    __table_args__ = (
        Index("organization_project_organization_id_idx", "organization_id"),
        Index("organization_project_project_id_idx", "project_id"),
        UniqueConstraint(
            "organization_id",
            "project_id",
            name="_organization_project_organization_project_uc",
        ),
    )

    __repr__ = make_repr("project_id", "organization_id", "is_active")

    is_active = Column(Boolean, nullable=False, server_default=sql.false())
    organization_id = Column(
        ForeignKey("organizations.id", onupdate="CASCADE", ondelete="CASCADE"),
        nullable=False,
    )
    project_id = Column(
        ForeignKey("projects.id", onupdate="CASCADE", ondelete="CASCADE"),
        nullable=False,
    )

    organization = orm.relationship("Organization", lazy=False)
    project = orm.relationship("Project", lazy=False)
Exemple #9
0
class BlacklistedProject(db.Model):

    __tablename__ = "blacklist"
    __table_args__ = (
        CheckConstraint(
            "name ~* '^([A-Z0-9]|[A-Z0-9][A-Z0-9._-]*[A-Z0-9])$'::text",
            name="blacklist_valid_name",
        ),
    )

    __repr__ = make_repr("name")

    created = Column(
        DateTime(timezone=False),
        nullable=False,
        server_default=sql.func.now(),
    )
    name = Column(Text, unique=True, nullable=False)
    _blacklisted_by = Column(
        "blacklisted_by",
        UUID(as_uuid=True),
        ForeignKey("accounts_user.id"),
    )
    blacklisted_by = orm.relationship(User)
    comment = Column(Text, nullable=False, server_default="")
Exemple #10
0
class Role(db.Model):

    __tablename__ = "roles"
    __table_args__ = (
        Index("roles_pack_name_idx", "package_name"),
        Index("roles_user_name_idx", "user_name"),
    )

    __repr__ = make_repr("role_name", "user_name", "package_name")

    role_name = Column(Text)
    user_name = Column(
        CIText,
        ForeignKey("accounts_user.username", onupdate="CASCADE", ondelete="CASCADE"),
    )
    package_name = Column(
        Text, ForeignKey("packages.name", onupdate="CASCADE", ondelete="CASCADE")
    )

    user = orm.relationship(User, lazy=False)
    project = orm.relationship("Project", lazy=False)

    def __gt__(self, other):
        """
        Temporary hack to allow us to only display the 'highest' role when
        there are multiple for a given user

        TODO: This should be removed when fixing GH-2745.
        """
        order = ["Maintainer", "Owner"]  # from lowest to highest
        return order.index(self.role_name) > order.index(other.role_name)
Exemple #11
0
class User(SitemapMixin, db.Model):

    __tablename__ = "accounts_user"
    __table_args__ = (
        CheckConstraint("length(username) <= 50", name="packages_valid_name"),
        CheckConstraint(
            "username ~* '^([A-Z0-9]|[A-Z0-9][A-Z0-9._-]*[A-Z0-9])$'",
            name="accounts_user_valid_username",
        ),
    )

    __repr__ = make_repr("username")

    username = Column(CIText, nullable=False, unique=True)
    name = Column(String(length=100), nullable=False)
    password = Column(String(length=128), nullable=False)
    password_date = Column(
        DateTime,
        nullable=True,
        server_default=sql.func.now(),
    )
    is_active = Column(Boolean, nullable=False)
    is_staff = Column(Boolean, nullable=False)
    is_superuser = Column(Boolean, nullable=False)
    date_joined = Column(DateTime, server_default=sql.func.now())
    last_login = Column(
        DateTime,
        nullable=False,
        server_default=sql.func.now(),
    )

    emails = orm.relationship(
        "Email",
        backref="user",
        cascade="all, delete-orphan",
        lazy=False,
    )

    @property
    def primary_email(self):
        primaries = [x for x in self.emails if x.primary]
        if primaries:
            return primaries[0]

    @hybrid_property
    def email(self):
        primary_email = self.primary_email
        return primary_email.email if primary_email else None

    @email.expression
    def email(self):
        return (select([Email.email
                        ]).where((Email.user_id == self.id)
                                 & (Email.primary.is_(True))).as_scalar())
Exemple #12
0
class Classifier(db.ModelBase):

    __tablename__ = "trove_classifiers"
    __tableargs__ = CheckConstraint(
        "classifier not ilike 'private ::%'",
        name="ck_disallow_private_top_level_classifier",
    )

    __repr__ = make_repr("classifier")

    id = Column(Integer, primary_key=True, nullable=False)
    classifier = Column(Text, unique=True)
Exemple #13
0
class Classifier(db.ModelBase):

    __tablename__ = "trove_classifiers"

    __repr__ = make_repr("classifier")

    id = Column(Integer, primary_key=True, nullable=False)
    classifier = Column(Text, unique=True)
    deprecated = Column(Boolean, nullable=False, server_default=sql.false())
    l2 = Column(Integer)
    l3 = Column(Integer)
    l4 = Column(Integer)
    l5 = Column(Integer)
class Dependency(db.Model):

    __tablename__ = "release_dependencies"
    __table_args__ = (Index("release_dependencies_release_kind_idx",
                            "release_id", "kind"), )
    __repr__ = make_repr("name", "version", "kind", "specifier")

    release_id = Column(
        ForeignKey("releases.id", onupdate="CASCADE", ondelete="CASCADE"),
        nullable=False,
    )
    kind = Column(Integer)
    specifier = Column(Text)
Exemple #15
0
class Project(db.ModelBase):

    __tablename__ = "packages"
    __table_args__ = (CheckConstraint(
        "name ~* '^([A-Z0-9]|[A-Z0-9][A-Z0-9._-]*[A-Z0-9])$'::text",
        name="packages_valid_name",
    ), )

    __repr__ = make_repr("name")

    name = Column(Text, primary_key=True, nullable=False)
    normalized_name = orm.column_property(func.normalize_pep426_name(name))
    stable_version = Column(Text)
    autohide = Column(Boolean, server_default=sql.true())
    comments = Column(Boolean, server_default=sql.true())
    bugtrack_url = Column(Text)
    hosting_mode = Column(Text, nullable=False, server_default="pypi-explicit")
    created = Column(
        DateTime(timezone=False),
        nullable=False,
        server_default=sql.func.now(),
    )

    releases = orm.relationship(
        "Release",
        backref="project",
        cascade="all, delete-orphan",
        lazy="dynamic",
    )

    def __getitem__(self, version):
        try:
            return self.releases.filter(Release.version == version).one()
        except NoResultFound:
            raise KeyError from None

    @property
    def documentation_url(self):
        # TODO: Move this into the database and elimnate the use of the
        #       threadlocal here.
        registry = get_current_registry()
        request = get_current_request()

        path = "/".join([self.name, "index.html"])

        # If the path doesn't exist, then we'll just return a None here.
        if not registry["filesystems"]["documentation"].exists(path):
            return

        return request.route_url("legacy.docs", project=self.name)
Exemple #16
0
class Classifier(db.ModelBase):

    __tablename__ = "trove_classifiers"
    __table_args__ = (
        Index("trove_class_class_idx", "classifier"),
        Index("trove_class_id_idx", "id"),
    )

    __repr__ = make_repr("classifier")

    id = Column(Integer, primary_key=True, nullable=False)
    classifier = Column(Text, unique=True)
    l2 = Column(Integer)
    l3 = Column(Integer)
    l4 = Column(Integer)
    l5 = Column(Integer)
Exemple #17
0
class Classifier(db.ModelBase):

    __tablename__ = "trove_classifiers"
    __tableargs__ = CheckConstraint(
        "classifier not ilike 'private ::%'",
        name="ck_disallow_private_top_level_classifier",
    )

    __repr__ = make_repr("classifier")

    id = Column(Integer, primary_key=True, nullable=False)
    classifier = Column(Text, unique=True)
    deprecated = Column(Boolean, nullable=False, server_default=sql.false())
    l2 = Column(Integer)
    l3 = Column(Integer)
    l4 = Column(Integer)
    l5 = Column(Integer)
Exemple #18
0
class Sponsor(db.Model):
    __tablename__ = "sponsors"
    __repr__ = make_repr("name")

    name = Column(String, nullable=False)
    service = Column(String)
    activity_markdown = Column(Text)

    link_url = Column(URLType, nullable=False)
    color_logo_url = Column(URLType, nullable=False)
    white_logo_url = Column(URLType)

    # control flags
    is_active = Column(Boolean, default=False, nullable=False)
    footer = Column(Boolean, default=False, nullable=False)
    psf_sponsor = Column(Boolean, default=False, nullable=False)
    infra_sponsor = Column(Boolean, default=False, nullable=False)
    one_time = Column(Boolean, default=False, nullable=False)
    sidebar = Column(Boolean, default=False, nullable=False)

    # pythondotorg integration
    origin = Column(String, default="manual")
    level_name = Column(String)
    level_order = Column(Integer, default=0)
    slug = Column(String)

    @property
    def color_logo_img(self):
        return f'<img src="{ self.color_logo_url }" alt="{ self.name }">'

    @property
    def white_logo_img(self):
        if not self.white_logo_url:
            return ""
        return f'<img class="sponsors__image" \
                  src="{ self.white_logo_url }" alt="{ self.name }">'

    @property
    def activity(self):
        """
        Render raw activity markdown as HTML
        """
        if not self.activity_markdown:
            return ""
        return readme.render(self.activity_markdown, "text/markdown")
Exemple #19
0
class Dependency(db.Model):

    __tablename__ = "release_dependencies"
    __table_args__ = (
        Index("rel_dep_name_version_kind_idx", "name", "version", "kind"),
        ForeignKeyConstraint(
            ["name", "version"],
            ["releases.name", "releases.version"],
            onupdate="CASCADE",
            ondelete="CASCADE",
        ),
    )
    __repr__ = make_repr("name", "version", "kind", "specifier")

    name = Column(Text)
    version = Column(Text)
    kind = Column(Integer)
    specifier = Column(Text)
Exemple #20
0
class OrganizationNameCatalog(db.Model):

    __tablename__ = "organization_name_catalog"
    __table_args__ = (
        Index("organization_name_catalog_normalized_name_idx",
              "normalized_name"),
        Index("organization_name_catalog_organization_id_idx",
              "organization_id"),
        UniqueConstraint(
            "normalized_name",
            "organization_id",
            name="_organization_name_catalog_normalized_name_organization_uc",
        ),
    )

    __repr__ = make_repr("normalized_name", "organization_id")

    normalized_name = Column(Text, nullable=False, index=True)
    organization_id = Column(UUID(as_uuid=True), nullable=True, index=True)
Exemple #21
0
class ProhibitedProjectName(db.Model):

    __tablename__ = "prohibited_project_names"
    __table_args__ = (CheckConstraint(
        "name ~* '^([A-Z0-9]|[A-Z0-9][A-Z0-9._-]*[A-Z0-9])$'::text",
        name="prohibited_project_valid_name",
    ), )

    __repr__ = make_repr("name")

    created = Column(DateTime(timezone=False),
                     nullable=False,
                     server_default=sql.func.now())
    name = Column(Text, unique=True, nullable=False)
    _prohibited_by = Column("prohibited_by",
                            UUID(as_uuid=True),
                            ForeignKey("users.id"),
                            index=True)
    prohibited_by = orm.relationship(User)
    comment = Column(Text, nullable=False, server_default="")
Exemple #22
0
class Role(db.Model):

    __tablename__ = "roles"
    __table_args__ = (
        Index("roles_pack_name_idx", "package_name"),
        Index("roles_user_name_idx", "user_name"),
    )

    __repr__ = make_repr("role_name", "user_name", "package_name")

    role_name = Column(Text)
    user_name = Column(
        CIText,
        ForeignKey("accounts_user.username", onupdate="CASCADE"),
    )
    package_name = Column(
        Text,
        ForeignKey("packages.name", onupdate="CASCADE"),
    )

    user = orm.relationship(User, lazy=False)
    project = orm.relationship("Project", lazy=False)
Exemple #23
0
class MalwareCheck(db.Model):

    __tablename__ = "malware_checks"
    __table_args__ = (UniqueConstraint("name", "version"), )
    __repr__ = make_repr("name", "version")

    name = Column(CIText, nullable=False)
    version = Column(Integer, default=1, nullable=False)
    short_description = Column(String(length=128), nullable=False)
    long_description = Column(Text, nullable=False)
    check_type = Column(
        Enum(MalwareCheckType, values_callable=lambda x: [e.value for e in x]),
        nullable=False,
    )
    # The object name that hooked-based checks operate on, e.g.
    # Project, File, Release
    hooked_object = Column(
        Enum(MalwareCheckObjectType,
             values_callable=lambda x: [e.value for e in x]),
        nullable=True,
    )
    # The run schedule for schedule-based checks.
    schedule = Column(JSONB, nullable=True)
    state = Column(
        Enum(MalwareCheckState,
             values_callable=lambda x: [e.value for e in x]),
        nullable=False,
        server_default=("disabled"),
    )
    created = Column(DateTime, nullable=False, server_default=sql.func.now())

    @property
    def is_stale(self):
        session = orm.object_session(self)
        newest = (session.query(MalwareCheck).filter(
            MalwareCheck.name == self.name).order_by(
                MalwareCheck.version.desc()).first())
        return self.version != newest.version
Exemple #24
0
class Banner(db.Model):
    __tablename__ = "banners"
    __repr__ = make_repr("text")
    DEFAULT_FA_ICON = "fa-comment-alt"
    DEFAULT_BTN_LABEL = "See more"

    # internal name
    name = Column(String, nullable=False)

    # banner display configuration
    text = Column(Text, nullable=False)
    link_url = Column(URLType, nullable=False)
    link_label = Column(String, nullable=False, default=DEFAULT_BTN_LABEL)
    fa_icon = Column(String, nullable=False, default=DEFAULT_FA_ICON)

    # visibility control
    active = Column(Boolean, nullable=False, default=False)
    end = Column(Date, nullable=False)

    @property
    def is_live(self):
        # date.today is using the server timezone which is UTC
        return self.active and date.today() <= self.end
Exemple #25
0
 def __repr__(self):
     self.__repr__ = make_repr(*self.__table__.columns.keys(), _self=self)
     return self.__repr__()
class Project(SitemapMixin, db.Model):

    __tablename__ = "projects"
    __table_args__ = (CheckConstraint(
        "name ~* '^([A-Z0-9]|[A-Z0-9][A-Z0-9._-]*[A-Z0-9])$'::text",
        name="projects_valid_name",
    ), )

    __repr__ = make_repr("name")

    name = Column(Text, nullable=False)
    normalized_name = orm.column_property(func.normalize_pep426_name(name))
    created = Column(
        DateTime(timezone=False),
        nullable=False,
        server_default=sql.func.now(),
        index=True,
    )
    has_docs = Column(Boolean)
    upload_limit = Column(Integer, nullable=True)
    last_serial = Column(Integer, nullable=False, server_default=sql.text("0"))
    zscore = Column(Float, nullable=True)

    total_size = Column(BigInteger, server_default=sql.text("0"))

    users = orm.relationship(User,
                             secondary=Role.__table__,
                             backref="projects")

    releases = orm.relationship(
        "Release",
        backref="project",
        cascade="all, delete-orphan",
        order_by=lambda: Release._pypi_ordering.desc(),
        passive_deletes=True,
    )

    events = orm.relationship("ProjectEvent",
                              backref="project",
                              cascade="all, delete-orphan",
                              lazy=True)

    def __getitem__(self, version):
        session = orm.object_session(self)
        canonical_version = packaging.utils.canonicalize_version(version)

        try:
            return (session.query(Release).filter(
                Release.project == self,
                Release.canonical_version == canonical_version,
            ).one())
        except MultipleResultsFound:
            # There are multiple releases of this project which have the same
            # canonical version that were uploaded before we checked for
            # canonical version equivalence, so return the exact match instead
            try:
                return (session.query(Release).filter(
                    Release.project == self, Release.version == version).one())
            except NoResultFound:
                # There are multiple releases of this project which have the
                # same canonical version, but none that have the exact version
                # specified, so just 404
                raise KeyError from None
        except NoResultFound:
            raise KeyError from None

    def __acl__(self):
        session = orm.object_session(self)
        acls = [
            (Allow, "group:admins", "admin"),
            (Allow, "group:moderators", "moderator"),
        ]

        # Get all of the users for this project.
        query = session.query(Role).filter(Role.project == self)
        query = query.options(orm.lazyload("project"))
        query = query.options(orm.joinedload("user").lazyload("emails"))
        query = query.join(User).order_by(User.id.asc())
        for role in sorted(
                query.all(),
                key=lambda x: ["Owner", "Maintainer"].index(x.role_name)):
            if role.role_name == "Owner":
                acls.append(
                    (Allow, str(role.user.id), ["manage:project", "upload"]))
            else:
                acls.append((Allow, str(role.user.id), ["upload"]))
        return acls

    def record_event(self, *, tag, ip_address, additional=None):
        session = orm.object_session(self)
        event = ProjectEvent(project=self,
                             tag=tag,
                             ip_address=ip_address,
                             additional=additional)
        session.add(event)
        session.flush()

        return event

    @property
    def documentation_url(self):
        # TODO: Move this into the database and eliminate the use of the
        #       threadlocal here.
        request = get_current_request()

        # If the project doesn't have docs, then we'll just return a None here.
        if not self.has_docs:
            return

        return request.route_url("legacy.docs", project=self.name)

    @property
    def all_versions(self):
        return (orm.object_session(self).query(
            Release.version, Release.created, Release.is_prerelease,
            Release.yanked).filter(Release.project == self).order_by(
                Release._pypi_ordering.desc()).all())

    @property
    def latest_version(self):
        return (orm.object_session(self).query(
            Release.version, Release.created, Release.is_prerelease).filter(
                Release.project == self, Release.yanked.is_(False)).order_by(
                    Release.is_prerelease.nullslast(),
                    Release._pypi_ordering.desc()).first())
class Release(db.Model):

    __tablename__ = "releases"

    @declared_attr
    def __table_args__(cls):  # noqa
        return (
            Index("release_created_idx", cls.created.desc()),
            Index("release_project_created_idx", cls.project_id,
                  cls.created.desc()),
            Index("release_version_idx", cls.version),
            UniqueConstraint("project_id", "version"),
        )

    __repr__ = make_repr("project", "version")
    __parent__ = dotted_navigator("project")
    __name__ = dotted_navigator("version")

    project_id = Column(
        ForeignKey("projects.id", onupdate="CASCADE", ondelete="CASCADE"),
        nullable=False,
    )
    version = Column(Text, nullable=False)
    canonical_version = Column(Text, nullable=False)
    is_prerelease = orm.column_property(func.pep440_is_prerelease(version))
    author = Column(Text)
    author_email = Column(Text)
    maintainer = Column(Text)
    maintainer_email = Column(Text)
    home_page = Column(Text)
    license = Column(Text)
    summary = Column(Text)
    keywords = Column(Text)
    platform = Column(Text)
    download_url = Column(Text)
    _pypi_ordering = Column(Integer)
    requires_python = Column(Text)
    created = Column(DateTime(timezone=False),
                     nullable=False,
                     server_default=sql.func.now())

    description_id = Column(
        ForeignKey("release_descriptions.id",
                   onupdate="CASCADE",
                   ondelete="CASCADE"),
        nullable=False,
    )
    description = orm.relationship(
        "Description",
        backref=orm.backref(
            "release",
            cascade="all, delete-orphan",
            passive_deletes=True,
            passive_updates=True,
            single_parent=True,
            uselist=False,
        ),
    )

    yanked = Column(Boolean, nullable=False, server_default=sql.false())

    yanked_reason = Column(Text, nullable=False, server_default="")

    _classifiers = orm.relationship(
        Classifier,
        backref="project_releases",
        secondary=lambda: release_classifiers,
        order_by=Classifier.classifier,
        passive_deletes=True,
    )
    classifiers = association_proxy("_classifiers", "classifier")

    files = orm.relationship(
        "File",
        backref="release",
        cascade="all, delete-orphan",
        lazy="dynamic",
        order_by=lambda: File.filename,
        passive_deletes=True,
    )

    dependencies = orm.relationship(
        "Dependency",
        backref="release",
        cascade="all, delete-orphan",
        passive_deletes=True,
    )

    _requires = _dependency_relation(DependencyKind.requires)
    requires = association_proxy("_requires", "specifier")

    _provides = _dependency_relation(DependencyKind.provides)
    provides = association_proxy("_provides", "specifier")

    _obsoletes = _dependency_relation(DependencyKind.obsoletes)
    obsoletes = association_proxy("_obsoletes", "specifier")

    _requires_dist = _dependency_relation(DependencyKind.requires_dist)
    requires_dist = association_proxy("_requires_dist", "specifier")

    _provides_dist = _dependency_relation(DependencyKind.provides_dist)
    provides_dist = association_proxy("_provides_dist", "specifier")

    _obsoletes_dist = _dependency_relation(DependencyKind.obsoletes_dist)
    obsoletes_dist = association_proxy("_obsoletes_dist", "specifier")

    _requires_external = _dependency_relation(DependencyKind.requires_external)
    requires_external = association_proxy("_requires_external", "specifier")

    _project_urls = _dependency_relation(DependencyKind.project_url)
    project_urls = association_proxy("_project_urls", "specifier")

    uploader_id = Column(
        ForeignKey("users.id", onupdate="CASCADE", ondelete="SET NULL"),
        nullable=True,
        index=True,
    )
    uploader = orm.relationship(User)
    uploaded_via = Column(Text)

    @property
    def urls(self):
        _urls = OrderedDict()

        if self.home_page:
            _urls["Homepage"] = self.home_page
        if self.download_url:
            _urls["Download"] = self.download_url

        for urlspec in self.project_urls:
            name, _, url = urlspec.partition(",")
            name = name.strip()
            url = url.strip()
            if name and url:
                _urls[name] = url

        return _urls

    @property
    def github_repo_info_url(self):
        for url in self.urls.values():
            parsed = urlparse(url)
            segments = parsed.path.strip("/").split("/")
            if parsed.netloc in {"github.com", "www.github.com"
                                 } and len(segments) >= 2:
                user_name, repo_name = segments[:2]
                return f"https://api.github.com/repos/{user_name}/{repo_name}"

    @property
    def has_meta(self):
        return any([
            self.license,
            self.keywords,
            self.author,
            self.author_email,
            self.maintainer,
            self.maintainer_email,
            self.requires_python,
        ])
Exemple #28
0
class Project(SitemapMixin, db.ModelBase):

    __tablename__ = "packages"
    __table_args__ = (CheckConstraint(
        "name ~* '^([A-Z0-9]|[A-Z0-9][A-Z0-9._-]*[A-Z0-9])$'::text",
        name="packages_valid_name",
    ), )

    __repr__ = make_repr("name")

    name = Column(Text, primary_key=True, nullable=False)
    normalized_name = orm.column_property(func.normalize_pep426_name(name))
    stable_version = Column(Text)
    autohide = Column(Boolean, server_default=sql.true())
    comments = Column(Boolean, server_default=sql.true())
    bugtrack_url = Column(Text)
    hosting_mode = Column(Text, nullable=False, server_default="pypi-only")
    created = Column(
        DateTime(timezone=False),
        nullable=False,
        server_default=sql.func.now(),
    )
    has_docs = Column(Boolean)
    upload_limit = Column(Integer, nullable=True)
    last_serial = Column(Integer, nullable=False, server_default=sql.text("0"))
    allow_legacy_files = Column(
        Boolean,
        nullable=False,
        server_default=sql.false(),
    )

    users = orm.relationship(
        User,
        secondary=Role.__table__,
        backref="projects",
    )

    releases = orm.relationship(
        "Release",
        backref="project",
        cascade="all, delete-orphan",
        order_by=lambda: Release._pypi_ordering.desc(),
    )

    def __getitem__(self, version):
        session = orm.object_session(self)

        try:
            return (session.query(Release).filter((Release.project == self) & (
                Release.version == version)).one())
        except NoResultFound:
            raise KeyError from None

    def __acl__(self):
        session = orm.object_session(self)
        acls = []

        # Get all of the users for this project.
        query = session.query(Role).filter(Role.project == self)
        query = query.options(orm.lazyload("project"))
        query = query.options(orm.joinedload("user").lazyload("emails"))
        for role in sorted(
                query.all(),
                key=lambda x: ["Owner", "Maintainer"].index(x.role_name)):
            acls.append((Allow, role.user.id, ["upload"]))

        return acls

    @property
    def documentation_url(self):
        # TODO: Move this into the database and elimnate the use of the
        #       threadlocal here.
        request = get_current_request()

        # If the project doesn't have docs, then we'll just return a None here.
        if not self.has_docs:
            return

        return request.route_url("legacy.docs", project=self.name)
Exemple #29
0
class Release(db.ModelBase):

    __tablename__ = "releases"

    @declared_attr
    def __table_args__(cls):  # noqa
        return (
            Index("release_created_idx", cls.created.desc()),
            Index("release_name_created_idx", cls.name, cls.created.desc()),
            Index("release_name_idx", cls.name),
            Index("release_pypi_hidden_idx", cls._pypi_hidden),
            Index("release_version_idx", cls.version),
        )

    __repr__ = make_repr("name", "version")

    name = Column(
        Text,
        ForeignKey("packages.name", onupdate="CASCADE"),
        primary_key=True,
    )
    version = Column(Text, primary_key=True)
    is_prerelease = orm.column_property(func.pep440_is_prerelease(version))
    author = Column(Text)
    author_email = Column(Text)
    maintainer = Column(Text)
    maintainer_email = Column(Text)
    home_page = Column(Text)
    license = Column(Text)
    summary = Column(Text)
    description = Column(Text)
    keywords = Column(Text)
    platform = Column(Text)
    download_url = Column(Text)
    _pypi_ordering = Column(Integer)
    _pypi_hidden = Column(Boolean)
    cheesecake_installability_id = Column(
        Integer,
        ForeignKey("cheesecake_main_indices.id"),
    )
    cheesecake_documentation_id = Column(
        Integer,
        ForeignKey("cheesecake_main_indices.id"),
    )
    cheesecake_code_kwalitee_id = Column(
        Integer,
        ForeignKey("cheesecake_main_indices.id"),
    )
    requires_python = Column(Text)
    description_from_readme = Column(Boolean)
    created = Column(
        DateTime(timezone=False),
        nullable=False,
        server_default=sql.func.now(),
    )

    _classifiers = orm.relationship(
        Classifier,
        backref="project_releases",
        secondary=lambda: release_classifiers,
        order_by=Classifier.classifier,
    )
    classifiers = association_proxy("_classifiers", "classifier")

    files = orm.relationship(
        "File",
        backref="release",
        cascade="all, delete-orphan",
        lazy="dynamic",
        order_by=lambda: File.filename,
    )

    dependencies = orm.relationship("Dependency")

    _requires = _dependency_relation(DependencyKind.requires)
    requires = association_proxy("_requires", "specifier")

    _provides = _dependency_relation(DependencyKind.provides)
    provides = association_proxy("_provides", "specifier")

    _obsoletes = _dependency_relation(DependencyKind.obsoletes)
    obsoletes = association_proxy("_obsoletes", "specifier")

    _requires_dist = _dependency_relation(DependencyKind.requires_dist)
    requires_dist = association_proxy("_requires_dist", "specifier")

    _provides_dist = _dependency_relation(DependencyKind.provides_dist)
    provides_dist = association_proxy("_provides_dist", "specifier")

    _obsoletes_dist = _dependency_relation(DependencyKind.obsoletes_dist)
    obsoletes_dist = association_proxy("_obsoletes_dist", "specifier")

    _requires_external = _dependency_relation(DependencyKind.requires_external)
    requires_external = association_proxy("_requires_external", "specifier")

    _project_urls = _dependency_relation(DependencyKind.project_url)
    project_urls = association_proxy("_project_urls", "specifier")

    uploader = orm.relationship(
        "User",
        secondary=lambda: JournalEntry.__table__,
        primaryjoin=lambda:
        ((JournalEntry.name == orm.foreign(Release.name)) &
         (JournalEntry.version == orm.foreign(Release.version)) &
         (JournalEntry.action == "new release")),
        secondaryjoin=lambda: (
            (User.username == orm.foreign(JournalEntry._submitted_by))),
        order_by=lambda: JournalEntry.submitted_date.desc(),
        # TODO: We have uselist=False here which raises a warning because
        # multiple items were returned. This should only be temporary because
        # we should add a nullable FK to JournalEntry so we don't need to rely
        # on ordering and implicitly selecting the first object to make this
        # happen,
        uselist=False,
        viewonly=True,
    )

    @property
    def urls(self):
        _urls = OrderedDict()

        if self.home_page:
            _urls["Homepage"] = self.home_page

        for urlspec in self.project_urls:
            name, url = urlspec.split(",", 1)
            _urls[name] = url

        if self.download_url and "Download" not in _urls:
            _urls["Download"] = self.download_url

        return _urls

    @property
    def has_meta(self):
        return any([
            self.keywords, self.author, self.author_email, self.maintainer,
            self.maintainer_email
        ])
Exemple #30
0
 def __repr__(self):
     self.__repr__ = make_repr("foo", _self=self)
     return self.__repr__()
Exemple #31
0
        class Fake:
            __repr__ = make_repr("foo")

            @property
            def foo(self):
                raise DetachedInstanceError
Exemple #32
0
class Organization(HasEvents, db.Model):
    __tablename__ = "organizations"
    __table_args__ = (CheckConstraint(
        "name ~* '^([A-Z0-9]|[A-Z0-9][A-Z0-9._-]*[A-Z0-9])$'::text",
        name="organizations_valid_name",
    ), )

    __repr__ = make_repr("name")

    name = Column(Text, nullable=False)
    normalized_name = orm.column_property(func.normalize_pep426_name(name))
    display_name = Column(Text, nullable=False)
    orgtype = Column(
        Enum(OrganizationType, values_callable=lambda x: [e.value for e in x]),
        nullable=False,
    )
    link_url = Column(URLType, nullable=False)
    description = Column(Text, nullable=False)
    is_active = Column(Boolean, nullable=False, server_default=sql.false())
    is_approved = Column(Boolean)
    created = Column(
        DateTime(timezone=False),
        nullable=False,
        server_default=sql.func.now(),
        index=True,
    )
    date_approved = Column(
        DateTime(timezone=False),
        nullable=True,
        onupdate=func.now(),
    )

    users = orm.relationship(
        User,
        secondary=OrganizationRole.__table__,
        backref="organizations"  # type: ignore # noqa
    )
    projects = orm.relationship(
        "Project",
        secondary=OrganizationProject.__table__,
        backref="organizations"  # type: ignore # noqa
    )

    def record_event(self, *, tag, ip_address, additional={}):
        """Record organization name in events in case organization is ever deleted."""
        super().record_event(
            tag=tag,
            ip_address=ip_address,
            additional={
                "organization_name": self.name,
                **additional
            },
        )

    def __acl__(self):
        session = orm.object_session(self)

        acls = [
            (Allow, "group:admins", "admin"),
            (Allow, "group:moderators", "moderator"),
        ]

        # Get all of the users for this organization.
        query = session.query(OrganizationRole).filter(
            OrganizationRole.organization == self)
        query = query.options(orm.lazyload("organization"))
        query = query.join(User).order_by(User.id.asc())
        for role in sorted(
                query.all(),
                key=lambda x: [e.value for e in OrganizationRoleType].index(
                    x.role_name),
        ):
            # Allow all people in organization read access.
            # Allow write access depending on role.
            if role.role_name == OrganizationRoleType.Owner:
                acls.append((
                    Allow,
                    f"user:{role.user.id}",
                    ["view:organization", "manage:organization"],
                ))
            elif role.role_name == OrganizationRoleType.BillingManager:
                acls.append((
                    Allow,
                    f"user:{role.user.id}",
                    ["view:organization", "manage:billing"],
                ))
            elif role.role_name == OrganizationRoleType.Manager:
                acls.append((
                    Allow,
                    f"user:{role.user.id}",
                    ["view:organization", "manage:team"],
                ))
            else:
                # No member-specific write access needed for now.
                acls.append(
                    (Allow, f"user:{role.user.id}", ["view:organization"]))
        return acls
Exemple #33
0
 def __repr__(self):
     self.__repr__ = make_repr(*self.__table__.columns.keys(), _self=self)
     return self.__repr__()