automate study guides

This commit is contained in:
lauren 2021-01-16 00:54:37 -05:00
parent 28dd5563a5
commit 3557f36069
18 changed files with 206 additions and 37 deletions

1
.gitignore vendored
View File

@ -6,3 +6,4 @@ venv
.venv .venv
db.sqlite3 db.sqlite3
media media
key.json

View File

@ -9,4 +9,5 @@ verify_ssl = true
django = "*" django = "*"
social-auth-app-django = "*" social-auth-app-django = "*"
pillow = "~=6.0" pillow = "~=6.0"
whitenoise = "*" whitenoise = "*"
django-googledrive-storage = "*"

View File

@ -1,8 +1,9 @@
from django.contrib import admin from django.contrib import admin
from .models import Subject, Course, Guide, Tag from .models import Subject, Course, Guide, Tag, Request
# Register your models here. # Register your models here.
admin.site.register(Subject) admin.site.register(Subject)
admin.site.register(Course) admin.site.register(Course)
admin.site.register(Guide) admin.site.register(Guide)
admin.site.register(Tag) admin.site.register(Tag)
admin.site.register(Request)

View File

@ -0,0 +1,9 @@
from django import forms
from .models import Request, Course, Tag
class StudyGuideRequestForm(forms.Form):
name = forms.CharField(max_length=100)
course = forms.ModelChoiceField(queryset=Course.objects.all())
tags = forms.ModelMultipleChoiceField(queryset=Tag.objects.all(), required=False)
guide = forms.FileField()

View File

@ -0,0 +1,28 @@
# Generated by Django 3.0.6 on 2021-01-16 03:49
from django.db import migrations, models
import gdstorage.storage
class Migration(migrations.Migration):
dependencies = [
('courses', '0008_auto_20201104_1557'),
]
operations = [
migrations.AlterModelOptions(
name='tag',
options={'ordering': ['url']},
),
migrations.CreateModel(
name='Request',
fields=[
('id', models.AutoField(primary_key=True, serialize=False)),
('name', models.CharField(max_length=100, unique=True)),
('guide', models.FileField(storage=gdstorage.storage.GoogleDriveStorage(), upload_to='guides')),
('course', models.ManyToManyField(related_name='proposed_course', to='courses.Course')),
('tags', models.ManyToManyField(related_name='proposed_tags', to='courses.Tag')),
],
),
]

View File

@ -1,6 +1,9 @@
from django.db import models from django.db import models
from django.core.validators import RegexValidator, FileExtensionValidator from django.core.validators import RegexValidator, FileExtensionValidator
from gdstorage.storage import GoogleDriveStorage
gd_storage = GoogleDriveStorage()
class Subject(models.Model): class Subject(models.Model):
id = models.AutoField(primary_key=True) id = models.AutoField(primary_key=True)
@ -45,4 +48,14 @@ class Tag(models.Model):
ordering = ['url'] ordering = ['url']
def __str__(self): def __str__(self):
return self.name return self.name
class Request(models.Model):
id = models.AutoField(primary_key=True)
course = models.ManyToManyField("Course", related_name="proposed_course")
tags = models.ManyToManyField("Tag", related_name="proposed_tags")
name = models.CharField(max_length=100, unique=True)
guide = models.FileField(upload_to='guides', storage=gd_storage)
def __str__(self):
return self.name

View File

@ -8,5 +8,8 @@ urlpatterns = [
path("subject/<str:subject_url>/", views.subject_view, name="subject_view"), path("subject/<str:subject_url>/", views.subject_view, name="subject_view"),
path("tag/<str:tag>/", views.tag_view, name="tag"), path("tag/<str:tag>/", views.tag_view, name="tag"),
path("course/<str:subject_url>/<str:course_url>/", views.course_view, name="course_view"), path("course/<str:subject_url>/<str:course_url>/", views.course_view, name="course_view"),
path("search/", views.search_view, name="search") path("search/", views.search_view, name="search"),
path("add/", views.add_view, name="add"),
path("approve-index/", views.approve_index_view, name="approve_index_view"),
path("approve/<int:request_id>/", views.approve_view, name="approve_view"),
] ]

View File

@ -6,8 +6,13 @@ from django import http
from django.shortcuts import render, redirect, reverse, get_object_or_404 from django.shortcuts import render, redirect, reverse, get_object_or_404
from django.db.models import Q from django.db.models import Q
from django.contrib.auth.decorators import login_required from django.contrib.auth.decorators import login_required
from gdstorage.storage import GoogleDriveStorage
from django.core.exceptions import PermissionDenied
from .models import Subject, Course, Guide, Tag from .models import Subject, Course, Guide, Tag, Request
from .forms import StudyGuideRequestForm
gd_storage = GoogleDriveStorage()
@login_required @login_required
def subject_view(request, subject_url): def subject_view(request, subject_url):
@ -41,6 +46,54 @@ def search_view(request):
"tag_results": Tag.objects.filter(reduce(operator.or_, (Q(name__icontains=x) for x in q_list))), "tag_results": Tag.objects.filter(reduce(operator.or_, (Q(name__icontains=x) for x in q_list))),
"sq": q "sq": q
} }
return render(request, 'search_results.html', context=context) return render(request, "search_results.html", context=context)
return redirect(request.META["HTTP_REFERER"]) return redirect(request.META["HTTP_REFERER"])
@login_required
def add_view(request):
if request.method == "POST":
form = StudyGuideRequestForm(request.POST, request.FILES)
if form.is_valid():
r = Request(name=form.cleaned_data["name"])
r.save()
r.course.add(form.cleaned_data["course"])
for t in form.cleaned_data["tags"]:
r.tags.add(t)
r.guide = form.cleaned_data["guide"]
r.save()
return redirect(reverse("home:index"))
return render(request, "add.html", context={"form": form})
else:
form = StudyGuideRequestForm()
return render(request, "add.html", context={"form": form})
@login_required
def approve_index_view(request):
if request.user.is_superuser or request.user.is_staff:
return render(request, "approve_index.html", context={"guide_requests": Request.objects.all()})
raise PermissionDenied
@login_required
def approve_view(request, request_id):
if request.user.is_superuser or request.user.is_staff:
guide_request = Request.objects.get(id=request_id)
if request.method == "POST":
if request.POST.get("approve"):
guide = Guide(name=guide_request.name)
guide.save()
for t in guide_request.tags.all():
guide.tags.add(t)
guide.course = guide_request.course.all()[0]
guide.url = guide_request.guide.url
guide.save()
guide_request.delete()
return redirect(reverse("courses:approve_index_view"))
else:
ctx = {
"guide_request": guide_request,
"course": guide_request.course.all()[0],
"tags": guide_request.tags.all()
}
return render(request, "approve.html", context=ctx)
raise PermissionDenied

View File

@ -40,6 +40,7 @@ INSTALLED_APPS = [
'django.contrib.sessions', 'django.contrib.sessions',
'django.contrib.messages', 'django.contrib.messages',
'django.contrib.staticfiles', 'django.contrib.staticfiles',
'gdstorage',
'social_django', 'social_django',
'studyguides.apps.courses', 'studyguides.apps.courses',
'studyguides.apps.auth', 'studyguides.apps.auth',
@ -164,9 +165,7 @@ STATICFILES_DIRS = (
os.path.join(BASE_DIR, 'studyguides/static'), os.path.join(BASE_DIR, 'studyguides/static'),
) )
MEDIA_ROOT = os.path.join(BASE_DIR, 'studyguides/media') GOOGLE_DRIVE_STORAGE_JSON_KEY_FILE = os.path.join(BASE_DIR, 'studyguides/settings/key.json')
MEDIA_URL = "/media/"
USE_X_FORWARDED_HOST = True USE_X_FORWARDED_HOST = True

View File

@ -0,0 +1,11 @@
{% extends "base.html" %}
{% load static %}
{% block content %}
<form action='' method='post' enctype="multipart/form-data">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Submit">
</form>
{% endblock %}

View File

@ -0,0 +1,23 @@
{% extends "base.html" %}
{% load static %}
{% block content %}
<form action='' method='post'>
{% csrf_token %}
Name: {{ guide_request.name }}<br><br>
Course: {{ course }}<br><br>
Tags:
<ul>
{% for t in tags %}
<li>
{{ t }}
</li>
{% endfor %}
</ul>
Guide: <a href="{{ guide_request.guide.url }}">{{ guide_request.guide }}</a><br>
<br>
<input type="submit" name="approve" value="Approve">
<input type="submit" name="reject" value="Reject">
</form>
{% endblock %}

View File

@ -0,0 +1,14 @@
{% extends "base.html" %}
{% load static %}
{% block content %}
Click on a guide below to view and approve or reject it.
<ul>
{% for r in guide_requests %}
<li>
<a href="{% url 'courses:approve_view' r.id %}" >{{ r }}</a>
</li>
{% endfor %}
</ul>
{% endblock %}

View File

@ -30,35 +30,14 @@
<main> <main>
{% block disclaimer %}{% endblock %} {% block disclaimer %}{% endblock %}
{% if user.is_authenticated %} {% block search %}{% endblock %}
<form action="/search" method="get" autocomplete="off">
<input type="text" name="q" value="{% if sq %}{{ sq }}{% endif %}" placeholder="Search" aria-label="Search">
<button type="submit" class="search-button" aria-label="Search">
<i class="fas fa-search"></i>
</button>
</form>
<br>
{% endif %}
<div class="my-2"> <div class="my-2">
{% block path %}{% endblock %} {% block path %}{% endblock %}
</div> </div>
{% block content %}{% endblock %} {% block content %}{% endblock %}
</main> </main>
{% if user.is_authenticated %}
<div class="size-5 my-2 josefin-sans text-center"> {% block links %}{% endblock %}
{% if user.is_teacher %}
<a style="padding:20px;" target="_blank" href="https://docs.google.com/forms/d/e/1FAIpQLSddHARB7zIgCBN-swWkejx6f4wJNslxh5AnkS65BzJ2pt7uLQ/viewform?usp=sf_link">Report a Study Guide</a>
{% elif user.is_superuser or user.is_staff %}
<a style="padding:20px;" target="_blank" href="https://docs.google.com/forms/d/e/1FAIpQLSddHARB7zIgCBN-swWkejx6f4wJNslxh5AnkS65BzJ2pt7uLQ/viewform?usp=sf_link">Report a Study Guide</a>
<a style="padding:20px;" href="/admin">Access Admin Console</a>
{% endif %}
<a style="padding:20px;" target="_blank" href="https://docs.google.com/forms/d/1p7DvGQfJM8nG88fC7eQ4lWcdEOKjNixUtFoJ8zpq_Co/viewform?edit_requested=true">Add Study Guide</a>
</div>
<br>
<div class="size-5 my-2 josefin-sans text-center">
<a href="{% url 'auth:logout' %}">Logout</a>
</div>
{% endif %}
</body> </body>
</html> </html>

View File

@ -1,4 +1,4 @@
{% extends "base.html" %} {% load static %} {% extends "head_foot.html" %} {% load static %}
{% block path %} {% block path %}
<span class="bold size-2 hoverable"> <span class="bold size-2 hoverable">
<a href="/"> <a href="/">

View File

@ -0,0 +1,34 @@
{% extends "base.html" %}
{% load static %}
{% block search %}
{% if user.is_authenticated %}
<form action="/search" method="get" autocomplete="off">
<input type="text" name="q" value="{% if sq %}{{ sq }}{% endif %}" placeholder="Search" aria-label="Search">
<button type="submit" class="search-button" aria-label="Search">
<i class="fas fa-search"></i>
</button>
</form>
<br>
{% endif %}
{% endblock %}
{% block links %}
{% if user.is_authenticated %}
<div class="size-5 my-2 josefin-sans text-center">
{% if user.is_teacher %}
<a style="padding:20px;" target="_blank" href="https://docs.google.com/forms/d/e/1FAIpQLSddHARB7zIgCBN-swWkejx6f4wJNslxh5AnkS65BzJ2pt7uLQ/viewform?usp=sf_link">Report a Study Guide</a>
{% elif user.is_superuser or user.is_staff %}
<a style="padding:20px;" target="_blank" href="https://docs.google.com/forms/d/e/1FAIpQLSddHARB7zIgCBN-swWkejx6f4wJNslxh5AnkS65BzJ2pt7uLQ/viewform?usp=sf_link">Report a Study Guide</a>
<a style="padding:20px;" href="/admin">Access Admin Console</a>
<a style="padding:20px;" href="{% url 'courses:approve_index_view' %}">Approve Study Guides</a>
{% endif %}
<a style="padding:20px;" href="{% url 'courses:add' %}">Add Study Guide</a>
</div>
<br>
<div class="size-5 my-2 josefin-sans text-center">
<a href="{% url 'auth:logout' %}">Logout</a>
</div>
{% endif %}
{% endblock %}

View File

@ -1,4 +1,4 @@
{% extends "base.html" %} {% load static %} {% extends "head_foot.html" %} {% load static %}
{% block disclaimer %} {% block disclaimer %}
<p> <p>
DISCLAIMER: Please note these materials are student-made study guides over the past years. Some information may be outdated or not 100% reflective of the content your teacher is teaching. It is also possible the information is not 100% accurate. Therefore, make sure to not solely rely on these study guides. If you see an inconsistency in a study guide that confuses you, ask your teacher to clarify. SGA maintains this site but is not liable for the credibility of the information found. To contact SGA, please email SGA.tjhsst@gmail.com. DISCLAIMER: Please note these materials are student-made study guides over the past years. Some information may be outdated or not 100% reflective of the content your teacher is teaching. It is also possible the information is not 100% accurate. Therefore, make sure to not solely rely on these study guides. If you see an inconsistency in a study guide that confuses you, ask your teacher to clarify. SGA maintains this site but is not liable for the credibility of the information found. To contact SGA, please email SGA.tjhsst@gmail.com.

View File

@ -1,4 +1,4 @@
{% extends "base.html" %} {% load static %} {% extends "head_foot.html" %} {% load static %}
{% block path %} {% block path %}
<span class="bold size-2 hoverable"> <span class="bold size-2 hoverable">
<a href="{% url 'home:index' %}"> <a href="{% url 'home:index' %}">

View File

@ -1,4 +1,4 @@
{% extends "base.html" %} {% extends "head_foot.html" %}
{% load static %} {% load static %}