Beispiel #1
0
def get_features_for_projects(
        all_projects: Sequence[Project],
        user: User) -> MutableMapping[Project, List[str]]:
    # Arrange to call features.has_for_batch rather than features.has
    # for performance's sake
    projects_by_org = defaultdict(list)
    for project in all_projects:
        projects_by_org[project.organization].append(project)

    features_by_project = defaultdict(list)
    project_features = [
        feature
        for feature in features.all(feature_type=ProjectFeature).keys()
        if feature.startswith(_PROJECT_SCOPE_PREFIX)
    ]

    batch_checked = set()
    for (organization, projects) in projects_by_org.items():
        batch_features = features.batch_has(project_features,
                                            actor=user,
                                            projects=projects,
                                            organization=organization)

        # batch_has has found some features
        if batch_features:
            for project in projects:
                for feature_name, active in batch_features.get(
                        f"project:{project.id}", {}).items():
                    if active:
                        features_by_project[project].append(
                            feature_name[len(_PROJECT_SCOPE_PREFIX):])

                    batch_checked.add(feature_name)

    for feature_name in project_features:
        if feature_name in batch_checked:
            continue
        abbreviated_feature = feature_name[len(_PROJECT_SCOPE_PREFIX):]
        for (organization, projects) in projects_by_org.items():
            result = features.has_for_batch(feature_name, organization,
                                            projects, user)
            for (project, flag) in result.items():
                if flag:
                    features_by_project[project].append(abbreviated_feature)

    for project in all_projects:
        if project.flags.has_releases:
            features_by_project[project].append("releases")

    return features_by_project
Beispiel #2
0
 def get_features(self, organization: Organization,
                  request: Request) -> Mapping[str, bool]:
     feature_names = [
         "organizations:performance-chart-interpolation",
         "organizations:discover-use-snql",
         "organizations:performance-use-metrics",
     ]
     batch_features = features.batch_has(
         feature_names,
         organization=organization,
         actor=request.user,
     )
     return (batch_features.get(f"organization:{organization.id}", {})
             if batch_features is not None else {
                 feature_name: features.has(feature_name,
                                            organization=organization,
                                            actor=request.user)
                 for feature_name in feature_names
             })
Beispiel #3
0
    def serialize(self, obj, attrs, user):
        from sentry import features
        from sentry.features.base import OrganizationFeature

        if attrs.get("avatar"):
            avatar = {
                "avatarType":
                attrs["avatar"].get_avatar_type_display(),
                "avatarUuid":
                attrs["avatar"].ident if attrs["avatar"].file_id else None,
            }
        else:
            avatar = {"avatarType": "letter_avatar", "avatarUuid": None}

        status = OrganizationStatus(obj.status)

        # Retrieve all registered organization features
        org_features = [
            feature for feature in features.all(
                feature_type=OrganizationFeature).keys()
            if feature.startswith(_ORGANIZATION_SCOPE_PREFIX)
        ]
        feature_list = set()

        batch_features = features.batch_has(org_features,
                                            actor=user,
                                            organization=obj)

        # batch_has has found some features
        if batch_features:
            for feature_name, active in batch_features.get(
                    "organization:{}".format(obj.id), {}).items():
                if active:
                    # Remove organization prefix
                    feature_list.add(
                        feature_name[len(_ORGANIZATION_SCOPE_PREFIX):])

                # This feature_name was found via `batch_has`, don't check again using `has`
                org_features.remove(feature_name)

        for feature_name in org_features:
            if features.has(feature_name, obj, actor=user):
                # Remove the organization scope prefix
                feature_list.add(
                    feature_name[len(_ORGANIZATION_SCOPE_PREFIX):])

        # Do not include the onboarding feature if OrganizationOptions exist
        if ("onboarding" in feature_list and
                OrganizationOption.objects.filter(organization=obj).exists()):
            feature_list.remove("onboarding")

        # Include api-keys feature if they previously had any api-keys
        if "api-keys" not in feature_list and ApiKey.objects.filter(
                organization=obj).exists():
            feature_list.add("api-keys")

        # Organization flag features (not provided through the features module)
        if OrganizationOption.objects.filter(
                organization=obj, key__in=LEGACY_RATE_LIMIT_OPTIONS).exists():
            feature_list.add("legacy-rate-limits")
        if getattr(obj.flags, "allow_joinleave"):
            feature_list.add("open-membership")
        if not getattr(obj.flags, "disable_shared_issues"):
            feature_list.add("shared-issues")

        return {
            "id": six.text_type(obj.id),
            "slug": obj.slug,
            "status": {
                "id": status.name.lower(),
                "name": status.label
            },
            "name": obj.name or obj.slug,
            "dateCreated": obj.date_added,
            "isEarlyAdopter": bool(obj.flags.early_adopter),
            "require2FA": bool(obj.flags.require_2fa),
            "avatar": avatar,
            "features": feature_list,
        }