Skip to content
Snippets Groups Projects
Commit b7f2cc69 authored by Odin Johan Vatne's avatar Odin Johan Vatne
Browse files

Add endpoints for My Projects, small fixes

parent 57607729
No related branches found
No related tags found
No related merge requests found
{% load custom_filters %} {% load custom_filters %}
{% load html_components %} {% load html_components %}
<form action="/applications/update_professor_status/" method="post" id="status_edit_form"> <form action="/applications/update_professor_status/#NEXT" method="post" id="status_edit_form">
{% csrf_token %} {% csrf_token %}
<input type="hidden" name="application" id="status_id"> <input type="hidden" name="application" id="status_id">
<input type="hidden" name="action" id="status_action"> <input type="hidden" name="action" id="status_action">
......
{% extends 'pasapp/templates/base_template.html' %}
{% load static %}
{% block imports %}
<script src="{% static 'pasapp/js/tag_edit.js' %}"></script>
<script>
{% for projectTag in projectTags %}
tagSet.add({{projectTag.id}});
{% endfor %}
</script>
<script src="{% static 'pasapp/js/project_status_edit.js' %}"></script>
<script>
initialStatus = "Open";
</script>
{% endblock %}
{% block title %} Copying {{project.title}} {% endblock %}
{% block onload %} setInitialStatus() {% endblock %}
{% block content %}
<form action="/project/create/?next=/projects/mine/" method="post">
{% csrf_token %} {{ form.as_p }}
{% load html_components %}
<p>{% status_select %}</p>
{% tags_dropdown tags %}
<br>
{% tagbox_categorized projectTags True %}
<br>
<input type="submit" value="Create Copy"/>
</form>
{% endblock %}
...@@ -17,7 +17,7 @@ ...@@ -17,7 +17,7 @@
{% block title %} Editing {{project.title}} {% endblock %} {% block title %} Editing {{project.title}} {% endblock %}
{% block onload %} setInitialStatus() {% endblock %} {% block onload %} setInitialStatus() {% endblock %}
{% block content %} {% block content %}
<form action="/project/{{project.id}}/edit/" method="post"> <form action="/project/{{project.id}}/edit/?next={{next}}" method="post">
{% csrf_token %} {{ form.as_p }} {% csrf_token %} {{ form.as_p }}
{% load html_components %} {% load html_components %}
......
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
{% if user|is_professor %} {% if user|is_professor %}
<div class="floating-header" style="height: 3em;"> <div class="floating-header" style="height: 3em;">
<div> <div>
<a href="/project/create/" class="undecorated-link nav-item">Add new project</a> <a href="/project/create/" class="undecorated-link nav-item">Add new project</a>
</div> </div>
</div> </div>
{% endif %} {% endif %}
...@@ -22,7 +22,7 @@ ...@@ -22,7 +22,7 @@
<ul class="project-list"> <ul class="project-list">
{% for project in projects %} {% for project in projects %}
<li class="dashed-box project-listing"> <li class="dashed-box project-listing">
<a href="{% url 'project_detail' project.id %}" class="undecorated-link underline-hover"><b>{{ project.title }}</b></a> <a href="{% url 'project_details' project.id %}" class="undecorated-link underline-hover"><b>{{ project.title }}</b></a>
by by
<a href="/user/{{project.professor.username}}" class="undecorated-link underline-hover"> <a href="/user/{{project.professor.username}}" class="undecorated-link underline-hover">
<b>{{project.professor.first_name}} {{project.professor.last_name}}</b> <b>{{project.professor.first_name}} {{project.professor.last_name}}</b>
...@@ -43,7 +43,7 @@ ...@@ -43,7 +43,7 @@
<div id="sidebar"> <div id="sidebar">
<form action="/projects/filter/" method="post"> <form action="/projects/filter/" method="post">
{% csrf_token %} {% csrf_token %}
<h3 class="nobreak">Filter projects</h3> <button onclick="clearFilters()">Clear</button> <input type="submit" value="Filter"/> <h3 class="nobreak">Filter projects</h3> <button onclick="clearFilters()" type="button">Clear</button> <input type="submit" value="Filter"/>
<div class="split-content-container"> <div class="split-content-container">
<div class="filter-column"> <div class="filter-column">
{% tagfilters allTags selectedTags %} {% tagfilters allTags selectedTags %}
...@@ -62,7 +62,7 @@ ...@@ -62,7 +62,7 @@
{% endfor %} {% endfor %}
</div> </div>
</div> </div>
<button onclick="clearFilters()">Clear</button> <input type="submit" value="Filter"/> <button onclick="clearFilters()" type="button">Clear</button> <input type="submit" value="Filter"/>
</form> </form>
</div> </div>
</div> </div>
......
...@@ -24,6 +24,12 @@ def student_status(application): ...@@ -24,6 +24,12 @@ def student_status(application):
def professor_status(application): def professor_status(application):
return application.professor_status_label() return application.professor_status_label()
@register.filter(name='is_closed')
def is_closed(application):
closed = application.student_status in ('RETR', 'DECL')
closed = closed or application.professor_status == 'DECL'
return closed
@register.filter(name='minify') @register.filter(name='minify')
def minify(label): def minify(label):
mapping = { mapping = {
......
...@@ -11,12 +11,16 @@ urlpatterns = [ ...@@ -11,12 +11,16 @@ urlpatterns = [
path('register/', views.register, name='register'), path('register/', views.register, name='register'),
path('project/create/', views.create_project, name='create_project'), path('project/create/', views.create_project, name='create_project'),
path('project/<int:project_id>/', path('project/<int:project_id>/',
views.project_details, name='project_detail'), views.project_details, name='project_details'),
path('project/<int:project_id>/apply/', views.apply, name='apply'), path('project/<int:project_id>/apply/', views.apply, name='apply'),
path('project/<int:project_id>/applications/', path('project/<int:project_id>/applications/',
views.project_applications, name='project_applications'), views.project_applications, name='project_applications'),
path('project/<int:project_id>/edit/', path('project/<int:project_id>/edit/',
views.edit_project, name='edit_project'), views.edit_project, name='edit_project'),
path('project/<int:project_id>/copy/',
views.copy_project, name='copy_project'),
path('project/update_status/', views.set_project_status, name='update_project_status'),
path('project/delete/', views.delete_project, name='delete_project'),
path('projects/filter/', views.index, name='filter_projects'), path('projects/filter/', views.index, name='filter_projects'),
path('projects/mine/', views.my_projects, name='my_projects'), path('projects/mine/', views.my_projects, name='my_projects'),
path('applications/', views.my_applications, name='my_applications'), path('applications/', views.my_applications, name='my_applications'),
......
...@@ -13,3 +13,9 @@ def tagsByCategory(tags): ...@@ -13,3 +13,9 @@ def tagsByCategory(tags):
else: else:
tags_by_category[tag.category] = [tag,] tags_by_category[tag.category] = [tag,]
return tags_by_category return tags_by_category
def get_next(request, fallback='/'):
next = request.GET.get('next', fallback)
if next is None or next == "":
return fallback
return next
from django.contrib.auth import authenticate, login, logout, get_user_model from django.contrib.auth import authenticate, login, logout, get_user_model
from django.contrib.auth.decorators import login_required, user_passes_test from django.contrib.auth.decorators import login_required, user_passes_test
from django.contrib.auth.forms import AuthenticationForm from django.contrib.auth.forms import AuthenticationForm
from django.http.response import HttpResponseBadRequest, HttpResponseForbidden from django.http.response import HttpResponseBadRequest, HttpResponseForbidden, HttpResponseServerError
from django.shortcuts import get_object_or_404, redirect, render from django.shortcuts import get_object_or_404, redirect, render
from django.http import HttpResponse from django.http import HttpResponse
from django.db.models import F from django.db.models import F, Q
from pasapp.forms import ApplicationForm, NewProjectForm, NewUserForm,CommentForm from pasapp.forms import ApplicationForm, NewProjectForm, NewUserForm,CommentForm
from pasapp.models import Application, Comment, Project, ProjectTag, UserTag, Tag, TagCategory from pasapp.models import Application, Comment, Project, ProjectTag, UserTag, Tag, TagCategory
from pasapp.utils import contextWithHeader from pasapp.utils import application_declined, contextWithHeader, get_next, student_accepted, project_closed
from pasapp.templatetags.custom_filters import is_professor, is_student from pasapp.templatetags.custom_filters import is_professor, is_student, professor_status, student_status
from pasapp.queries import * from pasapp.queries import *
revoked_query = Q(student_status=Application.StudentStatus.RETRACTED) | Q(student_status=Application.StudentStatus.DECLINED)
declined_query = Q(professor_status=Application.ProfessorStatus.DECLINED)
app_closed_query = revoked_query | declined_query
def index(request): def index(request):
''' '''
Lists all active projects. Also handles filtering those projects via POST requests. Lists all active projects. Also handles filtering those projects via POST requests.
...@@ -223,7 +227,7 @@ def create_project(request): ...@@ -223,7 +227,7 @@ def create_project(request):
project_tag = ProjectTag(project=project, tag=tag) project_tag = ProjectTag(project=project, tag=tag)
project_tag.save() project_tag.save()
return redirect("index") return redirect(get_next(request))
form = NewProjectForm() form = NewProjectForm()
tags = Tag.objects.all() tags = Tag.objects.all()
context = {'form': form, 'tags': tags} context = {'form': form, 'tags': tags}
...@@ -248,6 +252,7 @@ def edit_project(request, project_id): ...@@ -248,6 +252,7 @@ def edit_project(request, project_id):
if form.is_valid(): if form.is_valid():
title = form.cleaned_data.get('title') title = form.cleaned_data.get('title')
description = form.cleaned_data.get('description') description = form.cleaned_data.get('description')
capacity = form.cleaned_data.get('capacity')
status = form.cleaned_data.get('status') status = form.cleaned_data.get('status')
if status in DEFAULT_STATUSES: if status in DEFAULT_STATUSES:
hidden = False if status == OPEN_STATUS else True hidden = False if status == OPEN_STATUS else True
...@@ -255,6 +260,7 @@ def edit_project(request, project_id): ...@@ -255,6 +260,7 @@ def edit_project(request, project_id):
hidden = form.cleaned_data.get('hidden') hidden = form.cleaned_data.get('hidden')
project.title = title project.title = title
project.description = description project.description = description
project.capacity = capacity
project.status = status project.status = status
project.hidden = hidden project.hidden = hidden
project.save() project.save()
...@@ -273,17 +279,86 @@ def edit_project(request, project_id): ...@@ -273,17 +279,86 @@ def edit_project(request, project_id):
project_tag.save() project_tag.save()
project_tags.exclude(tag__in=[int(tag) for tag in tag_list]).delete() project_tags.exclude(tag__in=[int(tag) for tag in tag_list]).delete()
return redirect(f'/project/{project_id}/') return redirect(get_next(request, f'/project/{project_id}/'))
else: else:
form_tags = ' '.join(str(project_tag.tag.id) for project_tag in project_tags) form_tags = ' '.join(str(project_tag.tag.id) for project_tag in project_tags)
form = NewProjectForm(initial={ form = NewProjectForm(initial={
'title': project.title, 'description': project.description, 'status': project.status, 'hidden': project.hidden, 'tags':form_tags}) 'title': project.title, 'description': project.description, 'capacity': project.capacity,
'status': project.status, 'hidden': project.hidden, 'tags':form_tags})
tags = Tag.objects.all() tags = Tag.objects.all()
project_tags = [pair.tag for pair in project_tags] project_tags = [pair.tag for pair in project_tags]
context = {'form': form, 'project': project, 'tags': tags, 'projectTags': project_tags} next = request.GET.get('next', '')
context = {'form': form, 'project': project, 'tags': tags, 'projectTags': project_tags, 'next': next}
return render(request, 'pasapp/pages/edit_project.html', contextWithHeader(context, request)) return render(request, 'pasapp/pages/edit_project.html', contextWithHeader(context, request))
@login_required
@user_passes_test(is_professor)
def copy_project(request, project_id):
'''
GET route that copies an existing project into a new one. Saving is handled by create_project
URL: /project/update_status/
'''
if request.method == 'GET':
project = get_object_or_404(Project, pk=project_id)
if not request.user.id == project.professor.id:
return HttpResponseForbidden()
project_tags = ProjectTag.objects.filter(project=project.id)
form_tags = ' '.join(str(project_tag.tag.id) for project_tag in project_tags)
project_dict = {
'title': project.title,
'description': project.description,
'capacity': project.capacity,
'professor': request.user,
'group_size': project.group_size,
'tags': form_tags
}
form = NewProjectForm(initial=project_dict)
tags = Tag.objects.all()
project_tags = [pair.tag for pair in project_tags]
context = {'form': form, 'project': project, 'tags': tags, 'projectTags': project_tags}
return render(request, 'pasapp/pages/copy_project.html', contextWithHeader(context, request))
else:
return HttpResponseBadRequest("This endpoint only supports GET requests.")
@login_required
@user_passes_test(is_professor)
def set_project_status(request):
'''
POST route that edits the status of an existing project.
URL: /project/update_status/
'''
if request.method == 'POST':
project_id = request.POST['project']
project = get_object_or_404(Project, pk=project_id)
if not request.user.id == project.professor.id:
return HttpResponseForbidden()
status = request.POST['action']
project.status = status
if status in DEFAULT_STATUSES:
project.hidden = False if status == OPEN_STATUS else True
project.save()
return redirect(get_next(request))
else:
return HttpResponseBadRequest("This endpoint only supports POST requests.")
@login_required
@user_passes_test(is_professor)
def delete_project(request):
'''
POST route that deletes an existing project.
URL: /project/delete/
'''
if request.method == 'POST':
project_id = request.POST['project']
project = get_object_or_404(Project, pk=project_id)
if not request.user.id == project.professor.id:
return HttpResponseForbidden()
project.delete()
return redirect(get_next(request))
else:
return HttpResponseBadRequest("This endpoint only supports POST requests.")
@login_required @login_required
def my_applications(request): def my_applications(request):
...@@ -400,7 +475,8 @@ def update_student_status(request): ...@@ -400,7 +475,8 @@ def update_student_status(request):
elif state == 'RETR': # TODO: ensure application is removed from priority, call other stuff elif state == 'RETR': # TODO: ensure application is removed from priority, call other stuff
application.student_status = Application.StudentStatus.RETRACTED application.student_status = Application.StudentStatus.RETRACTED
application.save() application.save()
return redirect("/applications/")
return redirect(get_next(request,'/applications/'))
else: else:
return HttpResponseBadRequest("This endpoint only supports POST requests.") return HttpResponseBadRequest("This endpoint only supports POST requests.")
...@@ -432,7 +508,7 @@ def update_professor_status(request): ...@@ -432,7 +508,7 @@ def update_professor_status(request):
else: else:
return HttpResponseBadRequest("Unknown action.") return HttpResponseBadRequest("Unknown action.")
application.save() application.save()
return redirect("/applications/") return redirect(get_next(request,'/applications/'))
else: else:
return HttpResponseBadRequest("This endpoint only supports POST requests.") return HttpResponseBadRequest("This endpoint only supports POST requests.")
...@@ -451,7 +527,7 @@ def add_comment(request): ...@@ -451,7 +527,7 @@ def add_comment(request):
sender = request.user sender = request.user
comment = Comment(application_id=application, message=message, sender=sender) comment = Comment(application_id=application, message=message, sender=sender)
comment.save() comment.save()
return redirect(request.GET.get('next','/')) return redirect(get_next(request))
else: else:
return HttpResponseBadRequest("This endpoint only supports POST requests.") return HttpResponseBadRequest("This endpoint only supports POST requests.")
...@@ -496,11 +572,9 @@ def login_view(request): ...@@ -496,11 +572,9 @@ def login_view(request):
''' '''
if request.method == 'POST': if request.method == 'POST':
form = AuthenticationForm(data=request.POST) form = AuthenticationForm(data=request.POST)
print(form)
if form.is_valid(): if form.is_valid():
username = form.cleaned_data.get('username') username = form.cleaned_data.get('username')
password = form.cleaned_data.get('password') password = form.cleaned_data.get('password')
print(password)
user = authenticate(username=username, password=password) user = authenticate(username=username, password=password)
if user is not None: if user is not None:
login(request, user) login(request, user)
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment