CentreForDigitalHumanities / CentreForDigitalHumanities/langpro-annotator
Missing permission warnings when migrating
- Dominant language
- TypeScript
- Stars
- 0
- Forks
- 0
- Avg merge
- 7d 5h
- Merged PRs (30d)
- 4
Description
If I start with an empty database and try to run [this migration](https://github.com/CentreForDigitalHumanities/langpro-annotator/blob/develop/backend/user/migrations/0004_create_user_groups.py), my console is flooded with warnings such as `ContentType for problem.knowledgebase does not exist. Cannot add permission ('problem', 'add_knowledgebase') to group Master Annotators.`
My guess is that this is because Django only creates the permissions after the migrations have run.
The migrations themselves 'pass' and there is an easy workaround for the now missing permissions: unapply and reapply the migration in question with
```py
python manage.py migrate user 0003
python manage.py migrate
```
Still, it would be nicer to avoid having to do this manual step, especially since the warnings are easily missed.
One solution would be to create the relevant permissions themselves within the migration, i.e. update `create_groups` to:
```py
def create_groups(apps, schema_editor):
"""
Creates user groups for annotators and master annotators and assigns permissions to them.
"""
Group = apps.get_model("auth", "Group")
Permission = apps.get_model("auth", "Permission")
ContentType = apps.get_model("contenttypes", "ContentType")
problem_model_name = apps.get_model("problem", "Problem")._meta.model_name
knowledgebase_model_name = apps.get_model("problem", "KnowledgeBase")._meta.model_name
ContentType.objects.get_or_create(app_label="problem", model=problem_model_name)
ContentType.objects.get_or_create(app_label="problem", model=knowledgebase_model_name)
for group_name, perms in PERMISSION_MAP.items():
group, created = Group.objects.get_or_create(name=group_name.value)
for perm_codename in perms:
app_label, codename = perm_codename
# Determine which model this permission is for
if 'knowledgebase' in codename:
model_name = knowledgebase_model_name
else:
model_name = problem_model_name
try:
content_type = ContentType.objects.get(app_label=app_label, model=model_name)
permission, _ = Permission.objects.get_or_create(
content_type=content_type,
codename=codename,
defaults={'name': f'Can {codename.replace("_", " ")}'},
)
group.permissions.add(permission)
except ContentType.DoesNotExist:
print(
f"ContentType for {app_label}.{model_name} does not exist. Cannot add permission {perm_codename} to group {group_name.value}."
)
except Exception as e:
print(
f"Error adding permission {perm_codename} to group {group_name.value}: {e}"
)
```
This works, but it requires maintenance if we add permissions for more models, for instance. It also feels clunky to create permissions ourselves when Django is about to do that for us.
An alternative would be to use fixtures instead of data migrations. We can store the permission data as JSON and use Django's `loaddata` to populate a new database after migrations have run. This is how we do it in DIAPP, for instance, and I think it works well for this static/initial data that we need to load in.
What do you think @jgonggrijp ?
Contributor guide
Research direction
Read backend/user/migrations/0004_create_user_groups.py, especially create_groups and PERMISSION_MAP, then reproduce the warnings on an empty database with the migration commands described. Done means a fresh migration creates the groups and permissions without missing-permission warnings, without requiring manual unapplication and reapplication.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- authorization, backend, database
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 42/100