diff --git a/.github/workflows/ts_lint.yml b/.github/workflows/ts_lint.yml index 213baa3..78f34a3 100644 --- a/.github/workflows/ts_lint.yml +++ b/.github/workflows/ts_lint.yml @@ -1,33 +1,29 @@ -# This workflow will do a clean install of node dependencies, cache/restore them, build the source code and run tests across different versions of node -# For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions - -name: Full Clients Lint +name: TS-Client Lint on: push: - branches: [development, development_*] + branches: + - development pull_request: - branches: [development, development_*] + branches: + - development jobs: - lint: + build: runs-on: ubuntu-latest - strategy: - matrix: - node-version: [18.x] - # See supported Node.js release schedule at https://nodejs.org/en/about/releases/ steps: - - uses: actions/checkout@v2 - - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v2 - with: - node-version: ${{ matrix.node-version }} - cache: "yarn" + - name: Checkout code + uses: actions/checkout@v2 + + - name: Set up Node.js + uses: actions/setup-node@v3 + with: + node-version: '18.18.0' + + - name: Install dependencies + run: cd clients/typescript && yarn install + + - name: Run ESLint + run: cd clients/typescript && yarn lint - - name: Install - run: cd clients/typescript && yarn - - name: Lint - run: | - cd clients/typescript && yarn check-eslint - cd clients/typescript && yarn check-prettier diff --git a/Makefile b/Makefile index ebccf7a..4898b1b 100644 --- a/Makefile +++ b/Makefile @@ -2,6 +2,8 @@ # Backend commands. CMD:=poetry run backend:=cd backend +ts-client:=cd clients/typescript + get-poetry: curl -sSL https://install.python-poetry.org | python3 - migrate: @@ -29,6 +31,7 @@ endif lint: $(backend) && $(CMD) black . --exclude=__init__.py $(backend) && $(CMD) flake8 . --exclude=__init__.py + $(ts-client) && yarn lint # $(frontend) && yarn lint # Run examples diff --git a/backend/settings.py b/backend/settings.py index 33fc7b5..9de37e5 100644 --- a/backend/settings.py +++ b/backend/settings.py @@ -126,7 +126,9 @@ } SIMPLE_JWT = { - "ACCESS_TOKEN_LIFETIME": timedelta(minutes=3000 if config("ENV") == "development" else 250), + "ACCESS_TOKEN_LIFETIME": timedelta( + minutes=3000 if config("ENV") == "development" else 250 + ), "REFRESH_TOKEN_LIFETIME": timedelta(days=1), "ROTATE_REFRESH_TOKENS": False, "BLACKLIST_AFTER_ROTATION": True, diff --git a/backend/switchkeys/management/commands/create_superuser.py b/backend/switchkeys/management/commands/create_superuser.py index 4d8447c..112d9fc 100644 --- a/backend/switchkeys/management/commands/create_superuser.py +++ b/backend/switchkeys/management/commands/create_superuser.py @@ -6,18 +6,13 @@ class Command(BaseCommand): def handle(self, *args, **options): """Use this command only in development mode.""" - superuser_email = os.environ.get('DJANGO_SUPERUSER_EMAIL') - superuser_password = os.environ.get('DJANGO_SUPERUSER_PASSWORD') + superuser_email = os.environ.get("DJANGO_SUPERUSER_EMAIL") + superuser_password = os.environ.get("DJANGO_SUPERUSER_PASSWORD") if not User.objects.filter(email=superuser_email).exists(): User.objects.create_superuser( email=superuser_email, password=superuser_password, ) - print(f'Superuser with email {superuser_email} created.') + print(f"Superuser with email {superuser_email} created.") else: - print(f'Superuser with email {superuser_email} already exists.') - - - - - + print(f"Superuser with email {superuser_email} already exists.") diff --git a/backend/switchkeys/models/environments.py b/backend/switchkeys/models/environments.py index d7fb177..41a5bf4 100644 --- a/backend/switchkeys/models/environments.py +++ b/backend/switchkeys/models/environments.py @@ -5,6 +5,7 @@ from switchkeys.models.management import ProjectEnvironment from django.utils.translation import gettext_lazy as _ + class SwitchKeysFeature(TimeStampedModel): """ Model representing a feature in the SwitchKeys system. @@ -18,6 +19,7 @@ class SwitchKeysFeature(TimeStampedModel): - initial_value (`str`): The initial value of the feature. - is_default (`str`): if the feature is default feature. """ + name = models.CharField(_("Name"), max_length=50) value = models.TextField(_("Value"), max_length=5000) initial_value = models.TextField(_("Initial Value"), max_length=5000) @@ -34,6 +36,8 @@ def __str__(self) -> str: - Format: `{self.name}` """ return f"{self.name}" + + class EnvironmentFeature(TimeStampedModel): """ Model representing features associated with a project environment in the SwitchKeys system. @@ -50,7 +54,7 @@ class EnvironmentFeature(TimeStampedModel): verbose_name=_("Environment"), related_name="feature_environment", on_delete=models.CASCADE, - null=True + null=True, ) features = models.ManyToManyField( @@ -71,6 +75,7 @@ class Meta: verbose_name = _("Environment Feature") verbose_name_plural = _("Environment Features") + class UserFeature(TimeStampedModel): """ Model representing features associated with a user in a project environment. @@ -96,7 +101,7 @@ class UserFeature(TimeStampedModel): related_name="user_feature", on_delete=models.CASCADE, ) - + feature_value = models.TextField( _("Value"), max_length=5000, @@ -114,4 +119,4 @@ def __str__(self) -> str: class Meta: verbose_name = _("User Feature") verbose_name_plural = _("User Features") - unique_together = ("user", "feature") \ No newline at end of file + unique_together = ("user", "feature") diff --git a/backend/switchkeys/serializers/environments.py b/backend/switchkeys/serializers/environments.py index 06ccbfe..abfd78f 100644 --- a/backend/switchkeys/serializers/environments.py +++ b/backend/switchkeys/serializers/environments.py @@ -94,6 +94,7 @@ class AddEnvironmentUserSerializer(Serializer): """ Serializer to add user to an environment. """ + id = SerializerMethodField() device = EnvironmentUserDeviceSerializer() username = CharField() diff --git a/backend/switchkeys/serializers/organizations.py b/backend/switchkeys/serializers/organizations.py index f6ddaf1..957c4a3 100644 --- a/backend/switchkeys/serializers/organizations.py +++ b/backend/switchkeys/serializers/organizations.py @@ -5,7 +5,7 @@ ) from switchkeys.serializers.users import OrganizationUserSerializer -from switchkeys.models.management import Organization, OrganizationProject +from switchkeys.models.management import Organization class OrganizationSerializer(ModelSerializer): diff --git a/backend/switchkeys/serializers/projects.py b/backend/switchkeys/serializers/projects.py index b767342..1473560 100644 --- a/backend/switchkeys/serializers/projects.py +++ b/backend/switchkeys/serializers/projects.py @@ -19,6 +19,7 @@ class Meta: "environment_key", ] + class OrganizationProjectSerializer(ModelSerializer): """ ``Serializer`` for ``Organization project`` . diff --git a/backend/switchkeys/serializers/users.py b/backend/switchkeys/serializers/users.py index 086de35..4f54567 100644 --- a/backend/switchkeys/serializers/users.py +++ b/backend/switchkeys/serializers/users.py @@ -55,6 +55,7 @@ def get_device(self, obj: ProjectEnvironmentUser): def get_features(self, obj: ProjectEnvironmentUser): from switchkeys.serializers.environments import SwitchKeysFeatureSerializer + features = UserFeature.objects.filter(user=obj) serialized_features = [] @@ -63,5 +64,5 @@ def get_features(self, obj: ProjectEnvironmentUser): serialized_features.append( SwitchKeysFeatureSerializer(feature.feature).data ) - + return serialized_features diff --git a/backend/switchkeys/services/environments.py b/backend/switchkeys/services/environments.py index cdc8f6a..b001e67 100644 --- a/backend/switchkeys/services/environments.py +++ b/backend/switchkeys/services/environments.py @@ -117,6 +117,7 @@ def validate_unique_environment_name( return environments.exists() + def is_feature_created(name: str, environment: ProjectEnvironment) -> bool: """ Check if a feature with the given name is created in the specified environment. @@ -133,12 +134,19 @@ def is_feature_created(name: str, environment: ProjectEnvironment) -> bool: True """ - all_features = SwitchKeysFeature.objects.filter(name=name).values_list("id", flat=True) - env_features = EnvironmentFeature.objects.filter(environment=environment, features__id__in=all_features) - + all_features = SwitchKeysFeature.objects.filter(name=name).values_list( + "id", flat=True + ) + env_features = EnvironmentFeature.objects.filter( + environment=environment, features__id__in=all_features + ) + return env_features.exists() -def get_environment_feature(name: str, environment: ProjectEnvironment) -> Optional[EnvironmentFeature]: + +def get_environment_feature( + name: str, environment: ProjectEnvironment +) -> Optional[EnvironmentFeature]: """ Retrieve an environment feature by name and environment. @@ -158,8 +166,10 @@ def get_environment_feature(name: str, environment: ProjectEnvironment) -> Optio # Retrieve all features with the given name all_features = SwitchKeysFeature.objects.filter(name=name) - + # Filter environment features by environment and matching feature IDs - env_features = EnvironmentFeature.objects.get(environment=environment, features__in=all_features) + env_features = EnvironmentFeature.objects.get( + environment=environment, features__in=all_features + ) return env_features diff --git a/backend/switchkeys/services/organizations.py b/backend/switchkeys/services/organizations.py index 195a756..e706fb9 100644 --- a/backend/switchkeys/services/organizations.py +++ b/backend/switchkeys/services/organizations.py @@ -40,6 +40,7 @@ def get_organization_projects(organization_id: str) -> List[OrganizationProject] """Filter all projects and get only the projects that has the same organization ID.""" return OrganizationProject.objects.filter(organization__id=organization_id) + def filter_organization_by_owner(user: User) -> List[Organization]: """ Filter organizations by owner user diff --git a/backend/switchkeys/utils/wrappers.py b/backend/switchkeys/utils/wrappers.py index 7e0032f..ef922b2 100644 --- a/backend/switchkeys/utils/wrappers.py +++ b/backend/switchkeys/utils/wrappers.py @@ -22,12 +22,13 @@ def unique_field_error(field_name: str): """ return { "message": "Please note that you have passed a unique field.", - "fields": { - field_name: "This field is unique" - }, + "fields": {field_name: "This field is unique"}, } -def value_not_accepted_error(field_name: str, user_value: Any, default_value: Any) -> dict: + +def value_not_accepted_error( + field_name: str, user_value: Any, default_value: Any +) -> dict: """ Generate a field value error response for API requests. @@ -54,4 +55,3 @@ def value_not_accepted_error(field_name: str, user_value: Any, default_value: An field_name: f"You have sent '{user_value}' and this field accepts '{default_value}'." }, } - diff --git a/backend/switchkeys/views/environments.py b/backend/switchkeys/views/environments.py index 85243c3..e309946 100644 --- a/backend/switchkeys/views/environments.py +++ b/backend/switchkeys/views/environments.py @@ -28,7 +28,7 @@ from switchkeys.models.users import DeviceType from switchkeys.utils.wrappers import unique_field_error, value_not_accepted_error from switchkeys.services.projects import get_project_by_id -from switchkeys.models.management import OrganizationProject, ProjectEnvironment +from switchkeys.models.management import OrganizationProject from switchkeys.api.custom_response import CustomResponse from switchkeys.services.environments import ( create_environment_user, diff --git a/backend/switchkeys/views/users.py b/backend/switchkeys/views/users.py index b55ca52..3627694 100644 --- a/backend/switchkeys/views/users.py +++ b/backend/switchkeys/views/users.py @@ -3,7 +3,6 @@ from rest_framework.response import Response from switchkeys.api.permissions import ( IsAdminUser, - UserIsAuthenticated, ) from switchkeys.api.custom_response import CustomResponse from switchkeys.serializers.users import OrganizationUserSerializer @@ -51,6 +50,7 @@ def get(self, request: Request, id: str) -> Response: ) return CustomResponse.not_found(message="User not found", status_code=404) + class GetUserByEmailAPIView(GenericAPIView): permission_classes = [] serializer_class = OrganizationUserSerializer diff --git a/backend/views/home.py b/backend/views/home.py index 0fdda20..daf9842 100644 --- a/backend/views/home.py +++ b/backend/views/home.py @@ -2,6 +2,7 @@ from django.http import JsonResponse from components import config + def display_urls(request): """ View function to display all available URL patterns in the Django project.