Working Mod Pipeline

This commit is contained in:
Keegan 2020-03-23 05:14:18 -04:00
parent 78839a4e6c
commit 5d0a69c705
78 changed files with 593 additions and 14 deletions

View File

@ -2,4 +2,5 @@ from django.apps import AppConfig
class AuthConfig(AppConfig):
name = 'auth'
name = 'server.apps.auth'
label = 'authentication'

View File

@ -25,4 +25,11 @@ def login(request):
request.session["type"] = user_data["user_type"]
return redirect(reverse("index"))
except InvalidGrantError:
return redirect(reverse("login"))
return redirect(reverse("login"))
def logout(request):
if 'user' in request.session.keys():
del request.session["user"]
if 'type' in request.session.keys():
del request.session["type"]
return redirect(reverse("index"))

View File

@ -1,16 +1,14 @@
from django.shortcuts import render
from django.conf import settings
from ..decorators import login
from ..mod.models import Moderator
# Create your views here.
@login
def index(request):
if 'type' in request.session and request.session['type'] in settings.ALLOWED_USERS:
return render(
request,
'index.html',
{
'user': request.session['user'],
},
)
else:
request.session.flush()
return render(request, 'disallow.html')
is_mod = Moderator.objects.filter(username=request.session['user']).count() > 0
return render(request, 'index.html', { 'user': request.session['user'], 'is_mod': is_mod} )

View File

View File

@ -0,0 +1,6 @@
from django.contrib import admin
from .models import Course
# Register your models here.
admin.site.register(Course)

View File

@ -0,0 +1,5 @@
from django.apps import AppConfig
class ClassConfig(AppConfig):
name = 'course'

View File

@ -0,0 +1,23 @@
# Generated by Django 2.2.10 on 2020-03-02 04:05
from django.db import migrations, models
class Migration(migrations.Migration):
initial = True
dependencies = [
('files', '0002_auto_20200302_0345'),
]
operations = [
migrations.CreateModel(
name='Course',
fields=[
('id', models.AutoField(primary_key=True, serialize=False)),
('name', models.CharField(max_length=100, unique=True)),
('files', models.ManyToManyField(blank=True, related_name='classes', to='files.File')),
],
),
]

View File

@ -0,0 +1,19 @@
# Generated by Django 2.2.10 on 2020-03-02 04:19
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('course', '0001_initial'),
]
operations = [
migrations.AddField(
model_name='course',
name='url',
field=models.CharField(default='-', max_length=20, unique=True),
preserve_default=False,
),
]

View File

@ -0,0 +1,19 @@
# Generated by Django 2.2.10 on 2020-03-22 17:58
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('files', '0002_auto_20200302_0345'),
('course', '0002_course_url'),
]
operations = [
migrations.AddField(
model_name='course',
name='unapproved_files',
field=models.ManyToManyField(blank=True, related_name='classes_unap', to='files.File'),
),
]

View File

@ -0,0 +1,19 @@
# Generated by Django 2.2.10 on 2020-03-23 04:32
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('files', '0002_auto_20200302_0345'),
('course', '0003_course_unapproved_files'),
]
operations = [
migrations.AddField(
model_name='course',
name='rejected_files',
field=models.ManyToManyField(blank=True, related_name='classes_reject', to='files.File'),
),
]

View File

@ -0,0 +1,17 @@
from django.db import models
# Create your models here.
class Course(models.Model):
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=100, unique=True)
url = models.CharField(max_length=20, unique=True)
unapproved_files = models.ManyToManyField("files.File", related_name="classes_unap", blank=True)
files = models.ManyToManyField("files.File", related_name="classes", blank=True)
rejected_files = models.ManyToManyField("files.File", related_name="classes_reject", blank=True)
def __str__(self):
return self.name

View File

@ -0,0 +1,3 @@
from django.test import TestCase
# Create your tests here.

View File

@ -0,0 +1,13 @@
from django.urls import path
from . import views
app_name = "course"
urlpatterns = [
path("", views.index, name="index"),
path("<str:course_url>", views.show, name="show"),
path("<str:course_url>/approve/<int:doc_id>", views.approve, name="approve"),
path("<str:course_url>/remove/<int:doc_id>", views.remove, name="remove"),
path("<str:course_url>/undelete/<int:doc_id>", views.undelete, name="undelete"),
]

View File

@ -0,0 +1,111 @@
from django.shortcuts import render, get_object_or_404
from django.core.exceptions import PermissionDenied
from django.http import Http404
from .models import Course
from ..mod.models import Moderator
from ..files.models import File
from ..decorators import login
# Create your views here.
@login
def index(request):
courses = Course.objects.all()
return render(request, 'class/index.html', {'classes': courses})
@login
def show(request, course_url):
course = get_object_or_404(Course, url=course_url)
is_mod = False
try:
mod = Moderator.objects.get(username=request.session['user'])
except Moderator.DoesNotExist:
is_mod = False
if mod.admin:
is_mod = True
elif course in mod.classes.all():
is_mod = True
return render(request, 'class/show.html', {'course': course, 'is_mod': is_mod})
@login
def approve(request, course_url, doc_id):
course = get_object_or_404(Course, url=course_url)
try:
mod = Moderator.objects.get(username=request.session['user'])
except Moderator.DoesNotExist:
raise PermissionDenied
if mod.admin or (course in mod.classes.all()):
try:
doc = course.unapproved_files.get(id=doc_id)
except File.DoesNotExist:
try:
doc = course.files.get(id=doc_id)
except File.DoesNotExist:
raise Http404("Error: Document Not Related to this Course")
raise Http404("Error: Document Already Approved")
course.unapproved_files.remove(doc)
course.files.add(doc)
return render(request, 'class/approve.html', {'doc': doc, 'course': course})
else:
raise PermissionDenied
@login
def remove(request, course_url, doc_id):
course = get_object_or_404(Course, url=course_url)
try:
mod = Moderator.objects.get(username=request.session['user'])
except Moderator.DoesNotExist:
raise PermissionDenied
if mod.admin or (course in mod.classes.all()):
try:
doc = course.files.get(id=doc_id)
except File.DoesNotExist:
try:
doc = course.unapproved_files.get(id=doc_id)
except File.DoesNotExist:
raise Http404("Error: Document Not Related to this Course")
course.unapproved_files.remove(doc)
course.rejected_files.add(doc)
return render(request, 'class/remove.html', {'doc': doc, 'course': course})
course.files.remove(doc)
course.rejected_files.add(doc)
return render(request, 'class/remove.html', {'doc': doc, 'course': course})
else:
raise PermissionDenied
@login
def undelete(request, course_url, doc_id):
course = get_object_or_404(Course, url=course_url)
try:
mod = Moderator.objects.get(username=request.session['user'])
except Moderator.DoesNotExist:
raise PermissionDenied
if mod.admin or (course in mod.classes.all()):
try:
doc = course.rejected_files.get(id=doc_id)
except File.DoesNotExist:
raise Http404("Error: Document Not Related to this Course")
course.rejected_files.remove(doc)
course.files.add(doc)
return render(request, 'class/undelete.html', {'doc': doc, 'course': course})
else:
raise PermissionDenied

View File

@ -0,0 +1,15 @@
from django.shortcuts import render
from django.conf import settings
def login(function):
def wrap(request, *args, **kwargs):
if 'type' in request.session and request.session['type'] in settings.ALLOWED_USERS:
return function(request, *args, **kwargs)
else:
request.session.flush()
return render(request, 'disallow.html')
wrap.__doc__ = function.__doc__
wrap.__name__ = function.__name__
return wrap

View File

View File

@ -0,0 +1,8 @@
from django.contrib import admin
from .models import File
# Register your models here.
@admin.register(File)
class FileAdmin(admin.ModelAdmin):
readonly_fields = ('id',)

View File

@ -0,0 +1,5 @@
from django.apps import AppConfig
class FilesConfig(AppConfig):
name = 'files'

View File

@ -0,0 +1,8 @@
from django import forms
from .models import File
class UploadFileForm(forms.ModelForm):
class Meta:
model = File
fields = ["name", "payload"]

View File

@ -0,0 +1,21 @@
# Generated by Django 2.2.10 on 2020-03-02 01:51
from django.db import migrations, models
class Migration(migrations.Migration):
initial = True
dependencies = [
]
operations = [
migrations.CreateModel(
name='File',
fields=[
('id', models.AutoField(primary_key=True, serialize=False)),
('name', models.CharField(max_length=100, unique=True)),
],
),
]

View File

@ -0,0 +1,24 @@
# Generated by Django 2.2.10 on 2020-03-02 03:45
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('files', '0001_initial'),
]
operations = [
migrations.AddField(
model_name='file',
name='payload',
field=models.FileField(blank=True, upload_to=''),
),
migrations.AddField(
model_name='file',
name='uploader',
field=models.CharField(default='----', max_length=100),
preserve_default=False,
),
]

View File

@ -0,0 +1,20 @@
from django.db import models
from django.utils.text import slugify
from uuid import uuid4
from time import strftime
# Create your models here.
def gen_filename(instance, filename):
return "upload_{0}_{1}_{2}.{3}".format(strftime('%Y-%m-%d-%H-%M%S'), uuid4(), slugify(instance.name), filename.split('.')[-1])
class File(models.Model):
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=100, unique=True)
uploader = models.CharField(max_length=100)
payload = models.FileField(blank=True, upload_to=gen_filename)
def __str__(self):
return self.name

View File

@ -0,0 +1,3 @@
from django.test import TestCase
# Create your tests here.

View File

@ -0,0 +1,18 @@
from django.shortcuts import render
from django.http import HttpResponseRedirect
from .forms import UploadFileForm
from .models import File
# Create your views here.
def upload_file(request):
if 'type' in request.session and request.session['type'] in settings.ALLOWED_USERS:
if request.method == 'POST':
form = UploadFileForm(request.POST, request.FILES)
if form.is_valid():
inst = File(name=request.POST['title'] , payload=request.FILES['file'])
inst.save()
return HttpResponseRedirect('/upload/success')
else:
form = UploadFileForm()
return render(request, 'upload.html', {'form':form})

View File

Binary file not shown.

View File

@ -0,0 +1,7 @@
from django.contrib import admin
from .models import Moderator
# Register your models here.
admin.site.register(Moderator)

View File

@ -0,0 +1,5 @@
from django.apps import AppConfig
class ModConfig(AppConfig):
name = 'mod'

View File

@ -0,0 +1,24 @@
# Generated by Django 2.2.10 on 2020-03-02 04:06
from django.db import migrations, models
class Migration(migrations.Migration):
initial = True
dependencies = [
('course', '0001_initial'),
]
operations = [
migrations.CreateModel(
name='Moderator',
fields=[
('id', models.AutoField(primary_key=True, serialize=False)),
('username', models.CharField(max_length=16, unique=True)),
('admin', models.BooleanField(default=False)),
('classes', models.ManyToManyField(blank=True, related_name='mods', to='course.Course')),
],
),
]

View File

@ -0,0 +1,13 @@
from django.db import models
# Create your models here.
class Moderator(models.Model):
id = models.AutoField(primary_key=True)
username = models.CharField(max_length=16, unique=True)
admin = models.BooleanField(default=False)
classes = models.ManyToManyField("course.Course", related_name="mods", blank=True)
def __str__(self):
return self.username

View File

@ -0,0 +1,3 @@
from django.test import TestCase
# Create your tests here.

View File

@ -0,0 +1,9 @@
from django.urls import path
from . import views
app_name = "mod"
urlpatterns = [
path("", views.dashboard, name="dash"),
]

View File

@ -0,0 +1,24 @@
from django.shortcuts import render, get_object_or_404
from .models import Moderator
from ..course.models import Course
from ..decorators import login
# Create your views here.
@login
def dashboard(request):
try:
mod = Moderator.objects.get(username=request.session['user'])
except Moderator.DoesNotExist:
return render(request, 'mod/not_mod.html', {'user': request.session['user']})
classes = mod.classes.all()
if mod.admin:
classes = Course.objects.all()
if not classes:
return render(request, 'mod/not_mod.html', {'user': request.session['user']})
return render(request, 'mod/index.html', {'user': request.session['user'], 'classes': classes})

View File

@ -38,6 +38,11 @@ INSTALLED_APPS = [
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'server.apps.files',
'server.apps.mod',
'server.apps.content',
'server.apps.auth.apps.AuthConfig',
'server.apps.course',
]
MIDDLEWARE = [
@ -84,6 +89,10 @@ DATABASES = {
}
MEDIA_ROOT = os.path.join(BASE_DIR, 'media/')
STATIC_ROOT = os.path.join(BASE_DIR, 'static/')
MEDIA_URL = '/media/'
# Password validation
# https://docs.djangoproject.com/en/2.2/ref/settings/#auth-password-validators

View File

@ -0,0 +1,4 @@
{% extends 'base.html' %}
{% block body %}
Success. You have Approved {{ doc.name }} by {{ doc.uploader }} <a href="{{ doc.payload.url }}">Download</a> for the Course <a href="{% url 'courses:show' course.url %}">{{ course.name }}</a>.
{% endblock %}

View File

@ -0,0 +1,15 @@
{% extends 'base.html' %}
{% block body %}
<div class="header">
<h1>Classes</h1>
</div>
<div class="main">
{% for class in classes %}
<div>
<a href="{% url 'courses:show' class.url %}">{{class.name}}</a>
<p>{{ class.files.all|length }} Document</p>
</div>
{% endfor %}
</div>
{% endblock %}

View File

@ -0,0 +1,4 @@
{% extends 'base.html' %}
{% block body %}
Success. You have Removed {{ doc.name }} by {{ doc.uploader }} <a href="{{ doc.payload.url }}">Download</a> for the Course <a href="{% url 'courses:show' course.url %}">{{ course.name }}</a>.
{% endblock %}

View File

@ -0,0 +1,59 @@
{% extends 'base.html' %}
{% block head %}
<style>
.unapproved {
border: 5px;
border-color: blue;
border-style: solid;
}
.removed {
border: 5px;
border-color: red;
border-style: solid;
}
</style>
{% endblock %}
{% block body %}
<div class="header">
<h1>{{ course.name }}</h1>
</div>
<div class="main">
{% if is_mod %}
<h3>You have moderator permissions on this course, which means you can approve of reject uploaded files.</h3>
{% endif %}
{% for doc in course.files.all %}
<div>
<h3>{{ doc.name }}</h3>
<a href="{{ doc.payload.url }}">Download</a>
<p>Uploaded By {{ doc.uploader }}</p>
{% if is_mod %}
<a href="{% url 'courses:remove' course_url=course.url doc_id=doc.id %}">REMOVE</a>
{% endif %}
</div>
{% endfor %}
{% if is_mod %}
{% for doc in course.unapproved_files.all %}
<div class='unapproved'>
<h3>UNAPPROVED</h3>
<h3>{{ doc.name }}</h3>
<a href="{{ doc.payload.url }}">Download</a>
<p>Uploaded By {{ doc.uploader }}</p>
<a href="{% url 'courses:approve' course_url=course.url doc_id=doc.id %}">APPROVE</a>
<a href="{% url 'courses:remove' course_url=course.url doc_id=doc.id %}">REMOVE</a>
</div>
{% endfor %}
{% for doc in course.rejected_files.all %}
<div class='removed'>
<h3>UNAPPROVED</h3>
<h3>{{ doc.name }}</h3>
<a href="{{ doc.payload.url }}">Download</a>
<p>Uploaded By {{ doc.uploader }}</p>
<a href="{% url 'courses:undelete' course_url=course.url doc_id=doc.id %}">UNDELETE</a>
</div>
{% endfor %}
{% endif %}
</div>
{% endblock %}

View File

@ -0,0 +1,4 @@
{% extends 'base.html' %}
{% block body %}
Success. You have Restored {{ doc.name }} by {{ doc.uploader }} <a href="{{ doc.payload.url }}">Download</a> for the Course <a href="{% url 'courses:show' course.url %}">{{ course.name }}</a>.
{% endblock %}

View File

@ -2,4 +2,9 @@
{% block body %}
<h1 class="text-4xl font-bold">Study Bank</h1>
<h3> Welcome, {{ user }}</h3>
{% if is_mod %}
<a href='{% url 'mod:dash' %}'>Moderator Dashboard</a>
{% endif %}
<a href='{% url 'course:index' %}'>View Courses</a>
{% endblock %}

View File

@ -0,0 +1,16 @@
{% extends 'base.html' %}
{% block body %}
<div class="header">
<h1>Classes Moderated by {{ user }}</h1>
</div>
<div class="main">
{% for class in classes %}
<div>
<a href="{% url 'courses:show' class.url %}">{{class.name}}</a>
<p>{{ class.files.all|length }} Document</p>
</div>
{% endfor %}
</div>
{% endblock %}

View File

@ -0,0 +1,10 @@
{% extends 'base.html' %}
{% block body %}
<div class="header">
<h1>Access Denied</h1>
</div>
<div class="main">
<p>Sorry, {{ user }}, but you do not have moderator permissions over any sites.</p>
</div>
{% endblock %}

View File

@ -14,13 +14,18 @@ Including another URLconf
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
"""
from django.contrib import admin
from django.urls import path
from django.urls import path, include
from .apps.auth import views as auth_views
from .apps.content import views as content_views
from .apps.course import views as course_views
from .apps.mod import views as mod_views
urlpatterns = [
path('admin/', admin.site.urls),
path('login/', auth_views.login, name="login"),
path('logout/', auth_views.logout, name="logout"),
path('courses/', include("server.apps.course.urls", namespace="courses")),
path('mod/', include("server.apps.mod.urls", namespace="mod")),
path('', content_views.index, name="index"),
]