Functional
This commit is contained in:
parent
7a053983a7
commit
c924918387
|
@ -104,9 +104,9 @@ AUTH_PASSWORD_VALIDATORS = [
|
|||
# Internationalization
|
||||
# https://docs.djangoproject.com/en/4.0/topics/i18n/
|
||||
|
||||
LANGUAGE_CODE = 'en-us'
|
||||
LANGUAGE_CODE = 'fr-fr'
|
||||
|
||||
TIME_ZONE = 'UTC'
|
||||
TIME_ZONE = 'Europe/Paris'
|
||||
|
||||
USE_I18N = True
|
||||
|
||||
|
|
|
@ -1,8 +1,25 @@
|
|||
import re
|
||||
|
||||
from django import forms
|
||||
from . import models
|
||||
|
||||
|
||||
SCRATCH_ID_REGEX = re.compile(r'https://scratch\.mit\.edu/projects/([0-9]+)')
|
||||
|
||||
def get_scratch_id_from_url(url):
|
||||
match = SCRATCH_ID_REGEX.search(url)
|
||||
return int(match.group(1))
|
||||
|
||||
|
||||
class ScratchURLField(forms.URLField):
|
||||
def clean(self, value):
|
||||
url = super().clean(value)
|
||||
scratch_id = get_scratch_id_from_url(url)
|
||||
return scratch_id
|
||||
|
||||
|
||||
class ScratchProjectAddForm(forms.ModelForm):
|
||||
url = forms.URLField(label='Lien Scratch du projet (URL)')
|
||||
url = ScratchURLField(label='Lien Scratch du projet (URL)')
|
||||
|
||||
class Meta:
|
||||
fields = ('name', 'author_name', 'url')
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
# Generated by Django 4.0.4 on 2022-05-13 00:55
|
||||
# Generated by Django 4.0.4 on 2022-05-13 05:27
|
||||
|
||||
import datetime
|
||||
import django.core.validators
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
@ -28,7 +29,7 @@ class Migration(migrations.Migration):
|
|||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('name', models.CharField(max_length=128, verbose_name='Nom du projet')),
|
||||
('author_name', models.CharField(max_length=128, verbose_name='Auteur')),
|
||||
('project_id', models.PositiveBigIntegerField(unique=True, verbose_name='Scratch project id')),
|
||||
('project_url', models.URLField(validators=[django.core.validators.RegexValidator(regex='https?://scratch\\.mit\\.edu/projects/([0-9]+)/?')], verbose_name='Scratch project url')),
|
||||
('event', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='scratch_show.event')),
|
||||
],
|
||||
),
|
||||
|
|
|
@ -2,6 +2,7 @@ from datetime import date
|
|||
|
||||
from django.db import models
|
||||
from django.urls import reverse
|
||||
from django.core.validators import RegexValidator
|
||||
|
||||
class Event(models.Model):
|
||||
name = models.CharField("Nom de l'évènement", max_length=128)
|
||||
|
@ -12,7 +13,7 @@ class Event(models.Model):
|
|||
class ScratchProject(models.Model):
|
||||
name = models.CharField('Nom du projet', max_length=128)
|
||||
author_name = models.CharField('Auteur', max_length=128)
|
||||
project_id = models.PositiveBigIntegerField('Scratch project id', unique=True)
|
||||
project_url = models.URLField('Scratch project url', validators=[RegexValidator(regex=r'https?://scratch\.mit\.edu/projects/([0-9]+)/?')])
|
||||
event = models.ForeignKey(Event, on_delete=models.CASCADE)
|
||||
|
||||
def get_absolute_url(self):
|
||||
|
|
155
scratch_show/static/scratch_show/base.css
Normal file
155
scratch_show/static/scratch_show/base.css
Normal file
|
@ -0,0 +1,155 @@
|
|||
@font-face {
|
||||
font-family: "Helvetica Neue";
|
||||
src: url("fonts/helveticaneue.woff2") format("woff2");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "Helvetica";
|
||||
src: url("fonts/helvetica.woff2") format("woff2");
|
||||
}
|
||||
|
||||
h1, h2, h3, h4, h5, h6 {
|
||||
font-family: "Helvetica Neue", sans-serif;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 2em;
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
:root {
|
||||
--text-color: #282828;
|
||||
--bg-color: #f9f9f9;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: "Helvetica", sans-serif;
|
||||
font-size: 1.3em;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
color: var(--text-color);
|
||||
background-color: var(--bg-color);
|
||||
}
|
||||
|
||||
header.site-header {
|
||||
background-color: #35479A;
|
||||
text-align: center;
|
||||
color: var(--bg-color);
|
||||
padding: 0.4em 1em;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 3.4em;
|
||||
}
|
||||
|
||||
header.site-header img {
|
||||
width: 56px;
|
||||
margin-right: 1em;
|
||||
}
|
||||
|
||||
.container {
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
width: 868px;
|
||||
}
|
||||
|
||||
h1.site-title {
|
||||
margin: 0;
|
||||
font-size: 1.4em;
|
||||
}
|
||||
|
||||
h1.article-title {
|
||||
margin: 0;
|
||||
font-size: 3em;
|
||||
}
|
||||
|
||||
.article-subtitle {
|
||||
color: #575757;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.article-title-box {
|
||||
height: 15em;
|
||||
text-align: center;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
background-color: #ededed;
|
||||
margin-bottom: 4em;
|
||||
}
|
||||
|
||||
.article-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
align-content: flex-start;
|
||||
justify-content: flex-start;
|
||||
}
|
||||
|
||||
a.code-stub-button {
|
||||
text-decoration: none;
|
||||
border-radius: 6px;
|
||||
background-color: #35479a;
|
||||
color: white;
|
||||
padding: 0.5em 0.8em;
|
||||
font-weight: 600;
|
||||
display: inline-block;
|
||||
text-align: center;
|
||||
line-height: 28px;
|
||||
}
|
||||
|
||||
.home-title-box {
|
||||
background-color: #222;
|
||||
color: whitesmoke;
|
||||
text-align: center;
|
||||
padding: 2em 0;
|
||||
}
|
||||
|
||||
.site-header-title {
|
||||
margin: 0;
|
||||
font-size: 5em;
|
||||
}
|
||||
|
||||
.site-header-subtitle {
|
||||
color: #ccc;
|
||||
}
|
||||
|
||||
.article-list {
|
||||
list-style-type: none;
|
||||
max-width: 690px;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
padding: 0 1em;
|
||||
}
|
||||
|
||||
.article-item {
|
||||
display: block;
|
||||
background: lightgray;
|
||||
margin: 1em 0;
|
||||
padding: 1em;
|
||||
}
|
||||
|
||||
.article-item h2 {
|
||||
font-size: 1.2em;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.article-item a {
|
||||
text-decoration: none;
|
||||
color: inherit;
|
||||
display: block;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
img {
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.header-home-link {
|
||||
display: flex;
|
||||
text-decoration: none;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.header-home-link:visited {
|
||||
color: inherit;
|
||||
}
|
BIN
scratch_show/static/scratch_show/favicon.png
Normal file
BIN
scratch_show/static/scratch_show/favicon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.4 KiB |
BIN
scratch_show/static/scratch_show/fonts/helvetica.woff2
Normal file
BIN
scratch_show/static/scratch_show/fonts/helvetica.woff2
Normal file
Binary file not shown.
BIN
scratch_show/static/scratch_show/fonts/helveticaneue.woff2
Normal file
BIN
scratch_show/static/scratch_show/fonts/helveticaneue.woff2
Normal file
Binary file not shown.
27
scratch_show/templates/scratch_show/base.html
Normal file
27
scratch_show/templates/scratch_show/base.html
Normal file
|
@ -0,0 +1,27 @@
|
|||
{% load static %}
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link rel="stylesheet" href="{% static 'scratch_show/base.css' %}" />
|
||||
<link rel="icon" type="image/png" href="{% static 'scratch_show/favicon.png' %}" />
|
||||
<title>Ateliers Scratch by Prologin</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<header class="site-header">
|
||||
<a href="/" class="header-home-link">
|
||||
<img src="https://prologin.org/static/img/logo_cube.png" alt="Prologin Cube Logo">
|
||||
<h1 class="site-title">Ateliers Scratch by Prologin</h1>
|
||||
</a>
|
||||
</header>
|
||||
|
||||
<main>
|
||||
<div class="container">
|
||||
{% block content %}
|
||||
{% endblock %}
|
||||
</div>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
15
scratch_show/templates/scratch_show/event_detail.html
Normal file
15
scratch_show/templates/scratch_show/event_detail.html
Normal file
|
@ -0,0 +1,15 @@
|
|||
{% extends 'scratch_show/base.html' %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<h1>{{ event.name }}, le {{ event.date|date }}</h1>
|
||||
|
||||
<ul>
|
||||
{% for project in projects %}
|
||||
<li><a href="{% url 'scratch_show:project-detail' project.pk %}">{{ project.name }}</a> par {{ project.author_name }}</li>
|
||||
{% empty %}
|
||||
<li>Aucun projet pour le moment !</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
|
||||
{% endblock %}
|
21
scratch_show/templates/scratch_show/index.html
Normal file
21
scratch_show/templates/scratch_show/index.html
Normal file
|
@ -0,0 +1,21 @@
|
|||
{% extends 'scratch_show/base.html' %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
{% if current_event %}
|
||||
<h2>Atelier en cours: <a href="{% url 'scratch_show:event-detail' current_event.pk %}">{{ current_event.name }}</a></h2>
|
||||
|
||||
<b><a href="{% url 'scratch_show:project-add' %}">Clique ici pour ajouter ton projet !</a></b>
|
||||
{% endif %}
|
||||
|
||||
<h2>Ateliers passés</h2>
|
||||
|
||||
<ul>
|
||||
{% for event in past_events %}
|
||||
<li><a href="{% url 'scratch_show:event-detail' event.pk %}">{{ event.name }}</a> le {{ event.date|date}}</li>
|
||||
{% empty %}
|
||||
<li>Pas d'ancien atelier pour le moment.</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
|
||||
{% endblock %}
|
|
@ -1,4 +1,10 @@
|
|||
{% extends 'scratch_show/base.html' %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<h1>{{ object.name }}</h1>
|
||||
<p>Créateur : {{ object.author_name }}</p>
|
||||
|
||||
<iframe src="https://scratch.mit.edu/projects/{{ object.project_id }}/embed" allowtransparency="true" width="485" height="402" frameborder="0" scrolling="no" allowfullscreen></iframe>
|
||||
<iframe src="{{ object.project_url }}/embed" allowtransparency="true" width="485" height="402" frameborder="0" scrolling="no" allowfullscreen></iframe>
|
||||
|
||||
{% endblock %}
|
||||
|
|
|
@ -1,4 +1,11 @@
|
|||
{% extends 'scratch_show/base.html' %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
|
||||
<form method="post">{% csrf_token %}
|
||||
{{ form.as_p }}
|
||||
<input type="submit" value="Save">
|
||||
</form>
|
||||
|
||||
{% endblock %}
|
||||
|
|
|
@ -4,6 +4,8 @@ from . import views
|
|||
app_name = 'scratch_show'
|
||||
|
||||
urlpatterns = [
|
||||
path('', views.IndexView.as_view(), name='index'),
|
||||
path('add', views.ScratchProjectAddView.as_view(), name='project-add'),
|
||||
path('project/<int:pk>', views.ScratchProjectDetailView.as_view(), name='project-detail'),
|
||||
path('project/<int:pk>/', views.ScratchProjectDetailView.as_view(), name='project-detail'),
|
||||
path('event/<int:pk>/', views.EventDetailView.as_view(), name='event-detail'),
|
||||
]
|
||||
|
|
|
@ -1,34 +1,44 @@
|
|||
import re
|
||||
|
||||
from django.shortcuts import get_object_or_404
|
||||
from django.utils import timezone
|
||||
from django.views.generic.edit import CreateView
|
||||
from django.views.generic.base import TemplateView
|
||||
from django.views.generic.detail import DetailView
|
||||
from django.views.generic.edit import CreateView
|
||||
from django.core.exceptions import ValidationError
|
||||
|
||||
from . import forms, models
|
||||
|
||||
|
||||
SCRATCH_ID_REGEX = re.compile(r'https://scratch\.mit\.edu/projects/([0-9]+)')
|
||||
class IndexView(TemplateView):
|
||||
template_name = "scratch_show/index.html"
|
||||
|
||||
def get_scratch_id_from_url(url):
|
||||
match = SCRATCH_ID_REGEX.search(url)
|
||||
return int(match.group(1))
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
today = timezone.now().date()
|
||||
context['current_event'] = models.Event.objects.filter(date=today).first()
|
||||
context['past_events'] = models.Event.objects.exclude(date=today).order_by('-date')
|
||||
return context
|
||||
|
||||
|
||||
class ScratchProjectAddView(CreateView):
|
||||
form_class = forms.ScratchProjectAddForm
|
||||
template_name = 'scratch_show/scratchproject_form.html'
|
||||
model = models.ScratchProject
|
||||
fields = ['name', 'author_name', 'project_url']
|
||||
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
self.event = get_object_or_404(models.Event, date=timezone.now().date(), accept_projects=True)
|
||||
return super().dispatch(request, *args, **kwargs)
|
||||
|
||||
def form_valid(self, form):
|
||||
url = form.cleaned_data['url']
|
||||
form.instance.project_id = get_scratch_id_from_url(url)
|
||||
form.instance.event = self.event
|
||||
return super().form_valid(form)
|
||||
|
||||
|
||||
class ScratchProjectDetailView(DetailView):
|
||||
model = models.ScratchProject
|
||||
|
||||
class EventDetailView(DetailView):
|
||||
model = models.Event
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
context['projects'] = models.ScratchProject.objects.filter(event=context['object'].pk)
|
||||
return context
|
||||
|
|
Loading…
Reference in a new issue