This commit is contained in:
stupidcomputer 2024-06-21 03:02:03 -05:00
parent ca61adc1e6
commit 79d441d1f6
13 changed files with 214 additions and 13 deletions

10
docker-compose.yml Normal file
View File

@ -0,0 +1,10 @@
version: '3.8'
services:
web:
build: ./franklincce
command: gunicorn franklincce.wsgi:application --bind 0.0.0.0:8000
volumes:
- ./franklincce/:/usr/src/franklincce
ports:
- 8000:8000

20
franklincce/Dockerfile Normal file
View File

@ -0,0 +1,20 @@
FROM python:3.11.4-slim-buster
# set work directory
WORKDIR /usr/src/app
# set environment variables
ENV PYTHONDONTWRITEBYTECODE 1
ENV PYTHONUNBUFFERED 1
# install dependencies
RUN pip install --upgrade pip
COPY ./requirements.txt .
RUN pip install -r requirements.txt
# copy project
COPY . .
RUN mkdir /var/www/static -p
RUN python3 manage.py collectstatic --noinput

View File

@ -5,6 +5,8 @@ from .lib.parsers import HSYIG, HSMUN
import io import io
import fitz import fitz
from collections import namedtuple
class LegislationBook(models.Model): class LegislationBook(models.Model):
class ConferenceType(models.TextChoices): class ConferenceType(models.TextChoices):
MIDDLE = "M", _("Middle School") MIDDLE = "M", _("Middle School")
@ -106,3 +108,7 @@ class LegislativeText(models.Model):
self.committee, self.committee,
self.docket_order, self.docket_order,
) )
def get_lines(self):
cls = namedtuple('LegLine', ['linenumber', 'linetext'])
return [cls(i + 1, j) for i, j in enumerate(self.text.split('\n'))]

View File

@ -0,0 +1,15 @@
{% extends "explorer/base.html" %}
{% block content %}
<h1>All legislative texts</h1>
{% if legislative_texts %}
<ul>
{% for text in legislative_texts %}
<li><a href="{% url 'viewleg' text.id %}">{{ text.legislation_title }}</a></li>
{% endfor %}
</ul>
{% else %}
<p>No texts available</p>
{% endif %}
{% endblock content %}

View File

@ -0,0 +1,29 @@
<!DOCTYPE html>
<html>
<head>
{% if page_title %}
<title>explorer - {{ title }}</title>
{% else %}
<title>explorer</title>
{% endif %}
<link rel="stylesheet" href="/static/style.css">
</head>
<body>
<nav id="navbar">
<div id="leftnav">
<a href="/explorer">explorer</a>
</div>
<div id="rightnav">
<a href="/explorer/all">all</a>
<a href="/explorer/topics">by topic</a>
<a href="/explorer/search">search</a>
<a href="/explorer/stats">stats</a>
</div>
</nav>
{% block content %}
{% endblock content %}
</body>
</html>

View File

@ -1,3 +1,12 @@
{% extends "explorer/base.html" %}
{% block content %}
<h1>Welcome to explorer</h1>
<p><i>an interactive database for YMCA CCE legislation</i></p>
<h2>Some randomly selected legislation</h2>
{% if legislative_texts %} {% if legislative_texts %}
<ul> <ul>
{% for text in legislative_texts %} {% for text in legislative_texts %}
@ -7,3 +16,4 @@
{% else %} {% else %}
<p>No texts available</p> <p>No texts available</p>
{% endif %} {% endif %}
{% endblock content %}

View File

@ -1,9 +1,24 @@
<h1>{{ legislation.legislation_title }}</h1> {% extends "explorer/base.html" %}
{% block content %}
<div id="legcontainer">
<div id="leginfo" class="boxed">
<h1 class="no-margin-top wrapword">{{ legislation.legislation_title }}</h1>
<i>{{ legislation.assembly }}/{{ legislation.committee }}/{{ legislation.docket_order }}</i> <i>{{ legislation.assembly }}/{{ legislation.committee }}/{{ legislation.docket_order }}</i>
<p>Sponsored by {{ legislation.sponsors }} of {{ legislation.school }}</p> <p>Sponsored by {{ legislation.sponsors }} of {{ legislation.school }}</p>
</div>
<blockquote> <div id="legislation" class="boxed">
{{ legislation.text }} <table>
</blockquote> {% for line in lines %}
<tr>
<td class="legnumbers">{{ line.linenumber }}</td>
<td>{{ line.linetext }}</td>
</tr>
{% endfor %}
</table>
</div>
</div>
{% endblock content %}

View File

@ -4,5 +4,6 @@ from . import views
urlpatterns = [ urlpatterns = [
path("", views.index, name="index"), path("", views.index, name="index"),
path("all/", views.all, name="all"),
path("legislation/<int:legislation_id>/", views.view_legislation, name="viewleg"), path("legislation/<int:legislation_id>/", views.view_legislation, name="viewleg"),
] ]

View File

@ -3,16 +3,27 @@ from django.http import HttpResponse
from .models import LegislativeText, LegislationBook from .models import LegislativeText, LegislationBook
from random import sample
def index(request): def index(request):
legislative_texts = LegislativeText.objects.all() legislative_texts = list(LegislativeText.objects.all())
legislative_texts = sample(legislative_texts, 5)
context = { context = {
"legislative_texts": legislative_texts, "legislative_texts": legislative_texts,
} }
return render(request, "explorer/index.html", context) return render(request, "explorer/index.html", context)
def all(request):
legislative_texts = list(LegislativeText.objects.all())
context = {
"legislative_texts": legislative_texts,
}
return render(request, "explorer/all.html", context)
def view_legislation(request, legislation_id): def view_legislation(request, legislation_id):
legislation = get_object_or_404(LegislativeText, pk=legislation_id) legislation = get_object_or_404(LegislativeText, pk=legislation_id)
context = { context = {
"legislation": legislation, "legislation": legislation,
"lines": legislation.get_lines()
} }
return render(request, "explorer/legislation.html", context) return render(request, "explorer/legislation.html", context)

View File

@ -15,7 +15,6 @@ from pathlib import Path
# 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
# Quick-start development settings - unsuitable for production # Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/4.2/howto/deployment/checklist/ # See https://docs.djangoproject.com/en/4.2/howto/deployment/checklist/
@ -25,8 +24,7 @@ SECRET_KEY = 'django-insecure-1%p#re)z*_xd9umo0!1foh(yiz&2=*5q#0b4(m42r0^m%kxli#
# SECURITY WARNING: don't run with debug turned on in production! # SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True DEBUG = True
ALLOWED_HOSTS = [] ALLOWED_HOSTS = ["localhost", "127.0.0.1", "[::1]"]
# Application definition # Application definition
@ -81,6 +79,9 @@ DATABASES = {
} }
} }
STATICFILES_DIRS = [
BASE_DIR / "static",
]
# Password validation # Password validation
# https://docs.djangoproject.com/en/4.2/ref/settings/#auth-password-validators # https://docs.djangoproject.com/en/4.2/ref/settings/#auth-password-validators
@ -100,7 +101,6 @@ AUTH_PASSWORD_VALIDATORS = [
}, },
] ]
# Internationalization # Internationalization
# https://docs.djangoproject.com/en/4.2/topics/i18n/ # https://docs.djangoproject.com/en/4.2/topics/i18n/
@ -116,7 +116,7 @@ USE_TZ = True
# Static files (CSS, JavaScript, Images) # Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/4.2/howto/static-files/ # https://docs.djangoproject.com/en/4.2/howto/static-files/
STATIC_URL = 'static/' STATIC_URL = '/static/'
# Default primary key field type # Default primary key field type
# https://docs.djangoproject.com/en/4.2/ref/settings/#default-auto-field # https://docs.djangoproject.com/en/4.2/ref/settings/#default-auto-field

View File

@ -16,8 +16,10 @@ Including another URLconf
""" """
from django.contrib import admin from django.contrib import admin
from django.urls import include, path from django.urls import include, path
from django.conf import settings
from django.conf.urls.static import static
urlpatterns = [ urlpatterns = [
path('explorer/', include("explorer.urls")), path('explorer/', include("explorer.urls")),
path('admin/', admin.site.urls), path('admin/', admin.site.urls),
] ] + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)

View File

@ -0,0 +1,3 @@
django
pymupdf
gunicorn

View File

@ -0,0 +1,79 @@
body {
font-family: sans-serif;
}
nav#navbar {
border-bottom: 1px solid black; /* block for top bar */
padding-bottom: 10px;
display: flex; /* make it from left to right */
flex-direction: row;
}
#leftnav {
padding-right: 10px;
}
#rightnav {
padding-left: 10px;
/* make this part right justified */
margin-left: auto;
margin-right: 0;
}
#legcontainer {
display: flex;
flex-direction: row;
gap: 5px;
}
#leginfo {
width: 15em;
}
#legislation {
width: 100%;
}
@media only screen and (max-width: 280px) {
#rightnav {
display: none;
}
}
@media only screen and (max-width: 570px) {
#legcontainer {
flex-direction: column;
}
#leginfo {
width: 100%;
}
}
.no-margin-top {
margin-top: 0px;
}
.boxed {
margin-top: 10px;
padding: 5px;
padding-top: 0px;
border: solid 1px;
border-radius: 5px;
}
.wrapword {
white-space: -moz-pre-wrap !important;
white-space: -pre-wrap;
white-space: -o-pre-wrap;
white-space: pre-wrap;
word-wrap: break-word;
white-space: -webkit-pre-wrap;
word-break: break-all;
white-space: normal;
}
.legnumbers {
text-align: right;
user-select: none;
}