diff --git a/ontology/forms.py b/ontology/forms.py index 7a4c826ce46f41fd70860de3066c076da3eb2fa4..a00e9dd640559aa44162febf3e50762ed29dafea 100644 --- a/ontology/forms.py +++ b/ontology/forms.py @@ -6,8 +6,18 @@ from django import forms from ajax_select.fields import AutoCompleteSelectField -from .models import Topic +from .constants import TOPIC_RELATIONS_ASYM class SelectTagForm(forms.Form): - tag = AutoCompleteSelectField('tag_lookup', label='Add Tag:', help_text='') + tag = AutoCompleteSelectField('tag_lookup', label='', help_text='') + + +class SelectTopicForm(forms.Form): + topic = AutoCompleteSelectField('topic_lookup') + + +class AddRelationAsymForm(forms.Form): + A = AutoCompleteSelectField('topic_lookup', label='', help_text='') + relation = forms.ChoiceField(choices=TOPIC_RELATIONS_ASYM, label='') + B = AutoCompleteSelectField('topic_lookup', label='', help_text='') diff --git a/ontology/models.py b/ontology/models.py index c48bd025065a61f527f0f072e1efa649c457da39..662e140486c77674a32781d23d598c4f6177f74d 100644 --- a/ontology/models.py +++ b/ontology/models.py @@ -29,6 +29,9 @@ class Topic(models.Model): slug = models.SlugField(unique=True, allow_unicode=True) tags = models.ManyToManyField(Tag, blank=True) + class Meta: + ordering = ['name'] + def __str__(self): return self.name diff --git a/ontology/templates/ontology/_topic_card.html b/ontology/templates/ontology/_topic_card.html index 9f1b640e8c2949f0db4c276348fc2fc8c0d567bd..aee3174199836d2bbf345f5861ca50615926fee9 100644 --- a/ontology/templates/ontology/_topic_card.html +++ b/ontology/templates/ontology/_topic_card.html @@ -1,34 +1,46 @@ {% load bootstrap %} +<script> + $(document).ready(function() { + $("#id_A_text").keyup(function() { + $("#id_B_text").val("{{ topic }}"); + $("#id_B").val({{ topic.id }}); + }); + $("#id_B_text").keyup(function() { + $("#id_A_text").val("{{ topic }}"); + $("#id_A").val({{ topic.id }}); + }); + }); +</script> + <div class="card"> <div class="card-header"> - <div class="row"> - <div class="{% if perms.scipost.can_manage_ontology %}col-6{% else %}col-12{% endif %}"> - <ul class="list-inline"> - <li class="list-inline-item"><h3>{{ topic }}</h3></li> - {% if perms.scipost.can_manage_ontology %} - <li class="list-inline-item small"> - <a href="{% url 'ontology:topic_update' slug=topic.slug %}">Update</a> - </li> - {% endif %} - </ul> - {% if topic.tags.all %} - <ul class="list list-inline mb-0"> - <li class="list-inline-item"><strong>Tags</strong>:</li> - {% for tag in topic.tags.all %} - <li class="list-inline-item">{{ tag }}{% if perms.scipost.can_manage_ontology %} <a href="{% url 'ontology:topic_remove_tag' slug=topic.slug tag_id=tag.id %}"><i class="fa fa-times-circle text-danger"></i></a>{% endif %}</li> - {% endfor %} - </ul> - {% endif %} - </div> + <ul class="list-inline"> + <li class="list-inline-item"><h3>{{ topic }}</h3></li> {% if perms.scipost.can_manage_ontology %} - <div class="col-6"> - <form class="form-inline" action="{% url 'ontology:topic_add_tag' slug=topic.slug %}" method="post">{% csrf_token %}{{ select_tag_form|bootstrap }} - <input type="submit" class="form-control btn btn-outline-secondary" value="Add Tag"/> + <li class="list-inline-item small"> + <a href="{% url 'ontology:topic_update' slug=topic.slug %}">Update</a> + </li> + {% endif %} + </ul> + {% if topic.tags.all %} + <ul class="list list-inline mb-0"> + <li class="list-inline-item"><strong>Tags</strong>:</li> + {% for tag in topic.tags.all %} + <li class="list-inline-item">{{ tag }}{% if perms.scipost.can_manage_ontology %} <a href="{% url 'ontology:topic_remove_tag' slug=topic.slug tag_id=tag.id %}"><i class="fa fa-times-circle text-danger"></i></a>{% endif %}</li> + {% endfor %} + {% if perms.scipost.can_manage_ontology %} + <li class="list-inline-item pull-right"> + <form class="form-inline" action="{% url 'ontology:topic_add_tag' slug=topic.slug %}" method="post"> + <ul class="list-inline"> + <li class="list-inline-item">{% csrf_token %}{{ select_tag_form }}</li> + <li class="list-inline-item"><input type="submit" class="form-control btn btn-outline-secondary" value="Add Tag"/></li> + </ul> </form> - </div> + </li> {% endif %} - </div> + </ul> + {% endif %} </div> <div class="card-body"> @@ -38,11 +50,19 @@ <h5>asymmetric:</h5> <ul> {% for rel in relations_asym %} - <li>{% if rel.A != topic %}<a href="{% url 'ontology:topic_details' slug=rel.A.slug %}">{{ rel.A}}</a>{% else %}{{ rel.A }}{% endif %} <em>{{ rel.get_relation_display }}</em> {% if rel.B != topic %}<a href="{% url 'ontology:topic_details' slug=rel.B.slug %}">{{ rel.B }}</a>{% else %}{{ rel.B }}{% endif %}</li> + <li>{% if rel.A != topic %}<a href="{% url 'ontology:topic_details' slug=rel.A.slug %}">{{ rel.A}}</a>{% else %}{{ rel.A }}{% endif %} <em>{{ rel.get_relation_display }}</em> {% if rel.B != topic %}<a href="{% url 'ontology:topic_details' slug=rel.B.slug %}">{{ rel.B }}</a>{% else %}{{ rel.B }}{% endif %} {% if perms.scipost.can_manage_ontology %}<a href="{% url 'ontology:delete_relation_asym' relation_id=rel.id slug=topic.slug %}"><i class="fa fa-times-circle text-danger"></i></a>{% endif %}</li> {% empty %} <li>No relations have been defined</li> {% endfor %} </ul> + {% if perms.scipost.can_manage_ontology %} + <h5>Add an asymmetric relation:</h5> + <form action = "{% url 'ontology:add_relation_asym' slug=topic.slug %}" method="post"> + {% csrf_token %} + {{ add_relation_asym_form }} + <input type="submit" class="btn btn-outline-secondary" value="Add"/> + </form> + {% endif %} </div> <div class="col-6"> <h5>symmetric:</h5> diff --git a/ontology/templates/ontology/topic_list.html b/ontology/templates/ontology/topic_list.html index ccac22f92f3a19a85078878d7780ef10e128d219..2dc3311a27b4a41a9f6be85d86fd074646783a74 100644 --- a/ontology/templates/ontology/topic_list.html +++ b/ontology/templates/ontology/topic_list.html @@ -17,13 +17,15 @@ <li><a href="{% url 'ontology:topic_create' %}">Add a Topic</a></li> {% endif %} <li> - <ul class="list-inline"> - <li class="list-inline-item">Filter to Topic name containing:</li> - <li class="list-inline-item"> - <form action="" method="get">{{ searchform }} - </li> - <li class="list-inline-item"><input class="btn btn-outline-secondary" type="submit" value="Submit"></form></li> - </ul> + <form action="" method="get"> + <ul class="list-inline"> + <li class="list-inline-item">Filter to Topic name containing:</li> + <li class="list-inline-item"> + {{ searchform }} + </li> + <li class="list-inline-item"><input class="btn btn-outline-secondary" type="submit" value="Filter"></li> + </ul> + </form> </ul> </div> </div> diff --git a/ontology/templatetags/lookup.py b/ontology/templatetags/lookup.py index 295943ccc5d1306ba19aafcc04c77bf7b8e1c6f2..2fec056a229e6071a9c84f41398113c33252cf8c 100644 --- a/ontology/templatetags/lookup.py +++ b/ontology/templatetags/lookup.py @@ -6,7 +6,7 @@ from django.core.exceptions import PermissionDenied from ajax_select import register, LookupChannel -from ..models import Tag +from ..models import Tag, Topic @register('tag_lookup') @@ -25,3 +25,21 @@ class TagLookup(LookupChannel): def check_auth(self, request): if not request.user.has_perm('scipost.can_manage_ontology'): raise PermissionDenied + + +@register('topic_lookup') +class TopicLookup(LookupChannel): + model = Topic + + def get_query(self, q, request): + return (self.model.objects.filter(name__icontains=q)[:10]) + + def format_item_display(self, item): + return "<span class='auto_lookup_display'>%s</span>" % item + + def format_match(self, item): + return item.name + + def check_auth(self, request): + if not request.user.has_perm('scipost.can_manage_ontology'): + raise PermissionDenied diff --git a/ontology/urls.py b/ontology/urls.py index 94bbd5e3160c3a5a643cc7980e4f4cc047851f74..e7c1ad356250154f8f48591541de866b3ec57e9b 100644 --- a/ontology/urls.py +++ b/ontology/urls.py @@ -42,4 +42,14 @@ urlpatterns = [ views.TopicListView.as_view(), name='topics' ), + url( + r'^add_relation_asym/(?P<slug>[-\w]+)/$', + views.add_relation_asym, + name='add_relation_asym' + ), + url( + r'^delete_relation_asym/(?P<relation_id>[0-9]+)/(?P<slug>[-\w]+)/$', + views.delete_relation_asym, + name='delete_relation_asym' + ), ] diff --git a/ontology/views.py b/ontology/views.py index 8d2861cc61be87673f32cc5829bab3bb44bef466..a5d39ae9936fce962e942245301eeb529796a2cc 100644 --- a/ontology/views.py +++ b/ontology/views.py @@ -14,7 +14,7 @@ from django.views.generic.list import ListView from guardian.decorators import permission_required from .models import Tag, Topic, RelationAsym, RelationSym -from .forms import SelectTagForm +from .forms import SelectTagForm, AddRelationAsymForm from scipost.forms import SearchTextForm from scipost.mixins import PaginationMixin, PermissionsMixin @@ -94,5 +94,28 @@ class TopicDetailView(DetailView): def get_context_data(self, *args, **kwargs): context = super().get_context_data(*args, **kwargs) context['select_tag_form'] = SelectTagForm() + context['add_relation_asym_form'] = AddRelationAsymForm() context['relations_asym'] = RelationAsym.objects.filter(Q(A=self.object) | Q(B=self.object)) return context + + +@permission_required('scipost.can_manage_ontology', return_403=True) +def add_relation_asym(request, slug): + form = AddRelationAsymForm(request.POST or None) + if form.is_valid(): + relation = RelationAsym(A=form.cleaned_data['A'], relation=form.cleaned_data['relation'], + B=form.cleaned_data['B']) + relation.save() + messages.success(request, 'Relation successfully created') + else: + for error_messages in form.errors.values(): + messages.warning(request, *error_messages) + return redirect(reverse('ontology:topic_details', kwargs={'slug': slug})) + + +@permission_required('scipost.can_manage_ontology', return_403=True) +def delete_relation_asym(request, relation_id, slug): + relation = get_object_or_404(RelationAsym, pk=relation_id) + relation.delete() + messages.success(request, 'Relation deleted') + return redirect(reverse('ontology:topic_details', kwargs={'slug': slug}))