mirror of
				https://gitlab.crans.org/bde/nk20
				synced 2025-11-04 09:12:11 +01:00 
			
		
		
		
	First proro of trusting, with models and front, but no additional permissions
This commit is contained in:
		
							
								
								
									
										53
									
								
								apps/member/static/member/js/trust.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								apps/member/static/member/js/trust.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,53 @@
 | 
			
		||||
/**
 | 
			
		||||
 * On form submit, create a new friendship
 | 
			
		||||
 */
 | 
			
		||||
function create_trust (e) {
 | 
			
		||||
  // Do not submit HTML form
 | 
			
		||||
  e.preventDefault()
 | 
			
		||||
 | 
			
		||||
  // Get data and send to API
 | 
			
		||||
  const formData = new FormData(e.target)
 | 
			
		||||
  $.getJSON('/api/note/alias/'+formData.get('trusted') + '/',
 | 
			
		||||
    function (trusted_alias) {
 | 
			
		||||
      if ((trusted_alias.note == formData.get('trusting')))
 | 
			
		||||
      {
 | 
			
		||||
         addMsg(gettext("You can't add yourself as a friend"), "danger")
 | 
			
		||||
         return
 | 
			
		||||
      }
 | 
			
		||||
      $.post('/api/note/trust/', {
 | 
			
		||||
        csrfmiddlewaretoken: formData.get('csrfmiddlewaretoken'),
 | 
			
		||||
        trusting: formData.get('trusting'),
 | 
			
		||||
        trusted: trusted_alias.note
 | 
			
		||||
      }).done(function () {
 | 
			
		||||
        // Reload table
 | 
			
		||||
        $('#trust_table').load(location.pathname + ' #trust_table')
 | 
			
		||||
        addMsg(gettext('Friendship successfully added'), 'success')
 | 
			
		||||
      }).fail(function (xhr, _textStatus, _error) {
 | 
			
		||||
        errMsg(xhr.responseJSON)
 | 
			
		||||
      })
 | 
			
		||||
    }).fail(function (xhr, _textStatus, _error) {
 | 
			
		||||
        errMsg(xhr.responseJSON)
 | 
			
		||||
    })
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * On click of "delete", delete the alias
 | 
			
		||||
 * @param button_id:Integer Alias id to remove
 | 
			
		||||
 */
 | 
			
		||||
function delete_button (button_id) {
 | 
			
		||||
  $.ajax({
 | 
			
		||||
    url: '/api/note/trust/' + button_id + '/',
 | 
			
		||||
    method: 'DELETE',
 | 
			
		||||
    headers: { 'X-CSRFTOKEN': CSRF_TOKEN }
 | 
			
		||||
  }).done(function () {
 | 
			
		||||
    addMsg(gettext('Friendship successfully deleted'), 'success')
 | 
			
		||||
    $('#trust_table').load(location.pathname + ' #trust_table')
 | 
			
		||||
  }).fail(function (xhr, _textStatus, _error) {
 | 
			
		||||
    errMsg(xhr.responseJSON)
 | 
			
		||||
  })
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
$(document).ready(function () {
 | 
			
		||||
  // Attach event
 | 
			
		||||
  document.getElementById('form_trust').addEventListener('submit', create_trust)
 | 
			
		||||
})
 | 
			
		||||
@@ -25,6 +25,14 @@
 | 
			
		||||
        </a>
 | 
			
		||||
    </dd>
 | 
			
		||||
 | 
			
		||||
    <dt class="col-xl-6">{% trans 'friendships'|capfirst %}</dt>
 | 
			
		||||
    <dd class="col-xl-6">
 | 
			
		||||
        <a class="badge badge-secondary" href="{% url 'member:user_trust' user_object.pk %}">
 | 
			
		||||
            <i class="fa fa-edit"></i>
 | 
			
		||||
            {% trans 'Manage friendships' %} ({{ user_object.note.trusting.all|length }})
 | 
			
		||||
        </a>
 | 
			
		||||
    </dd>
 | 
			
		||||
 | 
			
		||||
    {% if "member.view_profile"|has_perm:user_object.profile %}
 | 
			
		||||
        <dt class="col-xl-6">{% trans 'section'|capfirst %}</dt>
 | 
			
		||||
        <dd class="col-xl-6">{{ user_object.profile.section }}</dd>
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										31
									
								
								apps/member/templates/member/profile_trust.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								apps/member/templates/member/profile_trust.html
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,31 @@
 | 
			
		||||
{% extends "member/base.html" %}
 | 
			
		||||
{% comment %}
 | 
			
		||||
SPDX-License-Identifier: GPL-3.0-or-later
 | 
			
		||||
{% endcomment %}
 | 
			
		||||
{% load static django_tables2 i18n %}
 | 
			
		||||
 | 
			
		||||
{% block profile_content %}
 | 
			
		||||
<div class="card bg-light">
 | 
			
		||||
    <h3 class="card-header text-center">
 | 
			
		||||
        {% trans "Note friendships" %}
 | 
			
		||||
    </h3>
 | 
			
		||||
    <div class="card-body">
 | 
			
		||||
        {% if can_create %}
 | 
			
		||||
            <form class="input-group" method="POST" id="form_trust">
 | 
			
		||||
                {% csrf_token %}
 | 
			
		||||
                <input type="hidden" name="trusting" value="{{ object.note.pk }}">
 | 
			
		||||
                {%include "autocomplete_model.html" %}
 | 
			
		||||
                <div class="input-group-append">
 | 
			
		||||
                    <input type="submit" class="btn btn-success" value="{% trans "Add" %}">
 | 
			
		||||
                </div>
 | 
			
		||||
            </form>
 | 
			
		||||
        {% endif %}
 | 
			
		||||
    </div>
 | 
			
		||||
    {% render_table trusting %}
 | 
			
		||||
</div>
 | 
			
		||||
{% endblock %}
 | 
			
		||||
 | 
			
		||||
{% block extrajavascript %}
 | 
			
		||||
<script src="{% static "member/js/trust.js" %}"></script>
 | 
			
		||||
<script src="{% static "js/autocomplete_model.js" %}"></script>
 | 
			
		||||
{% endblock%}
 | 
			
		||||
@@ -23,5 +23,6 @@ urlpatterns = [
 | 
			
		||||
    path('user/<int:pk>/update/', views.UserUpdateView.as_view(), name="user_update_profile"),
 | 
			
		||||
    path('user/<int:pk>/update_pic/', views.ProfilePictureUpdateView.as_view(), name="user_update_pic"),
 | 
			
		||||
    path('user/<int:pk>/aliases/', views.ProfileAliasView.as_view(), name="user_alias"),
 | 
			
		||||
    path('user/<int:pk>/trust', views.ProfileTrustView.as_view(), name="user_trust"),
 | 
			
		||||
    path('manage-auth-token/', views.ManageAuthTokens.as_view(), name='auth_token'),
 | 
			
		||||
]
 | 
			
		||||
 
 | 
			
		||||
@@ -8,6 +8,7 @@ from django.contrib.auth import logout
 | 
			
		||||
from django.contrib.auth.mixins import LoginRequiredMixin
 | 
			
		||||
from django.contrib.auth.models import User
 | 
			
		||||
from django.contrib.auth.views import LoginView
 | 
			
		||||
from django.contrib.contenttypes.models import ContentType
 | 
			
		||||
from django.db import transaction
 | 
			
		||||
from django.db.models import Q, F
 | 
			
		||||
from django.shortcuts import redirect
 | 
			
		||||
@@ -18,9 +19,9 @@ from django.views.generic import DetailView, UpdateView, TemplateView
 | 
			
		||||
from django.views.generic.edit import FormMixin
 | 
			
		||||
from django_tables2.views import SingleTableView
 | 
			
		||||
from rest_framework.authtoken.models import Token
 | 
			
		||||
from note.models import Alias, NoteUser, NoteClub
 | 
			
		||||
from note.models import Alias, NoteClub, NoteUser, Trust
 | 
			
		||||
from note.models.transactions import Transaction, SpecialTransaction
 | 
			
		||||
from note.tables import HistoryTable, AliasTable
 | 
			
		||||
from note.tables import HistoryTable, AliasTable, TrustTable
 | 
			
		||||
from note_kfet.middlewares import _set_current_request
 | 
			
		||||
from permission.backends import PermissionBackend
 | 
			
		||||
from permission.models import Role
 | 
			
		||||
@@ -243,6 +244,38 @@ class UserListView(ProtectQuerysetMixin, LoginRequiredMixin, SingleTableView):
 | 
			
		||||
        return context
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ProfileTrustView(ProtectQuerysetMixin, LoginRequiredMixin, DetailView):
 | 
			
		||||
    """
 | 
			
		||||
    View and manage user trust relationships
 | 
			
		||||
    """
 | 
			
		||||
    model = User
 | 
			
		||||
    template_name = 'member/profile_trust.html'
 | 
			
		||||
    context_object_name = 'user_object'
 | 
			
		||||
    extra_context = {"title":_("Note friendships")}
 | 
			
		||||
 | 
			
		||||
    def get_context_data(self, **kwargs):
 | 
			
		||||
        context = super().get_context_data(**kwargs)
 | 
			
		||||
        note = context['object'].note
 | 
			
		||||
        context["trusting"] = TrustTable(
 | 
			
		||||
            note.trusting.filter(PermissionBackend.filter_queryset(self.request, Trust, "view")).distinct().all())
 | 
			
		||||
        context["can_create"] = PermissionBackend.check_perm(self.request, "note.add_trust", Trust(
 | 
			
		||||
            trusting=context["object"].note,
 | 
			
		||||
            trusted=context["object"].note
 | 
			
		||||
        ))
 | 
			
		||||
        context["widget"] = {"name": "trusted",
 | 
			
		||||
            "attrs": { "model_pk": ContentType.objects.get_for_model(Alias).pk,
 | 
			
		||||
                "class": "autocomplete form-control",
 | 
			
		||||
                "id": "trusted",
 | 
			
		||||
                "resetable": True,
 | 
			
		||||
                "api_url": "/api/note/alias/?note__polymorphic_ctype__model=noteuser",
 | 
			
		||||
                "name_field": "name",
 | 
			
		||||
                "placeholder": ""
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        return context
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ProfileAliasView(ProtectQuerysetMixin, LoginRequiredMixin, DetailView):
 | 
			
		||||
    """
 | 
			
		||||
    View and manage user aliases.
 | 
			
		||||
 
 | 
			
		||||
@@ -12,7 +12,7 @@ from note_kfet.middlewares import get_current_request
 | 
			
		||||
from permission.backends import PermissionBackend
 | 
			
		||||
from rest_framework.utils import model_meta
 | 
			
		||||
 | 
			
		||||
from ..models.notes import Note, NoteClub, NoteSpecial, NoteUser, Alias
 | 
			
		||||
from ..models.notes import Note, NoteClub, NoteSpecial, NoteUser, Alias, Trust
 | 
			
		||||
from ..models.transactions import TransactionTemplate, Transaction, MembershipTransaction, TemplateCategory, \
 | 
			
		||||
    RecurrentTransaction, SpecialTransaction
 | 
			
		||||
 | 
			
		||||
@@ -77,6 +77,22 @@ class NoteUserSerializer(serializers.ModelSerializer):
 | 
			
		||||
        return str(obj)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class TrustSerializer(serializers.ModelSerializer):
 | 
			
		||||
    """
 | 
			
		||||
    REST API Serializer for Trusts.
 | 
			
		||||
    The djangorestframework plugin will analyse the model `Trust` and parse all fields in the API.
 | 
			
		||||
    """
 | 
			
		||||
 | 
			
		||||
    class Meta:
 | 
			
		||||
        model = Trust
 | 
			
		||||
        fields = '__all__'
 | 
			
		||||
 | 
			
		||||
    def validate(self, attrs):
 | 
			
		||||
        instance = Trust(**attrs)
 | 
			
		||||
        instance.clean()
 | 
			
		||||
        return attrs
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class AliasSerializer(serializers.ModelSerializer):
 | 
			
		||||
    """
 | 
			
		||||
    REST API Serializer for Aliases.
 | 
			
		||||
 
 | 
			
		||||
@@ -2,7 +2,8 @@
 | 
			
		||||
# SPDX-License-Identifier: GPL-3.0-or-later
 | 
			
		||||
 | 
			
		||||
from .views import NotePolymorphicViewSet, AliasViewSet, ConsumerViewSet, \
 | 
			
		||||
    TemplateCategoryViewSet, TransactionViewSet, TransactionTemplateViewSet
 | 
			
		||||
    TemplateCategoryViewSet, TransactionViewSet, TransactionTemplateViewSet, \
 | 
			
		||||
    TrustViewSet
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def register_note_urls(router, path):
 | 
			
		||||
@@ -11,6 +12,7 @@ def register_note_urls(router, path):
 | 
			
		||||
    """
 | 
			
		||||
    router.register(path + '/note', NotePolymorphicViewSet)
 | 
			
		||||
    router.register(path + '/alias', AliasViewSet)
 | 
			
		||||
    router.register(path + '/trust', TrustViewSet)
 | 
			
		||||
    router.register(path + '/consumer', ConsumerViewSet)
 | 
			
		||||
 | 
			
		||||
    router.register(path + '/transaction/category', TemplateCategoryViewSet)
 | 
			
		||||
 
 | 
			
		||||
@@ -14,8 +14,9 @@ from api.viewsets import ReadProtectedModelViewSet, ReadOnlyProtectedModelViewSe
 | 
			
		||||
from permission.backends import PermissionBackend
 | 
			
		||||
 | 
			
		||||
from .serializers import NotePolymorphicSerializer, AliasSerializer, ConsumerSerializer,\
 | 
			
		||||
    TemplateCategorySerializer, TransactionTemplateSerializer, TransactionPolymorphicSerializer
 | 
			
		||||
from ..models.notes import Note, Alias, NoteUser, NoteClub, NoteSpecial
 | 
			
		||||
    TemplateCategorySerializer, TransactionTemplateSerializer, TransactionPolymorphicSerializer, \
 | 
			
		||||
    TrustSerializer
 | 
			
		||||
from ..models.notes import Note, Alias, NoteUser, NoteClub, NoteSpecial, Trust
 | 
			
		||||
from ..models.transactions import TransactionTemplate, Transaction, TemplateCategory
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -56,11 +57,41 @@ class NotePolymorphicViewSet(ReadProtectedModelViewSet):
 | 
			
		||||
        return queryset.order_by("id")
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class TrustViewSet(ReadProtectedModelViewSet):
 | 
			
		||||
    """
 | 
			
		||||
    REST Trust View set.
 | 
			
		||||
    The djangorestframework plugin will get all `Trust` objects, serialize it to JSON with the given serializer,
 | 
			
		||||
    then render it on /api/note/trust/
 | 
			
		||||
    """
 | 
			
		||||
    queryset = Trust.objects
 | 
			
		||||
    serializer_class = TrustSerializer
 | 
			
		||||
    filter_backends = [SearchFilter, DjangoFilterBackend, OrderingFilter]
 | 
			
		||||
    search_fields = ['$trusting__alias__name', '$trusting__alias__normalized_name',
 | 
			
		||||
            '$trusted__alias__name', '$trusted__alias__normalized_name']
 | 
			
		||||
    filterset_fields = ['trusting', 'trusting__noteuser__user', 'trusted', 'trusted__noteuser__user',]
 | 
			
		||||
    ordering_fields = ['trusting', 'trusted', ]
 | 
			
		||||
 | 
			
		||||
    def get_serializer_class(self):
 | 
			
		||||
        serializer_class = self.serializer_class
 | 
			
		||||
        if self.request.method in ['PUT', 'PATCH']:
 | 
			
		||||
            # trust relationship can't change people involved
 | 
			
		||||
            serializer_class.Meta.read_only_fields = ('trusting', 'trusting',)
 | 
			
		||||
        return serializer_class
 | 
			
		||||
 | 
			
		||||
    def destroy(self, request, *args, **kwargs):
 | 
			
		||||
        instance = self.get_object()
 | 
			
		||||
        try:
 | 
			
		||||
            self.perform_destroy(instance)
 | 
			
		||||
        except ValidationError as e:
 | 
			
		||||
            return Response({e.code: str(e)}, status.HTTP_400_BAD_REQUEST)
 | 
			
		||||
        return Response(status=status.HTTP_204_NO_CONTENT)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class AliasViewSet(ReadProtectedModelViewSet):
 | 
			
		||||
    """
 | 
			
		||||
    REST API View set.
 | 
			
		||||
    The djangorestframework plugin will get all `Alias` objects, serialize it to JSON with the given serializer,
 | 
			
		||||
    then render it on /api/aliases/
 | 
			
		||||
    then render it on /api/note/aliases/
 | 
			
		||||
    """
 | 
			
		||||
    queryset = Alias.objects
 | 
			
		||||
    serializer_class = AliasSerializer
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										27
									
								
								apps/note/migrations/0006_trust.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								apps/note/migrations/0006_trust.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,27 @@
 | 
			
		||||
# Generated by Django 2.2.24 on 2021-09-05 19:16
 | 
			
		||||
 | 
			
		||||
from django.db import migrations, models
 | 
			
		||||
import django.db.models.deletion
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Migration(migrations.Migration):
 | 
			
		||||
 | 
			
		||||
    dependencies = [
 | 
			
		||||
        ('note', '0005_auto_20210313_1235'),
 | 
			
		||||
    ]
 | 
			
		||||
 | 
			
		||||
    operations = [
 | 
			
		||||
        migrations.CreateModel(
 | 
			
		||||
            name='Trust',
 | 
			
		||||
            fields=[
 | 
			
		||||
                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
 | 
			
		||||
                ('trusted', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='trusted', to='note.Note', verbose_name='trusted')),
 | 
			
		||||
                ('trusting', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='trusting', to='note.Note', verbose_name='trusting')),
 | 
			
		||||
            ],
 | 
			
		||||
            options={
 | 
			
		||||
                'verbose_name': 'frienship',
 | 
			
		||||
                'verbose_name_plural': 'friendships',
 | 
			
		||||
                'unique_together': {('trusting', 'trusted')},
 | 
			
		||||
            },
 | 
			
		||||
        ),
 | 
			
		||||
    ]
 | 
			
		||||
@@ -1,13 +1,13 @@
 | 
			
		||||
# Copyright (C) 2018-2021 by BDE ENS Paris-Saclay
 | 
			
		||||
# SPDX-License-Identifier: GPL-3.0-or-later
 | 
			
		||||
 | 
			
		||||
from .notes import Alias, Note, NoteClub, NoteSpecial, NoteUser
 | 
			
		||||
from .notes import Alias, Note, NoteClub, NoteSpecial, NoteUser, Trust
 | 
			
		||||
from .transactions import MembershipTransaction, Transaction, \
 | 
			
		||||
    TemplateCategory, TransactionTemplate, RecurrentTransaction, SpecialTransaction
 | 
			
		||||
 | 
			
		||||
__all__ = [
 | 
			
		||||
    # Notes
 | 
			
		||||
    'Alias', 'Note', 'NoteClub', 'NoteSpecial', 'NoteUser',
 | 
			
		||||
    'Alias', 'Trust', 'Note', 'NoteClub', 'NoteSpecial', 'NoteUser',
 | 
			
		||||
    # Transactions
 | 
			
		||||
    'MembershipTransaction', 'Transaction', 'TemplateCategory', 'TransactionTemplate',
 | 
			
		||||
    'RecurrentTransaction', 'SpecialTransaction',
 | 
			
		||||
 
 | 
			
		||||
@@ -229,16 +229,21 @@ class Trust(models.Model):
 | 
			
		||||
        Note,
 | 
			
		||||
        on_delete=models.CASCADE,
 | 
			
		||||
        related_name='trusting',
 | 
			
		||||
        verbose_name=('trusting')
 | 
			
		||||
        verbose_name=_('trusting')
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    trusted = models.ForeignKey(
 | 
			
		||||
        Note,
 | 
			
		||||
        on_delete=models.CASCADE,
 | 
			
		||||
        related_name='trusted',
 | 
			
		||||
        verbose_name=('trusted')
 | 
			
		||||
        verbose_name=_('trusted')
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    class Meta:
 | 
			
		||||
        verbose_name = _("frienship")
 | 
			
		||||
        verbose_name_plural = _("friendships")
 | 
			
		||||
        unique_together = ("trusting", "trusted")
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Alias(models.Model):
 | 
			
		||||
    """
 | 
			
		||||
 
 | 
			
		||||
@@ -10,7 +10,7 @@ from django.utils.translation import gettext_lazy as _
 | 
			
		||||
from note_kfet.middlewares import get_current_request
 | 
			
		||||
from permission.backends import PermissionBackend
 | 
			
		||||
 | 
			
		||||
from .models.notes import Alias
 | 
			
		||||
from .models.notes import Alias, Trust
 | 
			
		||||
from .models.transactions import Transaction, TransactionTemplate
 | 
			
		||||
from .templatetags.pretty_money import pretty_money
 | 
			
		||||
 | 
			
		||||
@@ -148,6 +148,27 @@ DELETE_TEMPLATE = """
 | 
			
		||||
"""
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class TrustTable(tables.Table):
 | 
			
		||||
    class Meta:
 | 
			
		||||
        attrs = {
 | 
			
		||||
            'class': 'table table condensed table-striped',
 | 
			
		||||
            'id': "trust_table"
 | 
			
		||||
        }
 | 
			
		||||
        model = Trust
 | 
			
		||||
        fields = ("trusted",)
 | 
			
		||||
        template_name = 'django_tables2/bootstrap4.html'
 | 
			
		||||
 | 
			
		||||
    show_header = False
 | 
			
		||||
    trusted = tables.Column(attrs={'td': {'class': 'text_center'}})
 | 
			
		||||
 | 
			
		||||
    delete_col = tables.TemplateColumn(template_code=DELETE_TEMPLATE,
 | 
			
		||||
            extra_context={"delete_trans": _('delete')},
 | 
			
		||||
            attrs={'td': {'class': lambda record: 'col-sm-1' + (' d-none'
 | 
			
		||||
                if not PermissionBackend.check_perm(get_current_request(),
 | 
			
		||||
                    "note.delete_trust", record) else '')}},
 | 
			
		||||
            verbose_name =_("Delete"), )
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class AliasTable(tables.Table):
 | 
			
		||||
    class Meta:
 | 
			
		||||
        attrs = {
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user