Skip to content

Commit

Permalink
Fix conflicts and merge branch 'main' into feat/create_change_request…
Browse files Browse the repository at this point in the history
…s_for_segments
  • Loading branch information
zachaysan committed Nov 13, 2024
2 parents f47922e + 4a310b0 commit ce7fca8
Show file tree
Hide file tree
Showing 58 changed files with 1,385 additions and 665 deletions.
2 changes: 1 addition & 1 deletion .release-please-manifest.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{
".": "2.150.0"
".": "2.153.0"
}
49 changes: 49 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,54 @@
# Changelog

## [2.153.0](https://github.com/Flagsmith/flagsmith/compare/v2.152.0...v2.153.0) (2024-11-12)


### Features

* log commands in Docker entrypoint ([#4826](https://github.com/Flagsmith/flagsmith/issues/4826)) ([b2d7500](https://github.com/Flagsmith/flagsmith/commit/b2d7500c6fffb80522e2c940a0031e8df5387556))
* **my-permissions:** Add tag based permissions ([#4824](https://github.com/Flagsmith/flagsmith/issues/4824)) ([cbd60d9](https://github.com/Flagsmith/flagsmith/commit/cbd60d942c5a58030af548f8b5af0057ada3cf18))


### Bug Fixes

* Allow any auth except LDAP and SAML to change email ([#4810](https://github.com/Flagsmith/flagsmith/issues/4810)) ([10eb571](https://github.com/Flagsmith/flagsmith/commit/10eb571bba1821324daf3d56edee96b3d391b977))
* Edit identity override with prevent flag defaults enabled ([#4809](https://github.com/Flagsmith/flagsmith/issues/4809)) ([0f9b24b](https://github.com/Flagsmith/flagsmith/commit/0f9b24b5df354f01b6de9c9c754c468e65c5c081))
* make clone_feature_states_async write only ([#4811](https://github.com/Flagsmith/flagsmith/issues/4811)) ([513b088](https://github.com/Flagsmith/flagsmith/commit/513b088edf25b05f2b7c15604826f21c2a0b3b18))

## [2.152.0](https://github.com/Flagsmith/flagsmith/compare/v2.151.0...v2.152.0) (2024-11-06)


### Features

* add environment processing UI ([#4812](https://github.com/Flagsmith/flagsmith/issues/4812)) ([9db91ae](https://github.com/Flagsmith/flagsmith/commit/9db91ae980ae3bf9fe445f68c8aaf438c68a47b9))
* Manage user's groups ([#4312](https://github.com/Flagsmith/flagsmith/issues/4312)) ([89b153c](https://github.com/Flagsmith/flagsmith/commit/89b153cb3694bf893a24e6d3e047992a6d456eae))
* restrict versioning by days ([#4547](https://github.com/Flagsmith/flagsmith/issues/4547)) ([dad864a](https://github.com/Flagsmith/flagsmith/commit/dad864aa2de0ed6ab704c8b83796ee0a7a8a780a))


### Bug Fixes

* feature stale message not showing ([#4801](https://github.com/Flagsmith/flagsmith/issues/4801)) ([70a7d81](https://github.com/Flagsmith/flagsmith/commit/70a7d81355f8787a68de52b53caf476a5c984103))
* Fix organisation meta ([#4802](https://github.com/Flagsmith/flagsmith/issues/4802)) ([c2fdc5b](https://github.com/Flagsmith/flagsmith/commit/c2fdc5b3e3485a22e8599e904800ca8c238a11b8))
* permanent tag icons ([#4804](https://github.com/Flagsmith/flagsmith/issues/4804)) ([57ad28c](https://github.com/Flagsmith/flagsmith/commit/57ad28cf033b2ec9554ad60bcade4bd40cedb117))
* users with VIEW_ENVIRONMENT should be able to retrieve environment ([#4814](https://github.com/Flagsmith/flagsmith/issues/4814)) ([e6f1bac](https://github.com/Flagsmith/flagsmith/commit/e6f1bac2f264ebdc1d012ad61539efb76ac43fd7))

## [2.151.0](https://github.com/Flagsmith/flagsmith/compare/v2.150.0...v2.151.0) (2024-11-04)


### Features

* async the logic for cloning feature states into a cloned environment ([#4005](https://github.com/Flagsmith/flagsmith/issues/4005)) ([02f5f71](https://github.com/Flagsmith/flagsmith/commit/02f5f71f82bae1ec3536cb522fc0b684a2c27605))
* **ci:** add command to rollback migrations ([#4768](https://github.com/Flagsmith/flagsmith/issues/4768)) ([483cc87](https://github.com/Flagsmith/flagsmith/commit/483cc87fde03d2da465f9ec799bdbc746533f8d2))
* **export:** Add support for edge identities data ([#4654](https://github.com/Flagsmith/flagsmith/issues/4654)) ([f72c764](https://github.com/Flagsmith/flagsmith/commit/f72c764e59d44f3c50bafd0cd2aef2dcf51af07b))
* **permissions:** update endpoints to expose tag-supported perms ([#4788](https://github.com/Flagsmith/flagsmith/issues/4788)) ([43e68c1](https://github.com/Flagsmith/flagsmith/commit/43e68c1b67eeb5587440cbe5017035b60d897212))


### Bug Fixes

* Extend user first name length to 150 characters ([#4797](https://github.com/Flagsmith/flagsmith/issues/4797)) ([364c565](https://github.com/Flagsmith/flagsmith/commit/364c565fed5ebdb0da86927a25d56631502b3792))
* hide view features from associated segment overrides ([#4786](https://github.com/Flagsmith/flagsmith/issues/4786)) ([49ff569](https://github.com/Flagsmith/flagsmith/commit/49ff569cabac19f70c0688f1fe58c3511ce8801b))
* Set tag to get or create ([#4790](https://github.com/Flagsmith/flagsmith/issues/4790)) ([fedd296](https://github.com/Flagsmith/flagsmith/commit/fedd296a5cc8eb07aa1db4a2cbb5eca8f124c098))

## [2.150.0](https://github.com/Flagsmith/flagsmith/compare/v2.149.0...v2.150.0) (2024-10-30)


Expand Down
2 changes: 1 addition & 1 deletion api/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ POETRY_VERSION ?= 1.8.3
GUNICORN_LOGGER_CLASS ?= util.logging.GunicornJsonCapableLogger

SAML_REVISION ?= v1.6.4
RBAC_REVISION ?= v0.9.0
RBAC_REVISION ?= v0.10.0

-include .env-local
-include $(DOTENV_OVERRIDE_FILE)
Expand Down
2 changes: 1 addition & 1 deletion api/environments/permissions/permissions.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ def has_permission(self, request, view):
def has_object_permission(self, request, view, obj):
if view.action == "clone":
return request.user.has_project_permission(CREATE_ENVIRONMENT, obj.project)
elif view.action == "get_document":
elif view.action in ("get_document", "retrieve", "trait_keys"):
return request.user.has_environment_permission(VIEW_ENVIRONMENT, obj)

return request.user.is_environment_admin(obj) or view.action in [
Expand Down
1 change: 1 addition & 0 deletions api/environments/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@ class CloneEnvironmentSerializer(EnvironmentSerializerLight):
help_text="If True, the environment will be created immediately, but the feature states "
"will be created asynchronously. Environment will have `is_creating: true` until "
"this process is completed.",
write_only=True,
)

class Meta:
Expand Down
7 changes: 5 additions & 2 deletions api/environments/views.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import logging

from common.environments.permissions import TAG_SUPPORTED_PERMISSIONS
from django.db.models import Count, Q
from django.utils.decorators import method_decorator
from drf_yasg import openapi
Expand Down Expand Up @@ -189,12 +190,14 @@ def delete_traits(self, request, *args, **kwargs):
status=status.HTTP_400_BAD_REQUEST,
)

@swagger_auto_schema(responses={200: PermissionModelSerializer})
@swagger_auto_schema(responses={200: PermissionModelSerializer(many=True)})
@action(detail=False, methods=["GET"])
def permissions(self, *args, **kwargs):
return Response(
PermissionModelSerializer(
instance=EnvironmentPermissionModel.objects.all(), many=True
instance=EnvironmentPermissionModel.objects.all(),
many=True,
context={"tag_supported_permissions": TAG_SUPPORTED_PERMISSIONS},
).data
)

Expand Down
8 changes: 4 additions & 4 deletions api/integrations/flagsmith/data/environment.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
"multivariate_feature_state_values": []
},
{
"django_id": 615532,
"django_id": 627339,
"enabled": true,
"feature": {
"id": 96656,
Expand All @@ -24,11 +24,11 @@
},
"feature_segment": null,
"feature_state_value": null,
"featurestate_uuid": "49db2260-d4d4-47be-b84c-7197c46b10fb",
"featurestate_uuid": "566228a6-78b0-4696-a023-feb149b61fd2",
"multivariate_feature_state_values": []
},
{
"django_id": 615534,
"django_id": 627341,
"enabled": true,
"feature": {
"id": 96657,
Expand All @@ -37,7 +37,7 @@
},
"feature_segment": null,
"feature_state_value": null,
"featurestate_uuid": "7489b387-31f8-436d-a862-e2aa12939b5b",
"featurestate_uuid": "4f7cae64-afed-416c-ada8-e6b034dff436",
"multivariate_feature_state_values": []
},
{
Expand Down
17 changes: 16 additions & 1 deletion api/permissions/permissions_calculator.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,11 +107,26 @@ def permissions(self) -> typing.Set[str]:
).union(
reduce(
lambda a, b: a.union(b),
[role.permissions for role in self.roles],
[
role_permission.permissions
for role_permission in self.roles
if not role_permission.role.tags
],
set(),
)
)

@property
def tag_based_permissions(self) -> list[dict]:
return [
{
"permissions": role_permission.permissions,
"tags": role_permission.role.tags,
}
for role_permission in self.roles
if role_permission.role.tags
]


def get_project_permission_data(project_id: int, user_id: int) -> PermissionData:
project_permission_svc = _ProjectPermissionService(project_id, user_id)
Expand Down
13 changes: 12 additions & 1 deletion api/permissions/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,14 @@


class PermissionModelSerializer(serializers.ModelSerializer):
supports_tag = serializers.SerializerMethodField()

class Meta:
model = PermissionModel
fields = ("key", "description")
fields = ("key", "description", "supports_tag")

def get_supports_tag(self, obj: PermissionModel) -> bool:
return obj.key in self.context.get("tag_supported_permissions", [])


class CreateUpdateUserPermissionSerializerABC(serializers.ModelSerializer):
Expand All @@ -32,6 +37,12 @@ def update(self, instance, validated_data):
return instance


class TagBasedPermissionSerializer(serializers.Serializer):
permissions = serializers.ListField(child=serializers.CharField())
tags = serializers.ListField(child=serializers.IntegerField())


class UserObjectPermissionsSerializer(serializers.Serializer):
permissions = serializers.ListField(child=serializers.CharField())
admin = serializers.BooleanField()
tag_based_permissions = TagBasedPermissionSerializer(many=True)
8 changes: 5 additions & 3 deletions api/projects/views.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals

from common.projects.permissions import VIEW_PROJECT
from common.projects.permissions import TAG_SUPPORTED_PERMISSIONS, VIEW_PROJECT
from django.conf import settings
from django.utils.decorators import method_decorator
from drf_yasg import openapi
Expand Down Expand Up @@ -123,13 +123,15 @@ def environments(self, request, pk):
return Response(EnvironmentSerializerLight(environments, many=True).data)

@swagger_auto_schema(
responses={200: PermissionModelSerializer}, request_body=no_body
responses={200: PermissionModelSerializer(many=True)}, request_body=no_body
)
@action(detail=False, methods=["GET"])
def permissions(self, *args, **kwargs):
return Response(
PermissionModelSerializer(
instance=ProjectPermissionModel.objects.all(), many=True
instance=ProjectPermissionModel.objects.all(),
many=True,
context={"tag_supported_permissions": TAG_SUPPORTED_PERMISSIONS},
).data
)

Expand Down
28 changes: 15 additions & 13 deletions api/scripts/run-docker.sh
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
#!/bin/sh
set -e

function waitfordb() {
waitfordb() {
if [ -z "${SKIP_WAIT_FOR_DB}" ]; then
python manage.py waitfordb "$@"
fi
}

function migrate () {
migrate () {
waitfordb && python manage.py migrate && python manage.py createcachetable
}
function serve() {
serve() {
# configuration parameters for statsd. Docs can be found here:
# https://docs.gunicorn.org/en/stable/instrumentation.html
export STATSD_PORT=${STATSD_PORT:-8125}
Expand All @@ -31,9 +31,9 @@ function serve() {
${STATSD_HOST:+--statsd-prefix $STATSD_PREFIX} \
app.wsgi
}
function run_task_processor() {
run_task_processor() {
waitfordb --waitfor 30 --migrations
if [[ -n "$ANALYTICS_DATABASE_URL" || -n "$DJANGO_DB_NAME_ANALYTICS" ]]; then
if [ -n "$ANALYTICS_DATABASE_URL" ] || [ -n "$DJANGO_DB_NAME_ANALYTICS" ]; then
waitfordb --waitfor 30 --migrations --database analytics
fi
RUN_BY_PROCESSOR=1 exec python manage.py runprocessor \
Expand All @@ -42,29 +42,31 @@ function run_task_processor() {
--numthreads ${TASK_PROCESSOR_NUM_THREADS:-5} \
--queuepopsize ${TASK_PROCESSOR_QUEUE_POP_SIZE:-10}
}
function migrate_analytics_db(){
migrate_analytics_db(){
# if `$ANALYTICS_DATABASE_URL` or DJANGO_DB_NAME_ANALYTICS is set
# run the migration command
if [[ -z "$ANALYTICS_DATABASE_URL" && -z "$DJANGO_DB_NAME_ANALYTICS" ]]; then
if [ -z "$ANALYTICS_DATABASE_URL" ] && [ -z "$DJANGO_DB_NAME_ANALYTICS" ]; then
return 0
fi
python manage.py migrate --database analytics
}
function bootstrap(){
bootstrap(){
python manage.py bootstrap
}
function default(){
default(){
python manage.py "$@"
}

if [ "$1" == "migrate" ]; then
set -x

if [ "$1" = "migrate" ]; then
migrate
migrate_analytics_db
elif [ "$1" == "serve" ]; then
elif [ "$1" = "serve" ]; then
serve
elif [ "$1" == "run-task-processor" ]; then
elif [ "$1" = "run-task-processor" ]; then
run_task_processor
elif [ "$1" == "migrate-and-serve" ]; then
elif [ "$1" = "migrate-and-serve" ]; then
migrate
migrate_analytics_db
bootstrap
Expand Down
13 changes: 10 additions & 3 deletions api/tests/integration/environments/test_clone_environment.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,11 @@
[lazy_fixture("admin_master_api_key_client"), lazy_fixture("admin_client")],
)
def test_clone_environment_clones_feature_states_with_value(
client, project, environment, environment_api_key, feature
client: APIClient,
project: int,
environment: int,
environment_api_key: str,
feature: int,
):
# Firstly, let's update feature state value of the source environment
# fetch the feature state id to update
Expand All @@ -43,11 +47,14 @@ def test_clone_environment_clones_feature_states_with_value(
# Now, clone the environment
env_name = "Cloned env"
url = reverse("api-v1:environments:environment-clone", args=[environment_api_key])
res = client.post(url, {"name": env_name})
res = client.post(url, {"name": env_name, "clone_feature_states_async": False})

# Then, check that the clone was successful
assert res.status_code == status.HTTP_200_OK

# And check that the write only field wasn't returned
assert "clone_feature_states_async" not in res.json()

# Now, fetch the feature states of the source environment
source_env_feature_states = get_env_feature_states_list_with_api(
client, {"environment": environment}
Expand All @@ -58,7 +65,7 @@ def test_clone_environment_clones_feature_states_with_value(
client, {"environment": res.json()["id"]}
)

# Finaly, compare the responses
# Finally, compare the responses
assert source_env_feature_states["count"] == 1
assert (
source_env_feature_states["results"][0]["id"]
Expand Down
Loading

0 comments on commit ce7fca8

Please sign in to comment.