Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

setuptools.setup(
name="squarelet_auth", # Replace with your own username
version="0.1.10",
version="0.1.14",
author="Mitchell Kotler",
author_email="mitch@muckrock.com",
description="Django authentication against the MuckRock user service",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
# Generated by Django 4.2 on 2025-12-22 16:09

from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion


class Migration(migrations.Migration):

dependencies = [
("squarelet_auth_organizations", "0009_organization_merged"),
]

operations = [
migrations.AddField(
model_name="organization",
name="members",
field=models.ManyToManyField(
blank=True,
help_text="Organizations which are members of this organization (useful for trade associations or other member groups)",
related_name="groups",
to=settings.SQUARELET_ORGANIZATION_MODEL,
),
),
migrations.AddField(
model_name="organization",
name="parent",
field=models.ForeignKey(
blank=True,
help_text="The parent organization",
null=True,
on_delete=django.db.models.deletion.PROTECT,
related_name="children",
to=settings.SQUARELET_ORGANIZATION_MODEL,
verbose_name="parent",
),
),
migrations.AddField(
model_name="organization",
name="share_resources",
field=models.BooleanField(
default=True,
help_text="Share resources (subscriptions, credits) with all children and member organizations. Global toggle that applies to all relationships.",
verbose_name="share resources",
),
),
migrations.AlterField(
model_name="organization",
name="merged",
field=models.ForeignKey(
blank=True,
help_text="The organization this organization was merged in to",
null=True,
on_delete=django.db.models.deletion.PROTECT,
related_name="+",
to=settings.SQUARELET_ORGANIZATION_MODEL,
),
),
]
57 changes: 57 additions & 0 deletions squarelet_auth/organizations/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,34 @@ class AbstractOrganization(models.Model):
null=True,
)

members = models.ManyToManyField(
to="self",
related_name="groups",
help_text=_(
"Organizations which are members of this organization "
"(useful for trade associations or other member groups)"
),
blank=True,
symmetrical=False,
)
parent = models.ForeignKey(
verbose_name=_("parent"),
to="self",
on_delete=models.PROTECT,
related_name="children",
help_text=_("The parent organization"),
blank=True,
null=True,
)
share_resources = models.BooleanField(
_("share resources"),
default=True,
help_text=_(
"Share resources (subscriptions, credits) with all children and member "
"organizations. Global toggle that applies to all relationships."
),
)

class Meta:
ordering = ("slug",)
abstract = True
Expand Down Expand Up @@ -195,6 +223,7 @@ def has_admin(self, user):

def update_data(self, data):
"""Set updated data from squarelet"""
from squarelet_auth.organizations.utils import squarelet_update_or_create

if data.get("merged") and not self.merged:
self.merge(data["merged"])
Expand Down Expand Up @@ -224,6 +253,12 @@ def update_data(self, data):

self._update_resources(data, date_update)

# set relationships
if data.get("parent"):
self.parent, _ = squarelet_update_or_create(
data["parent"]["uuid"], data["parent"]
)

Copy link
Member

@allanlasser allanlasser Jan 6, 2026

Choose a reason for hiding this comment

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

In this case, can we expect an Organization to have already been created in the local DB for each parent/group? I don't see the same pull_data logic as in muckrock/muckrock.

# update the remaining fields
fields = [
"name",
Expand All @@ -234,12 +269,21 @@ def update_data(self, data):
"payment_failed",
"avatar_url",
"verified_journalist",
"share_resources",
]
for field in fields:
if field in data:
setattr(self, field, data[field])
self.save()

# set group memberships after saving (requires pk)
if data.get("groups"):
groups = []
for group_data in data["groups"]:
group, _ = squarelet_update_or_create(group_data["uuid"], group_data)
groups.append(group)
self.groups.set(groups)

def _update_resources(self, data, date_update):
"""Allows subclasses to override to update their resources"""

Expand All @@ -253,6 +297,19 @@ def merge(self, uuid):
self.memberships.exclude(user__in=other.users.all()).update(organization=other)
self.memberships.all().delete()

# transfer children to the other organization
self.children.update(parent=other)

# transfer group memberships
groups = self.groups.all()
other.groups.add(*groups)
self.groups.clear()

# transfer members
members = self.members.all()
other.members.add(*members)
self.members.clear()

self.merged = other

def _choose_entitlement(self, entitlements):
Expand Down