-
-
Notifications
You must be signed in to change notification settings - Fork 633
Add module ordering #3101
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
Add module ordering #3101
Changes from all commits
974606d
78deaad
b894ff0
1201196
7126cc3
b122bda
5b12a84
61cbab6
b4f248e
f4d820d
52513af
0308438
6924205
038ff3d
a18f2e0
0882712
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 |
|---|---|---|
|
|
@@ -12,8 +12,10 @@ | |
| from apps.mentorship.api.internal.nodes.module import ( | ||
| CreateModuleInput, | ||
| ModuleNode, | ||
| SetModuleOrderInput, | ||
| UpdateModuleInput, | ||
| ) | ||
| from apps.mentorship.api.internal.nodes.program import ProgramNode | ||
| from apps.mentorship.models import Mentor, Module, Program | ||
| from apps.mentorship.models.issue_user_interest import IssueUserInterest | ||
| from apps.mentorship.models.task import Task | ||
|
|
@@ -75,9 +77,10 @@ def create_module(self, info: strawberry.Info, input_data: CreateModuleInput) -> | |
| user = info.context.request.user | ||
|
|
||
| try: | ||
| program = Program.objects.get(key=input_data.program_key) | ||
| program = Program.objects.select_for_update().get(key=input_data.program_key) | ||
| project = Project.objects.get(id=input_data.project_id) | ||
| creator_as_mentor = Mentor.objects.get(nest_user=user) | ||
| new_position = program.modules.count() | ||
| except (Program.DoesNotExist, Project.DoesNotExist) as e: | ||
| msg = f"{e.__class__.__name__} matching query does not exist." | ||
| raise ObjectDoesNotExist(msg) from e | ||
|
|
@@ -106,6 +109,7 @@ def create_module(self, info: strawberry.Info, input_data: CreateModuleInput) -> | |
| tags=input_data.tags, | ||
| program=program, | ||
| project=project, | ||
| position=new_position, | ||
| ) | ||
|
|
||
| if module.experience_level not in program.experience_levels: | ||
|
|
@@ -397,5 +401,60 @@ def update_module(self, info: strawberry.Info, input_data: UpdateModuleInput) -> | |
| module.program.experience_levels.remove(old_experience_level) | ||
|
|
||
| module.program.save(update_fields=["experience_levels"]) | ||
|
|
||
| return module | ||
|
|
||
| @strawberry.mutation(permission_classes=[IsAuthenticated]) | ||
| @transaction.atomic | ||
| def set_module_order( | ||
| self, info: strawberry.Info, input_data: SetModuleOrderInput | ||
| ) -> ProgramNode: | ||
| """Set the order of modules within a program. User must be an admin of the program.""" | ||
| user = info.context.request.user | ||
| try: | ||
| program = Program.objects.select_for_update().get(key=input_data.program_key) | ||
| except Program.DoesNotExist as e: | ||
| msg = f"Program with key '{input_data.program_key}' not found." | ||
| raise ObjectDoesNotExist(msg) from e | ||
|
|
||
| try: | ||
| admin = Mentor.objects.get(nest_user=user) | ||
| except Mentor.DoesNotExist as err: | ||
| msg = "You must be a mentor to update a program." | ||
|
Collaborator
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. @kart-u this check is incorrect. The basic structure is like this:
So admin does not have to be a mentor to update a program. But they have to be an admin of the program. Like the check you have below on L430-437.
Contributor
Author
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. hello @kasya I took inspiration from this to decide the permissions. If the permissions should be as you specified above, should I change it accordingly?
Collaborator
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. @kart-u the permissions should be as I described above, yes. They were not set correctly initially when this project was setup and was something we missed. As for your second point - kinda the same thing :) I'm working on updating that right now. Admins should not be a subset of mentors. I understand this blocks you from continuing work on this task. I'll try to push updates asap.
Contributor
Author
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. Hello @kasya
Collaborator
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. @kart-u thank you, but I'm already working on it 👍🏼 Don't worry about the deadline. I know I'm blocking you right now and this will not affect you. |
||
| logger.warning( | ||
| "User '%s' is not a mentor and cannot update programs.", | ||
| user.username, | ||
| exc_info=True, | ||
| ) | ||
| raise PermissionDenied(msg) from err | ||
|
|
||
| if not program.admins.filter(id=admin.id).exists(): | ||
| msg = "You must be an admin of this program to update it." | ||
| logger.warning( | ||
| "Permission denied for user '%s' to update program '%s'.", | ||
| user.username, | ||
| program.key, | ||
| ) | ||
| raise PermissionDenied(msg) | ||
|
|
||
| existing_modules = Module.objects.filter(program=program) | ||
| existing_module_keys = {m.key for m in existing_modules} | ||
|
|
||
| if len(input_data.module_keys) != len(set(input_data.module_keys)): | ||
| raise ValidationError(message="Duplicate module keys are not allowed in the ordering.") | ||
|
|
||
| if set(input_data.module_keys) != existing_module_keys: | ||
| raise ValidationError( | ||
| message="All modules in the program must be included in the ordering." | ||
| ) | ||
|
|
||
| modules_by_key = {m.key: m for m in existing_modules} | ||
| modules_to_update = [] | ||
|
|
||
| for index, module_key in enumerate(input_data.module_keys): | ||
| module = modules_by_key[module_key] | ||
| module.position = index | ||
| modules_to_update.append(module) | ||
|
|
||
| Module.objects.bulk_update(modules_to_update, ["position"]) | ||
|
kart-u marked this conversation as resolved.
|
||
|
|
||
| return program | ||
|
Collaborator
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.
Contributor
Author
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. I have added a custom db volume in commit 0882712 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| # Generated by Django 6.0 on 2025-12-29 08:41 | ||
|
|
||
| from django.db import migrations, models | ||
|
|
||
|
|
||
| class Migration(migrations.Migration): | ||
| dependencies = [ | ||
| ("mentorship", "0006_alter_menteemodule_ended_at"), | ||
| ] | ||
|
|
||
| operations = [ | ||
| migrations.AddField( | ||
| model_name="module", | ||
| name="position", | ||
| field=models.IntegerField(default=0, verbose_name="Position"), | ||
| ), | ||
| ] |
Uh oh!
There was an error while loading. Please reload this page.