diff --git a/beat/web/libraries/__init__.py b/beat/web/libraries/__init__.py index 3e7198cc7785c7da9bbec494fb34931622dbb90b..7f31614a3180f10e77a28dfd2cd68f230c62035a 100644 --- a/beat/web/libraries/__init__.py +++ b/beat/web/libraries/__init__.py @@ -25,4 +25,4 @@ # # ############################################################################### -default_app_config = 'beat.web.libraries.apps.LibrariesConfig' +default_app_config = "beat.web.libraries.apps.LibrariesConfig" diff --git a/beat/web/libraries/admin.py b/beat/web/libraries/admin.py index 732ea9f52cee2f0a80e3bea676febe79bf20c2e3..643c367038e054daead39437cb0720836913e012 100644 --- a/beat/web/libraries/admin.py +++ b/beat/web/libraries/admin.py @@ -25,70 +25,60 @@ # # ############################################################################### +import simplejson as json from django import forms from django.contrib import admin from django.core.files.base import ContentFile - -from ..ui.forms import CodeMirrorPythonFileField, CodeMirrorRSTFileField, \ - CodeMirrorJSONFileField - from ..common.texts import Messages - +from ..ui.forms import CodeMirrorJSONFileField +from ..ui.forms import CodeMirrorPythonFileField +from ..ui.forms import CodeMirrorRSTFileField +from ..ui.forms import NameField from .models import Library as LibraryModel from .models import validate_library -from ..ui.forms import NameField - -import simplejson as json - - -#---------------------------------------------------------- +# ---------------------------------------------------------- class LibraryModelForm(forms.ModelForm): name = NameField( - widget=forms.TextInput(attrs=dict(size=80)), - help_text=Messages['algo_name'], + widget=forms.TextInput(attrs=dict(size=80)), help_text=Messages["algo_name"], ) declaration_file = CodeMirrorJSONFileField( - label='Declaration', - help_text=Messages['json'], + label="Declaration", help_text=Messages["json"], ) source_code_file = CodeMirrorPythonFileField( - label='Source code', - help_text=Messages['code'], + label="Source code", help_text=Messages["code"], ) description_file = CodeMirrorRSTFileField( - label='Description', + label="Description", required=False, allow_empty_file=True, - help_text=Messages['description'], + help_text=Messages["description"], ) class Meta: model = LibraryModel exclude = [] widgets = { - 'short_description': forms.TextInput( - attrs=dict(size=100), - ), + "short_description": forms.TextInput(attrs=dict(size=100),), } def clean_declaration_file(self): """Cleans-up the declaration_file data, make sure it is really new""" - new_declaration = self.cleaned_data['declaration_file'].read() - old_declaration = '' + new_declaration = self.cleaned_data["declaration_file"].read() + old_declaration = "" if self.instance and self.instance.declaration_file.name is not None: old_declaration = self.instance.declaration_string if new_declaration == old_declaration: - self.changed_data.remove('declaration_file') + self.changed_data.remove("declaration_file") content_file = ContentFile(old_declaration) content_file.name = self.instance.declaration_file.name return content_file @@ -101,59 +91,63 @@ class LibraryModelForm(forms.ModelForm): raise forms.ValidationError(str(e)) # if that works out, then we return the passed file - self.cleaned_data['declaration_file'].seek(0) #reset ContentFile readout - return self.cleaned_data['declaration_file'] + self.cleaned_data["declaration_file"].seek(0) # reset ContentFile readout + return self.cleaned_data["declaration_file"] def clean(self): """Cleans-up the input data, make sure it overall validates""" # make sure we don't pass back a str field as 'file' - if 'declaration_file' in self.data and \ - isinstance(self.data['declaration_file'], str): + if "declaration_file" in self.data and isinstance( + self.data["declaration_file"], str + ): mutable_data = self.data.copy() - mutable_data['declaration_file'] = ContentFile(self.data['declaration_file'], name='unsaved') + mutable_data["declaration_file"] = ContentFile( + self.data["declaration_file"], name="unsaved" + ) self.data = mutable_data - -#---------------------------------------------------------- +# ---------------------------------------------------------- def rehash_library(modeladmin, request, queryset): """Recalculates the hash of a library""" - for q in queryset: q.save() + for q in queryset: + q.save() + -rehash_library.short_description = 'Rehash selected library' +rehash_library.short_description = "Rehash selected library" class Library(admin.ModelAdmin): - list_display = ( - 'id', - 'author', - 'name', - 'version', - 'short_description', - 'creation_date', - 'previous_version', - 'fork_of', - 'sharing', - 'hash', + list_display = ( + "id", + "author", + "name", + "version", + "short_description", + "creation_date", + "previous_version", + "fork_of", + "sharing", + "hash", ) - search_fields = [ - 'author__username', - 'name', - 'short_description', - 'previous_version__author__username', - 'previous_version__name', - 'fork_of__author__username', - 'fork_of__name' + search_fields = [ + "author__username", + "name", + "short_description", + "previous_version__author__username", + "previous_version__name", + "fork_of__author__username", + "fork_of__name", ] - list_filter = ['sharing'] - list_display_links = ['id', 'name'] - readonly_fields = ['hash', 'short_description'] + list_filter = ["sharing"] + list_display_links = ["id", "name"] + readonly_fields = ["hash", "short_description"] actions = [ rehash_library, @@ -162,48 +156,51 @@ class Library(admin.ModelAdmin): form = LibraryModelForm filter_horizontal = [ - 'shared_with', - 'shared_with_team', - 'usable_by', - 'usable_by_team', - 'referenced_libraries' + "shared_with", + "shared_with_team", + "usable_by", + "usable_by_team", + "referenced_libraries", ] fieldsets = ( - (None, - dict( - fields=('name', 'author',), - ), - ), - ('Documentation', - dict( - classes=('collapse',), - fields=('short_description', 'description_file',), - ), - ), - ('Versioning', - dict( - classes=('collapse',), - fields=('version', 'previous_version', 'fork_of'), - ), - ), - ('Sharing', - dict( - classes=('collapse',), - fields=('sharing', 'shared_with', 'shared_with_team', 'usable_by', 'usable_by_team'), - ), - ), - ('Cached Information (read-only)', - dict( - classes=('collapse',), - fields=('referenced_libraries',), - ), - ), - ('Definition', - dict( - fields=('hash', 'declaration_file', 'language', 'source_code_file'), - ), - ), + (None, dict(fields=("name", "author",),),), + ( + "Documentation", + dict( + classes=("collapse",), + fields=("short_description", "description_file",), + ), + ), + ( + "Versioning", + dict( + classes=("collapse",), + fields=("version", "previous_version", "fork_of"), + ), + ), + ( + "Sharing", + dict( + classes=("collapse",), + fields=( + "sharing", + "shared_with", + "shared_with_team", + "usable_by", + "usable_by_team", + ), + ), + ), + ( + "Cached Information (read-only)", + dict(classes=("collapse",), fields=("referenced_libraries",),), + ), + ( + "Definition", + dict(fields=("hash", "declaration_file", "language", "source_code_file"),), + ), ) + admin.site.register(LibraryModel, Library) diff --git a/beat/web/libraries/api.py b/beat/web/libraries/api.py index 1e40b3c7b6a269996b04668e3066233b4670b4f7..3b6536ad88ba5d13346087f5718f8bb819c71a51 100644 --- a/beat/web/libraries/api.py +++ b/beat/web/libraries/api.py @@ -25,22 +25,18 @@ # # ############################################################################### +from ..code.api import DiffView +from ..code.api import RetrieveUpdateDestroyCodeView +from ..code.api import ShareCodeView +from ..code.serializers import CodeDiffSerializer +from ..common.api import CheckContributionNameView +from ..common.api import ListContributionView +from ..common.api import ListCreateContributionView from .models import Library -from .serializers import LibrarySerializer from .serializers import FullLibrarySerializer from .serializers import LibraryCreationSerializer from .serializers import LibraryModSerializer - -from ..code.api import ShareCodeView, RetrieveUpdateDestroyCodeView -from ..code.serializers import CodeDiffSerializer - -from ..common.api import ( - CheckContributionNameView, - ListContributionView, - ListCreateContributionView, -) - -from ..code.api import DiffView +from .serializers import LibrarySerializer # ---------------------------------------------------------- diff --git a/beat/web/libraries/apps.py b/beat/web/libraries/apps.py index 790fe2b73ccede3198edd0f7b3e8c623065a05b7..50ca5c6a11aa6d90896a7700005797ba390d666a 100644 --- a/beat/web/libraries/apps.py +++ b/beat/web/libraries/apps.py @@ -25,15 +25,20 @@ # # ############################################################################### -from ..common.apps import CommonAppConfig from django.utils.translation import ugettext_lazy as _ +from ..common.apps import CommonAppConfig + + class LibrariesConfig(CommonAppConfig): - name = 'beat.web.libraries' - verbose_name = _('Libraries') + name = "beat.web.libraries" + verbose_name = _("Libraries") def ready(self): super(LibrariesConfig, self).ready() - from .signals import auto_delete_file_on_delete, auto_delete_file_on_change from actstream import registry - registry.register(self.get_model('Library')) + + from .signals import auto_delete_file_on_change # noqa: F401 + from .signals import auto_delete_file_on_delete # noqa: F401 + + registry.register(self.get_model("Library")) diff --git a/beat/web/libraries/migrations/0001_initial.py b/beat/web/libraries/migrations/0001_initial.py index 03a2ce5a74e4b37706dc66b123e9c296534a156d..9fe5930b6c8d0c6aa8d194d4f84dfd9a706c9faf 100644 --- a/beat/web/libraries/migrations/0001_initial.py +++ b/beat/web/libraries/migrations/0001_initial.py @@ -27,52 +27,202 @@ from __future__ import unicode_literals -from django.db import migrations, models +from django.conf import settings +from django.db import migrations +from django.db import models + import beat.web.code.models import beat.web.common.models import beat.web.libraries.models -from django.conf import settings class Migration(migrations.Migration): dependencies = [ migrations.swappable_dependency(settings.AUTH_USER_MODEL), - ('team', '0001_initial'), + ("team", "0001_initial"), ] operations = [ migrations.CreateModel( - name='Library', + name="Library", fields=[ - ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), - ('sharing', models.CharField(default='P', max_length=1, choices=[('P', 'Private'), ('S', 'Shared'), ('A', 'Public'), ('U', 'Usable')])), - ('name', models.CharField(help_text='The name for this object (space-like characters will be automatically replaced by dashes)', max_length=200)), - ('version', models.PositiveIntegerField(default=1, help_text='The version of this object (an integer starting from 1)')), - ('short_description', models.CharField(default='', help_text='Describe the object succinctly (try to keep it under 80 characters)', max_length=100, blank=True)), - ('creation_date', models.DateTimeField(auto_now_add=True, verbose_name='Creation date')), - ('hash', models.CharField(help_text='Hashed value of the object contents (<a href="https://docs.python.org/2/library/hashlib.html">SHA256, hexadecimal digest</a>). This field is auto-generated and managed by the platform.', max_length=64, editable=False)), - ('language', models.CharField(default='P', max_length=1, choices=[('U', 'Unknown'), ('', 'Binary'), ('M', 'Matla'), ('P', 'Python'), ('R', 'R')])), - ('declaration_file', models.FileField(db_column='declaration', upload_to=beat.web.common.models.get_contribution_declaration_filename, storage=beat.web.libraries.models.LibraryStorage(), max_length=200, blank=True, null=True)), - ('description_file', models.FileField(db_column='description', upload_to=beat.web.common.models.get_contribution_description_filename, storage=beat.web.libraries.models.LibraryStorage(), max_length=200, blank=True, null=True)), - ('source_code_file', models.FileField(db_column='source_code', upload_to=beat.web.code.models.get_contribution_source_code_filename, storage=beat.web.libraries.models.LibraryStorage(), max_length=200, blank=True, null=True)), - ('author', models.ForeignKey(related_name='librarys', to=settings.AUTH_USER_MODEL, on_delete=models.CASCADE)), - ('fork_of', models.ForeignKey(related_name='forks', blank=True, to='libraries.Library', null=True, on_delete=models.SET_NULL)), - ('previous_version', models.ForeignKey(related_name='next_versions', blank=True, to='libraries.Library', null=True, on_delete=models.SET_NULL)), - ('referenced_libraries', models.ManyToManyField(related_name='referencing', to='libraries.Library', blank=True)), - ('shared_with', models.ManyToManyField(related_name='shared_librarys', to=settings.AUTH_USER_MODEL, blank=True)), - ('shared_with_team', models.ManyToManyField(related_name='shared_librarys', to='team.Team', blank=True)), - ('usable_by', models.ManyToManyField(related_name='usable_librarys', to=settings.AUTH_USER_MODEL, blank=True)), - ('usable_by_team', models.ManyToManyField(related_name='usable_librarys', to='team.Team', blank=True)), + ( + "id", + models.AutoField( + verbose_name="ID", + serialize=False, + auto_created=True, + primary_key=True, + ), + ), + ( + "sharing", + models.CharField( + default="P", + max_length=1, + choices=[ + ("P", "Private"), + ("S", "Shared"), + ("A", "Public"), + ("U", "Usable"), + ], + ), + ), + ( + "name", + models.CharField( + help_text="The name for this object (space-like characters will be automatically replaced by dashes)", + max_length=200, + ), + ), + ( + "version", + models.PositiveIntegerField( + default=1, + help_text="The version of this object (an integer starting from 1)", + ), + ), + ( + "short_description", + models.CharField( + default="", + help_text="Describe the object succinctly (try to keep it under 80 characters)", + max_length=100, + blank=True, + ), + ), + ( + "creation_date", + models.DateTimeField( + auto_now_add=True, verbose_name="Creation date" + ), + ), + ( + "hash", + models.CharField( + help_text='Hashed value of the object contents (<a href="https://docs.python.org/2/library/hashlib.html">SHA256, hexadecimal digest</a>). This field is auto-generated and managed by the platform.', + max_length=64, + editable=False, + ), + ), + ( + "language", + models.CharField( + default="P", + max_length=1, + choices=[ + ("U", "Unknown"), + ("", "Binary"), + ("M", "Matla"), + ("P", "Python"), + ("R", "R"), + ], + ), + ), + ( + "declaration_file", + models.FileField( + db_column="declaration", + upload_to=beat.web.common.models.get_contribution_declaration_filename, + storage=beat.web.libraries.models.LibraryStorage(), + max_length=200, + blank=True, + null=True, + ), + ), + ( + "description_file", + models.FileField( + db_column="description", + upload_to=beat.web.common.models.get_contribution_description_filename, + storage=beat.web.libraries.models.LibraryStorage(), + max_length=200, + blank=True, + null=True, + ), + ), + ( + "source_code_file", + models.FileField( + db_column="source_code", + upload_to=beat.web.code.models.get_contribution_source_code_filename, + storage=beat.web.libraries.models.LibraryStorage(), + max_length=200, + blank=True, + null=True, + ), + ), + ( + "author", + models.ForeignKey( + related_name="librarys", + to=settings.AUTH_USER_MODEL, + on_delete=models.CASCADE, + ), + ), + ( + "fork_of", + models.ForeignKey( + related_name="forks", + blank=True, + to="libraries.Library", + null=True, + on_delete=models.SET_NULL, + ), + ), + ( + "previous_version", + models.ForeignKey( + related_name="next_versions", + blank=True, + to="libraries.Library", + null=True, + on_delete=models.SET_NULL, + ), + ), + ( + "referenced_libraries", + models.ManyToManyField( + related_name="referencing", to="libraries.Library", blank=True + ), + ), + ( + "shared_with", + models.ManyToManyField( + related_name="shared_librarys", + to=settings.AUTH_USER_MODEL, + blank=True, + ), + ), + ( + "shared_with_team", + models.ManyToManyField( + related_name="shared_librarys", to="team.Team", blank=True + ), + ), + ( + "usable_by", + models.ManyToManyField( + related_name="usable_librarys", + to=settings.AUTH_USER_MODEL, + blank=True, + ), + ), + ( + "usable_by_team", + models.ManyToManyField( + related_name="usable_librarys", to="team.Team", blank=True + ), + ), ], options={ - 'ordering': ['author__username', 'name', 'version'], - 'abstract': False, - 'verbose_name_plural': 'libraries', + "ordering": ["author__username", "name", "version"], + "abstract": False, + "verbose_name_plural": "libraries", }, ), migrations.AlterUniqueTogether( - name='library', - unique_together=set([('author', 'name', 'version')]), + name="library", unique_together=set([("author", "name", "version")]), ), ] diff --git a/beat/web/libraries/migrations/0002_cxx_backend.py b/beat/web/libraries/migrations/0002_cxx_backend.py index a0d8060e6a49bdb06c35fb3c7a0fc7e12053a420..37016332c893a437c6fa55bd1b2c373c6a888866 100644 --- a/beat/web/libraries/migrations/0002_cxx_backend.py +++ b/beat/web/libraries/migrations/0002_cxx_backend.py @@ -2,19 +2,30 @@ # Generated by Django 1.9.11 on 2016-11-09 11:05 from __future__ import unicode_literals -from django.db import migrations, models +from django.db import migrations +from django.db import models class Migration(migrations.Migration): dependencies = [ - ('libraries', '0001_initial'), + ("libraries", "0001_initial"), ] operations = [ migrations.AlterField( - model_name='library', - name='language', - field=models.CharField(choices=[(b'U', b'Unknown'), (b'C', b'C++'), (b'M', b'Matlab'), (b'P', b'Python'), (b'R', b'R')], default=b'P', max_length=1), + model_name="library", + name="language", + field=models.CharField( + choices=[ + (b"U", b"Unknown"), + (b"C", b"C++"), + (b"M", b"Matlab"), + (b"P", b"Python"), + (b"R", b"R"), + ], + default=b"P", + max_length=1, + ), ), ] diff --git a/beat/web/libraries/migrations/0003_auto_20161123_1218.py b/beat/web/libraries/migrations/0003_auto_20161123_1218.py index a9cf143a86ab1482f4e710604bbf88f49ca1b858..97c62a88d2ac9780f2544b4dcbc5e32efa5ab587 100644 --- a/beat/web/libraries/migrations/0003_auto_20161123_1218.py +++ b/beat/web/libraries/migrations/0003_auto_20161123_1218.py @@ -2,19 +2,30 @@ # Generated by Django 1.9.11 on 2016-11-23 12:18 from __future__ import unicode_literals -from django.db import migrations, models +from django.db import migrations +from django.db import models class Migration(migrations.Migration): dependencies = [ - ('libraries', '0002_cxx_backend'), + ("libraries", "0002_cxx_backend"), ] operations = [ migrations.AlterField( - model_name='library', - name='language', - field=models.CharField(choices=[(b'U', b'Unknown'), (b'C', b'Cxx'), (b'M', b'Matlab'), (b'P', b'Python'), (b'R', b'R')], default=b'P', max_length=1), + model_name="library", + name="language", + field=models.CharField( + choices=[ + (b"U", b"Unknown"), + (b"C", b"Cxx"), + (b"M", b"Matlab"), + (b"P", b"Python"), + (b"R", b"R"), + ], + default=b"P", + max_length=1, + ), ), ] diff --git a/beat/web/libraries/models.py b/beat/web/libraries/models.py index f74b9b7d1fbfea2924c92874b32ec02efdc54633..87311fe50131c5dddb332f39cd2b1b4c6a551194 100644 --- a/beat/web/libraries/models.py +++ b/beat/web/libraries/models.py @@ -25,23 +25,21 @@ # # ############################################################################### -from django.db import models +import collections + +import simplejson from django.conf import settings +from django.db import models from django.urls import reverse import beat.core.library -from ..common.storage import OverwriteStorage -from ..common.models import get_contribution_declaration_filename -from ..common.models import get_contribution_description_filename - from ..code.models import Code from ..code.models import CodeManager from ..code.models import get_contribution_source_code_filename - -import simplejson -import collections - +from ..common.models import get_contribution_declaration_filename +from ..common.models import get_contribution_description_filename +from ..common.storage import OverwriteStorage # ---------------------------------------------------------- @@ -190,10 +188,12 @@ class Library(Code): # reset referenced libraries self.referenced_libraries.clear() if wrapper.uses is not None: - for l in set(wrapper.uses.values()): - s = beat.core.library.Storage(settings.PREFIX, l) + for library_name in set(wrapper.uses.values()): + lib_storage = beat.core.library.Storage(settings.PREFIX, library_name) library = Library.objects.get( - author__username=s.username, name=s.name, version=s.version + author__username=lib_storage.username, + name=lib_storage.name, + version=lib_storage.version, ) self.referenced_libraries.add(library) @@ -234,8 +234,8 @@ class Library(Code): """ - from ..experiments.models import Block from ..backend.models import Environment + from ..experiments.models import Block # Tries to figure through a maximum if using algorithms have been # successfully used inside an environment. diff --git a/beat/web/libraries/serializers.py b/beat/web/libraries/serializers.py index e5a93c04498c9ecec2e3083bfd42677ab1d2e454..dd41a987f1bb56f8fec44503d31273890be92dcc 100644 --- a/beat/web/libraries/serializers.py +++ b/beat/web/libraries/serializers.py @@ -25,20 +25,17 @@ # # ############################################################################### -import beat.core.library - from rest_framework import serializers -from ..code.serializers import CodeSerializer -from ..code.serializers import CodeCreationSerializer -from ..code.serializers import CodeModSerializer +import beat.core.library from ..algorithms.models import Algorithm from ..backend.serializers import EnvironmentInfoSerializer - +from ..code.serializers import CodeCreationSerializer +from ..code.serializers import CodeModSerializer +from ..code.serializers import CodeSerializer from .models import Library - # ---------------------------------------------------------- diff --git a/beat/web/libraries/templates/libraries/list.html b/beat/web/libraries/templates/libraries/list.html index 2ca8f79c299c012f806ca8a4fdb17d5dd9aaa9cc..208c0593f49c47fb9e93960bf0ad2f95f3316610 100644 --- a/beat/web/libraries/templates/libraries/list.html +++ b/beat/web/libraries/templates/libraries/list.html @@ -2,21 +2,21 @@ {% comment %} * Copyright (c) 2016 Idiap Research Institute, http://www.idiap.ch/ * Contact: beat.support@idiap.ch - * + * * This file is part of the beat.web module of the BEAT platform. - * + * * Commercial License Usage * Licensees holding valid commercial BEAT licenses may use this file in * accordance with the terms contained in a written agreement between you * and Idiap. For further information contact tto@idiap.ch - * + * * Alternatively, this file may be used under the terms of the GNU Affero * Public License version 3 as published by the Free Software and appearing * in the file LICENSE.AGPL included in the packaging of this file. * The BEAT platform is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. - * + * * You should have received a copy of the GNU Affero Public License along * with the BEAT platform. If not, see http://www.gnu.org/licenses/. {% endcomment %} diff --git a/beat/web/libraries/templates/libraries/panels/actions.html b/beat/web/libraries/templates/libraries/panels/actions.html index 8aca3dda1b609f49f363167229224393476aab19..2840dab04bd3053c9d43df719df58b7ffc4ad54d 100644 --- a/beat/web/libraries/templates/libraries/panels/actions.html +++ b/beat/web/libraries/templates/libraries/panels/actions.html @@ -1,21 +1,21 @@ {% comment %} * Copyright (c) 2016 Idiap Research Institute, http://www.idiap.ch/ * Contact: beat.support@idiap.ch - * + * * This file is part of the beat.web module of the BEAT platform. - * + * * Commercial License Usage * Licensees holding valid commercial BEAT licenses may use this file in * accordance with the terms contained in a written agreement between you * and Idiap. For further information contact tto@idiap.ch - * + * * Alternatively, this file may be used under the terms of the GNU Affero * Public License version 3 as published by the Free Software and appearing * in the file LICENSE.AGPL included in the packaging of this file. * The BEAT platform is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. - * + * * You should have received a copy of the GNU Affero Public License along * with the BEAT platform. If not, see http://www.gnu.org/licenses/. {% endcomment %} diff --git a/beat/web/libraries/templates/libraries/panels/editor.html b/beat/web/libraries/templates/libraries/panels/editor.html index b86c3dafe533ebd4b51f31f6f6fb4e580cd3f2b6..00c7579f74ea40685173b9c11ffc1ac8c33da1f2 100644 --- a/beat/web/libraries/templates/libraries/panels/editor.html +++ b/beat/web/libraries/templates/libraries/panels/editor.html @@ -1,21 +1,21 @@ {% comment %} * Copyright (c) 2016 Idiap Research Institute, http://www.idiap.ch/ * Contact: beat.support@idiap.ch - * + * * This file is part of the beat.web module of the BEAT platform. - * + * * Commercial License Usage * Licensees holding valid commercial BEAT licenses may use this file in * accordance with the terms contained in a written agreement between you * and Idiap. For further information contact tto@idiap.ch - * + * * Alternatively, this file may be used under the terms of the GNU Affero * Public License version 3 as published by the Free Software and appearing * in the file LICENSE.AGPL included in the packaging of this file. * The BEAT platform is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. - * + * * You should have received a copy of the GNU Affero Public License along * with the BEAT platform. If not, see http://www.gnu.org/licenses/. {% endcomment %} diff --git a/beat/web/libraries/templates/libraries/panels/sharing.html b/beat/web/libraries/templates/libraries/panels/sharing.html index 0e71cf1d93266be8568e93a7c4d4173dc9f8fd62..e76deca2f93499c3b01994058830c11e4ee0a65f 100644 --- a/beat/web/libraries/templates/libraries/panels/sharing.html +++ b/beat/web/libraries/templates/libraries/panels/sharing.html @@ -1,21 +1,21 @@ {% comment %} * Copyright (c) 2016 Idiap Research Institute, http://www.idiap.ch/ * Contact: beat.support@idiap.ch - * + * * This file is part of the beat.web module of the BEAT platform. - * + * * Commercial License Usage * Licensees holding valid commercial BEAT licenses may use this file in * accordance with the terms contained in a written agreement between you * and Idiap. For further information contact tto@idiap.ch - * + * * Alternatively, this file may be used under the terms of the GNU Affero * Public License version 3 as published by the Free Software and appearing * in the file LICENSE.AGPL included in the packaging of this file. * The BEAT platform is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. - * + * * You should have received a copy of the GNU Affero Public License along * with the BEAT platform. If not, see http://www.gnu.org/licenses/. {% endcomment %} diff --git a/beat/web/libraries/templates/libraries/panels/table.html b/beat/web/libraries/templates/libraries/panels/table.html index 973a2780d0192027fbe63e22e219075a74897953..efb1c9c33303a0ed08b914b63c3eec56d5a757b3 100644 --- a/beat/web/libraries/templates/libraries/panels/table.html +++ b/beat/web/libraries/templates/libraries/panels/table.html @@ -1,21 +1,21 @@ {% comment %} * Copyright (c) 2016 Idiap Research Institute, http://www.idiap.ch/ * Contact: beat.support@idiap.ch - * + * * This file is part of the beat.web module of the BEAT platform. - * + * * Commercial License Usage * Licensees holding valid commercial BEAT licenses may use this file in * accordance with the terms contained in a written agreement between you * and Idiap. For further information contact tto@idiap.ch - * + * * Alternatively, this file may be used under the terms of the GNU Affero * Public License version 3 as published by the Free Software and appearing * in the file LICENSE.AGPL included in the packaging of this file. * The BEAT platform is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. - * + * * You should have received a copy of the GNU Affero Public License along * with the BEAT platform. If not, see http://www.gnu.org/licenses/. {% endcomment %} diff --git a/beat/web/libraries/templatetags/library_tags.py b/beat/web/libraries/templatetags/library_tags.py index 09b828786bd618a703a35673be8c2857d97c60a0..254e16bcc3d71b0c99f6088cfce49b5b5ff329d6 100644 --- a/beat/web/libraries/templatetags/library_tags.py +++ b/beat/web/libraries/templatetags/library_tags.py @@ -27,15 +27,15 @@ from django import template -from django.conf import settings + from ...common.texts import Messages as Texts register = template.Library() -@register.inclusion_tag('libraries/panels/table.html', takes_context=True) +@register.inclusion_tag("libraries/panels/table.html", takes_context=True) def library_table(context, objects, owner, id): - '''Composes a library list table + """Composes a library list table This panel primarily exists for user's library list page. @@ -47,18 +47,18 @@ def library_table(context, objects, owner, id): id: The HTML id to set on the generated table. This is handy for the filter functionality normally available on list pages. - ''' + """ return { - 'request': context['request'], - 'objects': objects, - 'owner': owner, - 'panel_id': id, + "request": context["request"], + "objects": objects, + "owner": owner, + "panel_id": id, } -@register.inclusion_tag('libraries/panels/actions.html', takes_context=True) +@register.inclusion_tag("libraries/panels/actions.html", takes_context=True) def library_actions(context, obj, display_count): - '''Composes the action buttons for a particular library + """Composes the action buttons for a particular library This panel primarily exists for showing action buttons for a given library taking into consideration it is being displayed for a given user. @@ -70,63 +70,73 @@ def library_actions(context, obj, display_count): display_count (bool): If the set of buttons should include one with the number of experiments using this library. - ''' - request = context['request'] + """ + request = context["request"] return { - 'request': request, - 'object': obj, - 'display_count': display_count, - 'open_source': obj.open_source(request.user), + "request": request, + "object": obj, + "display_count": display_count, + "open_source": obj.open_source(request.user), } -@register.inclusion_tag('libraries/panels/sharing.html', takes_context=True) +@register.inclusion_tag("libraries/panels/sharing.html", takes_context=True) def library_sharing(context, obj): - '''Composes the current sharing properties and a form to change them + """Composes the current sharing properties and a form to change them Parameters: obj (Library): The library object concerned for which the buttons will be drawn. - ''' + """ return { - 'request': context['request'], - 'object': obj, - 'owner': context['request'].user == obj.author, - 'users': context['users'], - 'teams': context['teams'], + "request": context["request"], + "object": obj, + "owner": context["request"].user == obj.author, + "users": context["users"], + "teams": context["teams"], } -@register.inclusion_tag('libraries/panels/editor.html', takes_context=True) +@register.inclusion_tag("libraries/panels/editor.html", takes_context=True) def library_editor(context, obj): - request = context['request'] + request = context["request"] return { - 'owner': request.user == obj.author, - 'object': obj, - 'texts': Texts, - 'open_source': obj.open_source(request.user), + "owner": request.user == obj.author, + "object": obj, + "texts": Texts, + "open_source": obj.open_source(request.user), } @register.simple_tag(takes_context=True) def visible_referrer_libraries(context, obj): - '''Calculates the visible usage for a given library and requestor''' + """Calculates the visible usage for a given library and requestor""" - return obj.referencing.for_user(context['request'].user, True).order_by('-creation_date').distinct() + return ( + obj.referencing.for_user(context["request"].user, True) + .order_by("-creation_date") + .distinct() + ) @register.simple_tag(takes_context=True) def visible_referrer_algorithms(context, obj): - '''Calculates the visible usage for a given library and requestor''' + """Calculates the visible usage for a given library and requestor""" - return obj.used_by_algorithms.for_user(context['request'].user, True).order_by('-creation_date').distinct() + return ( + obj.used_by_algorithms.for_user(context["request"].user, True) + .order_by("-creation_date") + .distinct() + ) @register.simple_tag(takes_context=True) def visible_referrers_count(context, obj): - '''Calculates the visible usage for a given library and requestor''' + """Calculates the visible usage for a given library and requestor""" - return visible_referrer_libraries(context, obj).count() + \ - visible_referrer_algorithms(context, obj).count() + return ( + visible_referrer_libraries(context, obj).count() + + visible_referrer_algorithms(context, obj).count() + ) diff --git a/beat/web/libraries/tests/core.py b/beat/web/libraries/tests/core.py index 48672f99999f25c04ec56fa4731d3eea209eab9e..1874d771bc2917e213bceee4f3d652c3b45dbdcc 100644 --- a/beat/web/libraries/tests/core.py +++ b/beat/web/libraries/tests/core.py @@ -30,23 +30,17 @@ import os import shutil import simplejson as json - -from django.contrib.auth.models import User from django.conf import settings +from django.contrib.auth.models import User -from ...dataformats.models import DataFormat +from beat.core.library import Storage from ...common.testutils import BaseTestCase -from ...common.testutils import ( # noqa test runner will call it, tearDownModule - tearDownModule, -) - +from ...common.testutils import tearDownModule # noqa test runner will call it +from ...dataformats.models import DataFormat from ...team.models import Team - from ..models import Library -from beat.core.library import Storage - TEST_PWD = "1234" diff --git a/beat/web/libraries/tests/tests_api.py b/beat/web/libraries/tests/tests_api.py index 9243efaf6b743a2ea6a254a41cbe00e0e454ed63..b46ced7f6e634265b73425771a0b7061ceffc04b 100644 --- a/beat/web/libraries/tests/tests_api.py +++ b/beat/web/libraries/tests/tests_api.py @@ -27,20 +27,15 @@ import simplejson as json - -from django.contrib.auth.models import User from django.conf import settings +from django.contrib.auth.models import User from django.urls import reverse import beat.core.library from ...common.testutils import get_algorithms_from_data -from ...common.testutils import ( # noqa test runner will call it, tearDownModule - tearDownModule, -) - +from ...common.testutils import tearDownModule # noqa test runner will call it from ..models import Library - from .core import LibrariesAPIBase diff --git a/beat/web/libraries/tests/tests_team.py b/beat/web/libraries/tests/tests_team.py index 03077bd382ce5f2f185979bfc40c4ca42d439d69..2190cb9907504e428f1b7664aa531410fd01b15f 100644 --- a/beat/web/libraries/tests/tests_team.py +++ b/beat/web/libraries/tests/tests_team.py @@ -27,14 +27,9 @@ from django.contrib.auth.models import User -from ...common.testutils import ( # noqa test runner will call it, tearDownModule - tearDownModule, -) - +from ...common.testutils import tearDownModule # noqa test runner will call it from ...team.models import Team - from ..models import Library - from .core import LibrariesAccessibilityFunctionsBase diff --git a/beat/web/libraries/tests/tests_user.py b/beat/web/libraries/tests/tests_user.py index 00ed6202d1dafa6185c49d34f41121cd6e8f93c1..fee89b9d9ee5dc29595489c4f8727b4c904c0e56 100644 --- a/beat/web/libraries/tests/tests_user.py +++ b/beat/web/libraries/tests/tests_user.py @@ -26,12 +26,8 @@ ############################################################################### -from ...common.testutils import ( # noqa test runner will call it, tearDownModule - tearDownModule, -) - +from ...common.testutils import tearDownModule # noqa test runner will call it from ..models import Library - from .core import LibrariesAccessibilityFunctionsBase diff --git a/beat/web/libraries/views.py b/beat/web/libraries/views.py index 79b3af4402372e611954a9e03c966c916fe29d6b..7e84a05920b773298176e3067bd8f94b8f30e297 100644 --- a/beat/web/libraries/views.py +++ b/beat/web/libraries/views.py @@ -25,22 +25,19 @@ # # ############################################################################### -from django.http import Http404, HttpResponseForbidden + +from django.conf import settings +from django.contrib.auth.decorators import login_required +from django.contrib.auth.models import User +from django.http import Http404 +from django.http import HttpResponseForbidden from django.shortcuts import get_object_or_404 from django.shortcuts import render from django.views.decorators.csrf import csrf_protect -from django.contrib.auth.decorators import login_required -from django.contrib.auth.models import User -from django.conf import settings -from .models import Library from ..common.texts import Messages from ..team.models import Team -from ..ui.templatetags.markup import restructuredtext - -from beat.core import prototypes - -import simplejson as json +from .models import Library @csrf_protect @@ -51,16 +48,15 @@ def create(request): The user must be authenticated before it can add a new library """ - visible_libraries = Library.objects.from_author_and_public(request.user, - request.user.username).order_by('-creation_date') + visible_libraries = Library.objects.from_author_and_public( + request.user, request.user.username + ).order_by("-creation_date") - return render(request, - 'libraries/edition.html', - dict( - op="new", - texts=Messages, - visible_libraries=visible_libraries, - )) + return render( + request, + "libraries/edition.html", + dict(op="new", texts=Messages, visible_libraries=visible_libraries,), + ) @csrf_protect @@ -71,22 +67,27 @@ def new_version(request, name): The user must be authenticated before it can add a new library """ - previous_version = Library.objects.filter(author=request.user, - name__iexact=name).order_by('-version') + previous_version = Library.objects.filter( + author=request.user, name__iexact=name + ).order_by("-version") - if not previous_version: raise Http404() + if not previous_version: + raise Http404() - visible_libraries = Library.objects.from_author_and_public(request.user, - request.user.username).order_by('-creation_date') + visible_libraries = Library.objects.from_author_and_public( + request.user, request.user.username + ).order_by("-creation_date") - return render(request, - 'libraries/edition.html', - dict( - op="new-version", - texts=Messages, - library=previous_version[0], - visible_libraries=visible_libraries, - )) + return render( + request, + "libraries/edition.html", + dict( + op="new-version", + texts=Messages, + library=previous_version[0], + visible_libraries=visible_libraries, + ), + ) @csrf_protect @@ -102,31 +103,35 @@ def fork(request, author_name, name, version): """ # Retrieves the forked library based on user accessible libraries - fork_of = get_object_or_404(Library.objects.for_user(request.user, True), - author__username__iexact=author_name, - name__iexact=name, - version=int(version) - ) + fork_of = get_object_or_404( + Library.objects.for_user(request.user, True), + author__username__iexact=author_name, + name__iexact=name, + version=int(version), + ) # The only case a user can't fork an library is if it's usable rather # than shared if fork_of.sharing == Library.USABLE and fork_of.author != request.user: - raise Http404() + raise Http404() - visible_libraries = Library.objects.from_author_and_public(request.user, - request.user.username).order_by('-creation_date') + visible_libraries = Library.objects.from_author_and_public( + request.user, request.user.username + ).order_by("-creation_date") - return render(request, - 'libraries/edition.html', - dict( - op="fork", - texts=Messages, - library=fork_of, - visible_libraries=visible_libraries, - )) + return render( + request, + "libraries/edition.html", + dict( + op="fork", + texts=Messages, + library=fork_of, + visible_libraries=visible_libraries, + ), + ) -#---------------------------------------------------------- +# ---------------------------------------------------------- @login_required @@ -137,30 +142,38 @@ def edit(request, author_name, name, version): """ # Retrieves the library - library = get_object_or_404(Library, author__username=author_name, - name__iexact=name, version=int(version)) + library = get_object_or_404( + Library, author__username=author_name, name__iexact=name, version=int(version) + ) # only author can edit it - if library.author != request.user: raise Http404() + if library.author != request.user: + raise Http404() if not library.modifiable(): - return HttpResponseForbidden('Library %s is not modifiable' % \ - library.fullname()) + return HttpResponseForbidden( + "Library %s is not modifiable" % library.fullname() + ) - visible_libraries = Library.objects.from_author_and_public(request.user, - request.user.username).exclude(id=library.id).order_by('-creation_date') + visible_libraries = ( + Library.objects.from_author_and_public(request.user, request.user.username) + .exclude(id=library.id) + .order_by("-creation_date") + ) - return render(request, - 'libraries/edition.html', - dict( - op="edit", - texts=Messages, - library=library, - visible_libraries=visible_libraries, - )) + return render( + request, + "libraries/edition.html", + dict( + op="edit", + texts=Messages, + library=library, + visible_libraries=visible_libraries, + ), + ) -#---------------------------------------------------------- +# ---------------------------------------------------------- def view(request, author_name, name, version=None): @@ -175,8 +188,9 @@ def view(request, author_name, name, version=None): version=int(version), ) else: - library = Library.objects.filter(author__username__iexact=author_name, - name__iexact=name).order_by('-version') + library = Library.objects.filter( + author__username__iexact=author_name, name__iexact=name + ).order_by("-version") if not library: raise Http404() else: @@ -184,25 +198,30 @@ def view(request, author_name, name, version=None): (has_access, _, __) = library.accessibility_for(request.user) - if not has_access: raise Http404() + if not has_access: + raise Http404() - owner = (request.user == library.author) + owner = request.user == library.author # Users the object can be shared with - users = User.objects.exclude(username__in=settings.ACCOUNTS_TO_EXCLUDE_FROM_TEAMS).order_by('username') + users = User.objects.exclude( + username__in=settings.ACCOUNTS_TO_EXCLUDE_FROM_TEAMS + ).order_by("username") # Render the page - return render(request, - 'libraries/view.html', - { - 'library': library, - 'owner': owner, - 'users': users, - 'teams': Team.objects.all(), - }) + return render( + request, + "libraries/view.html", + { + "library": library, + "owner": owner, + "users": users, + "teams": Team.objects.all(), + }, + ) -#---------------------------------------------------------- +# ---------------------------------------------------------- def diff(request, author1, name1, version1, author2, name2, version2): @@ -215,56 +234,57 @@ def diff(request, author1, name1, version1, author2, name2, version2): """ - return render(request, - 'libraries/diff.html', - {'library1_author': author1, - 'library1_name': name1, - 'library1_version': version1, - 'library2_author': author2, - 'library2_name': name2, - 'library2_version': version2, - }) + return render( + request, + "libraries/diff.html", + { + "library1_author": author1, + "library1_name": name1, + "library1_version": version1, + "library2_author": author2, + "library2_name": name2, + "library2_version": version2, + }, + ) -#---------------------------------------------------------- +# ---------------------------------------------------------- def ls(request, author_name): - '''List all accessible libraries to the request user''' + """List all accessible libraries to the request user""" - if not author_name: return public_ls(request) + if not author_name: + return public_ls(request) # check that the user exists on the system author = get_object_or_404(User, username=author_name) # orders libraries so that the latest information is displayed first - objects = Library.objects.from_author_and_public(request.user, - author_name).order_by('-creation_date') + objects = Library.objects.from_author_and_public( + request.user, author_name + ).order_by("-creation_date") objects = Library.filter_latest_versions(objects) - return render(request, - 'libraries/list.html', - dict( - objects=objects, - author=author, - owner=(request.user==author), - )) + return render( + request, + "libraries/list.html", + dict(objects=objects, author=author, owner=(request.user == author),), + ) -#---------------------------------------------------------- +# ---------------------------------------------------------- def public_ls(request): - '''List all publicly accessible objects''' + """List all publicly accessible objects""" # orders so that latest is displayed first - objects = Library.objects.public().order_by('-creation_date') + objects = Library.objects.public().order_by("-creation_date") objects = Library.filter_latest_versions(objects) - return render(request, - 'libraries/list.html', - dict( - objects=objects, - author=request.user, #anonymous - owner=False, - )) + return render( + request, + "libraries/list.html", + dict(objects=objects, author=request.user, owner=False,), # anonymous + )