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

added tags to projects

parent d1999007
No related branches found
No related tags found
No related merge requests found
...@@ -5,3 +5,5 @@ from .models import * ...@@ -5,3 +5,5 @@ from .models import *
# Register your models here. # Register your models here.
admin.site.register(Project) admin.site.register(Project)
admin.site.register(Application) admin.site.register(Application)
admin.site.register(Tag)
admin.site.register(ProjectTag)
...@@ -28,6 +28,7 @@ class NewUserForm(UserCreationForm): ...@@ -28,6 +28,7 @@ class NewUserForm(UserCreationForm):
class NewProjectForm(forms.Form): class NewProjectForm(forms.Form):
title = forms.CharField(label="Title", max_length=200) title = forms.CharField(label="Title", max_length=200)
description = forms.CharField(label="Description", max_length=2048) description = forms.CharField(label="Description", max_length=2048)
tags = forms.CharField(widget=forms.HiddenInput(), required=False)
class ApplicationForm(forms.Form): class ApplicationForm(forms.Form):
......
# Generated by Django 3.2.9 on 2021-12-12 18:59
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('pasapp', '0003_rename_date sent_application_date_sent'),
]
operations = [
migrations.CreateModel(
name='Tag',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=256, unique=True)),
],
),
migrations.CreateModel(
name='ProjectTag',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('project', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='pasapp.project')),
('tag', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='pasapp.tag')),
],
),
]
...@@ -10,6 +10,7 @@ class Project(models.Model): ...@@ -10,6 +10,7 @@ class Project(models.Model):
professor = models.ForeignKey(User, on_delete=models.CASCADE) professor = models.ForeignKey(User, on_delete=models.CASCADE)
description = models.CharField(max_length=2048) description = models.CharField(max_length=2048)
status = models.CharField(max_length=128) status = models.CharField(max_length=128)
# Tags - see ProjectTag below
def __str__(self): def __str__(self):
return f'{self.title}, by {self.professor}. Status: {self.status}' return f'{self.title}, by {self.professor}. Status: {self.status}'
...@@ -23,3 +24,18 @@ class Application(models.Model): ...@@ -23,3 +24,18 @@ class Application(models.Model):
def __str__(self): def __str__(self):
return f'{self.student} on {self.project}' return f'{self.student} on {self.project}'
class Tag(models.Model):
name = models.CharField(max_length=256, unique=True)
def __str__(self):
return self.name
class ProjectTag(models.Model):
project = models.ForeignKey(Project, on_delete=models.CASCADE)
tag = models.ForeignKey(Tag, on_delete=models.CASCADE)
def __str__(self):
return f'{self.project.title}: {self.tag.name}'
...@@ -32,3 +32,25 @@ ...@@ -32,3 +32,25 @@
.undecorated-link { .undecorated-link {
text-decoration: none; text-decoration: none;
} }
#tagBox {
display: flex;
flex-wrap: wrap;
justify-content: left;
align-items: flex-start;
padding: 0;
}
.tag {
display: inline;
background-color: lightpink;
border: 1px indianred solid;
border-radius: 4px;
padding: 4px;
margin: 0px 4px;
}
.closable .tag:hover {
background-color: white;
border: 1px indianred dashed;
}
...@@ -2,8 +2,45 @@ ...@@ -2,8 +2,45 @@
{% block title %} New Project {% endblock %} {% block title %} New Project {% endblock %}
{% block content %} {% block content %}
<script type="text/javascript">
const tagSet = new Set();
function addTag(item) {
const tagId = parseInt(item.value);
const tagName = item.options[tagId].text;
if (tagSet.has(tagId)) {
return;
}
tagSet.add(tagId);
const tagBox = document.getElementById("tagBox");
tagBox.innerHTML += `<li class="tag" onclick="removeTag(this, ${tagId})">${tagName}</li>`;
const tagForm = document.getElementById("id_tags");
tagForm.value = [...tagSet].join(' ');
}
function removeTag(item, tagId) {
tagSet.delete(tagId);
item.remove();
const tagForm = document.getElementById("id_tags");
tagForm.value = [...tagSet].join(' ');
}
</script>
<form action="/project/create/" method="post"> <form action="/project/create/" method="post">
{% csrf_token %} {{ form }} {% csrf_token %} {{ form.as_p }}
<select id="tagDropdown" oninput="addTag(this)" >
<option value="" disabled selected>Select tags</option>
{% for tag in tags %}
<option value="{{tag.id}}">{{tag.name}}</option>
{% endfor %}
</select>
<br>
<ul id="tagBox" class="closable">
<!-- Generated tags from the dropdown go here -->
</ul>
<br>
<input type="submit" value="Create Project"/> <input type="submit" value="Create Project"/>
</form> </form>
{% endblock %} {% endblock %}
...@@ -15,4 +15,12 @@ ...@@ -15,4 +15,12 @@
<a href="/project/{{project.id}}/apply/">Apply to this project</a> <a href="/project/{{project.id}}/apply/">Apply to this project</a>
{% endif %} {% endif %}
<p>(i) {{numApplicants}} students have applied so far.</p> <p>(i) {{numApplicants}} students have applied so far.</p>
{% if tags %}
<h4>Tags:</h4>
<ul id="tagBox">
{% for tag in tags %}
<li class="tag">{{tag}}</li>
{% endfor %}
</ul>
{% endif %}
{% endblock %} {% endblock %}
...@@ -2,6 +2,10 @@ ...@@ -2,6 +2,10 @@
{% block title %} Projects {% endblock %} {% block title %} Projects {% endblock %}
{% block content %} {% block content %}
{% load custom_filters %}
{% if user|is_professor %}
<a href="/project/create/">Add new project</a>
{% endif %}
{% if projects %} {% if projects %}
<ul> <ul>
{% for project in projects %} {% for project in projects %}
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
{% block title %} Register {% endblock %} {% block title %} Register {% endblock %}
{% block content %} {% block content %}
<form action="/register/" method="post"> <form action="/register/" method="post">
{% csrf_token %} {{ form }} {% csrf_token %} {{ form.as_p }}
<input type="submit" value="Sign Up" /> <input type="submit" value="Sign Up" />
</form> </form>
{% endblock %} {% endblock %}
...@@ -6,7 +6,7 @@ from django.shortcuts import get_object_or_404, redirect, render ...@@ -6,7 +6,7 @@ from django.shortcuts import get_object_or_404, redirect, render
from django.http import HttpResponse from django.http import HttpResponse
from pasapp.forms import ApplicationForm, NewProjectForm, NewUserForm from pasapp.forms import ApplicationForm, NewProjectForm, NewUserForm
from pasapp.models import Application, Project from pasapp.models import Application, Project, ProjectTag, Tag
from pasapp.utils import contextWithHeader, is_professor, is_student from pasapp.utils import contextWithHeader, is_professor, is_student
...@@ -20,7 +20,10 @@ def index(request): ...@@ -20,7 +20,10 @@ def index(request):
def project_details(request, project_id): def project_details(request, project_id):
project = get_object_or_404(Project, pk=project_id) project = get_object_or_404(Project, pk=project_id)
numApplicants = Application.objects.filter(project=project_id).count() numApplicants = Application.objects.filter(project=project_id).count()
context = {'project': project, 'numApplicants': numApplicants} tags = [entry.tag.name for entry in ProjectTag.objects.filter(
project=project).all()]
context = {'project': project,
'numApplicants': numApplicants, 'tags': tags}
return render(request, 'pasapp/project_details.html', contextWithHeader(context, request)) return render(request, 'pasapp/project_details.html', contextWithHeader(context, request))
...@@ -61,15 +64,26 @@ def create_project(request): ...@@ -61,15 +64,26 @@ def create_project(request):
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')
status = 'Hidden'
professor = request.user professor = request.user
status = 'Hidden'
project = Project(title=title, description=description, project = Project(title=title, description=description,
status=status, professor=professor) status=status, professor=professor)
project.save() project.save()
tags = form.cleaned_data.get('tags')
tag_list = tags.split()
for tag_id_str in tag_list:
tag_id = int(tag_id_str)
tag = Tag.objects.get(pk=tag_id)
if tag is None:
raise ValueError("Unknown tag found")
projectTag = ProjectTag(project=project, tag=tag)
projectTag.save()
return redirect("index") return redirect("index")
else:
form = NewProjectForm() form = NewProjectForm()
context = {'form': form} tags = Tag.objects.all()
context = {'form': form, 'tags': tags}
return render(request, 'pasapp/create_project.html', contextWithHeader(context, request)) return render(request, 'pasapp/create_project.html', contextWithHeader(context, request))
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment