Skip to content

5971: added organizations to invitation model#6008

Open
ArthurMousatov wants to merge 7 commits into
learningequality:unstablefrom
ArthurMousatov:add-organizations-to-invitation-model
Open

5971: added organizations to invitation model#6008
ArthurMousatov wants to merge 7 commits into
learningequality:unstablefrom
ArthurMousatov:add-organizations-to-invitation-model

Conversation

@ArthurMousatov

@ArthurMousatov ArthurMousatov commented Jun 29, 2026

Copy link
Copy Markdown

Summary

As detailed in Issue #5971, this PR adds organizations to the invitation model. The saving behavior for organizations is slightly different to channels, as there is a separate model for org roles.

I have also omitted tests in this PR, as this is just a model change and does not affect current code (organizations are fully optional in the invitation). I suggest moving testing to the next implementation step (Organization/Invitation viewsets).

References

Direct PR for Issue #5971.

Reviewer guidance

As part of these changes, migrations were run successfully. I tried running make test, but it ran into 905 failures, mostly related to S3Storage errors. No linting was performed, since no frontend work was done.

AI usage

Only basic VS code autocomplete was used.

@learning-equality-bot

Copy link
Copy Markdown

👋 Hi @ArthurMousatov, thanks for contributing!

For the review process to begin, please verify that the following is satisfied:

  • Contribution is aligned with our contributing guidelines

  • Pull request description has correctly filled AI usage section & follows our AI guidance:

    AI guidance

    State explicitly whether you didn't use or used AI & how.

    If you used it, ensure that the PR is aligned with Using AI as well as our DEEP framework. DEEP asks you:

    • Disclose — Be open about when you've used AI for support.
    • Engage critically — Question what is generated. Review code for correctness and unnecessary complexity.
    • Edit — Review and refine AI output. Remove unnecessary code and verify it still works after your edits.
    • Process sharing — Explain how you used the AI so others can learn.

    Examples of good disclosures:

    "I used Claude Code to implement the component, prompting it to follow the pattern in ComponentX. I reviewed the generated code, removed unnecessary error handling, and verified the tests pass."

    "I brainstormed the approach with Gemini, then had it write failing tests for the feature. After reviewing the tests, I used Claude Code to generate the implementation. I refactored the output to reduce verbosity and ran the full test suite."

Also check that issue requirements are satisfied & you ran pre-commit locally.

Pull requests that don't follow the guidelines will be closed.

Reviewer assignment can take up to 2 weeks.

@learning-equality-bot

Copy link
Copy Markdown

📢✨ Before we assign a reviewer, we'll turn on @rtibblesbot to pre-review. Its comments are generated by an LLM, and should be evaluated accordingly.

@rtibblesbot rtibblesbot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Three blocking issues must be resolved before merge: broken method dispatch in accept(), a two-write invalid-state pattern in _accept_organization_invitation, and missing acceptance-criteria tests. One migration safety concern is flagged as a suggestion. CI was pending at review time.

  • blocking accept() calls non-existent method names — every invitation acceptance raises AttributeError (see inline models.py:3754)
  • blocking _accept_organization_invitation writes an empty-string role on first create(), then overwrites it; unknown share_mode silently persists invalid data; re-acceptance raises IntegrityError (see inline models.py:3767)
  • blocking Acceptance criteria require unit tests for the invitation–organization relationship, the mutual-exclusivity constraint violation case, and the share_mode → org-role mapping — none are present in this PR
  • suggestion AddConstraint in the migration may fail at deployment if any existing rows have channel=NULL (see inline migration:19)
  • praise Splitting accept() into named per-type helpers is a clean refactor — the dispatch logic is now symmetrical and the original comment about the nullable channel field is correctly removed

@rtibblesbot's comments are generated by an LLM, and should be evaluated accordingly

How was this generated?

Ran a phased review pipeline over the pull request diff:

  • Classified the diff to select review passes (core, frontend, backend) and whether manual QA was required
  • Core review pass checked correctness, design, architecture, testing, completeness, and DRY/SRP/Rule-of-Three principles
  • Specialized frontend/backend review passes applied framework-specific lenses where those files changed
  • For UI changes: manual QA and an accessibility audit against a live dev server, when available
  • Checked CI status and linked issue acceptance criteria
  • Synthesized one review from those passes and chose the verdict from the findings, CI status, and QA evidence

Comment thread contentcuration/contentcuration/models.py
Comment thread contentcuration/contentcuration/models.py
Comment thread contentcuration/contentcuration/migrations/0168_auto_20260627_2219.py Outdated
Comment thread contentcuration/contentcuration/migrations/0168_auto_20260627_2219.py Outdated
@rtibbles rtibbles self-assigned this Jun 30, 2026
…thurMousatov/studio into add-organizations-to-invitation-model

@rtibblesbot rtibblesbot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 of 4 prior findings resolved; 3 still open (see below).

  • blocking _accept_organization_invitation unchanged from last round — still writes an empty role, silently drops unknown share_mode, raises IntegrityError on re-accept. See inline comment.
  • blocking The mutual-exclusivity CheckConstraint on Invitation was deleted with no replacement (no Meta.constraints remains; not visible in the diff since it was added and removed within this branch's own history). The maintainer thread called for NOT VALID + separate validate, not removal.
  • blocking This leaves the XOR invariant ("Organizations XOR channels", #5971) enforced nowhere, so the required "invitations with channel & organization set" unit test has nothing to validate against — and no such test was added anyway.
  • nitpick Duplicate imports in the new migration (see inline comment).
Prior-finding status

RESOLVED — models.py:3746 — accept() dispatch to nonexistent method names
UNADDRESSED — models.py:3761 — _accept_organization_invitation two-write invalid-state pattern, silent corruption, IntegrityError on re-acceptance
UNADDRESSED — missing acceptance-criteria unit tests
UNADDRESSED — mutual-exclusivity constraint: previously a deployment-safety suggestion on the AddConstraint, now the constraint has been removed entirely rather than fixed, regressing the acceptance criterion


@rtibblesbot's comments are generated by an LLM, and should be evaluated accordingly

How was this generated?

Ran an automatic code-only delta review triggered by new commits on a previously reviewed PR:

  • Retrieved prior bot reviews via the GitHub API
  • Classified each prior finding as RESOLVED, UNADDRESSED, ACKNOWLEDGED, or CONTESTED
  • Only raised NEW findings for newly introduced code
  • Core review pass only — specialized frontend/backend lenses and manual QA run when a review is explicitly requested
  • Synthesized one review from the passes and chose the verdict from the findings, CI status, and QA evidence

Comment thread contentcuration/contentcuration/models.py

@rtibblesbot rtibblesbot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2 of 5 prior findings resolved; 3 still open (see below). CI passing.

  • [blocking] Mutual-exclusivity constraint between channel and organization still not restored — see inline comment.
  • [blocking] No unit tests added for the invitation–organization relationship, mutual-exclusivity violation, or share_mode→role mapping, despite these being acceptance criteria for #5971.
  • [nitpick] Duplicate imports in migrations/0168_invitation_organization.py (lines 3, 5, 6) — still unresolved from the open thread on this PR.
  • New [suggestion] — see inline comment on the bare ValueError in _accept_organization_invitation.
Prior-finding status

RESOLVED — models.py:3746 — accept() dispatch to nonexistent method names
RESOLVED — models.py:3761 — _accept_organization_invitation two-write invalid-state pattern, silent corruption, IntegrityError on re-acceptance
UNADDRESSED — missing acceptance-criteria unit tests
UNADDRESSED — models.py:3742 — mutual-exclusivity constraint removed entirely, XOR invariant enforced nowhere
UNADDRESSED — migrations/0168_invitation_organization.py:3-6 — duplicate imports


@rtibblesbot's comments are generated by an LLM, and should be evaluated accordingly

How was this generated?

Ran an automatic code-only delta review triggered by new commits on a previously reviewed PR:

  • Retrieved prior bot reviews via the GitHub API
  • Classified each prior finding as RESOLVED, UNADDRESSED, ACKNOWLEDGED, or CONTESTED
  • Only raised NEW findings for newly introduced code
  • Core review pass only — specialized frontend/backend lenses and manual QA run when a review is explicitly requested
  • Synthesized one review from the passes and chose the verdict from the findings, CI status, and QA evidence

Comment thread contentcuration/contentcuration/models.py
Comment thread contentcuration/contentcuration/models.py Outdated

@rtibblesbot rtibblesbot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2 of 6 prior findings resolved.
4 still open, listed below.

  • [blocking] Mutual-exclusivity constraint between channel and organization still missing.
  • [blocking] Missing acceptance-criteria unit tests.
  • [blocking] Invalid-share_mode path still raises an exception DRF won't convert to a 400.
  • [nitpick] Migration still has duplicate imports.
Prior-finding status

RESOLVED — models.py:3746 — accept() dispatch to nonexistent method names
RESOLVED — models.py:3761 — two-write invalid-state pattern / IntegrityError on re-acceptance
UNADDRESSED — models.py:3742 — mutual-exclusivity constraint removed entirely, XOR invariant enforced nowhere
UNADDRESSED — missing acceptance-criteria unit tests
UNADDRESSED — migrations/0168_invitation_organization.py:3-6 — duplicate imports
UNADDRESSED — models.py:3770 — invalid-share_mode error path still won't surface as a clean 400


@rtibblesbot's comments are generated by an LLM, and should be evaluated accordingly

How was this generated?

Ran an automatic code-only delta review triggered by new commits on a previously reviewed PR:

  • Retrieved prior bot reviews via the GitHub API
  • Classified each prior finding as RESOLVED, UNADDRESSED, ACKNOWLEDGED, or CONTESTED
  • Only raised NEW findings for newly introduced code
  • Core review pass only — specialized frontend/backend lenses and manual QA run when a review is explicitly requested
  • Synthesized one review from the passes and chose the verdict from the findings, CI status, and QA evidence

Comment thread contentcuration/contentcuration/models.py
Comment thread contentcuration/contentcuration/models.py

@rtibblesbot rtibblesbot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

3 of 6 prior findings resolved; 3 still open (see below).

CI passing.

  • blockingInvitation.Meta still lacks a mutual-exclusivity guard for channel/organization. See inline comment.
  • blocking — No test for the invitation–organization relationship (organization FK usage in accept()).
  • blocking — No test for the mutual-exclusivity violation case (channel + organization both set).
  • blocking — No test for the share_mode→role mapping in _accept_organization_invitation.
  • blocking — Invalid share_mode still raises a non-DRF ValidationError. See inline comment.
Prior-finding status

RESOLVED — models.py:3746 — accept() dispatch fix
RESOLVED — models.py:3761 — two-write pattern fix
UNADDRESSED — models.py:3742 — mutual-exclusivity constraint missing
UNADDRESSED — missing acceptance-criteria tests
UNADDRESSED — models.py:3770 — non-DRF ValidationError
RESOLVED — migrations/0168_invitation_organization.py:3-6 — duplicate imports


@rtibblesbot's comments are generated by an LLM, and should be evaluated accordingly

How was this generated?

Ran an automatic code-only delta review triggered by new commits on a previously reviewed PR:

  • Retrieved prior bot reviews via the GitHub API
  • Classified each prior finding as RESOLVED, UNADDRESSED, ACKNOWLEDGED, or CONTESTED
  • Only raised NEW findings for newly introduced code
  • Core review pass only — specialized frontend/backend lenses and manual QA run when a review is explicitly requested
  • Synthesized one review from the passes and chose the verdict from the findings, CI status, and QA evidence

Comment thread contentcuration/contentcuration/models.py
Comment thread contentcuration/contentcuration/models.py
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants