-
Notifications
You must be signed in to change notification settings - Fork 0
Tech officer tools #21
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
base: uat
Are you sure you want to change the base?
Changes from all commits
c2875c4
476bb16
dd409f1
6d08c6d
a0a6a6d
b649e75
b91d748
8f4eb47
42b2e00
622692c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,19 @@ | ||
| # Generated by Django 5.2.9 on 2026-03-20 08:41 | ||
|
|
||
| from django.db import migrations, models | ||
|
|
||
|
|
||
| class Migration(migrations.Migration): | ||
|
|
||
| dependencies = [ | ||
| ('auth', '0012_alter_user_first_name_max_length'), | ||
| ('processes', '0001_initial'), | ||
| ] | ||
|
|
||
| operations = [ | ||
| migrations.AddField( | ||
| model_name='authorisationprocess', | ||
| name='reviewer_groups', | ||
| field=models.ManyToManyField(blank=True, help_text='Reviewer groups responsible for this authorisation process.', related_name='+', to='auth.group'), | ||
| ), | ||
| ] |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -50,6 +50,14 @@ class Questionnaire(models.Model): | |
| on_delete=models.PROTECT, | ||
| editable=False, | ||
| ) | ||
| members = models.ManyToManyField( | ||
| "users.User", | ||
| through="QuestionnaireMembership", | ||
| related_name="+", | ||
| blank=True, | ||
| null=True, | ||
| help_text="Users who participate in managing (or reporting) this questionnaire.", | ||
| ) | ||
|
|
||
| class Meta: | ||
| ordering = ( | ||
|
|
@@ -70,6 +78,76 @@ def __str__(self): | |
| return f'Questionnaire "{self.name}" (v{self.version}) for {self.process.slug}' | ||
|
|
||
|
|
||
| class QuestionnairePermission(models.Model): | ||
| """ | ||
| Declarative permissions for questionnaire membership. | ||
|
|
||
| - codename: stable machine-readable identifier (used in code checks) | ||
| - name: human-friendly label shown in the Django admin | ||
| - description: free text explaining what this permission allows | ||
| """ | ||
|
|
||
| id = models.BigAutoField(primary_key=True) | ||
|
Comment on lines
+81
to
+90
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Bug: The new models Suggested FixGenerate the missing migrations by running Prompt for AI Agent |
||
| codename = models.SlugField( | ||
| max_length=100, | ||
| unique=True, | ||
| help_text="Machine-readable permission identifier, e.g. 'view_applications'.", | ||
| ) | ||
| name = models.CharField(max_length=255, help_text="Human readable permission name.") | ||
| description = models.TextField( | ||
| blank=True, default="", help_text="Optional description/help text." | ||
| ) | ||
| created_at = models.DateTimeField(auto_now_add=True) | ||
| updated_at = models.DateTimeField(auto_now=True) | ||
|
|
||
| class Meta: | ||
| ordering = ("codename",) | ||
| verbose_name = "Questionnaire permission" | ||
| verbose_name_plural = "Questionnaire permissions" | ||
|
|
||
| def __str__(self): | ||
| return f"{self.name} ({self.codename})" | ||
|
|
||
|
|
||
| class QuestionnaireMembership(models.Model): | ||
| """ | ||
| Through model for Questionnaire.members -> users.User. | ||
|
|
||
| Stores role permissions and other metadata about the member relationship. | ||
| """ | ||
|
|
||
| id = models.BigAutoField(primary_key=True) | ||
| questionnaire = models.ForeignKey( | ||
| Questionnaire, | ||
| on_delete=models.CASCADE, | ||
| related_name="+", | ||
| ) | ||
| user = models.ForeignKey( | ||
| "users.User", | ||
| on_delete=models.CASCADE, | ||
| related_name="+", | ||
| ) | ||
| permissions = models.ManyToManyField( | ||
| QuestionnairePermission, | ||
| blank=False, | ||
| null=False, | ||
| related_name="+", | ||
| help_text="Permissions assigned to this user for this questionnaire.", | ||
| ) | ||
|
|
||
| created_at = models.DateTimeField(auto_now_add=True) | ||
| updated_at = models.DateTimeField(auto_now=True) | ||
|
|
||
| class Meta: | ||
| # ensure a user has at most one membership row per questionnaire | ||
| unique_together = ("questionnaire", "user") | ||
| ordering = ("-created_at",) | ||
|
|
||
| def __str__(self): | ||
| # avoid referring to a non-existing role field; show a concise summary | ||
| return f"{self.user} member for {self.questionnaire}" | ||
|
|
||
|
|
||
| class QuestionnaireSerialiser(JsonSchemaSerialiserMixin, serializers.ModelSerializer): | ||
| """Serializer for the Questionnaire model. | ||
| nb: putting this into serialisers.py will cause circular import issue | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Bug: The
QuestionnaireMembershipAdminsearch_fieldsreferencesquestionnaire__slug, but theslugfield is removed from theQuestionnairemodel in a later migration, which will cause aFieldError.Severity: HIGH
Suggested Fix
Remove the
'questionnaire__slug'entry from thesearch_fieldstuple in theQuestionnaireMembershipAdminclass located inbackend/questionnaires/admin.py. Replace it with a valid field from theQuestionnairemodel if search functionality on a related field is still desired.Prompt for AI Agent
Did we get this right? 👍 / 👎 to inform future reviews.