We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Errors caused by Social Auth Organization and Team Mapping; Users unable to login
### Please confirm the following

- [X] I agree to follow this project's [code of conduct](http://docs.ansible.com/ansible/latest/community/code_of_conduct.html).
- [X] I have checked the [current issues](https://github.com/ansible/awx/issues) for duplicates.
- [X] I understand that AWX is open source software provided for free and that I am not entitled to status updates or other assurances.

### Summary

Attempting to configure Social Organization/Team Mapping prevents social-auth users from logging in.  `awx-web` and postgres show errors.  If ORGANIZATION_MAP and TEAM_MAP are reverted to default/empty, user is able to login.


### AWX version

19.2.2

### Installation method

kubernetes

### Modifications

yes

### Ansible version

_No response_

### Operating system

_No response_

### Web browser

Chrome

### Steps to reproduce

1. Fresh AWX 19.2.2 installation via awx-operator (0.12.0) with `create_preload_data: 'false'`
2.  Log in as Admin; Configure Github Organization OAuth2 Social Auth ( do not configure org/team maps )
```json
{
    "SOCIAL_AUTH_GITHUB_ORG_CALLBACK_URL": "https://my-awx-install.com/sso/complete/github-org/",
    "SOCIAL_AUTH_GITHUB_ORG_KEY": "<redacted>",
    "SOCIAL_AUTH_GITHUB_ORG_SECRET": "$encrypted$",
    "SOCIAL_AUTH_GITHUB_ORG_ORGANIZATION_MAP": null,
    "SOCIAL_AUTH_GITHUB_ORG_TEAM_MAP": null
}
```
3. Validate Step 2 configs by logging in via Github Org Social Auth
4. Log out.

5. Login as Admin; Configure Org/Team Maps (I tried this in both the Global and GitHub Org specific configs)
```json
{
    "SOCIAL_AUTH_GITHUB_ORG_CALLBACK_URL": "https://my-awx-install.com/sso/complete/github-org/",
    "SOCIAL_AUTH_GITHUB_ORG_KEY": "<redacted>",
    "SOCIAL_AUTH_GITHUB_ORG_SECRET": "$encrypted$",
    "SOCIAL_AUTH_GITHUB_ORG_NAME": "MyOrg",
    "SOCIAL_AUTH_GITHUB_ORG_ORGANIZATION_MAP": {
        "MyOrg": {
            "users": [
                "me@example.com"
            ],
            "admins": [
                "admin@example.com"
            ],
            "remove_users": true,
            "remove_admins": true
        }
    },
    "SOCIAL_AUTH_GITHUB_ORG_TEAM_MAP": {
        "operations-team": {
            "remove": true,
            "organization": "MyOrg",
            "users": [
                "me@example.com"
            ]
        }
    }
}
```

6. Attempt to login as user; Get redirected to login page; Observe error awx-web and postgres error logs

### Expected results

Organizations specified by valid Social Auth Org map(s) are created automatically
Teams specified by valid Social Auth Team map(s) are created automatically
Users are able to login as specified by Social Auth Org/Team maps

### Actual results

User was not able to login following Org/Map configuration.  Organization and Teams were not created on our behalf.

`postgres` errors
```bash
2021-08-13 21:39:42.438 UTC [2886] STATEMENT:  INSERT INTO "main_organizationgalaxycredentialmembership" ("organization_id", "credential_id", "position") VALUES (1, NULL, NULL) RETURNING "main_organizationgalaxycredentialmembership"."id"
2021-08-13 21:39:42.438 UTC [2886] ERROR:  null value in column "credential_id" violates not-null constraint
2021-08-13 21:39:42.438 UTC [2886] DETAIL:  Failing row contains (1, null, null, 1).
```

`awx-web` errors
```
2021-08-13 21:39:42,440 ERROR    [c6496ec03db747d3a7800f653acd316b] social null value in column "credential_id" violates not-null constraint
DETAIL:  Failing row contains (1, null, null, 1).
.
```

### Additional information

* Installed via awx-operator with `create_preload_data: false`
* Prior to opening this issue, I've also attempted this against 19.3.0 to no success.

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `awx/main/models/organization.py`
Content:
```
1 # Copyright (c) 2015 Ansible, Inc.
2 # All Rights Reserved.
3 
4 
5 # Django
6 from django.conf import settings
7 from django.db import models
8 from django.contrib.auth.models import User
9 from django.contrib.sessions.models import Session
10 from django.utils.timezone import now as tz_now
11 from django.utils.translation import ugettext_lazy as _
12 
13 
14 # AWX
15 from awx.api.versioning import reverse
16 from awx.main.fields import AutoOneToOneField, ImplicitRoleField, OrderedManyToManyField
17 from awx.main.models.base import BaseModel, CommonModel, CommonModelNameNotUnique, CreatedModifiedModel, NotificationFieldsModel
18 from awx.main.models.rbac import (
19     ROLE_SINGLETON_SYSTEM_ADMINISTRATOR,
20     ROLE_SINGLETON_SYSTEM_AUDITOR,
21 )
22 from awx.main.models.unified_jobs import UnifiedJob
23 from awx.main.models.mixins import ResourceMixin, CustomVirtualEnvMixin, RelatedJobsMixin
24 
25 __all__ = ['Organization', 'Team', 'Profile', 'UserSessionMembership']
26 
27 
28 class Organization(CommonModel, NotificationFieldsModel, ResourceMixin, CustomVirtualEnvMixin, RelatedJobsMixin):
29     """
30     An organization is the basic unit of multi-tenancy divisions
31     """
32 
33     class Meta:
34         app_label = 'main'
35         ordering = ('name',)
36 
37     instance_groups = OrderedManyToManyField('InstanceGroup', blank=True, through='OrganizationInstanceGroupMembership')
38     galaxy_credentials = OrderedManyToManyField(
39         'Credential', blank=True, through='OrganizationGalaxyCredentialMembership', related_name='%(class)s_galaxy_credentials'
40     )
41     max_hosts = models.PositiveIntegerField(
42         blank=True,
43         default=0,
44         help_text=_('Maximum number of hosts allowed to be managed by this organization.'),
45     )
46     notification_templates_approvals = models.ManyToManyField("NotificationTemplate", blank=True, related_name='%(class)s_notification_templates_for_approvals')
47     default_environment = models.ForeignKey(
48         'ExecutionEnvironment',
49         null=True,
50         blank=True,
51         default=None,
52         on_delete=models.SET_NULL,
53         related_name='+',
54         help_text=_('The default execution environment for jobs run by this organization.'),
55     )
56 
57     admin_role = ImplicitRoleField(
58         parent_role='singleton:' + ROLE_SINGLETON_SYSTEM_ADMINISTRATOR,
59     )
60     execute_role = ImplicitRoleField(
61         parent_role='admin_role',
62     )
63     project_admin_role = ImplicitRoleField(
64         parent_role='admin_role',
65     )
66     inventory_admin_role = ImplicitRoleField(
67         parent_role='admin_role',
68     )
69     credential_admin_role = ImplicitRoleField(
70         parent_role='admin_role',
71     )
72     workflow_admin_role = ImplicitRoleField(
73         parent_role='admin_role',
74     )
75     notification_admin_role = ImplicitRoleField(
76         parent_role='admin_role',
77     )
78     job_template_admin_role = ImplicitRoleField(
79         parent_role='admin_role',
80     )
81     execution_environment_admin_role = ImplicitRoleField(
82         parent_role='admin_role',
83     )
84     auditor_role = ImplicitRoleField(
85         parent_role='singleton:' + ROLE_SINGLETON_SYSTEM_AUDITOR,
86     )
87     member_role = ImplicitRoleField(parent_role=['admin_role'])
88     read_role = ImplicitRoleField(
89         parent_role=[
90             'member_role',
91             'auditor_role',
92             'execute_role',
93             'project_admin_role',
94             'inventory_admin_role',
95             'workflow_admin_role',
96             'notification_admin_role',
97             'credential_admin_role',
98             'job_template_admin_role',
99             'approval_role',
100             'execution_environment_admin_role',
101         ],
102     )
103     approval_role = ImplicitRoleField(
104         parent_role='admin_role',
105     )
106 
107     def get_absolute_url(self, request=None):
108         return reverse('api:organization_detail', kwargs={'pk': self.pk}, request=request)
109 
110     '''
111     RelatedJobsMixin
112     '''
113 
114     def _get_related_jobs(self):
115         return UnifiedJob.objects.non_polymorphic().filter(organization=self)
116 
117     def create_default_galaxy_credential(self):
118         from awx.main.models import Credential
119 
120         public_galaxy_credential = Credential.objects.filter(managed=True, name='Ansible Galaxy').first()
121         if public_galaxy_credential not in self.galaxy_credentials.all():
122             self.galaxy_credentials.add(public_galaxy_credential)
123 
124 
125 class OrganizationGalaxyCredentialMembership(models.Model):
126 
127     organization = models.ForeignKey('Organization', on_delete=models.CASCADE)
128     credential = models.ForeignKey('Credential', on_delete=models.CASCADE)
129     position = models.PositiveIntegerField(
130         null=True,
131         default=None,
132         db_index=True,
133     )
134 
135 
136 class Team(CommonModelNameNotUnique, ResourceMixin):
137     """
138     A team is a group of users that work on common projects.
139     """
140 
141     class Meta:
142         app_label = 'main'
143         unique_together = [('organization', 'name')]
144         ordering = ('organization__name', 'name')
145 
146     organization = models.ForeignKey(
147         'Organization',
148         blank=False,
149         null=False,
150         on_delete=models.CASCADE,
151         related_name='teams',
152     )
153     admin_role = ImplicitRoleField(
154         parent_role='organization.admin_role',
155     )
156     member_role = ImplicitRoleField(
157         parent_role='admin_role',
158     )
159     read_role = ImplicitRoleField(
160         parent_role=['organization.auditor_role', 'member_role'],
161     )
162 
163     def get_absolute_url(self, request=None):
164         return reverse('api:team_detail', kwargs={'pk': self.pk}, request=request)
165 
166 
167 class Profile(CreatedModifiedModel):
168     """
169     Profile model related to User object. Currently stores LDAP DN for users
170     loaded from LDAP.
171     """
172 
173     class Meta:
174         app_label = 'main'
175 
176     user = AutoOneToOneField('auth.User', related_name='profile', editable=False, on_delete=models.CASCADE)
177     ldap_dn = models.CharField(
178         max_length=1024,
179         default='',
180     )
181 
182 
183 class UserSessionMembership(BaseModel):
184     """
185     A lookup table for API session membership given user. Note, there is a
186     different session created by channels for websockets using the same
187     underlying model.
188     """
189 
190     class Meta:
191         app_label = 'main'
192 
193     user = models.ForeignKey('auth.User', related_name='+', blank=False, null=False, on_delete=models.CASCADE)
194     session = models.OneToOneField(Session, related_name='+', blank=False, null=False, on_delete=models.CASCADE)
195     created = models.DateTimeField(default=None, editable=False)
196 
197     @staticmethod
198     def get_memberships_over_limit(user_id, now=None):
199         if settings.SESSIONS_PER_USER == -1:
200             return []
201         if now is None:
202             now = tz_now()
203         query_set = UserSessionMembership.objects.select_related('session').filter(user_id=user_id).order_by('-created')
204         non_expire_memberships = [x for x in query_set if x.session.expire_date > now]
205         return non_expire_memberships[settings.SESSIONS_PER_USER :]
206 
207 
208 # Add get_absolute_url method to User model if not present.
209 if not hasattr(User, 'get_absolute_url'):
210 
211     def user_get_absolute_url(user, request=None):
212         return reverse('api:user_detail', kwargs={'pk': user.pk}, request=request)
213 
214     User.add_to_class('get_absolute_url', user_get_absolute_url)
215
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/awx/main/models/organization.py b/awx/main/models/organization.py
--- a/awx/main/models/organization.py
+++ b/awx/main/models/organization.py
@@ -118,7 +118,7 @@
         from awx.main.models import Credential
 
         public_galaxy_credential = Credential.objects.filter(managed=True, name='Ansible Galaxy').first()
-        if public_galaxy_credential not in self.galaxy_credentials.all():
+        if public_galaxy_credential is not None and public_galaxy_credential not in self.galaxy_credentials.all():
             self.galaxy_credentials.add(public_galaxy_credential)

{"golden_diff": "diff --git a/awx/main/models/organization.py b/awx/main/models/organization.py\n--- a/awx/main/models/organization.py\n+++ b/awx/main/models/organization.py\n@@ -118,7 +118,7 @@\n         from awx.main.models import Credential\n \n         public_galaxy_credential = Credential.objects.filter(managed=True, name='Ansible Galaxy').first()\n-        if public_galaxy_credential not in self.galaxy_credentials.all():\n+        if public_galaxy_credential is not None and public_galaxy_credential not in self.galaxy_credentials.all():\n             self.galaxy_credentials.add(public_galaxy_credential)\n", "issue": "Errors caused by Social Auth Organization and Team Mapping; Users unable to login\n### Please confirm the following\r\n\r\n- [X] I agree to follow this project's [code of conduct](http://docs.ansible.com/ansible/latest/community/code_of_conduct.html).\r\n- [X] I have checked the [current issues](https://github.com/ansible/awx/issues) for duplicates.\r\n- [X] I understand that AWX is open source software provided for free and that I am not entitled to status updates or other assurances.\r\n\r\n### Summary\r\n\r\nAttempting to configure Social Organization/Team Mapping prevents social-auth users from logging in.  `awx-web` and postgres show errors.  If ORGANIZATION_MAP and TEAM_MAP are reverted to default/empty, user is able to login.\r\n\r\n\r\n### AWX version\r\n\r\n19.2.2\r\n\r\n### Installation method\r\n\r\nkubernetes\r\n\r\n### Modifications\r\n\r\nyes\r\n\r\n### Ansible version\r\n\r\n_No response_\r\n\r\n### Operating system\r\n\r\n_No response_\r\n\r\n### Web browser\r\n\r\nChrome\r\n\r\n### Steps to reproduce\r\n\r\n1. Fresh AWX 19.2.2 installation via awx-operator (0.12.0) with `create_preload_data: 'false'`\r\n2.  Log in as Admin; Configure Github Organization OAuth2 Social Auth ( do not configure org/team maps )\r\n```json\r\n{\r\n    \"SOCIAL_AUTH_GITHUB_ORG_CALLBACK_URL\": \"https://my-awx-install.com/sso/complete/github-org/\",\r\n    \"SOCIAL_AUTH_GITHUB_ORG_KEY\": \"<redacted>\",\r\n    \"SOCIAL_AUTH_GITHUB_ORG_SECRET\": \"$encrypted$\",\r\n    \"SOCIAL_AUTH_GITHUB_ORG_ORGANIZATION_MAP\": null,\r\n    \"SOCIAL_AUTH_GITHUB_ORG_TEAM_MAP\": null\r\n}\r\n```\r\n3. Validate Step 2 configs by logging in via Github Org Social Auth\r\n4. Log out.\r\n\r\n5. Login as Admin; Configure Org/Team Maps (I tried this in both the Global and GitHub Org specific configs)\r\n```json\r\n{\r\n    \"SOCIAL_AUTH_GITHUB_ORG_CALLBACK_URL\": \"https://my-awx-install.com/sso/complete/github-org/\",\r\n    \"SOCIAL_AUTH_GITHUB_ORG_KEY\": \"<redacted>\",\r\n    \"SOCIAL_AUTH_GITHUB_ORG_SECRET\": \"$encrypted$\",\r\n    \"SOCIAL_AUTH_GITHUB_ORG_NAME\": \"MyOrg\",\r\n    \"SOCIAL_AUTH_GITHUB_ORG_ORGANIZATION_MAP\": {\r\n        \"MyOrg\": {\r\n            \"users\": [\r\n                \"me@example.com\"\r\n            ],\r\n            \"admins\": [\r\n                \"admin@example.com\"\r\n            ],\r\n            \"remove_users\": true,\r\n            \"remove_admins\": true\r\n        }\r\n    },\r\n    \"SOCIAL_AUTH_GITHUB_ORG_TEAM_MAP\": {\r\n        \"operations-team\": {\r\n            \"remove\": true,\r\n            \"organization\": \"MyOrg\",\r\n            \"users\": [\r\n                \"me@example.com\"\r\n            ]\r\n        }\r\n    }\r\n}\r\n```\r\n\r\n6. Attempt to login as user; Get redirected to login page; Observe error awx-web and postgres error logs\r\n\r\n### Expected results\r\n\r\nOrganizations specified by valid Social Auth Org map(s) are created automatically\r\nTeams specified by valid Social Auth Team map(s) are created automatically\r\nUsers are able to login as specified by Social Auth Org/Team maps\r\n\r\n### Actual results\r\n\r\nUser was not able to login following Org/Map configuration.  Organization and Teams were not created on our behalf.\r\n\r\n`postgres` errors\r\n```bash\r\n2021-08-13 21:39:42.438 UTC [2886] STATEMENT:  INSERT INTO \"main_organizationgalaxycredentialmembership\" (\"organization_id\", \"credential_id\", \"position\") VALUES (1, NULL, NULL) RETURNING \"main_organizationgalaxycredentialmembership\".\"id\"\r\n2021-08-13 21:39:42.438 UTC [2886] ERROR:  null value in column \"credential_id\" violates not-null constraint\r\n2021-08-13 21:39:42.438 UTC [2886] DETAIL:  Failing row contains (1, null, null, 1).\r\n```\r\n\r\n`awx-web` errors\r\n```\r\n2021-08-13 21:39:42,440 ERROR    [c6496ec03db747d3a7800f653acd316b] social null value in column \"credential_id\" violates not-null constraint\r\nDETAIL:  Failing row contains (1, null, null, 1).\r\n.\r\n```\r\n\r\n### Additional information\r\n\r\n* Installed via awx-operator with `create_preload_data: false`\r\n* Prior to opening this issue, I've also attempted this against 19.3.0 to no success.\n", "before_files": [{"content": "# Copyright (c) 2015 Ansible, Inc.\n# All Rights Reserved.\n\n\n# Django\nfrom django.conf import settings\nfrom django.db import models\nfrom django.contrib.auth.models import User\nfrom django.contrib.sessions.models import Session\nfrom django.utils.timezone import now as tz_now\nfrom django.utils.translation import ugettext_lazy as _\n\n\n# AWX\nfrom awx.api.versioning import reverse\nfrom awx.main.fields import AutoOneToOneField, ImplicitRoleField, OrderedManyToManyField\nfrom awx.main.models.base import BaseModel, CommonModel, CommonModelNameNotUnique, CreatedModifiedModel, NotificationFieldsModel\nfrom awx.main.models.rbac import (\n    ROLE_SINGLETON_SYSTEM_ADMINISTRATOR,\n    ROLE_SINGLETON_SYSTEM_AUDITOR,\n)\nfrom awx.main.models.unified_jobs import UnifiedJob\nfrom awx.main.models.mixins import ResourceMixin, CustomVirtualEnvMixin, RelatedJobsMixin\n\n__all__ = ['Organization', 'Team', 'Profile', 'UserSessionMembership']\n\n\nclass Organization(CommonModel, NotificationFieldsModel, ResourceMixin, CustomVirtualEnvMixin, RelatedJobsMixin):\n    \"\"\"\n    An organization is the basic unit of multi-tenancy divisions\n    \"\"\"\n\n    class Meta:\n        app_label = 'main'\n        ordering = ('name',)\n\n    instance_groups = OrderedManyToManyField('InstanceGroup', blank=True, through='OrganizationInstanceGroupMembership')\n    galaxy_credentials = OrderedManyToManyField(\n        'Credential', blank=True, through='OrganizationGalaxyCredentialMembership', related_name='%(class)s_galaxy_credentials'\n    )\n    max_hosts = models.PositiveIntegerField(\n        blank=True,\n        default=0,\n        help_text=_('Maximum number of hosts allowed to be managed by this organization.'),\n    )\n    notification_templates_approvals = models.ManyToManyField(\"NotificationTemplate\", blank=True, related_name='%(class)s_notification_templates_for_approvals')\n    default_environment = models.ForeignKey(\n        'ExecutionEnvironment',\n        null=True,\n        blank=True,\n        default=None,\n        on_delete=models.SET_NULL,\n        related_name='+',\n        help_text=_('The default execution environment for jobs run by this organization.'),\n    )\n\n    admin_role = ImplicitRoleField(\n        parent_role='singleton:' + ROLE_SINGLETON_SYSTEM_ADMINISTRATOR,\n    )\n    execute_role = ImplicitRoleField(\n        parent_role='admin_role',\n    )\n    project_admin_role = ImplicitRoleField(\n        parent_role='admin_role',\n    )\n    inventory_admin_role = ImplicitRoleField(\n        parent_role='admin_role',\n    )\n    credential_admin_role = ImplicitRoleField(\n        parent_role='admin_role',\n    )\n    workflow_admin_role = ImplicitRoleField(\n        parent_role='admin_role',\n    )\n    notification_admin_role = ImplicitRoleField(\n        parent_role='admin_role',\n    )\n    job_template_admin_role = ImplicitRoleField(\n        parent_role='admin_role',\n    )\n    execution_environment_admin_role = ImplicitRoleField(\n        parent_role='admin_role',\n    )\n    auditor_role = ImplicitRoleField(\n        parent_role='singleton:' + ROLE_SINGLETON_SYSTEM_AUDITOR,\n    )\n    member_role = ImplicitRoleField(parent_role=['admin_role'])\n    read_role = ImplicitRoleField(\n        parent_role=[\n            'member_role',\n            'auditor_role',\n            'execute_role',\n            'project_admin_role',\n            'inventory_admin_role',\n            'workflow_admin_role',\n            'notification_admin_role',\n            'credential_admin_role',\n            'job_template_admin_role',\n            'approval_role',\n            'execution_environment_admin_role',\n        ],\n    )\n    approval_role = ImplicitRoleField(\n        parent_role='admin_role',\n    )\n\n    def get_absolute_url(self, request=None):\n        return reverse('api:organization_detail', kwargs={'pk': self.pk}, request=request)\n\n    '''\n    RelatedJobsMixin\n    '''\n\n    def _get_related_jobs(self):\n        return UnifiedJob.objects.non_polymorphic().filter(organization=self)\n\n    def create_default_galaxy_credential(self):\n        from awx.main.models import Credential\n\n        public_galaxy_credential = Credential.objects.filter(managed=True, name='Ansible Galaxy').first()\n        if public_galaxy_credential not in self.galaxy_credentials.all():\n            self.galaxy_credentials.add(public_galaxy_credential)\n\n\nclass OrganizationGalaxyCredentialMembership(models.Model):\n\n    organization = models.ForeignKey('Organization', on_delete=models.CASCADE)\n    credential = models.ForeignKey('Credential', on_delete=models.CASCADE)\n    position = models.PositiveIntegerField(\n        null=True,\n        default=None,\n        db_index=True,\n    )\n\n\nclass Team(CommonModelNameNotUnique, ResourceMixin):\n    \"\"\"\n    A team is a group of users that work on common projects.\n    \"\"\"\n\n    class Meta:\n        app_label = 'main'\n        unique_together = [('organization', 'name')]\n        ordering = ('organization__name', 'name')\n\n    organization = models.ForeignKey(\n        'Organization',\n        blank=False,\n        null=False,\n        on_delete=models.CASCADE,\n        related_name='teams',\n    )\n    admin_role = ImplicitRoleField(\n        parent_role='organization.admin_role',\n    )\n    member_role = ImplicitRoleField(\n        parent_role='admin_role',\n    )\n    read_role = ImplicitRoleField(\n        parent_role=['organization.auditor_role', 'member_role'],\n    )\n\n    def get_absolute_url(self, request=None):\n        return reverse('api:team_detail', kwargs={'pk': self.pk}, request=request)\n\n\nclass Profile(CreatedModifiedModel):\n    \"\"\"\n    Profile model related to User object. Currently stores LDAP DN for users\n    loaded from LDAP.\n    \"\"\"\n\n    class Meta:\n        app_label = 'main'\n\n    user = AutoOneToOneField('auth.User', related_name='profile', editable=False, on_delete=models.CASCADE)\n    ldap_dn = models.CharField(\n        max_length=1024,\n        default='',\n    )\n\n\nclass UserSessionMembership(BaseModel):\n    \"\"\"\n    A lookup table for API session membership given user. Note, there is a\n    different session created by channels for websockets using the same\n    underlying model.\n    \"\"\"\n\n    class Meta:\n        app_label = 'main'\n\n    user = models.ForeignKey('auth.User', related_name='+', blank=False, null=False, on_delete=models.CASCADE)\n    session = models.OneToOneField(Session, related_name='+', blank=False, null=False, on_delete=models.CASCADE)\n    created = models.DateTimeField(default=None, editable=False)\n\n    @staticmethod\n    def get_memberships_over_limit(user_id, now=None):\n        if settings.SESSIONS_PER_USER == -1:\n            return []\n        if now is None:\n            now = tz_now()\n        query_set = UserSessionMembership.objects.select_related('session').filter(user_id=user_id).order_by('-created')\n        non_expire_memberships = [x for x in query_set if x.session.expire_date > now]\n        return non_expire_memberships[settings.SESSIONS_PER_USER :]\n\n\n# Add get_absolute_url method to User model if not present.\nif not hasattr(User, 'get_absolute_url'):\n\n    def user_get_absolute_url(user, request=None):\n        return reverse('api:user_detail', kwargs={'pk': user.pk}, request=request)\n\n    User.add_to_class('get_absolute_url', user_get_absolute_url)\n", "path": "awx/main/models/organization.py"}], "after_files": [{"content": "# Copyright (c) 2015 Ansible, Inc.\n# All Rights Reserved.\n\n\n# Django\nfrom django.conf import settings\nfrom django.db import models\nfrom django.contrib.auth.models import User\nfrom django.contrib.sessions.models import Session\nfrom django.utils.timezone import now as tz_now\nfrom django.utils.translation import ugettext_lazy as _\n\n\n# AWX\nfrom awx.api.versioning import reverse\nfrom awx.main.fields import AutoOneToOneField, ImplicitRoleField, OrderedManyToManyField\nfrom awx.main.models.base import BaseModel, CommonModel, CommonModelNameNotUnique, CreatedModifiedModel, NotificationFieldsModel\nfrom awx.main.models.rbac import (\n    ROLE_SINGLETON_SYSTEM_ADMINISTRATOR,\n    ROLE_SINGLETON_SYSTEM_AUDITOR,\n)\nfrom awx.main.models.unified_jobs import UnifiedJob\nfrom awx.main.models.mixins import ResourceMixin, CustomVirtualEnvMixin, RelatedJobsMixin\n\n__all__ = ['Organization', 'Team', 'Profile', 'UserSessionMembership']\n\n\nclass Organization(CommonModel, NotificationFieldsModel, ResourceMixin, CustomVirtualEnvMixin, RelatedJobsMixin):\n    \"\"\"\n    An organization is the basic unit of multi-tenancy divisions\n    \"\"\"\n\n    class Meta:\n        app_label = 'main'\n        ordering = ('name',)\n\n    instance_groups = OrderedManyToManyField('InstanceGroup', blank=True, through='OrganizationInstanceGroupMembership')\n    galaxy_credentials = OrderedManyToManyField(\n        'Credential', blank=True, through='OrganizationGalaxyCredentialMembership', related_name='%(class)s_galaxy_credentials'\n    )\n    max_hosts = models.PositiveIntegerField(\n        blank=True,\n        default=0,\n        help_text=_('Maximum number of hosts allowed to be managed by this organization.'),\n    )\n    notification_templates_approvals = models.ManyToManyField(\"NotificationTemplate\", blank=True, related_name='%(class)s_notification_templates_for_approvals')\n    default_environment = models.ForeignKey(\n        'ExecutionEnvironment',\n        null=True,\n        blank=True,\n        default=None,\n        on_delete=models.SET_NULL,\n        related_name='+',\n        help_text=_('The default execution environment for jobs run by this organization.'),\n    )\n\n    admin_role = ImplicitRoleField(\n        parent_role='singleton:' + ROLE_SINGLETON_SYSTEM_ADMINISTRATOR,\n    )\n    execute_role = ImplicitRoleField(\n        parent_role='admin_role',\n    )\n    project_admin_role = ImplicitRoleField(\n        parent_role='admin_role',\n    )\n    inventory_admin_role = ImplicitRoleField(\n        parent_role='admin_role',\n    )\n    credential_admin_role = ImplicitRoleField(\n        parent_role='admin_role',\n    )\n    workflow_admin_role = ImplicitRoleField(\n        parent_role='admin_role',\n    )\n    notification_admin_role = ImplicitRoleField(\n        parent_role='admin_role',\n    )\n    job_template_admin_role = ImplicitRoleField(\n        parent_role='admin_role',\n    )\n    execution_environment_admin_role = ImplicitRoleField(\n        parent_role='admin_role',\n    )\n    auditor_role = ImplicitRoleField(\n        parent_role='singleton:' + ROLE_SINGLETON_SYSTEM_AUDITOR,\n    )\n    member_role = ImplicitRoleField(parent_role=['admin_role'])\n    read_role = ImplicitRoleField(\n        parent_role=[\n            'member_role',\n            'auditor_role',\n            'execute_role',\n            'project_admin_role',\n            'inventory_admin_role',\n            'workflow_admin_role',\n            'notification_admin_role',\n            'credential_admin_role',\n            'job_template_admin_role',\n            'approval_role',\n            'execution_environment_admin_role',\n        ],\n    )\n    approval_role = ImplicitRoleField(\n        parent_role='admin_role',\n    )\n\n    def get_absolute_url(self, request=None):\n        return reverse('api:organization_detail', kwargs={'pk': self.pk}, request=request)\n\n    '''\n    RelatedJobsMixin\n    '''\n\n    def _get_related_jobs(self):\n        return UnifiedJob.objects.non_polymorphic().filter(organization=self)\n\n    def create_default_galaxy_credential(self):\n        from awx.main.models import Credential\n\n        public_galaxy_credential = Credential.objects.filter(managed=True, name='Ansible Galaxy').first()\n        if public_galaxy_credential is not None and public_galaxy_credential not in self.galaxy_credentials.all():\n            self.galaxy_credentials.add(public_galaxy_credential)\n\n\nclass OrganizationGalaxyCredentialMembership(models.Model):\n\n    organization = models.ForeignKey('Organization', on_delete=models.CASCADE)\n    credential = models.ForeignKey('Credential', on_delete=models.CASCADE)\n    position = models.PositiveIntegerField(\n        null=True,\n        default=None,\n        db_index=True,\n    )\n\n\nclass Team(CommonModelNameNotUnique, ResourceMixin):\n    \"\"\"\n    A team is a group of users that work on common projects.\n    \"\"\"\n\n    class Meta:\n        app_label = 'main'\n        unique_together = [('organization', 'name')]\n        ordering = ('organization__name', 'name')\n\n    organization = models.ForeignKey(\n        'Organization',\n        blank=False,\n        null=False,\n        on_delete=models.CASCADE,\n        related_name='teams',\n    )\n    admin_role = ImplicitRoleField(\n        parent_role='organization.admin_role',\n    )\n    member_role = ImplicitRoleField(\n        parent_role='admin_role',\n    )\n    read_role = ImplicitRoleField(\n        parent_role=['organization.auditor_role', 'member_role'],\n    )\n\n    def get_absolute_url(self, request=None):\n        return reverse('api:team_detail', kwargs={'pk': self.pk}, request=request)\n\n\nclass Profile(CreatedModifiedModel):\n    \"\"\"\n    Profile model related to User object. Currently stores LDAP DN for users\n    loaded from LDAP.\n    \"\"\"\n\n    class Meta:\n        app_label = 'main'\n\n    user = AutoOneToOneField('auth.User', related_name='profile', editable=False, on_delete=models.CASCADE)\n    ldap_dn = models.CharField(\n        max_length=1024,\n        default='',\n    )\n\n\nclass UserSessionMembership(BaseModel):\n    \"\"\"\n    A lookup table for API session membership given user. Note, there is a\n    different session created by channels for websockets using the same\n    underlying model.\n    \"\"\"\n\n    class Meta:\n        app_label = 'main'\n\n    user = models.ForeignKey('auth.User', related_name='+', blank=False, null=False, on_delete=models.CASCADE)\n    session = models.OneToOneField(Session, related_name='+', blank=False, null=False, on_delete=models.CASCADE)\n    created = models.DateTimeField(default=None, editable=False)\n\n    @staticmethod\n    def get_memberships_over_limit(user_id, now=None):\n        if settings.SESSIONS_PER_USER == -1:\n            return []\n        if now is None:\n            now = tz_now()\n        query_set = UserSessionMembership.objects.select_related('session').filter(user_id=user_id).order_by('-created')\n        non_expire_memberships = [x for x in query_set if x.session.expire_date > now]\n        return non_expire_memberships[settings.SESSIONS_PER_USER :]\n\n\n# Add get_absolute_url method to User model if not present.\nif not hasattr(User, 'get_absolute_url'):\n\n    def user_get_absolute_url(user, request=None):\n        return reverse('api:user_detail', kwargs={'pk': user.pk}, request=request)\n\n    User.add_to_class('get_absolute_url', user_get_absolute_url)\n", "path": "awx/main/models/organization.py"}]}