mirror of
https://github.com/PostHog/posthog.git
synced 2024-11-24 00:47:50 +01:00
feat: add access control model (#26076)
This commit is contained in:
parent
b7809c44d9
commit
23db9545fc
@ -138,7 +138,7 @@ class BillingManager:
|
||||
|
||||
def update_billing_organization_users(self, organization: Organization) -> None:
|
||||
try:
|
||||
distinct_ids = list(organization.members.values_list("distinct_id", flat=True))
|
||||
distinct_ids = list(organization.members.values_list("distinct_id", flat=True)) # type: ignore
|
||||
|
||||
first_owner_membership = (
|
||||
OrganizationMembership.objects.filter(organization=organization, level=15)
|
||||
@ -157,7 +157,7 @@ class BillingManager:
|
||||
)
|
||||
|
||||
org_users = list(
|
||||
organization.members.values(
|
||||
organization.members.values( # type: ignore
|
||||
"email",
|
||||
"distinct_id",
|
||||
"organization_membership__level",
|
||||
|
75
ee/migrations/0017_accesscontrol_and_more.py
Normal file
75
ee/migrations/0017_accesscontrol_and_more.py
Normal file
@ -0,0 +1,75 @@
|
||||
# Generated by Django 4.2.15 on 2024-11-07 17:05
|
||||
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
import posthog.models.utils
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
dependencies = [
|
||||
("posthog", "0512_errortrackingissue_errortrackingissuefingerprintv2_and_more"),
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
("ee", "0016_rolemembership_organization_member"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name="AccessControl",
|
||||
fields=[
|
||||
(
|
||||
"id",
|
||||
models.UUIDField(
|
||||
default=posthog.models.utils.UUIDT, editable=False, primary_key=True, serialize=False
|
||||
),
|
||||
),
|
||||
("access_level", models.CharField(max_length=32)),
|
||||
("resource", models.CharField(max_length=32)),
|
||||
("resource_id", models.CharField(max_length=36, null=True)),
|
||||
("created_at", models.DateTimeField(auto_now_add=True)),
|
||||
("updated_at", models.DateTimeField(auto_now=True)),
|
||||
(
|
||||
"created_by",
|
||||
models.ForeignKey(
|
||||
null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL
|
||||
),
|
||||
),
|
||||
(
|
||||
"organization_member",
|
||||
models.ForeignKey(
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="access_controls",
|
||||
related_query_name="access_controls",
|
||||
to="posthog.organizationmembership",
|
||||
),
|
||||
),
|
||||
(
|
||||
"role",
|
||||
models.ForeignKey(
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="access_controls",
|
||||
related_query_name="access_controls",
|
||||
to="ee.role",
|
||||
),
|
||||
),
|
||||
(
|
||||
"team",
|
||||
models.ForeignKey(
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="access_controls",
|
||||
related_query_name="access_controls",
|
||||
to="posthog.team",
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
migrations.AddConstraint(
|
||||
model_name="accesscontrol",
|
||||
constraint=models.UniqueConstraint(
|
||||
fields=("resource", "resource_id", "team", "organization_member", "role"),
|
||||
name="unique resource per target",
|
||||
),
|
||||
),
|
||||
]
|
@ -1 +1 @@
|
||||
0016_rolemembership_organization_member
|
||||
0017_accesscontrol_and_more
|
||||
|
@ -5,16 +5,18 @@ from .feature_flag_role_access import FeatureFlagRoleAccess
|
||||
from .hook import Hook
|
||||
from .license import License
|
||||
from .property_definition import EnterprisePropertyDefinition
|
||||
from .rbac.access_control import AccessControl
|
||||
from .rbac.role import Role, RoleMembership
|
||||
|
||||
__all__ = [
|
||||
"EnterpriseEventDefinition",
|
||||
"ExplicitTeamMembership",
|
||||
"AccessControl",
|
||||
"DashboardPrivilege",
|
||||
"EnterpriseEventDefinition",
|
||||
"EnterprisePropertyDefinition",
|
||||
"ExplicitTeamMembership",
|
||||
"FeatureFlagRoleAccess",
|
||||
"Hook",
|
||||
"License",
|
||||
"Role",
|
||||
"RoleMembership",
|
||||
"EnterprisePropertyDefinition",
|
||||
"FeatureFlagRoleAccess",
|
||||
]
|
||||
|
@ -11,6 +11,7 @@ class EnterprisePropertyDefinition(PropertyDefinition):
|
||||
|
||||
verified = models.BooleanField(default=False, blank=True)
|
||||
verified_at = models.DateTimeField(null=True, blank=True)
|
||||
|
||||
verified_by = models.ForeignKey(
|
||||
"posthog.User",
|
||||
null=True,
|
||||
|
53
ee/models/rbac/access_control.py
Normal file
53
ee/models/rbac/access_control.py
Normal file
@ -0,0 +1,53 @@
|
||||
from django.db import models
|
||||
|
||||
from posthog.models.utils import UUIDModel
|
||||
|
||||
|
||||
class AccessControl(UUIDModel):
|
||||
class Meta:
|
||||
constraints = [
|
||||
models.UniqueConstraint(
|
||||
fields=["resource", "resource_id", "team", "organization_member", "role"],
|
||||
name="unique resource per target",
|
||||
)
|
||||
]
|
||||
|
||||
team = models.ForeignKey(
|
||||
"posthog.Team",
|
||||
on_delete=models.CASCADE,
|
||||
related_name="access_controls",
|
||||
related_query_name="access_controls",
|
||||
)
|
||||
|
||||
# Configuration of what we are accessing
|
||||
access_level: models.CharField = models.CharField(max_length=32)
|
||||
resource: models.CharField = models.CharField(max_length=32)
|
||||
resource_id: models.CharField = models.CharField(max_length=36, null=True)
|
||||
|
||||
# Optional scope it to a specific member
|
||||
organization_member = models.ForeignKey(
|
||||
"posthog.OrganizationMembership",
|
||||
on_delete=models.CASCADE,
|
||||
related_name="access_controls",
|
||||
related_query_name="access_controls",
|
||||
null=True,
|
||||
)
|
||||
|
||||
# Optional scope it to a specific role
|
||||
role = models.ForeignKey(
|
||||
"Role",
|
||||
on_delete=models.CASCADE,
|
||||
related_name="access_controls",
|
||||
related_query_name="access_controls",
|
||||
null=True,
|
||||
)
|
||||
|
||||
created_by = models.ForeignKey(
|
||||
"posthog.User",
|
||||
on_delete=models.SET_NULL,
|
||||
null=True,
|
||||
)
|
||||
created_at: models.DateTimeField = models.DateTimeField(auto_now_add=True)
|
||||
updated_at: models.DateTimeField = models.DateTimeField(auto_now=True)
|
||||
|
||||
# TODO: add model validation for access_level and resource
|
@ -5,6 +5,9 @@ from posthog.models.utils import UUIDModel
|
||||
|
||||
|
||||
class Role(UUIDModel):
|
||||
class Meta:
|
||||
constraints = [models.UniqueConstraint(fields=["organization", "name"], name="unique_role_name")]
|
||||
|
||||
name = models.CharField(max_length=200)
|
||||
organization = models.ForeignKey(
|
||||
"posthog.Organization",
|
||||
@ -12,10 +15,7 @@ class Role(UUIDModel):
|
||||
related_name="roles",
|
||||
related_query_name="role",
|
||||
)
|
||||
feature_flags_access_level = models.PositiveSmallIntegerField(
|
||||
default=OrganizationResourceAccess.AccessLevel.CAN_ALWAYS_EDIT,
|
||||
choices=OrganizationResourceAccess.AccessLevel.choices,
|
||||
)
|
||||
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
created_by = models.ForeignKey(
|
||||
"posthog.User",
|
||||
@ -25,11 +25,17 @@ class Role(UUIDModel):
|
||||
null=True,
|
||||
)
|
||||
|
||||
class Meta:
|
||||
constraints = [models.UniqueConstraint(fields=["organization", "name"], name="unique_role_name")]
|
||||
# TODO: Deprecate this field
|
||||
feature_flags_access_level = models.PositiveSmallIntegerField(
|
||||
default=OrganizationResourceAccess.AccessLevel.CAN_ALWAYS_EDIT,
|
||||
choices=OrganizationResourceAccess.AccessLevel.choices,
|
||||
)
|
||||
|
||||
|
||||
class RoleMembership(UUIDModel):
|
||||
class Meta:
|
||||
constraints = [models.UniqueConstraint(fields=["role", "user"], name="unique_user_and_role")]
|
||||
|
||||
role = models.ForeignKey(
|
||||
"Role",
|
||||
on_delete=models.CASCADE,
|
||||
@ -53,6 +59,3 @@ class RoleMembership(UUIDModel):
|
||||
)
|
||||
joined_at = models.DateTimeField(auto_now_add=True)
|
||||
updated_at = models.DateTimeField(auto_now=True)
|
||||
|
||||
class Meta:
|
||||
constraints = [models.UniqueConstraint(fields=["role", "user"], name="unique_user_and_role")]
|
||||
|
@ -327,8 +327,6 @@ ee/tasks/subscriptions/email_subscriptions.py:0: error: Item "None" of "datetime
|
||||
ee/tasks/subscriptions/email_subscriptions.py:0: error: Item "None" of "datetime | None" has no attribute "strftime" [union-attr]
|
||||
ee/tasks/subscriptions/email_subscriptions.py:0: error: Item "None" of "User | None" has no attribute "first_name" [union-attr]
|
||||
ee/billing/billing_manager.py:0: error: Module has no attribute "utc" [attr-defined]
|
||||
ee/billing/billing_manager.py:0: error: Cannot resolve keyword 'distinct_id' into field. Choices are: explicit_team_membership, id, joined_at, level, organization, organization_id, role_membership, updated_at, user, user_id [misc]
|
||||
ee/billing/billing_manager.py:0: error: Cannot resolve keyword 'email' into field. Choices are: explicit_team_membership, id, joined_at, level, organization, organization_id, role_membership, updated_at, user, user_id [misc]
|
||||
ee/billing/billing_manager.py:0: error: Incompatible types in assignment (expression has type "object", variable has type "bool | Combinable | None") [assignment]
|
||||
posthog/models/property/util.py:0: error: Incompatible type for lookup 'pk': (got "str | int | list[str]", expected "str | int") [misc]
|
||||
posthog/models/property/util.py:0: error: Argument 3 to "format_filter_query" has incompatible type "HogQLContext | None"; expected "HogQLContext" [arg-type]
|
||||
@ -642,6 +640,9 @@ posthog/tasks/exports/test/test_csv_exporter.py:0: error: Argument 1 to "read" h
|
||||
posthog/tasks/exports/test/test_csv_exporter.py:0: error: Argument 1 to "read" has incompatible type "str | None"; expected "str" [arg-type]
|
||||
posthog/tasks/exports/test/test_csv_exporter.py:0: error: Argument 1 to "read" has incompatible type "str | None"; expected "str" [arg-type]
|
||||
posthog/tasks/exports/test/test_csv_exporter.py:0: error: Argument 1 to "read" has incompatible type "str | None"; expected "str" [arg-type]
|
||||
posthog/session_recordings/session_recording_api.py:0: error: Argument "team_id" to "get_realtime_snapshots" has incompatible type "int"; expected "str" [arg-type]
|
||||
posthog/session_recordings/session_recording_api.py:0: error: Value of type variable "SupportsRichComparisonT" of "sorted" cannot be "str | None" [type-var]
|
||||
posthog/session_recordings/session_recording_api.py:0: error: Argument 1 to "get" of "dict" has incompatible type "str | None"; expected "str" [arg-type]
|
||||
posthog/queries/trends/test/test_person.py:0: error: "str" has no attribute "get" [attr-defined]
|
||||
posthog/queries/trends/test/test_person.py:0: error: Invalid index type "int" for "_MonkeyPatchedResponse"; expected type "str" [index]
|
||||
posthog/queries/trends/test/test_person.py:0: error: "str" has no attribute "get" [attr-defined]
|
||||
@ -800,9 +801,6 @@ posthog/temporal/data_imports/pipelines/pipeline_sync.py:0: error: "type[Filesys
|
||||
posthog/temporal/data_imports/pipelines/pipeline_sync.py:0: error: Incompatible types in assignment (expression has type "object", variable has type "DataWarehouseCredential | Combinable | None") [assignment]
|
||||
posthog/temporal/data_imports/pipelines/pipeline_sync.py:0: error: Incompatible types in assignment (expression has type "object", variable has type "str | int | Combinable") [assignment]
|
||||
posthog/temporal/data_imports/pipelines/pipeline_sync.py:0: error: Incompatible types in assignment (expression has type "dict[str, dict[str, str | bool]] | dict[str, str]", variable has type "dict[str, dict[str, str]]") [assignment]
|
||||
posthog/session_recordings/session_recording_api.py:0: error: Argument "team_id" to "get_realtime_snapshots" has incompatible type "int"; expected "str" [arg-type]
|
||||
posthog/session_recordings/session_recording_api.py:0: error: Value of type variable "SupportsRichComparisonT" of "sorted" cannot be "str | None" [type-var]
|
||||
posthog/session_recordings/session_recording_api.py:0: error: Argument 1 to "get" of "dict" has incompatible type "str | None"; expected "str" [arg-type]
|
||||
posthog/queries/app_metrics/test/test_app_metrics.py:0: error: Argument 3 to "AppMetricsErrorDetailsQuery" has incompatible type "AppMetricsRequestSerializer"; expected "AppMetricsErrorsRequestSerializer" [arg-type]
|
||||
posthog/queries/app_metrics/test/test_app_metrics.py:0: error: Argument 3 to "AppMetricsErrorDetailsQuery" has incompatible type "AppMetricsRequestSerializer"; expected "AppMetricsErrorsRequestSerializer" [arg-type]
|
||||
posthog/queries/app_metrics/test/test_app_metrics.py:0: error: Argument 3 to "AppMetricsErrorDetailsQuery" has incompatible type "AppMetricsRequestSerializer"; expected "AppMetricsErrorsRequestSerializer" [arg-type]
|
||||
|
Loading…
Reference in New Issue
Block a user