From 3b1d08fe7c2fbb94ab3e9820f51c0d20adf13bdb Mon Sep 17 00:00:00 2001 From: renzon Date: Sun, 3 Jun 2018 20:55:15 -0300 Subject: [PATCH] Implemented Cohort Page close #44 --- pythonpro/cohorts/__init__.py | 0 pythonpro/cohorts/admin.py | 9 +++ pythonpro/cohorts/apps.py | 5 ++ pythonpro/cohorts/context_processors.py | 11 +++ pythonpro/cohorts/facade.py | 5 ++ pythonpro/cohorts/migrations/0001_initial.py | 46 ++++++++++++ pythonpro/cohorts/migrations/__init__.py | 0 pythonpro/cohorts/models.py | 25 +++++++ .../templates/cohorts/cohort_detail.html | 45 ++++++++++++ pythonpro/cohorts/tests.py | 71 +++++++++++++++++++ pythonpro/cohorts/urls.py | 8 +++ pythonpro/cohorts/views.py | 8 +++ .../migrations/0005_auto_20180603_2026.py | 18 +++++ pythonpro/core/models.py | 3 +- pythonpro/core/templates/core/base.html | 17 ++++- pythonpro/settings.py | 4 +- pythonpro/tests/test_urls.py | 2 +- pythonpro/urls.py | 14 +++- requirements-dev.txt | 2 +- requirements.txt | 2 + 20 files changed, 286 insertions(+), 9 deletions(-) create mode 100644 pythonpro/cohorts/__init__.py create mode 100644 pythonpro/cohorts/admin.py create mode 100644 pythonpro/cohorts/apps.py create mode 100644 pythonpro/cohorts/context_processors.py create mode 100644 pythonpro/cohorts/facade.py create mode 100644 pythonpro/cohorts/migrations/0001_initial.py create mode 100644 pythonpro/cohorts/migrations/__init__.py create mode 100644 pythonpro/cohorts/models.py create mode 100644 pythonpro/cohorts/templates/cohorts/cohort_detail.html create mode 100644 pythonpro/cohorts/tests.py create mode 100644 pythonpro/cohorts/urls.py create mode 100644 pythonpro/cohorts/views.py create mode 100644 pythonpro/core/migrations/0005_auto_20180603_2026.py diff --git a/pythonpro/cohorts/__init__.py b/pythonpro/cohorts/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/pythonpro/cohorts/admin.py b/pythonpro/cohorts/admin.py new file mode 100644 index 00000000..3bed0b41 --- /dev/null +++ b/pythonpro/cohorts/admin.py @@ -0,0 +1,9 @@ +from django.contrib import admin + +from pythonpro.cohorts.models import Cohort + + +@admin.register(Cohort) +class ModuleAdmin(admin.ModelAdmin): + list_display = 'title start end'.split() + ordering = ('-start',) diff --git a/pythonpro/cohorts/apps.py b/pythonpro/cohorts/apps.py new file mode 100644 index 00000000..60cc3369 --- /dev/null +++ b/pythonpro/cohorts/apps.py @@ -0,0 +1,5 @@ +from django.apps import AppConfig + + +class CohortsConfig(AppConfig): + name = 'pythonpro.cohorts' diff --git a/pythonpro/cohorts/context_processors.py b/pythonpro/cohorts/context_processors.py new file mode 100644 index 00000000..d49c2a0e --- /dev/null +++ b/pythonpro/cohorts/context_processors.py @@ -0,0 +1,11 @@ +from pythonpro.cohorts.facade import get_all_cohorts_desc + + +def global_settings(request): + # return any necessary values + if not request.user.is_authenticated: + return {} + + return { + 'ALL_COHORTS': get_all_cohorts_desc(), + } diff --git a/pythonpro/cohorts/facade.py b/pythonpro/cohorts/facade.py new file mode 100644 index 00000000..44c3e072 --- /dev/null +++ b/pythonpro/cohorts/facade.py @@ -0,0 +1,5 @@ +from pythonpro.cohorts.models import Cohort as _Cohort + + +def get_all_cohorts_desc(): + return tuple(_Cohort.objects.order_by('-start')) diff --git a/pythonpro/cohorts/migrations/0001_initial.py b/pythonpro/cohorts/migrations/0001_initial.py new file mode 100644 index 00000000..b0ed74b3 --- /dev/null +++ b/pythonpro/cohorts/migrations/0001_initial.py @@ -0,0 +1,46 @@ +# Generated by Django 2.0.6 on 2018-06-03 23:26 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + initial = True + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.CreateModel( + name='Cohort', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('title', models.CharField(max_length=50)), + ('slug', models.SlugField()), + ('image', models.ImageField(upload_to='cohorts/')), + ('quote', models.TextField()), + ('mail_list', models.URLField()), + ('forum_post', models.URLField()), + ('start', models.DateField()), + ('end', models.DateField()), + ], + ), + migrations.CreateModel( + name='CohortStudent', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('cohort', models.ForeignKey(on_delete=django.db.models.deletion.DO_NOTHING, to='cohorts.Cohort')), + ( + 'user', + models.ForeignKey(on_delete=django.db.models.deletion.DO_NOTHING, to=settings.AUTH_USER_MODEL) + ), + ], + ), + migrations.AddField( + model_name='cohort', + name='students', + field=models.ManyToManyField(through='cohorts.CohortStudent', to=settings.AUTH_USER_MODEL), + ), + ] diff --git a/pythonpro/cohorts/migrations/__init__.py b/pythonpro/cohorts/migrations/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/pythonpro/cohorts/models.py b/pythonpro/cohorts/models.py new file mode 100644 index 00000000..38c8dc86 --- /dev/null +++ b/pythonpro/cohorts/models.py @@ -0,0 +1,25 @@ +from django.contrib.auth import get_user_model +from django.db import models + +# Create your models here. +from django.urls import reverse + + +class Cohort(models.Model): + title = models.CharField(max_length=50) + slug = models.SlugField() + image = models.ImageField(upload_to='cohorts/') + quote = models.TextField() + mail_list = models.URLField() + forum_post = models.URLField() + start = models.DateField() + end = models.DateField() + students = models.ManyToManyField(get_user_model(), through='CohortStudent') + + def get_absolute_url(self): + return reverse('cohorts:detail', kwargs={'slug': self.slug}) + + +class CohortStudent(models.Model): + cohort = models.ForeignKey(Cohort, on_delete=models.DO_NOTHING) + user = models.ForeignKey(get_user_model(), on_delete=models.DO_NOTHING) diff --git a/pythonpro/cohorts/templates/cohorts/cohort_detail.html b/pythonpro/cohorts/templates/cohorts/cohort_detail.html new file mode 100644 index 00000000..02eaa96a --- /dev/null +++ b/pythonpro/cohorts/templates/cohorts/cohort_detail.html @@ -0,0 +1,45 @@ +{% extends 'core/base.html' %} +{% load static %} + +{% block title %}Turma {{ cohort.title }}{% endblock %} + +{% block body %} +
+
+
+

Turma {{ cohort.title }}

+ Foto de {{ cohort.title }} +
+

"{{ cohort.quote }}"

+
{{ cohort.title }} +
+
+
+ Inicio: +
+
+ {{ cohort.start }} +
+
+ Fim: +
+
+ {{ cohort.end }} +
+ +
+
+
+
+

Intruções

+
Passo 1
+
Cadastre-se na lista de emails da turma
+
Passo 2
+
Se apresente no post do fórum
+
Passo 3
+
Entre no nosso grupo do Telegram para tirar dúvidas e interagir!
+
+
+
+{% endblock body %} diff --git a/pythonpro/cohorts/tests.py b/pythonpro/cohorts/tests.py new file mode 100644 index 00000000..56f87f71 --- /dev/null +++ b/pythonpro/cohorts/tests.py @@ -0,0 +1,71 @@ +from os import path + +import pytest +from django.core.files.uploadedfile import SimpleUploadedFile +from django.template.defaultfilters import date +from django.urls import reverse +from model_mommy import mommy + +from pythonpro import settings +from pythonpro.cohorts.models import Cohort +from pythonpro.django_assertions import dj_assert_contains, dj_assert_not_contains + +_img_path = path.join(settings.BASE_DIR, 'pythonpro', 'core', 'static', 'img', 'instructors', 'renzo-nuccitelli.png') + + +@pytest.fixture +def cohort(client, django_user_model): + user = mommy.make(django_user_model) + client.force_login(user) + image = SimpleUploadedFile(name='renzo-nuccitelli.png', content=open(_img_path, 'rb').read(), + content_type='image/png') + cohort = mommy.make(Cohort, slug='guido-van-rossum', students=[user], image=image) + return cohort + + +@pytest.fixture +def resp(client, cohort): + resp = client.get(reverse('cohorts:detail', kwargs={'slug': cohort.slug}), secure=True) + return resp + + +def test_cohort_links_for_logged_user(client, django_user_model): + user = mommy.make(django_user_model) + client.force_login(user) + image = SimpleUploadedFile(name='renzo-nuccitelli.png', content=open(_img_path, 'rb').read(), + content_type='image/png') + cohorts = mommy.make(Cohort, 4, image=image) + resp = client.get('/', secure=True) + for c in cohorts: + dj_assert_contains(resp, c.get_absolute_url()) + + +@pytest.mark.django_db +def test_cohort_links_not_avaliable_for_no_user(client): + image = SimpleUploadedFile(name='renzo-nuccitelli.png', content=open(_img_path, 'rb').read(), + content_type='image/png') + cohorts = mommy.make(Cohort, 4, image=image) + resp = client.get('/', secure=True) + for c in cohorts: + dj_assert_not_contains(resp, c.get_absolute_url()) + + +def test_status_code(resp): + assert 200 == resp.status_code + + +@pytest.mark.parametrize('property_name', 'title mail_list forum_post'.split()) +def test_cohort_propeties(cohort, resp, property_name): + dj_assert_contains(resp, getattr(cohort, property_name)) + + +def test_cohort_img(cohort: Cohort, resp): + dj_assert_contains(resp, cohort.image.url) + + +def test_cohort_start(cohort: Cohort, resp): + dj_assert_contains(resp, date(cohort.start)) + + +def test_cohort_end(cohort: Cohort, resp): + dj_assert_contains(resp, date(cohort.end)) diff --git a/pythonpro/cohorts/urls.py b/pythonpro/cohorts/urls.py new file mode 100644 index 00000000..0882698d --- /dev/null +++ b/pythonpro/cohorts/urls.py @@ -0,0 +1,8 @@ +from django.urls import path + +from pythonpro.cohorts import views + +app_name = 'cohorts' +urlpatterns = [ + path('/', views.detail, name='detail'), +] diff --git a/pythonpro/cohorts/views.py b/pythonpro/cohorts/views.py new file mode 100644 index 00000000..4af7ffcd --- /dev/null +++ b/pythonpro/cohorts/views.py @@ -0,0 +1,8 @@ +from django.shortcuts import render + +# Create your views here. +from pythonpro.cohorts.models import Cohort + + +def detail(request, slug): + return render(request, 'cohorts/cohort_detail.html', {'cohort': Cohort.objects.get(slug=slug)}) diff --git a/pythonpro/core/migrations/0005_auto_20180603_2026.py b/pythonpro/core/migrations/0005_auto_20180603_2026.py new file mode 100644 index 00000000..ba8abe93 --- /dev/null +++ b/pythonpro/core/migrations/0005_auto_20180603_2026.py @@ -0,0 +1,18 @@ +# Generated by Django 2.0.6 on 2018-06-03 23:26 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('core', '0004_auto_20180601_1108'), + ] + + operations = [ + migrations.AlterField( + model_name='user', + name='first_name', + field=models.CharField(max_length=30, verbose_name='first name'), + ), + ] diff --git a/pythonpro/core/models.py b/pythonpro/core/models.py index bd2884a2..3db82547 100644 --- a/pythonpro/core/models.py +++ b/pythonpro/core/models.py @@ -52,8 +52,7 @@ def get_full_name(self): """ Return the first_name plus the last_name, with a space in between. """ - full_name = '%s %s' % (self.first_name, self.last_name) - return full_name.strip() + return self.get_short_name() def get_short_name(self): """Return the short name for the user.""" diff --git a/pythonpro/core/templates/core/base.html b/pythonpro/core/templates/core/base.html index e50db30d..197e3ad3 100644 --- a/pythonpro/core/templates/core/base.html +++ b/pythonpro/core/templates/core/base.html @@ -11,7 +11,7 @@ - +