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

[draft] Membership #18

Open
wants to merge 9 commits into
base: main
Choose a base branch
from
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
7 changes: 7 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
.python-version
.venv/
db.sqlite3
__pycache__
media/
.env
.temp
5 changes: 3 additions & 2 deletions peacock/membership/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
# Register your models here.
from django.contrib import admin

from .models import Member
from .models import Member, Contribution

admin.site.register(Member)
admin.site.register(Member)
admin.site.register(Contribution)
56 changes: 56 additions & 0 deletions peacock/membership/management/commands/getprinfo.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
from django.core.management.base import BaseCommand, CommandError
from django.utils import timezone

from membership.models import Member, Contribution
from projects.models import Project

import os, json

import requests

class Command(BaseCommand):
help = "Get contribution information from GitHub for all members"

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

with open("projects.txt", "r") as file:
repos = file.read().split()

headers = {"Authorization": os.environ["GH_TOKEN"]}

for member in Member.objects.all():
url = f'https://api.github.com/search/issues?q=type:pr+author:{member.github_handle}&per_page=100'
while url is not None:
res = requests.get(url, headers=headers)
# set url to the next page, or None is no next page
url = None
for link in res.headers["Link"].split(","):
parts = link.strip().split(";")
if parts[1].strip() == 'rel="next"':
url = parts[0].strip("<").strip(">")
# parse and handle results
prs_json = json.loads(res.text)["items"]
for pr in prs_json:
repo = "/".join(pr["repository_url"].split("/")[-2:])
id = "/".join(pr["html_url"].split("/")[-4:])
if repo in repos:
pr_obj = list(Contribution.objects.filter(gh_id=pr["id"]))
if len(pr_obj) != 0:
obj = pr_obj[0]
obj.title = pr["title"]
obj.state = pr["state"]
obj.merged_at = pr.get("merged_at", None)
obj.save()
else:
obj = Contribution.objects.create(
id = id,
gh_id = pr["id"],
author = member,
html_url = pr["html_url"],
repo = Project.objects.get(full_name=repo),
title = pr["title"],
state = pr["state"],
created_at = pr["created_at"],
merged_at = pr.get("merged_at", None)
)
obj.save()
32 changes: 30 additions & 2 deletions peacock/membership/migrations/0001_initial.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
# Generated by Django 5.1 on 2024-08-29 20:15
# Generated by Django 5.1.1 on 2024-09-10 00:02

import django.contrib.auth.models
import django.contrib.auth.validators
import django.db.models.deletion
import django.utils.timezone
from django.conf import settings
from django.db import migrations, models


Expand All @@ -12,6 +14,7 @@ class Migration(migrations.Migration):

dependencies = [
('auth', '0012_alter_user_first_name_max_length'),
('projects', '0001_initial'),
]

operations = [
Expand All @@ -29,7 +32,18 @@ class Migration(migrations.Migration):
('is_staff', models.BooleanField(default=False, help_text='Designates whether the user can log into this admin site.', verbose_name='staff status')),
('is_active', models.BooleanField(default=True, help_text='Designates whether this user should be treated as active. Unselect this instead of deleting accounts.', verbose_name='active')),
('date_joined', models.DateTimeField(default=django.utils.timezone.now, verbose_name='date joined')),
('twitter_url', models.CharField(max_length=100)),
('website_url', models.URLField(blank=True, null=True)),
('twitter_url', models.URLField(blank=True, null=True)),
('linkedin_url', models.URLField(blank=True, null=True)),
('mastodon_url', models.URLField(blank=True, null=True)),
('bio', models.CharField(blank=True, max_length=1000, null=True)),
('avatar', models.ImageField(blank=True, null=True, upload_to='images/')),
('pronouns', models.CharField(blank=True, max_length=40, null=True)),
('location', models.CharField(blank=True, max_length=100, null=True)),
('github_handle', models.CharField(max_length=40)),
('confirmed_status', models.BooleanField(default=False)),
('approved_status', models.BooleanField(default=False)),
('approved_by', models.CharField(blank=True, max_length=40, null=True)),
('groups', models.ManyToManyField(blank=True, help_text='The groups this user belongs to. A user will get all permissions granted to each of their groups.', related_name='user_set', related_query_name='user', to='auth.group', verbose_name='groups')),
('user_permissions', models.ManyToManyField(blank=True, help_text='Specific permissions for this user.', related_name='user_set', related_query_name='user', to='auth.permission', verbose_name='user permissions')),
],
Expand All @@ -42,4 +56,18 @@ class Migration(migrations.Migration):
('objects', django.contrib.auth.models.UserManager()),
],
),
migrations.CreateModel(
name='Contribution',
fields=[
('id', models.CharField(max_length=100, primary_key=True, serialize=False)),
('gh_id', models.PositiveIntegerField()),
('html_url', models.URLField()),
('title', models.CharField(max_length=200)),
('state', models.CharField(max_length=10)),
('created_at', models.DateTimeField()),
('merged_at', models.DateTimeField(blank=True, null=True)),
('author', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
('repo', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='projects.project')),
],
),
]
27 changes: 25 additions & 2 deletions peacock/membership/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,36 @@
# avatar: (optional)
# pronouns (optional)
# location (?)
# List of projects. (optional for now)
# List of projects. (optional for now) **imprement later**
# GitHub handle: connect with GitHub API.
# confirmed status: whether email address is confirmed
# approval status: whether approved by us. (True false)
# approved by: the username of the admin who approved
from django.contrib.auth.models import AbstractUser
from django.db import models
from projects.models import Project

class Member(AbstractUser):
twitter_url = models.CharField(max_length=100)
website_url = models.URLField(null=True, blank=True)
twitter_url = models.URLField(null=True, blank=True)
linkedin_url = models.URLField(null=True, blank=True)
mastodon_url = models.URLField(null=True, blank=True)
bio = models.CharField(max_length=1000, null=True, blank=True)
avatar = models.ImageField(upload_to='images/', null=True, blank=True)
pronouns = models.CharField(max_length=40, null=True, blank=True)
location = models.CharField(max_length=100, null=True, blank=True)
github_handle = models.CharField(max_length=40)
confirmed_status = models.BooleanField(default = False)
approved_status = models.BooleanField(default = False)
approved_by = models.CharField(max_length=40, null=True, blank=True)

class Contribution(models.Model):
id = models.CharField(max_length=100, primary_key=True)
gh_id = models.PositiveIntegerField()
author = models.ForeignKey(Member, on_delete=models.CASCADE)
html_url = models.URLField()
repo = models.ForeignKey(Project, on_delete=models.CASCADE)
title = models.CharField(max_length=200)
state = models.CharField(max_length=10)
created_at = models.DateTimeField()
merged_at = models.DateTimeField(null=True, blank=True)
3 changes: 2 additions & 1 deletion peacock/membership/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,5 @@

urlpatterns = [
path("", views.index, name="index"),
]
path("<username>/", views.profile, name="profile"),
]
8 changes: 7 additions & 1 deletion peacock/membership/views.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from django.http import HttpResponse
from django.template import loader
from django.shortcuts import get_object_or_404, render
from .models import Member


Expand All @@ -12,4 +13,9 @@ def index(request):
context = {"members" : members
}

return HttpResponse(template.render(context, request))
return HttpResponse(template.render(context, request))

def profile(request, username):
member = get_object_or_404(Member, username=username)
return render(request, "membership/profile.html", {"member": member})

Empty file added peacock/pages/__init__.py
Empty file.
3 changes: 3 additions & 0 deletions peacock/pages/admin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
from django.contrib import admin

# Register your models here.
6 changes: 6 additions & 0 deletions peacock/pages/apps.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
from django.apps import AppConfig


class PagesConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'pages'
Empty file.
3 changes: 3 additions & 0 deletions peacock/pages/models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
from django.db import models

# Create your models here.
3 changes: 3 additions & 0 deletions peacock/pages/tests.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
from django.test import TestCase

# Create your tests here.
7 changes: 7 additions & 0 deletions peacock/pages/urls.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
from django.urls import path

from . import views

urlpatterns = [
path("<page_slug>/", views.page, name="page"),
]
9 changes: 9 additions & 0 deletions peacock/pages/views.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
from django.shortcuts import render
import markdown


def page(request, page_slug):
f = open(f"static/pages/{page_slug}.md","r")
f = f.read()
html = markdown.markdown(f)
return render(request, "pages/page.html", {"content": html})
16 changes: 13 additions & 3 deletions peacock/peacock/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
"""

from pathlib import Path
import os

# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent
Expand All @@ -37,7 +38,9 @@
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'membership'
'membership',
'pages',
'projects'
]

MIDDLEWARE = [
Expand All @@ -55,7 +58,7 @@
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [],
'DIRS': [BASE_DIR / "templates"],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
Expand Down Expand Up @@ -117,10 +120,17 @@
# https://docs.djangoproject.com/en/4.2/howto/static-files/

STATIC_URL = 'static/'
STATICFILES_DIRS = [
BASE_DIR / "static",
]
# STATIC_ROOT = os.path.join(BASE_DIR, 'static')

# Default primary key field type
# https://docs.djangoproject.com/en/4.2/ref/settings/#default-auto-field

DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'

AUTH_USER_MODEL = 'membership.Member'
AUTH_USER_MODEL = 'membership.Member'

MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
MEDIA_URL = '/media/'
8 changes: 7 additions & 1 deletion peacock/peacock/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,14 @@
"""
from django.contrib import admin
from django.urls import include, path
from django.conf import settings
from django.conf.urls.static import static
from django.views.generic import TemplateView

urlpatterns = [
path('admin/', admin.site.urls),
path("membership/", include("membership.urls")),
]
path("pages/", include("pages.urls")),
path('', TemplateView.as_view(template_name='index.html')),
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
# + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
29 changes: 29 additions & 0 deletions peacock/projects.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
pandas-dev/pandas
numpy/numpy
scikit-learn/scikit-learn
scikit-image/scikit-image
pola-rs/polars
pola-rs/pyo3-polars
pallets/flask
django/django
adamchainz/django-htmx
PyO3/pyo3
PyO3/maturin
astral-sh/uv
astral-sh/ruff
pytest-dev/pytest
HypothesisWorks/hypothesis
pygame/pygame
Rapptz/discord.py
tox-dev/tox
fastapi/fastapi
pydantic/pydantic
tensorflow/tensorflow
keras-team/keras
pytorch/pytorch
matplotlib/matplotlib
bokeh/bokeh
plotly/dash
mwaskom/seaborn
napari/napari
narwhals-dev/narwhals
Empty file added peacock/projects/__init__.py
Empty file.
6 changes: 6 additions & 0 deletions peacock/projects/admin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
from django.contrib import admin

from .models import Owner, Project

admin.site.register(Owner)
admin.site.register(Project)
6 changes: 6 additions & 0 deletions peacock/projects/apps.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
from django.apps import AppConfig


class ProjectsConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'projects'
Loading