New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Unify feature check for organization/project #8920
Conversation
ca94e89
to
e489f0c
Compare
e489f0c
to
f29401f
Compare
project, | ||
type=PlanFeature.TYPE_CONCURRENT_BUILDS, | ||
default=settings.RTD_MAX_CONCURRENT_BUILDS, | ||
) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we had an override just to check for the value from the plan on .com.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't this method contain all the logic? I mean, also check for project.max_concurrent_builds or max_concurrent_organization
as well?
Otherwise, it's only being called for the default value, but it won't affect the project's value.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems my suggestion is already applied, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks good as a start. However, I think it needs to encapsulate more logic in the .get_feature_value()
so we can trust 100% on it instead of mixing it with some extra logic in other places (e.g. max concurrent builds)
I'd like to do PlanFeature.objects.get_feature_value(project, type=PlanFeature.TYPE_CONCURRENT_BUILDS, default=settings.RTD_MAX_CONCURRENT_BUILDS)
and don't worry if the project is under an organization or not and if it has a particular max concurrent defined at the project level. I'd like to rely on the .get_feature_value()
to handle all that logic for me.
BTW, it would have been good to have a better description in the PR to understand what this code should do to reduce guessing.
project, | ||
type=PlanFeature.TYPE_CONCURRENT_BUILDS, | ||
default=settings.RTD_MAX_CONCURRENT_BUILDS, | ||
) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't this method contain all the logic? I mean, also check for project.max_concurrent_builds or max_concurrent_organization
as well?
Otherwise, it's only being called for the default value, but it won't affect the project's value.
if not settings.RTD_ALL_FEATURES_ENABLED: | ||
feature = self.get_feature(obj, type) | ||
if feature: | ||
return feature.value | ||
return default |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here is where I think it needs to encapsulate more logic, so we can rely 100% on it without mixing the .get_feature_value
with other logic in the code.
Not really sure about that, concurrent build is the only one, and is very specific about the attributes and order that should be checked. It makes more sense to have that on project model class. |
Yeah, even if it's the only one now, I think it could be better to handle each special case we may have in the future inside the |
I'm not really convince about having that special case there, the logic is already encapsulated in the project queryset
If someone else thinks that's fine, I can change it. |
That's my point here. For all the PlanFeature(s) it's enough to do |
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions. |
I have changed this slightly, instead of having a setting to enable all features, now we have a setting to enable a set of features, this is for users that don't have a subscription (.org), on .com this will I'd like to merge this, so we can continue with the djstripe migration, this is useful since we would have only one place where to change the queryset/lookup logic. This also removes a lot of overrides on .com (and probably we can remove more!). The only blocker before was a disagreement on #8920 (comment), I still don't think we should merge that logic there (we only want to know the value of the feature, not the value of the org/project), and the |
Looks like there's an update here, if you remember much from the past to review it @humitos |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good. I left some minor details to be considered and make the code more readable, basically.
TYPE_CNAME = "cname" | ||
TYPE_CDN = "cdn" | ||
TYPE_SSL = "ssl" | ||
TYPE_SUPPORT = "support" | ||
|
||
TYPE_PRIVATE_DOCS = "private_docs" | ||
TYPE_EMBED_API = "embed_api" | ||
TYPE_SEARCH_ANALYTICS = "search_analytics" | ||
TYPE_PAGEVIEW_ANALYTICS = "pageviews_analytics" | ||
TYPE_CONCURRENT_BUILDS = "concurrent_builds" | ||
TYPE_SSO = "sso" | ||
TYPE_CUSTOM_URL = "urls" | ||
TYPE_AUDIT_LOGS = "audit-logs" | ||
TYPE_AUDIT_PAGEVIEWS = "audit-pageviews" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there any reason why these are prefixed with TYPE_
instead of FEATURE_
? TYPE_EMBED_API
does not make too much sense to me, but FEATURE_EMBED_API
does.
In places like this one, it will be more readable: https://github.com/readthedocs/readthedocs.org/pull/8920/files#diff-e7f36d6ba29b1ae0d1c6e12781ba3f54dc4cb434cf07057f73e2f5d57b545ae9R166
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is also why I've preferred model constants are defined on the models themselves. The added context and readability of Feature.TYPE_EMBED_API
or Feature.EMBED_API
is quite nicer than a list of constants.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a place where I'd love to use enums instead p:
def _is_enabled(self, project): | ||
"""Should we show search analytics for this project?""" | ||
return True | ||
|
||
|
||
class SearchAnalytics(SettingsOverrideObject): | ||
_default_class = SearchAnalyticsBase | ||
return PlanFeature.objects.has_feature( | ||
project, | ||
type=self.feature_type, | ||
) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This method should go in a mixin since it's shared among multiple classes.
def _is_feature_enabled(self, organization): | ||
return PlanFeature.objects.has_feature( | ||
organization, | ||
type=self.feature_type, | ||
) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is the same method as _is_enabled
. However, it uses organization=
instead of project=
and it's named differently. We should decide whether naming it _is_feature_enabled
or _is_enabled
to keep consistency.
project, | ||
type=PlanFeature.TYPE_CONCURRENT_BUILDS, | ||
default=settings.RTD_MAX_CONCURRENT_BUILDS, | ||
) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems my suggestion is already applied, right?
@stsewd Is this ready to get merged as well? |
Mostly I guess, need to update the PR, maybe revising using enums at #8920 (comment). |
@stsewd It would be good to move forward with this PR since the work is already done and reviewed. Can you update it to be in a meargeable state? |
We are overriding classes and skipping tests con .com just because on .com we require a subscription for some features.
Now that we have subs on .org we can share more code between both sites. I have added a new setting to check if features should always be present or if we should check for a subscription.
Refs #9313