FossilRepo

Blame History Raw 179 lines
1
import logging
2
3
from django.contrib.auth.models import Group, Permission, User
4
from django.core.management.base import BaseCommand
5
6
from organization.models import Organization, OrganizationMember, OrgRole, Team
7
from pages.models import Page
8
from projects.models import Project, ProjectTeam
9
10
logger = logging.getLogger(__name__)
11
12
13
class Command(BaseCommand):
14
help = "Seed the database with initial data for development."
15
16
def add_arguments(self, parser):
17
parser.add_argument("--flush", action="store_true", help="Flush non-system tables before seeding.")
18
19
def handle(self, *args, **options):
20
if options["flush"]:
21
self.stdout.write("Flushing data...")
22
Page.all_objects.all().delete()
23
ProjectTeam.all_objects.all().delete()
24
Project.all_objects.all().delete()
25
Team.all_objects.all().delete()
26
OrganizationMember.all_objects.all().delete()
27
Organization.all_objects.all().delete()
28
29
# Groups and permissions
30
admin_group, _ = Group.objects.get_or_create(name="Administrators")
31
viewer_group, _ = Group.objects.get_or_create(name="Viewers")
32
33
# Admin group gets all permissions for org, projects, and pages
34
for app_label in ["organization", "projects", "pages"]:
35
perms = Permission.objects.filter(content_type__app_label=app_label)
36
admin_group.permissions.add(*perms)
37
38
# Viewer group gets view permissions for org, projects, and pages
39
view_perms = Permission.objects.filter(
40
content_type__app_label__in=["organization", "projects", "pages"],
41
codename__startswith="view_",
42
)
43
viewer_group.permissions.set(view_perms)
44
45
# Superuser
46
admin_user, created = User.objects.get_or_create(
47
username="admin",
48
defaults={"email": "[email protected]", "is_staff": True, "is_superuser": True},
49
)
50
if created:
51
admin_user.set_password("admin")
52
admin_user.save()
53
self.stdout.write(self.style.SUCCESS("Created superuser: admin / admin"))
54
55
# Regular user
56
viewer_user, created = User.objects.get_or_create(
57
username="viewer",
58
defaults={"email": "[email protected]", "is_staff": False, "is_superuser": False},
59
)
60
if created:
61
viewer_user.set_password("viewer")
62
viewer_user.save()
63
viewer_user.groups.add(viewer_group)
64
self.stdout.write(self.style.SUCCESS("Created viewer user: viewer / viewer"))
65
66
# Organization
67
org, _ = Organization.objects.get_or_create(name="Fossilrepo HQ", defaults={"description": "Default organization"})
68
OrganizationMember.objects.get_or_create(member=admin_user, organization=org)
69
OrganizationMember.objects.get_or_create(member=viewer_user, organization=org)
70
71
# Teams
72
core_devs, _ = Team.objects.get_or_create(name="Core Devs", defaults={"organization": org, "description": "Core development team"})
73
core_devs.members.add(admin_user)
74
75
contributors, _ = Team.objects.get_or_create(
76
name="Contributors", defaults={"organization": org, "description": "Community contributors"}
77
)
78
contributors.members.add(viewer_user)
79
80
reviewers, _ = Team.objects.get_or_create(name="Reviewers", defaults={"organization": org, "description": "Code review team"})
81
reviewers.members.add(admin_user, viewer_user)
82
83
# Projects
84
projects_data = [
85
{"name": "Frontend App", "description": "User-facing web application", "visibility": "internal"},
86
{"name": "Backend API", "description": "Core API service", "visibility": "private"},
87
{"name": "Documentation", "description": "Project documentation and guides", "visibility": "public"},
88
{"name": "Infrastructure", "description": "Deployment and infrastructure tooling", "visibility": "private"},
89
]
90
for pdata in projects_data:
91
project, _ = Project.objects.get_or_create(
92
name=pdata["name"],
93
defaults={**pdata, "organization": org, "created_by": admin_user},
94
)
95
96
# Team-project assignments
97
frontend = Project.objects.filter(name="Frontend App").first()
98
backend = Project.objects.filter(name="Backend API").first()
99
docs = Project.objects.filter(name="Documentation").first()
100
101
if frontend:
102
ProjectTeam.objects.get_or_create(project=frontend, team=core_devs, defaults={"role": "admin"})
103
ProjectTeam.objects.get_or_create(project=frontend, team=contributors, defaults={"role": "write"})
104
if backend:
105
ProjectTeam.objects.get_or_create(project=backend, team=core_devs, defaults={"role": "admin"})
106
ProjectTeam.objects.get_or_create(project=backend, team=reviewers, defaults={"role": "read"})
107
if docs:
108
ProjectTeam.objects.get_or_create(project=docs, team=contributors, defaults={"role": "write"})
109
ProjectTeam.objects.get_or_create(project=docs, team=reviewers, defaults={"role": "write"})
110
111
# Sample docs pages
112
pages_data = [
113
{
114
"name": "Getting Started",
115
"content": "# Getting Started\n\nWelcome to Fossilrepo. This guide covers initial setup and configuration.\n\n## Prerequisites\n\n- Docker and Docker Compose\n- A domain name (for SSL)\n- S3-compatible storage (for backups)\n\n## Quick Start\n\n1. Clone the repository\n2. Copy `.env.example` to `.env`\n3. Run `fossilrepo-ctl reconfigure`\n4. Run `fossilrepo-ctl start`\n",
116
},
117
{
118
"name": "Admin Guide",
119
"content": "# Admin Guide\n\nThis guide covers day-to-day administration of your Fossilrepo instance.\n\n## Managing Users\n\nUsers can be added through the Django admin or the Settings > Members page.\n\n## Backups\n\nLitestream continuously replicates all `.fossil` files to S3. Manual backups can be created with `fossilrepo-ctl backup create`.\n\n## Monitoring\n\nCheck `/health/` for service status and `/status/` for an overview page.\n",
120
},
121
{
122
"name": "Architecture Overview",
123
"content": "# Architecture Overview\n\n## Stack\n\n| Component | Technology |\n|-----------|------------|\n| Backend | Django 5 + HTMX |\n| Database | PostgreSQL 16 |\n| SCM | Fossil |\n| Proxy | Caddy |\n| Backups | Litestream → S3 |\n| Jobs | Celery + Redis |\n\n## How It Works\n\nEach Fossil repository is a single `.fossil` SQLite file. Caddy routes subdomain requests to the Fossil server. Django provides the management UI. Litestream continuously replicates repo files to S3.\n",
124
},
125
]
126
for pdata in pages_data:
127
Page.objects.get_or_create(
128
name=pdata["name"],
129
defaults={**pdata, "organization": org, "created_by": admin_user},
130
)
131
132
# --- Seed sample users per role ---
133
roles = OrgRole.objects.all()
134
if not roles.exists():
135
from django.core.management import call_command
136
137
call_command("seed_roles")
138
roles = OrgRole.objects.all()
139
140
role_users = {
141
"admin": {"email": "[email protected]", "first_name": "Admin", "last_name": "User"},
142
"manager": {"email": "[email protected]", "first_name": "Manager", "last_name": "User"},
143
"developer": {"email": "[email protected]", "first_name": "Dev", "last_name": "User"},
144
"viewer": {"email": "[email protected]", "first_name": "Viewer", "last_name": "RoleUser"},
145
}
146
147
for role in roles:
148
slug = role.slug
149
if slug not in role_users:
150
continue
151
info = role_users[slug]
152
username = f"role-{slug}"
153
user, created = User.objects.get_or_create(
154
username=username,
155
defaults={
156
"email": info["email"],
157
"first_name": info["first_name"],
158
"last_name": info["last_name"],
159
"is_active": True,
160
},
161
)
162
if created:
163
user.set_password(username)
164
user.save()
165
166
membership, _ = OrganizationMember.objects.get_or_create(
167
member=user,
168
organization=org,
169
defaults={"created_by": admin_user},
170
)
171
if membership.role != role:
172
membership.role = role
173
membership.save()
174
role.apply_to_user(user)
175
176
self.stdout.write(f" User: {username} / {username} (role: {role.name})")
177
178
self.stdout.write(self.style.SUCCESS("Seed complete."))
179

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button