Skip to content
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

Settings org 2 #5285

Merged
merged 50 commits into from
Oct 23, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
1c7ff31
New Model:
androolloyd Aug 16, 2019
4e3eabb
Merge branch 'master' of github.com:gitcoinco/web into feature/bounty…
androolloyd Aug 16, 2019
db6cedb
Merge branch 'master' of github.com:gitcoinco/web into feature/bounty…
androolloyd Aug 23, 2019
e5fc617
sync_profile helper
androolloyd Aug 23, 2019
ddc28c2
Fix for edge case where users wont have their orgs cleared correctly,…
androolloyd Aug 24, 2019
8bde246
Reconiliation Updated
androolloyd Aug 26, 2019
35b09c8
Merge branch 'master' of github.com:gitcoinco/web into feature/bounty…
androolloyd Aug 26, 2019
4450713
migrations added to solve build issues with 4969
androolloyd Aug 26, 2019
e8e5710
modified previously commited migration to ensure accuracy
androolloyd Aug 26, 2019
7f43a79
reverting formatting changes
androolloyd Sep 3, 2019
d78dbe6
Fixed an issue with reconciliation, correct the conditional to check…
androolloyd Sep 3, 2019
526d8bb
removed stub
androolloyd Sep 3, 2019
3b53af3
filtering user queries based around the is_active flag
androolloyd Sep 3, 2019
8f47727
adding GithubRepo
androolloyd Sep 3, 2019
f141e7f
Repo Model Class Added to dashboard/models
androolloyd Sep 5, 2019
6db6e25
Merge branch 'master' of github.com:gitcoinco/web into feature/bounty…
androolloyd Sep 5, 2019
0cdec36
Merge branch 'master' into feature/bounty-payout-4969
androolloyd Sep 10, 2019
7f41c2a
Merge branch 'master' of github.com:gitcoinco/web into feature/bounty…
androolloyd Sep 16, 2019
508a81f
add merge migration
danlipert Sep 16, 2019
50b9516
fix isort
danlipert Sep 16, 2019
bd3ce81
wip debugging to get around more edge cases with null data/bad token …
androolloyd Sep 16, 2019
d5d0d64
Merge branch 'feature/bounty-payout-4969' of github.com:gitcoinco/web…
androolloyd Sep 19, 2019
d441edb
Merge branch 'master' of github.com:gitcoinco/web into feature/bounty…
androolloyd Sep 20, 2019
ef8d506
streamlined migrations
androolloyd Sep 20, 2019
b2af37c
get_user method updated
androolloyd Sep 28, 2019
2e0dedf
html structure
octavioamu Sep 26, 2019
64c01a4
sync_orgs_repos mgmt command updated
androolloyd Sep 30, 2019
238e31a
Merge branch 'master' of github.com:gitcoinco/web into feature/bounty…
androolloyd Sep 30, 2019
7e8fdbd
add styles
octavioamu Sep 30, 2019
9532bc1
Merge branch 'master' into settings-org-2
octavioamu Sep 30, 2019
77c6bb6
sync_orgs_repo management command
androolloyd Oct 1, 2019
27e75bd
Merge branch 'master' of github.com:gitcoinco/web into feature/bounty…
androolloyd Oct 1, 2019
ecf15ff
add header styles
octavioamu Oct 1, 2019
e8ee0b8
sync_orgs_repos management cmd
androolloyd Oct 1, 2019
1831ab9
sync_orgs_repo management command
androolloyd Oct 2, 2019
6dd7685
updated the error message to correct the text
androolloyd Oct 2, 2019
372d46e
Merge branch 'feature/bounty-payout-4969' into settings-org-2
octavioamu Oct 2, 2019
93e0582
add orgs query
octavioamu Oct 2, 2019
46eea1f
add credentials
octavioamu Oct 2, 2019
8b0cd15
fix tests
octavioamu Oct 2, 2019
c8d192d
add credentials and fix tests
octavioamu Oct 2, 2019
a3e1b1a
remove typo
octavioamu Oct 2, 2019
c7e743a
add dynamic data to view
octavioamu Oct 2, 2019
9c10ab2
fix travis
octavioamu Oct 2, 2019
675be93
clean code
octavioamu Oct 22, 2019
ee32980
Merge branch 'master' into settings-org-2
octavioamu Oct 22, 2019
70c4192
Bounty Payout
androolloyd Oct 22, 2019
82e0b90
remove migration
octavioamu Oct 22, 2019
41be52a
Merge branch 'feature/bounty-payout-4969' into settings-org-2
octavioamu Oct 22, 2019
935c579
add missing migration
octavioamu Oct 22, 2019
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
187 changes: 187 additions & 0 deletions app/app/management/commands/sync_orgs_repos.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,187 @@
from django.contrib.auth.models import Group, User
from django.core.management.base import BaseCommand

from app.utils import sync_profile
from dashboard.models import Organization, Profile, Repo
from git.utils import get_organization, get_repo, get_user


class Command(BaseCommand):
help = 'Synchronizes Organizations and Repo roles to members'

def handle(self, *args, **options):

try:
print("Loading Users....")
all_users = Profile.objects.filter(
user__is_active=True
).prefetch_related('user')

synced = []
orgs_synced = []

def recursive_sync(lsynced, handle):
try:

if handle not in lsynced:

print(f'Syncing User Handle: {handle}')
profile = sync_profile(handle)
access_token = profile.user.social_auth.filter(provider='github').latest('pk').access_token
print('Removing Stale Organizations and Groups')
remove_org_groups = [x for x in profile.profile_organizations.all() if
x.name not in profile.organizations]
for y in remove_org_groups:
profile.profile_organizations.remove(y)
profile.user.groups.filter(name__contains=y.name).delete()
print(f'Removing: {profile.handle} from Organization: {y.name} ')

user_access_repos = get_repo(handle, '/repos', (handle, access_token), is_user=True)
# Question around user repo acccess if we can't get user repos, should we assume all repos are no longer available in the platform?

if 'message' in user_access_repos:
print(user_access_repos['message'])
return lsynced

current_user_repos = []
for y in user_access_repos:
current_user_repos.append(y['name'])

remove_user_repos_names = [x for x in profile.repos.all() if
x.name not in current_user_repos]

remove_user_repos = Repo.objects.filter(name__in=remove_user_repos_names,
profile__handle=handle)
for y in remove_user_repos:
profile.repos.remove(y)

lsynced.append(handle)
else:
return lsynced

members_to_sync = []
if profile.organizations is None:
print("no organizations to sync")
return []

for org in profile.organizations:
try:
if org in orgs_synced:
print(f'{org} has been synced already')
continue

orgs_synced.append(org)
db_org = Organization.objects.get_or_create(name=org)[0]

print(f'Syncing Organization: {db_org.name}')
profile.profile_organizations.add(db_org)
org_members = get_organization(
db_org.name,
'/members',
(handle, access_token)
)

if 'message' in org_members:
print(org_members['message'])
continue

for member in org_members:

try:
membership = get_organization(
db_org.name,
f'/memberships/{member["login"]}',
(handle, access_token)
)
if 'message' in membership:
print(membership['message'])
continue
role = membership['role'] if 'role' in membership else "member"
db_group = Group.objects.get_or_create(name=f'{db_org.name}-role-{role}')[0]
db_org.groups.add(db_group)
member_profile_obj = Profile.objects.get(
handle=member['login'],
user__is_active=True
)
member_profile_obj.user.groups.add(db_group)
members_to_sync.append(member['login'])
except Exception as e:
print(f'An exception happened in the Organization Loop: handle {member["login"]} {e}')
continue

org_repos = get_organization(
db_org.name,
'/repos',
(handle, access_token)
)


if 'message' in org_repos:
print(org_repos['message'])
continue

for repo in org_repos:
db_repo = Repo.objects.get_or_create(name=repo['name'])[0]
db_org.repos.add(db_repo)
print(f'Syncing Repo: {db_repo.name}')
repo_collabs = get_repo(
repo['full_name'],
'/collaborators',
(handle, access_token)
)
if 'message' in repo_collabs:
print(repo_collabs['message'])
continue

for collaborator in repo_collabs:

if collaborator['permissions']['admin']:
permission = "admin"
elif collaborator['permissions']['push']:
permission = "write"
elif collaborator['permissions']['pull']:
permission = "pull"
else:
permission = "none"

db_group = Group.objects.get_or_create(
name=f'{db_org.name}-repo-{repo["name"]}-{permission}')[0]
db_org.groups.add(db_group)

try:
member_user_profile = Profile.objects.get(handle=collaborator['login'],
user__is_active=True)
member_user_profile.user.groups.add(db_group)
member_user_profile.repos.add(db_repo)
if collaborator['login'] not in members_to_sync or \
collaborator['login'] not in lsynced:
members_to_sync.append(collaborator['login'])
except Exception as e:
print(f'An exception happened in the Collaborators sync Loop: handle: '
f'{collaborator["login"]} {e}')

for x in members_to_sync:
try:
lsynced = lsynced + recursive_sync(lsynced, x)
except Exception as e:
print(f'An exception happened in the Members sync Loop: handle: {handle} {e}')
except Exception as e:
print(f'An exception happened in the Organization Loop: handle {handle} {e}')
except Exception as exc:
print(f'Exception occurred inside recursive_sync: {exc}')

return lsynced

for profile in all_users:
try:
if profile.handle is not None:
synced = recursive_sync(synced, profile.handle)
except ValueError as loop_exc:
print(f'Error syncing user id:{profile.user.id}')
print(loop_exc)
except Exception as e:
print(e)

print("Sync Completed")
except ValueError as e:
print(e)
2 changes: 1 addition & 1 deletion app/app/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -531,7 +531,7 @@
SOCIAL_AUTH_GITHUB_SECRET = GITHUB_CLIENT_SECRET
SOCIAL_AUTH_POSTGRES_JSONFIELD = True
SOCIAL_AUTH_ADMIN_USER_SEARCH_FIELDS = ['username', 'first_name', 'last_name', 'email']
SOCIAL_AUTH_GITHUB_SCOPE = ['read:public_repo', 'read:user', 'user:email', ]
SOCIAL_AUTH_GITHUB_SCOPE = ['read:public_repo', 'read:user', 'user:email', 'read:org', 'repo']
SOCIAL_AUTH_SANITIZE_REDIRECTS = True

SOCIAL_AUTH_PIPELINE = (
Expand Down
2 changes: 2 additions & 0 deletions app/app/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@
dashboard.views.social_contribution_email,
name='social_contribution_email'
),
url(r'^api/v0.1/org_perms', dashboard.views.org_perms, name='org_perms'),
url(r'^api/v0.1/bulk_invite', dashboard.views.bulk_invite, name='bulk_invite'),
url(r'^api/v0.1/bountydocument', dashboard.views.bounty_upload_nda, name='bounty_upload_nda'),
url(r'^api/v0.1/faucet/save/?', faucet.views.save_faucet, name='save_faucet'),
Expand Down Expand Up @@ -518,6 +519,7 @@
re_path(r'^settings/account/?', marketing.views.account_settings, name='account_settings'),
re_path(r'^settings/tokens/?', marketing.views.token_settings, name='token_settings'),
re_path(r'^settings/job/?', marketing.views.job_settings, name='job_settings'),
re_path(r'^settings/organizations/?', marketing.views.org_settings, name='org_settings'),
re_path(r'^settings/(.*)?', marketing.views.email_settings, name='settings'),

# marketing views
Expand Down
7 changes: 4 additions & 3 deletions app/app/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ def get_upload_filename(instance, filename):


def sync_profile(handle, user=None, hide_profile=True):
from dashboard.models import Profile
from dashboard.models import Profile, Organization
handle = handle.strip().replace('@', '').lower()
data = get_user(handle)
email = ''
Expand All @@ -207,9 +207,10 @@ def sync_profile(handle, user=None, hide_profile=True):
# store the org info in postgres
try:
profile, created = Profile.objects.update_or_create(handle=handle, defaults=defaults)
print("Profile:", profile, "- created" if created else "- updated")
orgs = get_user(handle, '/orgs')
access_token = profile.user.social_auth.filter(provider='github').latest('pk').access_token
orgs = get_user(handle, '', scope='orgs', auth=(profile.handle, access_token))
profile.organizations = [ele['login'] for ele in orgs]
print("Profile:", profile, "- created" if created else "- updated")
keywords = []
for repo in profile.repos_data_lite:
language = repo.get('language') if repo.get('language') else ''
Expand Down
51 changes: 51 additions & 0 deletions app/dashboard/migrations/0054_auto_20190930_1525.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# Generated by Django 2.2.4 on 2019-09-30 15:25

from django.db import migrations, models
import economy.models


class Migration(migrations.Migration):

dependencies = [
('auth', '0011_update_proxy_permissions'),
('dashboard', '0053_auto_20190920_1816'),
]

operations = [
migrations.CreateModel(
name='Repo',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('created_on', models.DateTimeField(db_index=True, default=economy.models.get_time)),
('modified_on', models.DateTimeField(default=economy.models.get_time)),
('name', models.CharField(max_length=255)),
],
options={
'ordering': ('name',),
},
),
migrations.CreateModel(
name='Organization',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('created_on', models.DateTimeField(db_index=True, default=economy.models.get_time)),
('modified_on', models.DateTimeField(default=economy.models.get_time)),
('name', models.CharField(max_length=255)),
('groups', models.ManyToManyField(blank=True, to='auth.Group')),
('repos', models.ManyToManyField(blank=True, to='dashboard.Repo')),
],
options={
'ordering': ('name',),
},
),
migrations.AddField(
model_name='profile',
name='profile_organizations',
field=models.ManyToManyField(blank=True, to='dashboard.Organization'),
),
migrations.AddField(
model_name='profile',
name='repos',
field=models.ManyToManyField(blank=True, to='dashboard.Repo'),
),
]
14 changes: 14 additions & 0 deletions app/dashboard/migrations/0059_merge_20191022_1603.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Generated by Django 2.2.4 on 2019-10-22 16:03

from django.db import migrations


class Migration(migrations.Migration):

dependencies = [
('dashboard', '0054_auto_20190930_1525'),
('dashboard', '0058_auto_20191017_1723'),
]

operations = [
]
31 changes: 24 additions & 7 deletions app/dashboard/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -2153,6 +2153,28 @@ def hidden(self):
return self.filter(hide_profile=True)


class Repo(SuperModel):
name = models.CharField(max_length=255)

class Meta:
ordering = ('name',)

def __str__(self):
return self.name


class Organization(SuperModel):
name = models.CharField(max_length=255)
groups = models.ManyToManyField('auth.Group', blank=True)
repos = models.ManyToManyField(Repo, blank=True)

class Meta:
ordering = ('name',)

def __str__(self):
return self.name


class HackathonRegistration(SuperModel):
"""Defines the Hackthon profiles registrations"""
name = models.CharField(max_length=255, help_text='Hackathon slug')
Expand All @@ -2170,10 +2192,6 @@ class HackathonRegistration(SuperModel):
on_delete=models.CASCADE,
help_text='User profile'
)

class Meta:
ordering = ('name',)

def __str__(self):
return f"Name: {self.name}; Hackathon: {self.hackathon}; Referer: {self.referer}; Registrant: {self.registrant}"

Expand Down Expand Up @@ -2226,6 +2244,8 @@ class Profile(SuperModel):
)
keywords = ArrayField(models.CharField(max_length=200), blank=True, default=list)
organizations = ArrayField(models.CharField(max_length=200), blank=True, default=list)
profile_organizations = models.ManyToManyField(Organization, blank=True)
repos = models.ManyToManyField(Repo, blank=True)
form_submission_records = JSONField(default=list, blank=True)
max_num_issues_start_work = models.IntegerField(default=3)
preferred_payout_address = models.CharField(max_length=255, default='', blank=True)
Expand Down Expand Up @@ -2273,10 +2293,8 @@ class Profile(SuperModel):
rank_coder = models.IntegerField(default=0)
referrer = models.ForeignKey('dashboard.Profile', related_name='referred', on_delete=models.CASCADE, null=True, db_index=True, blank=True)


objects = ProfileQuerySet.as_manager()


@property
def quest_level(self):
return self.quest_attempts.filter(success=True).distinct('quest').count() + 1
Expand Down Expand Up @@ -2689,7 +2707,6 @@ def calc_activity_level(self):
return "Low"



def calc_longest_streak(self):
""" Determines the longest streak, in workdays, of this user

Expand Down
Loading