mirror of
https://gitlab.com/bramw/baserow.git
synced 2025-04-16 10:01:05 +00:00
Add management command to load test data
This commit is contained in:
parent
679363191c
commit
1ffcd490c5
7 changed files with 341 additions and 9 deletions
backend/src/baserow
changelog.mddev.shenterprise/backend/src/baserow_enterprise
premium/backend/src/baserow_premium
180
backend/src/baserow/contrib/database/populate.py
Normal file
180
backend/src/baserow/contrib/database/populate.py
Normal file
|
@ -0,0 +1,180 @@
|
||||||
|
from django.contrib.auth import get_user_model
|
||||||
|
from django.db import transaction
|
||||||
|
|
||||||
|
from baserow.contrib.database.fields.models import Field, SelectOption
|
||||||
|
from baserow.contrib.database.models import Database
|
||||||
|
from baserow.contrib.database.rows.handler import RowHandler
|
||||||
|
from baserow.contrib.database.table.handler import TableHandler
|
||||||
|
from baserow.contrib.database.table.models import Table
|
||||||
|
from baserow.core.handler import CoreHandler
|
||||||
|
|
||||||
|
User = get_user_model()
|
||||||
|
|
||||||
|
|
||||||
|
@transaction.atomic
|
||||||
|
def load_test_data():
|
||||||
|
|
||||||
|
print("Add basic data...")
|
||||||
|
|
||||||
|
user = User.objects.get(email="admin@baserow.io")
|
||||||
|
group = user.groupuser_set.get(group__name="Acme Corp").group
|
||||||
|
|
||||||
|
try:
|
||||||
|
database = Database.objects.get(name="Back to local")
|
||||||
|
except Database.DoesNotExist:
|
||||||
|
database = CoreHandler().create_application(
|
||||||
|
user, group, "database", name="Back to local"
|
||||||
|
)
|
||||||
|
|
||||||
|
try:
|
||||||
|
products_table = Table.objects.get(name="Products", database=database)
|
||||||
|
except Table.DoesNotExist:
|
||||||
|
products_table = TableHandler().create_table_and_fields(
|
||||||
|
user,
|
||||||
|
database,
|
||||||
|
name="Products",
|
||||||
|
fields=[
|
||||||
|
("Name", "text", {}),
|
||||||
|
(
|
||||||
|
"Category",
|
||||||
|
"single_select",
|
||||||
|
{},
|
||||||
|
),
|
||||||
|
("Notes", "long_text", {"field_options": {"width": 400}}),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
select_field = Field.objects.get(table=products_table, name="Category")
|
||||||
|
select_by_name = {}
|
||||||
|
|
||||||
|
for order, option in enumerate(
|
||||||
|
[
|
||||||
|
{"color": "dark-green", "value": "Fruit & Vegetable"},
|
||||||
|
{"color": "light-orange", "value": "Dairy"},
|
||||||
|
{"color": "dark-red", "value": "Meat"},
|
||||||
|
{"color": "blue", "value": "Fish"},
|
||||||
|
{"color": "dark-gray", "value": "Bakery"},
|
||||||
|
{"color": "dark-blue", "value": "Beverage"},
|
||||||
|
{"color": "light-green", "value": "Grocery"},
|
||||||
|
]
|
||||||
|
):
|
||||||
|
|
||||||
|
select_option = SelectOption.objects.create(
|
||||||
|
field=select_field,
|
||||||
|
order=order,
|
||||||
|
value=option["value"],
|
||||||
|
color=option["color"],
|
||||||
|
)
|
||||||
|
select_by_name[select_option.value] = select_option.id
|
||||||
|
|
||||||
|
data = [
|
||||||
|
("Bread", select_by_name["Bakery"], ""),
|
||||||
|
("Croissant", select_by_name["Bakery"], ""),
|
||||||
|
("Vine", select_by_name["Beverage"], ""),
|
||||||
|
("Beer", select_by_name["Beverage"], ""),
|
||||||
|
("Milk", select_by_name["Dairy"], ""),
|
||||||
|
("Cheese", select_by_name["Dairy"], ""),
|
||||||
|
("Butter", select_by_name["Dairy"], ""),
|
||||||
|
("Fish", select_by_name["Fish"], ""),
|
||||||
|
("Apple", select_by_name["Fruit & Vegetable"], ""),
|
||||||
|
("Grapes", select_by_name["Fruit & Vegetable"], ""),
|
||||||
|
("Carrot", select_by_name["Fruit & Vegetable"], ""),
|
||||||
|
("Onion", select_by_name["Fruit & Vegetable"], ""),
|
||||||
|
("Flour", select_by_name["Grocery"], ""),
|
||||||
|
("Honey", select_by_name["Grocery"], ""),
|
||||||
|
("Oil", select_by_name["Grocery"], ""),
|
||||||
|
("Pork", select_by_name["Meat"], ""),
|
||||||
|
("Beef", select_by_name["Meat"], ""),
|
||||||
|
("Chicken", select_by_name["Meat"], ""),
|
||||||
|
("Rabbit", select_by_name["Meat"], ""),
|
||||||
|
]
|
||||||
|
|
||||||
|
RowHandler().import_rows(user, products_table, data, send_signal=False)
|
||||||
|
|
||||||
|
try:
|
||||||
|
suppliers_table = Table.objects.get(name="Suppliers", database=database)
|
||||||
|
except Table.DoesNotExist:
|
||||||
|
suppliers_table = TableHandler().create_table_and_fields(
|
||||||
|
user,
|
||||||
|
database,
|
||||||
|
name="Suppliers",
|
||||||
|
fields=[
|
||||||
|
("Name", "text", {}),
|
||||||
|
("Products", "link_row", {"link_row_table": products_table}),
|
||||||
|
("Production", "rating", {}),
|
||||||
|
("Notes", "long_text", {"field_options": {"width": 400}}),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
products = products_table.get_model(attribute_names=True)
|
||||||
|
|
||||||
|
products_by_name = {p.name: p.id for p in products.objects.all()}
|
||||||
|
|
||||||
|
data = [
|
||||||
|
(
|
||||||
|
"The happy cow",
|
||||||
|
[products_by_name["Milk"], products_by_name["Butter"]],
|
||||||
|
3,
|
||||||
|
"",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"Jack's farm",
|
||||||
|
[
|
||||||
|
products_by_name["Carrot"],
|
||||||
|
products_by_name["Onion"],
|
||||||
|
products_by_name["Chicken"],
|
||||||
|
],
|
||||||
|
5,
|
||||||
|
"",
|
||||||
|
),
|
||||||
|
("Horse & crocodile", [products_by_name["Beef"]], 2, ""),
|
||||||
|
(
|
||||||
|
"Vines LTD",
|
||||||
|
[products_by_name["Vine"], products_by_name["Grapes"]],
|
||||||
|
4,
|
||||||
|
"",
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
||||||
|
RowHandler().import_rows(user, suppliers_table, data, send_signal=False)
|
||||||
|
|
||||||
|
try:
|
||||||
|
retailers_table = Table.objects.get(name="Retailers", database=database)
|
||||||
|
except Table.DoesNotExist:
|
||||||
|
retailers_table = TableHandler().create_table_and_fields(
|
||||||
|
user,
|
||||||
|
database,
|
||||||
|
name="Retailers",
|
||||||
|
fields=[
|
||||||
|
("Name", "text", {}),
|
||||||
|
("Suppliers", "link_row", {"link_row_table": suppliers_table}),
|
||||||
|
("Rating", "rating", {}),
|
||||||
|
("Notes", "long_text", {"field_options": {"width": 400}}),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
suppliers = suppliers_table.get_model(attribute_names=True)
|
||||||
|
suppliers_by_name = {p.name: p.id for p in suppliers.objects.all()}
|
||||||
|
|
||||||
|
data = [
|
||||||
|
(
|
||||||
|
"All from the farm",
|
||||||
|
[suppliers_by_name["The happy cow"], suppliers_by_name["Jack's farm"]],
|
||||||
|
3,
|
||||||
|
"",
|
||||||
|
),
|
||||||
|
("My little supermarket", [suppliers_by_name["Vines LTD"]], 1, ""),
|
||||||
|
("Organic4U", [suppliers_by_name["The happy cow"]], 5, ""),
|
||||||
|
(
|
||||||
|
"Ecomarket",
|
||||||
|
[
|
||||||
|
suppliers_by_name["Horse & crocodile"],
|
||||||
|
suppliers_by_name["Jack's farm"],
|
||||||
|
],
|
||||||
|
3,
|
||||||
|
"",
|
||||||
|
),
|
||||||
|
("Welcome to the farm", [suppliers_by_name["The happy cow"]], 4, ""),
|
||||||
|
]
|
||||||
|
|
||||||
|
RowHandler().import_rows(user, retailers_table, data, send_signal=False)
|
|
@ -0,0 +1,56 @@
|
||||||
|
from django.apps import apps
|
||||||
|
from django.conf import settings
|
||||||
|
from django.core.management import CommandError
|
||||||
|
from django.core.management.base import BaseCommand
|
||||||
|
from django.db import transaction
|
||||||
|
from django.utils.module_loading import import_string
|
||||||
|
|
||||||
|
POPULATE_MODULE_NAME = "populate"
|
||||||
|
LOAD_TEST_DATA_NAME = "load_test_data"
|
||||||
|
|
||||||
|
|
||||||
|
class Command(BaseCommand):
|
||||||
|
help = "Populate test data from installed apps"
|
||||||
|
|
||||||
|
def add_arguments(self, parser):
|
||||||
|
parser.add_argument("-d", "--dry-run", action="store_true", help="Dry-run mode")
|
||||||
|
parser.add_argument(
|
||||||
|
"-m",
|
||||||
|
"--modules",
|
||||||
|
action="store",
|
||||||
|
nargs="?",
|
||||||
|
help="Load data for this modules",
|
||||||
|
)
|
||||||
|
|
||||||
|
def handle(self, *args, **options):
|
||||||
|
if not settings.DEBUG:
|
||||||
|
raise CommandError(
|
||||||
|
"This command is not intended to be executed in production."
|
||||||
|
)
|
||||||
|
|
||||||
|
sid = transaction.savepoint()
|
||||||
|
|
||||||
|
for app_name, load_data_fn in self.available_modules().items():
|
||||||
|
with transaction.atomic():
|
||||||
|
self.stdout.write("Loading data for application {}".format(app_name))
|
||||||
|
load_data_fn()
|
||||||
|
|
||||||
|
if options.get("dry_run"):
|
||||||
|
transaction.savepoint_rollback(sid)
|
||||||
|
|
||||||
|
def available_modules(self):
|
||||||
|
available_modules = {}
|
||||||
|
|
||||||
|
for app_name, app_config in apps.app_configs.items():
|
||||||
|
try:
|
||||||
|
available_modules[app_name] = import_string(
|
||||||
|
"{}.{}.{}".format(
|
||||||
|
app_config.module.__package__,
|
||||||
|
POPULATE_MODULE_NAME,
|
||||||
|
LOAD_TEST_DATA_NAME,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
except ImportError:
|
||||||
|
print(f"Application {app_name} has no populate module")
|
||||||
|
|
||||||
|
return available_modules
|
35
backend/src/baserow/core/populate.py
Normal file
35
backend/src/baserow/core/populate.py
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
from django.contrib.auth import get_user_model
|
||||||
|
from django.db import transaction
|
||||||
|
|
||||||
|
from baserow.core.models import GroupUser
|
||||||
|
from baserow.core.user.exceptions import UserAlreadyExist
|
||||||
|
from baserow.core.user.handler import UserHandler
|
||||||
|
|
||||||
|
User = get_user_model()
|
||||||
|
|
||||||
|
|
||||||
|
@transaction.atomic
|
||||||
|
def load_test_data():
|
||||||
|
|
||||||
|
print("Add basic users...")
|
||||||
|
user_handler = UserHandler()
|
||||||
|
try:
|
||||||
|
user = user_handler.create_user("Admin", "admin@baserow.io", "password")
|
||||||
|
except UserAlreadyExist:
|
||||||
|
user = User.objects.get(email="admin@baserow.io")
|
||||||
|
|
||||||
|
user.is_staff = True
|
||||||
|
user.save()
|
||||||
|
|
||||||
|
group = user.groupuser_set.all().order_by("id").first().group
|
||||||
|
group.name = "Acme Corp"
|
||||||
|
group.save()
|
||||||
|
|
||||||
|
try:
|
||||||
|
user = user_handler.create_user("Member", "member@baserow.io", "password")
|
||||||
|
except UserAlreadyExist:
|
||||||
|
user = User.objects.get(email="member@baserow.io")
|
||||||
|
|
||||||
|
GroupUser.objects.update_or_create(
|
||||||
|
group=group, user=user, defaults=dict(permissions="MEMBER", order=1)
|
||||||
|
)
|
|
@ -32,6 +32,7 @@ For example:
|
||||||
* The ordering APIs can now accept a partial list of ids to order only these ids.
|
* The ordering APIs can now accept a partial list of ids to order only these ids.
|
||||||
* Add support for wildcard '*' in the FEATURE_FLAG env variable which enables all features.
|
* Add support for wildcard '*' in the FEATURE_FLAG env variable which enables all features.
|
||||||
* Added more Maths formula functions. [#1183](https://gitlab.com/bramw/baserow/-/issues/1183)
|
* Added more Maths formula functions. [#1183](https://gitlab.com/bramw/baserow/-/issues/1183)
|
||||||
|
* Supports now "docker compose" command in dev.
|
||||||
|
|
||||||
### Bug Fixes
|
### Bug Fixes
|
||||||
* Fixed an issue where you would get an error if you accepted a group invitation with `NO_ACCESS` as you role [#1394](https://gitlab.com/bramw/baserow/-/issues/1394)
|
* Fixed an issue where you would get an error if you accepted a group invitation with `NO_ACCESS` as you role [#1394](https://gitlab.com/bramw/baserow/-/issues/1394)
|
||||||
|
|
24
dev.sh
24
dev.sh
|
@ -18,6 +18,12 @@ print_manual_instructions(){
|
||||||
echo " $COMMAND"
|
echo " $COMMAND"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DOCKER_COMPOSE="docker-compose"
|
||||||
|
|
||||||
|
if docker compose version &> /dev/null; then
|
||||||
|
DOCKER_COMPOSE="docker compose"
|
||||||
|
fi
|
||||||
|
|
||||||
PRINT_WARNING=true
|
PRINT_WARNING=true
|
||||||
new_tab() {
|
new_tab() {
|
||||||
TAB_NAME=$1
|
TAB_NAME=$1
|
||||||
|
@ -60,7 +66,7 @@ new_tab() {
|
||||||
launch_tab_and_attach(){
|
launch_tab_and_attach(){
|
||||||
tab_name=$1
|
tab_name=$1
|
||||||
service_name=$2
|
service_name=$2
|
||||||
container_name=$(docker inspect -f '{{.Name}}' "$(docker-compose -f "$CORE_FILE" "${OVERRIDE_FILE[@]}" ps -q "$service_name")" | cut -c2-)
|
container_name=$(docker inspect -f '{{.Name}}' "$($DOCKER_COMPOSE -f "$CORE_FILE" "${OVERRIDE_FILE[@]}" ps -q "$service_name")" | cut -c2-)
|
||||||
command="docker logs $container_name && docker attach $container_name"
|
command="docker logs $container_name && docker attach $container_name"
|
||||||
if [[ $(docker inspect "$container_name" --format='{{.State.ExitCode}}') -eq 0 ]]; then
|
if [[ $(docker inspect "$container_name" --format='{{.State.ExitCode}}') -eq 0 ]]; then
|
||||||
new_tab "$tab_name" "$command"
|
new_tab "$tab_name" "$command"
|
||||||
|
@ -75,7 +81,7 @@ launch_tab_and_exec(){
|
||||||
tab_name=$1
|
tab_name=$1
|
||||||
service_name=$2
|
service_name=$2
|
||||||
exec_command=$3
|
exec_command=$3
|
||||||
container_name=$(docker inspect -f '{{.Name}}' "$(docker-compose -f "$CORE_FILE" "${OVERRIDE_FILE[@]}" ps -q "$service_name")" | cut -c2-)
|
container_name=$(docker inspect -f '{{.Name}}' "$($DOCKER_COMPOSE -f "$CORE_FILE" "${OVERRIDE_FILE[@]}" ps -q "$service_name")" | cut -c2-)
|
||||||
command="docker exec -it $container_name $exec_command"
|
command="docker exec -it $container_name $exec_command"
|
||||||
new_tab "$tab_name" "$command"
|
new_tab "$tab_name" "$command"
|
||||||
}
|
}
|
||||||
|
@ -381,12 +387,12 @@ set -x
|
||||||
|
|
||||||
if [ "$down" = true ] ; then
|
if [ "$down" = true ] ; then
|
||||||
# Remove the containers and remove the anonymous volumes for cleanliness sake.
|
# Remove the containers and remove the anonymous volumes for cleanliness sake.
|
||||||
docker-compose -f "$CORE_FILE" "${OVERRIDE_FILE[@]}" rm -s -v -f
|
$DOCKER_COMPOSE -f "$CORE_FILE" "${OVERRIDE_FILE[@]}" rm -s -v -f
|
||||||
docker-compose -f "$CORE_FILE" "${OVERRIDE_FILE[@]}" down --remove-orphans
|
$DOCKER_COMPOSE -f "$CORE_FILE" "${OVERRIDE_FILE[@]}" down --remove-orphans
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ "$kill" = true ] ; then
|
if [ "$kill" = true ] ; then
|
||||||
docker-compose -f "$CORE_FILE" "${OVERRIDE_FILE[@]}" kill
|
$DOCKER_COMPOSE -f "$CORE_FILE" "${OVERRIDE_FILE[@]}" kill
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ "$build" = true ] ; then
|
if [ "$build" = true ] ; then
|
||||||
|
@ -397,19 +403,19 @@ if [ "$build" = true ] ; then
|
||||||
done
|
done
|
||||||
fi
|
fi
|
||||||
|
|
||||||
docker-compose -f "$CORE_FILE" "${OVERRIDE_FILE[@]}" build "$@"
|
$DOCKER_COMPOSE -f "$CORE_FILE" "${OVERRIDE_FILE[@]}" build "$@"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ "$delete_volumes" = true ] ; then
|
if [ "$delete_volumes" = true ] ; then
|
||||||
docker-compose -f "$CORE_FILE" "${OVERRIDE_FILE[@]}" down -v
|
$DOCKER_COMPOSE -f "$CORE_FILE" "${OVERRIDE_FILE[@]}" down -v
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ "$up" = true ] ; then
|
if [ "$up" = true ] ; then
|
||||||
docker-compose -f "$CORE_FILE" "${OVERRIDE_FILE[@]}" up -d "$@"
|
$DOCKER_COMPOSE -f "$CORE_FILE" "${OVERRIDE_FILE[@]}" up -d "$@"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ "$run" = true ] ; then
|
if [ "$run" = true ] ; then
|
||||||
docker-compose -f "$CORE_FILE" "${OVERRIDE_FILE[@]}" run "$@"
|
$DOCKER_COMPOSE -f "$CORE_FILE" "${OVERRIDE_FILE[@]}" run "$@"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
set +x
|
set +x
|
||||||
|
|
27
enterprise/backend/src/baserow_enterprise/populate.py
Normal file
27
enterprise/backend/src/baserow_enterprise/populate.py
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
from django.contrib.auth import get_user_model
|
||||||
|
|
||||||
|
from baserow.core.models import GroupUser
|
||||||
|
from baserow.core.user.exceptions import UserAlreadyExist
|
||||||
|
from baserow.core.user.handler import UserHandler
|
||||||
|
from baserow_enterprise.role.default_roles import default_roles
|
||||||
|
|
||||||
|
User = get_user_model()
|
||||||
|
|
||||||
|
|
||||||
|
def load_test_data():
|
||||||
|
|
||||||
|
# Get the user created in the main module
|
||||||
|
user = User.objects.get(email="admin@baserow.io")
|
||||||
|
group = user.groupuser_set.get(group__name="Acme Corp").group
|
||||||
|
|
||||||
|
print("Add one user per existing role in the same group as admin")
|
||||||
|
for i, r in enumerate(default_roles.keys()):
|
||||||
|
rl = r.lower()
|
||||||
|
try:
|
||||||
|
user = UserHandler().create_user(rl, f"{rl}@baserow.io", "password")
|
||||||
|
except UserAlreadyExist:
|
||||||
|
user = User.objects.get(email=f"{rl}@baserow.io")
|
||||||
|
|
||||||
|
GroupUser.objects.update_or_create(
|
||||||
|
group=group, user=user, defaults=dict(permissions=r, order=i + 1)
|
||||||
|
)
|
27
premium/backend/src/baserow_premium/populate.py
Normal file
27
premium/backend/src/baserow_premium/populate.py
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
from baserow_premium.license.models import License
|
||||||
|
|
||||||
|
from baserow.core.models import Settings
|
||||||
|
|
||||||
|
LICENSE = (
|
||||||
|
"eyJ2ZXJzaW9uIjogMSwgImlkIjogIjUzODczYmVkLWJlNTQtNDEwZS04N2EzLTE2OTM2"
|
||||||
|
"ODY2YjBiNiIsICJ2YWxpZF9mcm9tIjogIjIwMjItMTAtMDFUMDA6MDA6MDAiLCAidmFsaWRfdGhy"
|
||||||
|
"b3VnaCI6ICIyMDY5LTA4LTA5VDIzOjU5OjU5IiwgInByb2R1Y3RfY29kZSI6ICJlbnRlcnByaXNlI"
|
||||||
|
"iwgInNlYXRzIjogMSwgImlzc3VlZF9vbiI6ICIyMDIyLTEwLTI2VDE0OjQ4OjU0LjI1OTQyMyIsIC"
|
||||||
|
"Jpc3N1ZWRfdG9fZW1haWwiOiAidGVzdEB0ZXN0LmNvbSIsICJpc3N1ZWRfdG9fbmFtZSI6ICJ0ZX"
|
||||||
|
"N0QHRlc3QuY29tIiwgImluc3RhbmNlX2lkIjogIjEifQ==.B7aPXR0R4Fxr28AL7B5oopa2Yiz_M"
|
||||||
|
"mEBZGdzSEHHLt4wECpnzjd_SF440KNLEZYA6WL1rhNkZ5znbjYIp6KdCqLdcm1XqNYOIKQvNTOtl"
|
||||||
|
"9tUAYj_Qvhq1jhqSja-n3HFBjIh9Ve7a6T1PuaPLF1DoxSRGFZFXliMeJRBSzfTsiHiO22xRQ4Gw"
|
||||||
|
"afscYfUIWvIJJHGHtYEd9rk0tG6mfGEaQGB4e6KOsN-zw-bgLDBOKmKTGrVOkZnaGHBVVhUdpBn25"
|
||||||
|
"r3CFWqHIApzUCo81zAA96fECHPlx_fBHhvIJXLsN5i3LdeJlwysg5SBO15Vt-tsdPmdcsec-fOzi"
|
||||||
|
"k-k3ib0A=="
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def load_test_data():
|
||||||
|
|
||||||
|
Settings.objects.update(instance_id="1")
|
||||||
|
|
||||||
|
License.objects.get_or_create(
|
||||||
|
license=LICENSE,
|
||||||
|
cached_untrusted_instance_wide=True,
|
||||||
|
)
|
Loading…
Add table
Reference in a new issue