Skip to content
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

feat: Add validation to prevent spaces in App name input #397

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions backend/pytest.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
[pytest]
DJANGO_SETTINGS_MODULE = test_project.settings
python_files = test_*.py
addopts = -v --durations=0
9 changes: 9 additions & 0 deletions backend/src/zango/apps/dynamic_models/workspace/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ def __init__(self, wobj: object, request=None, as_systemuser=False) -> None:
self.modules = self.get_ws_modules()
self.packages = self.get_packages()
self.models = [] # sorted with bfs
self._module_paths_cache = None # cache

@classmethod
def get_plugin_source(cls):
Expand Down Expand Up @@ -113,6 +114,11 @@ def get_all_module_paths(self) -> list[str]:
"""
returns path of all ws modules as well as package modules
"""

# Return cached result if available
if self._module_paths_cache is not None:
return self._module_paths_cache

modules = []
ws_tree = self.get_wtree()
bfs = ws_tree.bfs()
Expand All @@ -127,6 +133,9 @@ def get_all_module_paths(self) -> list[str]:
path = self.path + item["path"]
if path not in modules:
modules.append(path)

# Cache the result
self._module_paths_cache = modules
return modules

def get_models(self) -> list[str]:
Expand Down
17 changes: 17 additions & 0 deletions backend/src/zango/test/timing_runner.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import time
from django.test.runner import DiscoverRunner

class TimingDiscoverRunner(DiscoverRunner):
def get_resultclass(self):
return TimingTextTestResult

class TimingTextTestResult(DiscoverRunner.test_runner().resultclass):
def startTest(self, test):
self._started_at = time.time()
super().startTest(test)

def addSuccess(self, test):
elapsed = time.time() - self._started_at
name = self.getDescription(test)
self.stream.writeln(f"\n{name} ... ok ({elapsed:.3f}s)")
super().addSuccess(test)
4 changes: 4 additions & 0 deletions backend/test_project/test_project/pytest.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
[pytest]
DJANGO_SETTINGS_MODULE = test_project.settings
python_files = test_*.py *_test.py *_tests.py
testpaths = tests
50 changes: 50 additions & 0 deletions backend/test_project/test_project/settings.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
from pathlib import Path

from zango.config.settings.base import * # noqa: F403


BASE_DIR = Path(__file__).resolve().parent.parent

environ.Env.read_env(os.path.join(BASE_DIR, ".env"))


class AttrDict(dict):
"""
A dictionary subclass for managing global settings with attribute-style access.

This class allows getting and setting items in the global namespace
using both attribute and item notation.
"""

def __getattr__(self, item):
return globals()[item]

def __setattr__(self, item, value):
globals()[item] = value

def __setitem__(self, key, value):
globals()[key] = value


# Call setup_settings to initialize the settings
settings_result = setup_settings(AttrDict(vars()), BASE_DIR)

# Setting Overrides
# Any settings that need to be overridden or added should be done below this line
# to ensure they take effect after the initial setup

SECRET_KEY = "django-insecure-3uvu-m1-#a7sm8f#nr@p@&e6t70^q67uzfz^rmn7nyd*8)jc*4" # pragma: allowlist secret
TEST_MIGRATION_RUNNING = True
PROJECT_NAME = "test_project"
TEST_RUNNER = 'zango.test.timing_runner.TimingDiscoverRunner'

# To change the media storage to S3 you can use the BACKEND class provided by the default storage
# To change the static storage to S3 you can use the BACKEND class provided by the staticfiles storage
# STORAGES = {
# "default": {"BACKEND": "zango.core.storage_utils.S3MediaStorage"},
# "staticfiles": {"BACKEND": "zango.core.storage_utils.S3StaticStorage"},
# }


# INTERNAL_IPS can contain a list of IP addresses or CIDR blocks that are considered internal.
# Both individual IP addresses and CIDR notation (e.g., '192.168.1.1' or '192.168.1.0/24') can be provided.
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,11 @@ const LaunchNewAppForm = ({ closeModal }) => {
};

let validationSchema = Yup.object({
name: Yup.string().required('Required'),
name: Yup.string()
.required('Required')
.test('no-spaces',
'App name cannot contain spaces',
value => !/\s/.test(value)),
description: Yup.string().required('Required'),
});

Expand Down
31 changes: 31 additions & 0 deletions runtests.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#!/bin/bash

set -e

# Colorful output.
function greenprint {
echo -e "\033[1;32m[$(date -Isecond)] ${1}\033[0m"
}


DATABASE=${DATABASE_HOST:-localhost}
DATABASE_PORT=${DATABASE_PORT:-5432}

echo "Database: $DATABASE"

while ! nc -v -w 1 "$DATABASE" "$DATABASE_PORT" > /dev/null 2>&1 < /dev/null; do
i=`expr $i + 1`
if [ $i -ge 50 ]; then
echo "$(date) - $DATABASE:$DATABASE_PORT still not reachable, giving up"
exit 1
fi
echo "$(date) - waiting for $DATABASE:$DATABASE_PORT..."
sleep 1
done
echo "postgres connection established"

pushd backend/test_project


# PYTHOWARNINGS=d coverage run manage.py test -v2 zango --timing
PYTHOWARNINGS=d coverage run manage.py test -v2 zango