зеркало из https://github.com/mozilla/mentoring.git
add pycodestyle checks
This commit is contained in:
Родитель
b74fbe4d0c
Коммит
26457f8b31
|
@ -31,6 +31,11 @@ tasks:
|
||||||
command: >-
|
command: >-
|
||||||
pip install -r requirements.txt &&
|
pip install -r requirements.txt &&
|
||||||
python3 manage.py test
|
python3 manage.py test
|
||||||
|
- name: Python code style
|
||||||
|
image: python:3.9
|
||||||
|
command: >-
|
||||||
|
pip install pycodestyle &&
|
||||||
|
pycodestyle ./mentoring
|
||||||
each(opts):
|
each(opts):
|
||||||
provisionerId: 'proj-misc'
|
provisionerId: 'proj-misc'
|
||||||
workerType: 'ci'
|
workerType: 'ci'
|
||||||
|
|
|
@ -8,6 +8,7 @@ from django.test import Client
|
||||||
from ..participants.models import Participant
|
from ..participants.models import Participant
|
||||||
from .views import time_availability
|
from .views import time_availability
|
||||||
|
|
||||||
|
|
||||||
class TimeAvailabilityTest(TestCase):
|
class TimeAvailabilityTest(TestCase):
|
||||||
|
|
||||||
def test_no_avail(self):
|
def test_no_avail(self):
|
||||||
|
@ -73,7 +74,7 @@ class PostTest(TestCase):
|
||||||
assert(p.full_name == 'Alex Doe')
|
assert(p.full_name == 'Alex Doe')
|
||||||
assert(p.manager == 'Mana Jerr')
|
assert(p.manager == 'Mana Jerr')
|
||||||
assert(p.manager_email == 'mjerr@mozilla.com')
|
assert(p.manager_email == 'mjerr@mozilla.com')
|
||||||
assert(p.approved == None)
|
assert(p.approved is None)
|
||||||
assert(p.time_availability == 'YYYYYYNNNYYYNNNNNNNNNNNN')
|
assert(p.time_availability == 'YYYYYYNNNYYYNNNNNNNNNNNN')
|
||||||
assert(p.org == 'Firefox')
|
assert(p.org == 'Firefox')
|
||||||
assert(p.org_level == 'P3')
|
assert(p.org_level == 'P3')
|
||||||
|
@ -121,7 +122,7 @@ class PostTest(TestCase):
|
||||||
assert(p.full_name == 'Alex Doe')
|
assert(p.full_name == 'Alex Doe')
|
||||||
assert(p.manager == 'Mana Jerr')
|
assert(p.manager == 'Mana Jerr')
|
||||||
assert(p.manager_email == 'mjerr@mozilla.com')
|
assert(p.manager_email == 'mjerr@mozilla.com')
|
||||||
assert(p.approved == None)
|
assert(p.approved is None)
|
||||||
assert(p.time_availability == 'NNNNNNNNNYYYNNNNNNNNNNNN')
|
assert(p.time_availability == 'NNNNNNNNNYYYNNNNNNNNNNNN')
|
||||||
assert(p.org == 'Firefox')
|
assert(p.org == 'Firefox')
|
||||||
assert(p.org_level == 'P3')
|
assert(p.org_level == 'P3')
|
||||||
|
@ -130,7 +131,7 @@ class PostTest(TestCase):
|
||||||
'Increasing Impact on Mozilla Mission',
|
'Increasing Impact on Mozilla Mission',
|
||||||
'Public Speaking',
|
'Public Speaking',
|
||||||
])
|
])
|
||||||
assert(p.track_change == None)
|
assert(p.track_change is None)
|
||||||
assert(p.org_chart_distance == 'Prefer distant')
|
assert(p.org_chart_distance == 'Prefer distant')
|
||||||
assert(p.comments == 'asdf')
|
assert(p.comments == 'asdf')
|
||||||
|
|
||||||
|
|
|
@ -14,6 +14,7 @@ from ..participants.models import Participant
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
def time_availability(time_availability):
|
def time_availability(time_availability):
|
||||||
'''Parse a list of 'xx:00 - xx:00 UTC' strings into the 24-hour format in the model'''
|
'''Parse a list of 'xx:00 - xx:00 UTC' strings into the 24-hour format in the model'''
|
||||||
rv = ['N'] * 24
|
rv = ['N'] * 24
|
||||||
|
@ -61,7 +62,6 @@ def parse_form(form):
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@require_http_methods(["POST"])
|
@require_http_methods(["POST"])
|
||||||
@csrf_exempt
|
@csrf_exempt
|
||||||
def webhook(request):
|
def webhook(request):
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
from django.shortcuts import render
|
from django.shortcuts import render
|
||||||
from django.contrib.auth.decorators import user_passes_test
|
from django.contrib.auth.decorators import user_passes_test
|
||||||
|
|
||||||
|
|
||||||
# Check that a user is authenticated; this automatically redirects un-authenticated
|
# Check that a user is authenticated; this automatically redirects un-authenticated
|
||||||
# users to the SSO login page (and right back if auto-login is enabled)
|
# users to the SSO login page (and right back if auto-login is enabled)
|
||||||
@user_passes_test(lambda user: user.is_authenticated)
|
@user_passes_test(lambda user: user.is_authenticated)
|
||||||
|
|
|
@ -2,12 +2,16 @@ from django.contrib import admin
|
||||||
|
|
||||||
from .models import Pair, HistoricalPair
|
from .models import Pair, HistoricalPair
|
||||||
|
|
||||||
|
|
||||||
class PairAdmin(admin.ModelAdmin):
|
class PairAdmin(admin.ModelAdmin):
|
||||||
list_display = ('mentor', 'learner', 'pair_id')
|
list_display = ('mentor', 'learner', 'pair_id')
|
||||||
|
|
||||||
|
|
||||||
admin.site.register(Pair, PairAdmin)
|
admin.site.register(Pair, PairAdmin)
|
||||||
|
|
||||||
|
|
||||||
class HistoricalPairAdmin(admin.ModelAdmin):
|
class HistoricalPairAdmin(admin.ModelAdmin):
|
||||||
list_display = ('pair_id',)
|
list_display = ('pair_id',)
|
||||||
|
|
||||||
|
|
||||||
admin.site.register(HistoricalPair, HistoricalPairAdmin)
|
admin.site.register(HistoricalPair, HistoricalPairAdmin)
|
||||||
|
|
|
@ -8,6 +8,7 @@ from django.db import models
|
||||||
|
|
||||||
from ..participants.models import Participant
|
from ..participants.models import Participant
|
||||||
|
|
||||||
|
|
||||||
class Pair(models.Model):
|
class Pair(models.Model):
|
||||||
"""
|
"""
|
||||||
An active pairing in the program.
|
An active pairing in the program.
|
||||||
|
@ -31,7 +32,7 @@ class Pair(models.Model):
|
||||||
|
|
||||||
start_date = models.DateTimeField(
|
start_date = models.DateTimeField(
|
||||||
null=False,
|
null=False,
|
||||||
default=lambda: datetime.datetime.now(pytz.UTC),
|
default=lambda: datetime.datetime.now(pytz.UTC),
|
||||||
help_text=dedent('''Date this pairing began''')
|
help_text=dedent('''Date this pairing began''')
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,7 @@ from rest_framework import serializers, viewsets, permissions, mixins
|
||||||
from .models import Pair
|
from .models import Pair
|
||||||
from ..participants.models import Participant
|
from ..participants.models import Participant
|
||||||
|
|
||||||
|
|
||||||
class PairSerializer(serializers.HyperlinkedModelSerializer):
|
class PairSerializer(serializers.HyperlinkedModelSerializer):
|
||||||
mentor = serializers.PrimaryKeyRelatedField(
|
mentor = serializers.PrimaryKeyRelatedField(
|
||||||
queryset=Participant.objects.all().filter(role=Participant.MENTOR))
|
queryset=Participant.objects.all().filter(role=Participant.MENTOR))
|
||||||
|
|
|
@ -8,10 +8,11 @@ from rest_framework.test import APIClient
|
||||||
from .models import Pair, HistoricalPair
|
from .models import Pair, HistoricalPair
|
||||||
from ..participants.models import Participant
|
from ..participants.models import Participant
|
||||||
|
|
||||||
|
|
||||||
class PairTest(TestCase):
|
class PairTest(TestCase):
|
||||||
|
|
||||||
def make_particips(self):
|
def make_particips(self):
|
||||||
l = Participant(
|
learner = Participant(
|
||||||
expires=datetime.datetime.now(pytz.UTC),
|
expires=datetime.datetime.now(pytz.UTC),
|
||||||
email='llearner@mozilla.com',
|
email='llearner@mozilla.com',
|
||||||
role=Participant.LEARNER,
|
role=Participant.LEARNER,
|
||||||
|
@ -20,9 +21,9 @@ class PairTest(TestCase):
|
||||||
manager_email='mshur@mozilla.com',
|
manager_email='mshur@mozilla.com',
|
||||||
time_availability='N' * 24,
|
time_availability='N' * 24,
|
||||||
)
|
)
|
||||||
l.save()
|
learner.save()
|
||||||
|
|
||||||
m = Participant(
|
mentor = Participant(
|
||||||
expires=datetime.datetime.now(pytz.UTC),
|
expires=datetime.datetime.now(pytz.UTC),
|
||||||
email='mmentor@mozilla.com',
|
email='mmentor@mozilla.com',
|
||||||
role=Participant.MENTOR,
|
role=Participant.MENTOR,
|
||||||
|
@ -31,13 +32,13 @@ class PairTest(TestCase):
|
||||||
manager_email='mshur@mozilla.com',
|
manager_email='mshur@mozilla.com',
|
||||||
time_availability='N' * 24,
|
time_availability='N' * 24,
|
||||||
)
|
)
|
||||||
m.save()
|
mentor.save()
|
||||||
|
|
||||||
return l, m
|
return learner, mentor
|
||||||
|
|
||||||
def test_model_make_pair(self):
|
def test_model_make_pair(self):
|
||||||
l, m = self.make_particips()
|
learner, mentor = self.make_particips()
|
||||||
p = Pair(learner=l, mentor=m)
|
p = Pair(learner=learner, mentor=mentor)
|
||||||
p.save()
|
p.save()
|
||||||
|
|
||||||
self.assertEqual(p.learner.email, 'llearner@mozilla.com')
|
self.assertEqual(p.learner.email, 'llearner@mozilla.com')
|
||||||
|
@ -53,7 +54,7 @@ class PairTest(TestCase):
|
||||||
self.assertTrue(HistoricalPair.already_paired(p))
|
self.assertTrue(HistoricalPair.already_paired(p))
|
||||||
|
|
||||||
def test_make_pair_rest_mentor_as_learner(self):
|
def test_make_pair_rest_mentor_as_learner(self):
|
||||||
l, m = self.make_particips()
|
learner, mentor = self.make_particips()
|
||||||
|
|
||||||
client = APIClient()
|
client = APIClient()
|
||||||
user = User.objects.create_superuser('test')
|
user = User.objects.create_superuser('test')
|
||||||
|
@ -62,6 +63,6 @@ class PairTest(TestCase):
|
||||||
res = client.post(
|
res = client.post(
|
||||||
'/api/pairs',
|
'/api/pairs',
|
||||||
# note that these are reversed
|
# note that these are reversed
|
||||||
{'mentor': l.id, 'learner': m.id},
|
{'mentor': learner.id, 'learner': mentor.id},
|
||||||
format='json')
|
format='json')
|
||||||
self.assertEqual(res.status_code, 400)
|
self.assertEqual(res.status_code, 400)
|
||||||
|
|
|
@ -14,7 +14,7 @@ def validate_time_availability(time_availability):
|
||||||
def validate_interests(interests):
|
def validate_interests(interests):
|
||||||
if type(interests) != list:
|
if type(interests) != list:
|
||||||
raise ValidationError('interests must be a list')
|
raise ValidationError('interests must be a list')
|
||||||
if any(type(i) != type('') for i in interests):
|
if any(not isinstance(i, str) for i in interests):
|
||||||
raise ValidationError('interests must contain strings')
|
raise ValidationError('interests must contain strings')
|
||||||
|
|
||||||
|
|
||||||
|
@ -45,7 +45,7 @@ class Participant(models.Model):
|
||||||
help_text=dedent('''\
|
help_text=dedent('''\
|
||||||
The participant's role in the program. Note that the same email may appear
|
The participant's role in the program. Note that the same email may appear
|
||||||
at most once in each role.'''),
|
at most once in each role.'''),
|
||||||
)
|
)
|
||||||
|
|
||||||
full_name = models.CharField(null=False, max_length=512, help_text=dedent('''\
|
full_name = models.CharField(null=False, max_length=512, help_text=dedent('''\
|
||||||
The participant's full name (as they would prefer to be called).'''))
|
The participant's full name (as they would prefer to be called).'''))
|
||||||
|
@ -67,7 +67,7 @@ class Participant(models.Model):
|
||||||
help_text=dedent('''\
|
help_text=dedent('''\
|
||||||
The participant's time availability, as a sequence of Y and N for each UTC hour,
|
The participant's time availability, as a sequence of Y and N for each UTC hour,
|
||||||
so `NNNYYYYYYYYYNNNNNNNNNNNN` indicates availability from 03:00-12:00 UTC.'''),
|
so `NNNYYYYYYYYYNNNNNNNNNNNN` indicates availability from 03:00-12:00 UTC.'''),
|
||||||
)
|
)
|
||||||
|
|
||||||
org = models.CharField(max_length=100, null=True, help_text=dedent('''\
|
org = models.CharField(max_length=100, null=True, help_text=dedent('''\
|
||||||
Participant's organization (roughly, executive to whom they report)'''))
|
Participant's organization (roughly, executive to whom they report)'''))
|
||||||
|
@ -78,11 +78,14 @@ class Participant(models.Model):
|
||||||
time_at_org_level = models.CharField(max_length=10, null=True, help_text=dedent('''\
|
time_at_org_level = models.CharField(max_length=10, null=True, help_text=dedent('''\
|
||||||
Participant's time at current organizational level, e.g., `2-3 y`'''))
|
Participant's time at current organizational level, e.g., `2-3 y`'''))
|
||||||
|
|
||||||
interests = models.JSONField(null=True, blank=False, help_text=dedent('''\
|
interests = models.JSONField(
|
||||||
A learner's areas of interest, or a mentor's areas in which they can offer mentorship;
|
null=True,
|
||||||
format is an array of open-text strings.'''),
|
blank=False,
|
||||||
|
help_text=dedent('''\
|
||||||
|
A learner's areas of interest, or a mentor's areas in which they can offer mentorship;
|
||||||
|
format is an array of open-text strings.'''),
|
||||||
validators=[validate_interests],
|
validators=[validate_interests],
|
||||||
)
|
)
|
||||||
|
|
||||||
track_change = models.CharField(null=True, max_length=64, help_text=dedent('''\
|
track_change = models.CharField(null=True, max_length=64, help_text=dedent('''\
|
||||||
Whether the participant is interested in changing tracks (between IC and Manager)'''))
|
Whether the participant is interested in changing tracks (between IC and Manager)'''))
|
||||||
|
@ -92,13 +95,13 @@ class Participant(models.Model):
|
||||||
null=True,
|
null=True,
|
||||||
blank=False,
|
blank=False,
|
||||||
help_text=dedent('''Preference for a pairing nearby or distant in the org chart (open text)''')
|
help_text=dedent('''Preference for a pairing nearby or distant in the org chart (open text)''')
|
||||||
)
|
)
|
||||||
|
|
||||||
comments = models.TextField(
|
comments = models.TextField(
|
||||||
null=False,
|
null=False,
|
||||||
blank=True,
|
blank=True,
|
||||||
help_text=dedent('''Open comments from the participant's enrollment'''),
|
help_text=dedent('''Open comments from the participant's enrollment'''),
|
||||||
)
|
)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
db_table = "participants"
|
db_table = "participants"
|
||||||
|
|
|
@ -2,6 +2,7 @@ from rest_framework import serializers, viewsets, permissions
|
||||||
|
|
||||||
from .models import Participant
|
from .models import Participant
|
||||||
|
|
||||||
|
|
||||||
class ParticipantSerializer(serializers.HyperlinkedModelSerializer):
|
class ParticipantSerializer(serializers.HyperlinkedModelSerializer):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Participant
|
model = Participant
|
||||||
|
|
|
@ -5,6 +5,7 @@ from configurations import Configuration, values
|
||||||
# Build paths inside the project like this: BASE_DIR / 'subdir'.
|
# Build paths inside the project like this: BASE_DIR / 'subdir'.
|
||||||
BASE_DIR = Path(__file__).resolve().parent.parent
|
BASE_DIR = Path(__file__).resolve().parent.parent
|
||||||
|
|
||||||
|
|
||||||
class Base(Configuration):
|
class Base(Configuration):
|
||||||
# Application definition
|
# Application definition
|
||||||
|
|
||||||
|
@ -98,6 +99,7 @@ class Base(Configuration):
|
||||||
STATIC_URL = '/static/'
|
STATIC_URL = '/static/'
|
||||||
STATICFILES_DIRS = [BASE_DIR / "static"]
|
STATICFILES_DIRS = [BASE_DIR / "static"]
|
||||||
|
|
||||||
|
|
||||||
class Production(Base):
|
class Production(Base):
|
||||||
DEBUG = False
|
DEBUG = False
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,7 @@ from django.test import TestCase
|
||||||
|
|
||||||
from .auth import MentoringAuthBackend
|
from .auth import MentoringAuthBackend
|
||||||
|
|
||||||
|
|
||||||
class Auth(TestCase):
|
class Auth(TestCase):
|
||||||
|
|
||||||
def get_username(self):
|
def get_username(self):
|
||||||
|
|
|
@ -16,7 +16,7 @@ urlpatterns = [
|
||||||
|
|
||||||
# if (and only if) we are in DEBUG mode (meaning Development), we allow
|
# if (and only if) we are in DEBUG mode (meaning Development), we allow
|
||||||
# users to sign in using simple Django auth
|
# users to sign in using simple Django auth
|
||||||
] + ([path('accounts/', include('django.contrib.auth.urls'))] if settings.DEBUG else []) + [
|
] + ([path('accounts/', include('django.contrib.auth.urls'))] if settings.DEBUG else []) + [
|
||||||
|
|
||||||
# ..and anything else renders the frontend
|
# ..and anything else renders the frontend
|
||||||
path('', include('mentoring.frontend.urls')),
|
path('', include('mentoring.frontend.urls')),
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
[pycodestyle]
|
||||||
|
# E501 = line length
|
||||||
|
ignore = E501
|
Загрузка…
Ссылка в новой задаче