diff --git a/FAIRshakeAPI/assessments/base/__init__.py b/FAIRshakeAPI/assessments/base/__init__.py index 264deb6..f56121e 100644 --- a/FAIRshakeAPI/assessments/base/__init__.py +++ b/FAIRshakeAPI/assessments/base/__init__.py @@ -4,7 +4,7 @@ class Assessment: def perform(target, rubric): - want = ['metric:%d' % (metric.id) for metric in rubric.metrics.all()] + want = ['metric:%s' % (metric.slug) for metric in rubric.metrics.all()] have = dict({ 'target:%s' % (attr): v for attr, v in target.attrs().items() diff --git a/FAIRshakeAPI/forms.py b/FAIRshakeAPI/forms.py index f5bf271..55cc79a 100644 --- a/FAIRshakeAPI/forms.py +++ b/FAIRshakeAPI/forms.py @@ -17,7 +17,21 @@ def __init__(self, *args, **kwargs): help_text=None, initial=getattr(self.instance, child).all() if self.instance and self.instance.id else [], ) - + + def clean_slug(self): + slug = self.cleaned_data.get('slug') + try: + if any([ + self.Meta.model.objects.current.get(slug=slug) != self.instance, + self.Meta.model.objects.get(id=slug) != self.instance, + ]): + raise forms.ValidationError( + 'Slug was already taken, please try something different.' + ) + except self.Meta.model.DoesNotExist: + pass + return slug + def save(self, *args, commit=True, **kwargs): ''' Explicitly add children for children in the reverse direction. ''' @@ -44,6 +58,7 @@ class Meta: 'image', 'tags', 'type', + 'slug', 'digital_objects', 'authors', ) @@ -58,6 +73,7 @@ class Meta: 'image', 'tags', 'type', + 'slug', 'rubrics', 'authors', ) @@ -72,6 +88,7 @@ class Meta: 'image', 'tags', 'type', + 'slug', 'license', 'metrics', 'authors', @@ -87,6 +104,7 @@ class Meta: 'image', 'tags', 'type', + 'slug', 'license', 'rationale', 'principle', diff --git a/FAIRshakeAPI/migrations/0008_auto_20180912_2050.py b/FAIRshakeAPI/migrations/0008_auto_20180912_2050.py new file mode 100644 index 0000000..5162ecc --- /dev/null +++ b/FAIRshakeAPI/migrations/0008_auto_20180912_2050.py @@ -0,0 +1,38 @@ +# Generated by Django 2.0.7 on 2018-09-12 20:50 + +import builtins +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('FAIRshakeAPI', '0007_auto_20180924_1435'), + ] + + operations = [ + migrations.AddField( + model_name='digitalobject', + name='slug', + field=models.CharField(max_length=255, default=None, null=True), + preserve_default=False, + ), + migrations.AddField( + model_name='metric', + name='slug', + field=models.CharField(max_length=255, default=None, null=True), + preserve_default=False, + ), + migrations.AddField( + model_name='project', + name='slug', + field=models.CharField(max_length=255, default=None, null=True), + preserve_default=False, + ), + migrations.AddField( + model_name='rubric', + name='slug', + field=models.CharField(max_length=255, default=None, null=True), + preserve_default=False, + ), + ] diff --git a/FAIRshakeAPI/migrations/0009_auto_20180912_2051.py b/FAIRshakeAPI/migrations/0009_auto_20180912_2051.py new file mode 100644 index 0000000..a89cbc3 --- /dev/null +++ b/FAIRshakeAPI/migrations/0009_auto_20180912_2051.py @@ -0,0 +1,36 @@ +# Generated by Django 2.0.7 on 2018-09-12 20:51 + +from django.db import migrations + +def migrate(apps, schema_editor): + Project = apps.get_model('FAIRshakeAPI', 'Project') + for project in Project.objects.all(): + project.slug = project.id + project.save() + + DigitalObject = apps.get_model('FAIRshakeAPI', 'DigitalObject') + for obj in DigitalObject.objects.all(): + obj.slug = obj.id + obj.save() + + Rubric = apps.get_model('FAIRshakeAPI', 'Rubric') + for rubric in Rubric.objects.all(): + rubric.slug = rubric.id + rubric.save() + + Metric = apps.get_model('FAIRshakeAPI', 'Metric') + for metric in Metric.objects.all(): + metric.slug = metric.id + metric.save() + +class Migration(migrations.Migration): + + dependencies = [ + ('FAIRshakeAPI', '0008_auto_20180912_2050'), + ] + + operations = [ + migrations.RunPython( + migrate + ) + ] diff --git a/FAIRshakeAPI/migrations/0010_auto_20180912_2054.py b/FAIRshakeAPI/migrations/0010_auto_20180912_2054.py new file mode 100644 index 0000000..6d2d7b2 --- /dev/null +++ b/FAIRshakeAPI/migrations/0010_auto_20180912_2054.py @@ -0,0 +1,33 @@ +# Generated by Django 2.0.7 on 2018-09-12 20:54 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('FAIRshakeAPI', '0009_auto_20180912_2051'), + ] + + operations = [ + migrations.AlterField( + model_name='digitalobject', + name='slug', + field=models.CharField(max_length=255, unique=True), + ), + migrations.AlterField( + model_name='metric', + name='slug', + field=models.CharField(max_length=255, unique=True), + ), + migrations.AlterField( + model_name='project', + name='slug', + field=models.CharField(max_length=255, unique=True), + ), + migrations.AlterField( + model_name='rubric', + name='slug', + field=models.CharField(max_length=255, unique=True), + ), + ] diff --git a/FAIRshakeAPI/migrations/0011_merge_20181211_2221.py b/FAIRshakeAPI/migrations/0011_merge_20181211_2221.py new file mode 100644 index 0000000..89ec7ee --- /dev/null +++ b/FAIRshakeAPI/migrations/0011_merge_20181211_2221.py @@ -0,0 +1,14 @@ +# Generated by Django 2.0.7 on 2018-12-11 22:21 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('FAIRshakeAPI', '0010_remove_answer_answer_tmp'), + ('FAIRshakeAPI', '0010_auto_20180912_2054'), + ] + + operations = [ + ] diff --git a/FAIRshakeAPI/models.py b/FAIRshakeAPI/models.py index 16e74b5..7907cd9 100644 --- a/FAIRshakeAPI/models.py +++ b/FAIRshakeAPI/models.py @@ -12,6 +12,7 @@ class IdentifiableModelMixin(models.Model): title = models.CharField(max_length=255, blank=False) url = models.TextField(blank=True, null=False, default='') + slug = models.CharField(max_length=255, unique=True, blank=False, null=False) description = models.TextField(blank=True, null=False, default='') image = models.CharField(max_length=255, blank=True, null=False, default='') tags = models.CharField(max_length=255, blank=True, null=False, default='') @@ -55,7 +56,7 @@ def attrs(self): 'tags': self.tags_as_list(), 'type': self.type, } - + def has_permission(self, user, perm): if perm in ['list', 'retrieve', 'stats']: return True @@ -188,7 +189,7 @@ def save(self, *args, **kwargs): def invalidate_cache(self): if self.target is not None: - k = '#target={pk}'.format(pk=self.target.pk) + k = '#target={slug}'.format(slug=self.target.slug) l = list( set( json.loads( @@ -198,7 +199,7 @@ def invalidate_cache(self): ) cache.delete_many(l) if self.rubric is not None: - k = '#rubric={pk}'.format(pk=self.rubric.pk) + k = '#rubric={slug}'.format(slug=self.rubric.slug) l = list( set( json.loads( @@ -208,7 +209,7 @@ def invalidate_cache(self): ) cache.delete_many(l) if self.project is not None: - k = '#project={pk}'.format(pk=self.project.pk) + k = '#project={slug}'.format(slug=self.project.slug) l = list( set( json.loads( diff --git a/FAIRshakeAPI/serializers.py b/FAIRshakeAPI/serializers.py index d47d226..4a1af1f 100644 --- a/FAIRshakeAPI/serializers.py +++ b/FAIRshakeAPI/serializers.py @@ -20,6 +20,7 @@ def update(self, instance, validated_data): class Meta: abstract = True + lookup_field = 'slug' read_only_fields = ( 'id', diff --git a/FAIRshakeAPI/tests.py b/FAIRshakeAPI/tests.py index 779b81b..2c8ab8b 100644 --- a/FAIRshakeAPI/tests.py +++ b/FAIRshakeAPI/tests.py @@ -13,14 +13,17 @@ def setUp(cls, Client=Client): ) metrics = [ models.Metric.objects.create( + slug='1', title='yesnobut test', type='yesnobut', ), models.Metric.objects.create( + slug='2', title='text test', type='text', ), models.Metric.objects.create( + slug='3', title='url test', type='url', ), @@ -28,17 +31,20 @@ def setUp(cls, Client=Client): for metric in metrics: metric.authors.add(user) rubric = models.Rubric.objects.create( + slug='1', title='rubric test', ) rubric.authors.add(user) for metric in metrics: rubric.metrics.add(metric) obj = models.DigitalObject.objects.create( + slug='1', title='digital object test', url='https://fairshake.cloud/', ) obj.rubrics.add(rubric) project = models.Project.objects.create( + slug='1', title='project test', ) project.authors.add(user) @@ -56,6 +62,7 @@ def setUp(cls, Client=Client): answer=1.0, ) obj2 = models.DigitalObject.objects.create( + slug='2', title='test object create', url='https://fairshake.cloud' ) @@ -163,7 +170,7 @@ def test_score_viewset_list(self): def test_project_viewset_detail(self): response = self.anonymous_client.get( reverse('project-detail', kwargs=dict( - pk=models.Project.objects.first().pk + slug=models.Project.objects.first().slug )), HTTP_ACCEPT='text/html', ) @@ -172,7 +179,7 @@ def test_project_viewset_detail(self): response = self.anonymous_client.get( reverse('project-detail', kwargs=dict( - pk=models.Project.objects.first().pk + slug=models.Project.objects.first().slug )), HTTP_ACCEPT='application/json', ) @@ -181,7 +188,7 @@ def test_project_viewset_detail(self): response = self.authenticated_client.get( reverse('project-detail', kwargs=dict( - pk=models.Project.objects.first().pk + slug=models.Project.objects.first().slug )), HTTP_ACCEPT='text/html', ) @@ -190,7 +197,7 @@ def test_project_viewset_detail(self): response = self.authenticated_client.get( reverse('project-detail', kwargs=dict( - pk=models.Project.objects.first().pk + slug=models.Project.objects.first().slug )), HTTP_ACCEPT='application/json', ) @@ -200,7 +207,7 @@ def test_project_viewset_detail(self): def test_digital_object_viewset_detail(self): response = self.anonymous_client.get( reverse('digital_object-detail', kwargs=dict( - pk=models.DigitalObject.objects.first().pk + slug=models.DigitalObject.objects.first().slug )), HTTP_ACCEPT='text/html', ) @@ -209,7 +216,7 @@ def test_digital_object_viewset_detail(self): response = self.anonymous_client.get( reverse('digital_object-detail', kwargs=dict( - pk=models.DigitalObject.objects.first().pk + slug=models.DigitalObject.objects.first().slug )), HTTP_ACCEPT='application/json', ) @@ -218,7 +225,7 @@ def test_digital_object_viewset_detail(self): response = self.authenticated_client.get( reverse('digital_object-detail', kwargs=dict( - pk=models.DigitalObject.objects.first().pk + slug=models.DigitalObject.objects.first().slug )), HTTP_ACCEPT='text/html', ) @@ -227,7 +234,7 @@ def test_digital_object_viewset_detail(self): response = self.authenticated_client.get( reverse('digital_object-detail', kwargs=dict( - pk=models.DigitalObject.objects.first().pk + slug=models.DigitalObject.objects.first().slug )), HTTP_ACCEPT='application/json', ) @@ -237,7 +244,7 @@ def test_digital_object_viewset_detail(self): def test_rubric_viewset_detail(self): response = self.anonymous_client.get( reverse('rubric-detail', kwargs=dict( - pk=models.Rubric.objects.first().pk + slug=models.Rubric.objects.first().slug )), HTTP_ACCEPT='text/html', ) @@ -246,7 +253,7 @@ def test_rubric_viewset_detail(self): response = self.anonymous_client.get( reverse('rubric-detail', kwargs=dict( - pk=models.Rubric.objects.first().pk + slug=models.Rubric.objects.first().slug )), HTTP_ACCEPT='application/json', ) @@ -255,7 +262,7 @@ def test_rubric_viewset_detail(self): response = self.authenticated_client.get( reverse('rubric-detail', kwargs=dict( - pk=models.Rubric.objects.first().pk + slug=models.Rubric.objects.first().slug )), HTTP_ACCEPT='text/html', ) @@ -264,7 +271,7 @@ def test_rubric_viewset_detail(self): response = self.authenticated_client.get( reverse('rubric-detail', kwargs=dict( - pk=models.Rubric.objects.first().pk + slug=models.Rubric.objects.first().slug )), HTTP_ACCEPT='application/json', ) @@ -274,7 +281,7 @@ def test_rubric_viewset_detail(self): def test_metric_viewset_detail(self): response = self.anonymous_client.get( reverse('metric-detail', kwargs=dict( - pk=models.Metric.objects.first().pk + slug=models.Metric.objects.first().slug )), HTTP_ACCEPT='text/html', ) @@ -283,7 +290,7 @@ def test_metric_viewset_detail(self): response = self.anonymous_client.get( reverse('metric-detail', kwargs=dict( - pk=models.Metric.objects.first().pk + slug=models.Metric.objects.first().slug )), HTTP_ACCEPT='application/json', ) @@ -292,7 +299,7 @@ def test_metric_viewset_detail(self): response = self.authenticated_client.get( reverse('metric-detail', kwargs=dict( - pk=models.Metric.objects.first().pk + slug=models.Metric.objects.first().slug )), HTTP_ACCEPT='text/html', ) @@ -301,7 +308,7 @@ def test_metric_viewset_detail(self): response = self.authenticated_client.get( reverse('metric-detail', kwargs=dict( - pk=models.Metric.objects.first().pk + slug=models.Metric.objects.first().slug )), HTTP_ACCEPT='application/json', ) @@ -351,9 +358,9 @@ def test_assessment_prepare_all_params(self): baseUrl=reverse( 'assessment-prepare' ), - target=models.DigitalObject.objects.first().pk, - rubric=models.Rubric.objects.first().pk, - project=models.Project.objects.first().pk, + target=models.DigitalObject.objects.first().slug, + rubric=models.Rubric.objects.first().slug, + project=models.Project.objects.first().slug, ), HTTP_ACCEPT='text/html', ) @@ -365,9 +372,9 @@ def test_assessment_prepare_all_params(self): baseUrl=reverse( 'assessment-prepare' ), - target=models.DigitalObject.objects.first().pk, - rubric=models.Rubric.objects.first().pk, - project=models.Project.objects.first().pk, + target=models.DigitalObject.objects.first().slug, + rubric=models.Rubric.objects.first().slug, + project=models.Project.objects.first().slug, ), HTTP_ACCEPT='text/html', ) @@ -403,7 +410,7 @@ def test_assessment_prepare_target(self): baseUrl=reverse( 'assessment-prepare' ), - target=models.DigitalObject.objects.first().pk, + target=models.DigitalObject.objects.first().slug, ), HTTP_ACCEPT='text/html', ) @@ -415,7 +422,7 @@ def test_assessment_prepare_target(self): baseUrl=reverse( 'assessment-prepare' ), - target=models.DigitalObject.objects.first().pk, + target=models.DigitalObject.objects.first().slug, ), HTTP_ACCEPT='text/html', ) @@ -428,8 +435,8 @@ def test_assessment_prepare_target_rubric(self): baseUrl=reverse( 'assessment-prepare' ), - target=models.DigitalObject.objects.first().pk, - rubric=models.Rubric.objects.first().pk, + target=models.DigitalObject.objects.first().slug, + rubric=models.Rubric.objects.first().slug, ), HTTP_ACCEPT='text/html', ) @@ -441,8 +448,8 @@ def test_assessment_prepare_target_rubric(self): baseUrl=reverse( 'assessment-prepare' ), - target=models.DigitalObject.objects.first().pk, - rubric=models.Rubric.objects.first().pk, + target=models.DigitalObject.objects.first().slug, + rubric=models.Rubric.objects.first().slug, ), HTTP_ACCEPT='text/html', ) @@ -455,8 +462,8 @@ def test_assessment_prepare_target_project(self): baseUrl=reverse( 'assessment-prepare' ), - target=models.DigitalObject.objects.first().pk, - project=models.Project.objects.first().pk, + target=models.DigitalObject.objects.first().slug, + project=models.Project.objects.first().slug, ), HTTP_ACCEPT='text/html', ) @@ -468,8 +475,8 @@ def test_assessment_prepare_target_project(self): baseUrl=reverse( 'assessment-prepare' ), - target=models.DigitalObject.objects.first().pk, - project=models.Project.objects.first().pk, + target=models.DigitalObject.objects.first().slug, + project=models.Project.objects.first().slug, ), HTTP_ACCEPT='text/html', ) @@ -482,7 +489,7 @@ def test_assessment_prepare_rubric(self): baseUrl=reverse( 'assessment-prepare' ), - rubric=models.Rubric.objects.first().pk, + rubric=models.Rubric.objects.first().slug, ), HTTP_ACCEPT='text/html', ) @@ -494,7 +501,7 @@ def test_assessment_prepare_rubric(self): baseUrl=reverse( 'assessment-prepare' ), - rubric=models.Rubric.objects.first().pk, + rubric=models.Rubric.objects.first().slug, ), HTTP_ACCEPT='text/html', ) @@ -507,8 +514,8 @@ def test_assessment_prepare_rubric_project(self): baseUrl=reverse( 'assessment-prepare' ), - rubric=models.Rubric.objects.first().pk, - project=models.Project.objects.first().pk, + rubric=models.Rubric.objects.first().slug, + project=models.Project.objects.first().slug, ), HTTP_ACCEPT='text/html', ) @@ -520,8 +527,8 @@ def test_assessment_prepare_rubric_project(self): baseUrl=reverse( 'assessment-prepare' ), - rubric=models.Rubric.objects.first().pk, - project=models.Project.objects.first().pk, + rubric=models.Rubric.objects.first().slug, + project=models.Project.objects.first().slug, ), HTTP_ACCEPT='text/html', ) @@ -534,7 +541,7 @@ def test_assessment_prepare_project(self): baseUrl=reverse( 'assessment-prepare' ), - project=models.Project.objects.first().pk, + project=models.Project.objects.first().slug, ), HTTP_ACCEPT='text/html', ) @@ -546,7 +553,7 @@ def test_assessment_prepare_project(self): baseUrl=reverse( 'assessment-prepare' ), - project=models.Project.objects.first().pk, + project=models.Project.objects.first().slug, ), HTTP_ACCEPT='text/html', ) @@ -560,9 +567,9 @@ def test_assessment_perform_all_params(self): baseUrl=reverse( 'assessment-perform' ), - target=models.DigitalObject.objects.first().pk, - rubric=models.Rubric.objects.first().pk, - project=models.Project.objects.first().pk, + target=models.DigitalObject.objects.first().slug, + rubric=models.Rubric.objects.first().slug, + project=models.Project.objects.first().slug, ), HTTP_ACCEPT='text/html', ) @@ -574,9 +581,9 @@ def test_assessment_perform_all_params(self): baseUrl=reverse( 'assessment-perform' ), - target=models.DigitalObject.objects.first().pk, - rubric=models.Rubric.objects.first().pk, - project=models.Project.objects.first().pk, + target=models.DigitalObject.objects.first().slug, + rubric=models.Rubric.objects.first().slug, + project=models.Project.objects.first().slug, ), HTTP_ACCEPT='text/html', ) @@ -589,7 +596,7 @@ def test_assessment_perform_target_only(self): baseUrl=reverse( 'assessment-perform' ), - target=models.DigitalObject.objects.first().pk, + target=models.DigitalObject.objects.first().slug, ), HTTP_ACCEPT='text/html', ) @@ -601,7 +608,7 @@ def test_assessment_perform_target_only(self): baseUrl=reverse( 'assessment-perform' ), - target=models.DigitalObject.objects.first().pk, + target=models.DigitalObject.objects.first().slug, ), HTTP_ACCEPT='text/html', ) @@ -614,8 +621,8 @@ def test_assessment_perform_target_rubric(self): baseUrl=reverse( 'assessment-perform' ), - target=models.DigitalObject.objects.first().pk, - rubric=models.Rubric.objects.first().pk, + target=models.DigitalObject.objects.first().slug, + rubric=models.Rubric.objects.first().slug, ), HTTP_ACCEPT='text/html', ) @@ -627,8 +634,8 @@ def test_assessment_perform_target_rubric(self): baseUrl=reverse( 'assessment-perform' ), - target=models.DigitalObject.objects.first().pk, - rubric=models.Rubric.objects.first().pk, + target=models.DigitalObject.objects.first().slug, + rubric=models.Rubric.objects.first().slug, ), HTTP_ACCEPT='text/html', ) @@ -641,8 +648,8 @@ def test_assessment_perform_target_project(self): baseUrl=reverse( 'assessment-perform' ), - target=models.DigitalObject.objects.first().pk, - project=models.Project.objects.first().pk, + target=models.DigitalObject.objects.first().slug, + project=models.Project.objects.first().slug, ), HTTP_ACCEPT='text/html', ) @@ -654,8 +661,8 @@ def test_assessment_perform_target_project(self): baseUrl=reverse( 'assessment-perform' ), - target=models.DigitalObject.objects.first().pk, - project=models.Project.objects.first().pk, + target=models.DigitalObject.objects.first().slug, + project=models.Project.objects.first().slug, ), HTTP_ACCEPT='text/html', ) @@ -668,7 +675,7 @@ def test_assessment_perform_rubric(self): baseUrl=reverse( 'assessment-perform' ), - rubric=models.Rubric.objects.first().pk, + rubric=models.Rubric.objects.first().slug, ), HTTP_ACCEPT='text/html', ) @@ -680,7 +687,7 @@ def test_assessment_perform_rubric(self): baseUrl=reverse( 'assessment-perform' ), - rubric=models.Rubric.objects.first().pk, + rubric=models.Rubric.objects.first().slug, ), HTTP_ACCEPT='text/html', ) @@ -693,8 +700,8 @@ def test_assessment_perform_rubric_project(self): baseUrl=reverse( 'assessment-perform' ), - rubric=models.Rubric.objects.first().pk, - project=models.Project.objects.first().pk, + rubric=models.Rubric.objects.first().slug, + project=models.Project.objects.first().slug, ), HTTP_ACCEPT='text/html', ) @@ -706,8 +713,8 @@ def test_assessment_perform_rubric_project(self): baseUrl=reverse( 'assessment-perform' ), - rubric=models.Rubric.objects.first().pk, - project=models.Project.objects.first().pk, + rubric=models.Rubric.objects.first().slug, + project=models.Project.objects.first().slug, ), HTTP_ACCEPT='text/html', ) @@ -720,7 +727,7 @@ def test_assessment_perform_project_only(self): baseUrl=reverse( 'assessment-perform' ), - project=models.Project.objects.first().pk, + project=models.Project.objects.first().slug, ), HTTP_ACCEPT='text/html', ) @@ -732,7 +739,7 @@ def test_assessment_perform_project_only(self): baseUrl=reverse( 'assessment-perform' ), - project=models.Project.objects.first().pk, + project=models.Project.objects.first().slug, ), HTTP_ACCEPT='text/html', ) @@ -783,7 +790,7 @@ def test_stats_project_view(self): # stats response = self.anonymous_client.get( reverse('project-stats', kwargs=dict( - pk=models.Project.objects.first().pk + slug=models.Project.objects.first().slug )), HTTP_ACCEPT='text/html', ) @@ -792,7 +799,7 @@ def test_stats_project_view(self): response = self.authenticated_client.get( reverse('project-stats', kwargs=dict( - pk=models.Project.objects.first().pk + slug=models.Project.objects.first().slug )), HTTP_ACCEPT='text/html', ) @@ -802,7 +809,7 @@ def test_stats_project_view(self): def test_modify_project_view(self): response = self.authenticated_client.get( reverse('project-modify', kwargs=dict( - pk=models.Project.objects.first().pk + slug=models.Project.objects.first().slug )), HTTP_ACCEPT='text/html', ) @@ -811,7 +818,7 @@ def test_modify_project_view(self): response = self.authenticated_client.post( reverse('project-modify', kwargs=dict( - pk=models.Project.objects.first().pk + slug=models.Project.objects.first().slug )), HTTP_ACCEPT='text/html', ) @@ -819,28 +826,28 @@ def test_modify_project_view(self): self.assertEqual(response['Content-Type'], 'text/html; charset=utf-8', response) def test_digital_object_remove(self): - pk = models.Project.objects.first().pk + slug = models.Project.objects.first().slug response = self.anonymous_client.get( reverse('project-remove', kwargs=dict( - pk=pk + slug=slug )), HTTP_ACCEPT='text/html', ) self.assertEqual(response.status_code, 302, 'Login redirect expected') self.assertEqual(response['Content-Type'], 'text/html; charset=utf-8', response) - self.assertEqual(models.DigitalObject.objects.first().pk, pk) + self.assertEqual(models.DigitalObject.objects.first().slug, slug) response = self.authenticated_client.get( reverse('project-remove', kwargs=dict( - pk=pk + slug=slug )), HTTP_ACCEPT='text/html', ) self.assertEqual(response.status_code, 302) self.assertEqual(response['Content-Type'], 'text/html; charset=utf-8', response) try: - models.Project.objects.get(pk=pk) + models.Project.objects.get(slug=slug) self.fail('Project was not deleted') except: pass @@ -868,6 +875,7 @@ def test_project_create(self): response = self.authenticated_client.post( '/project/', { + 'slug': '2', 'title': 'test project 2', }, HTTP_ACCEPT='application/json', @@ -881,7 +889,7 @@ def test_project_create(self): def test_project_update(self): response = self.anonymous_client.put( - '/project/{pk}/'.format(pk=models.Project.objects.first().pk), + '/project/{slug}/'.format(slug=models.Project.objects.first().slug), { 'title': 'test project improved', }, @@ -892,7 +900,7 @@ def test_project_update(self): self.assertNotEqual(models.Project.objects.first().title, 'test project improved') response = self.authenticated_client.patch( - '/project/{pk}/'.format(pk=models.Project.objects.first().pk), + '/project/{slug}/'.format(slug=models.Project.objects.first().slug), { 'title': 'test project improved', }, @@ -904,7 +912,7 @@ def test_project_update(self): def test_project_partial_update(self): response = self.anonymous_client.patch( - '/project/{pk}/'.format(pk=models.Project.objects.first().pk), + '/project/{slug}/'.format(slug=models.Project.objects.first().slug), { 'description': 'test improved', }, @@ -915,7 +923,7 @@ def test_project_partial_update(self): self.assertNotEqual(models.Project.objects.first().description, 'test improved') response = self.authenticated_client.patch( - '/project/{pk}/'.format(pk=models.Project.objects.first().pk), + '/project/{slug}/'.format(slug=models.Project.objects.first().slug), { 'description': 'test improved', }, @@ -926,23 +934,23 @@ def test_project_partial_update(self): self.assertEqual(models.Project.objects.first().description, 'test improved') def test_project_destroy(self): - pk = models.Project.objects.first().pk + slug = models.Project.objects.first().slug response = self.anonymous_client.delete( - '/project/{pk}/'.format(pk=pk), + '/project/{slug}/'.format(slug=slug), HTTP_ACCEPT='application/json', ) self.assertEqual(response.status_code, 401) self.assertEqual(response['Content-Type'], 'application/json', response) - self.assertEqual(models.Project.objects.first().pk, pk) + self.assertEqual(models.Project.objects.first().slug, slug) response = self.authenticated_client.delete( - '/project/{pk}/'.format(pk=pk), + '/project/{slug}/'.format(slug=slug), HTTP_ACCEPT='application/json', ) self.assertEqual(response.status_code, 204) # self.assertEqual(response['Content-Type'], 'application/json', response) try: - models.Project.objects.get(pk=pk) + models.Project.objects.get(slug=slug) self.fail('Project was not deleted') except: pass @@ -957,9 +965,9 @@ def test_assessment_create(self): response = self.anonymous_client.post( '/assessment/', json.dumps({ - 'project': project.id, - 'target': target.id, - 'rubric': rubric.id, + 'project': project.slug, + 'target': target.slug, + 'rubric': rubric.slug, 'answers': json.dumps([ { 'metric': 1, @@ -989,9 +997,9 @@ def test_assessment_create(self): response = self.authenticated_client.post( '/assessment/', json.dumps({ - 'project': project.id, - 'target': target.id, - 'rubric': rubric.id, + 'project': project.slug, + 'target': target.slug, + 'rubric': rubric.slug, 'answers': [ { 'metric': 1, diff --git a/FAIRshakeAPI/views.py b/FAIRshakeAPI/views.py index 94d1f7e..b3118f6 100644 --- a/FAIRshakeAPI/views.py +++ b/FAIRshakeAPI/views.py @@ -63,6 +63,8 @@ def get_template_context(self, data, renderer_context): return view.get_template_context(request, context) class CustomModelViewSet(viewsets.ModelViewSet): + lookup_field = 'slug' + renderer_classes = [ renderers.JSONRenderer, CustomTemplateHTMLRenderer, @@ -130,7 +132,7 @@ def save_form(self, request, form): detail=False, methods=['get', 'post'], renderer_classes=[CustomTemplateHTMLRenderer], ) - def add(self, request, pk=None, **kwargs): + def add(self, request, slug=None, **kwargs): self.check_permissions(request) if request.method == 'GET': return response.Response() @@ -153,7 +155,7 @@ def add(self, request, pk=None, **kwargs): )) return callback_or_redirect(request, self.get_model_name()+'-detail', - pk=instance.id, + slug=instance.slug, ) return response.Response() @@ -162,7 +164,7 @@ def add(self, request, pk=None, **kwargs): methods=['get', 'post'], renderer_classes=[CustomTemplateHTMLRenderer], ) - def modify(self, request, pk=None): + def modify(self, request, slug=None): item = self.get_object() if request.method == 'GET': return response.Response() @@ -171,7 +173,7 @@ def modify(self, request, pk=None): if instance: return callback_or_redirect(request, self.get_model_name()+'-detail', - pk=pk, + slug=instance.slug, ) return response.Response() @@ -179,7 +181,7 @@ def modify(self, request, pk=None): detail=True, methods=['get'], ) - def remove(self, request, pk=None): + def remove(self, request, slug=None): item = self.get_object() self.check_object_permissions(request, item) item.delete() @@ -257,7 +259,7 @@ class ProjectViewSet(IdentifiableModelViewSet): methods=['get'], renderer_classes=[CustomTemplateHTMLRenderer], ) - def stats(self, request, pk=None): + def stats(self, request, slug=None): item = self.get_object() self.check_object_permissions(request, item) return response.Response() @@ -282,6 +284,7 @@ class RubricViewSet(IdentifiableModelViewSet): filter_class = filters.RubricFilterSet class AssessmentViewSet(CustomModelViewSet): + lookup_field = 'pk' model = models.Assessment serializer_class = serializers.AssessmentSerializer filter_class = filters.AssessmentFilterSet @@ -350,7 +353,7 @@ def get_answer_forms(self, assessment): if assessment: initial = query_dict( { - '%s-%s' % (answer.metric.id, key): getattr(answer, key) + '%s-%s' % (answer.metric.slug, key): getattr(answer, key) for answer in assessment.answers.all() for key in ['answer', 'comment', 'url_comment'] if getattr(answer, key, None) is not None @@ -366,8 +369,8 @@ def get_answer_forms(self, assessment): target=assessment.target, ) for answer in assessment.answers.all(): - for key, attr in auto_assessment_results.get('metric:%d' % (answer.metric.id), {}).items(): - k = '%s-%s' % (answer.metric.id, key) + for key, attr in auto_assessment_results.get('metric:%s' % (answer.metric.slug), {}).items(): + k = '%s-%s' % (answer.metric.slug, key) if attr is not None and initial.get(k) is not None: initial[k] = attr @@ -375,7 +378,7 @@ def get_answer_forms(self, assessment): forms.AnswerForm( initial, instance=answer, - prefix=answer.metric.id, + prefix=answer.metric.slug, ) for answer in assessment.answers.all() ] @@ -407,7 +410,7 @@ def get_suggestions(self): ] if target: - targets = models.DigitalObject.objects.filter(id=target) + targets = models.DigitalObject.objects.filter(slug=target) else: if target_filters: targets = models.DigitalObject.objects.filter( @@ -416,7 +419,7 @@ def get_suggestions(self): target_filters, None, ) - ).order_by('id').distinct() + ).order_by('slug').distinct() else: targets = None @@ -424,13 +427,13 @@ def get_suggestions(self): targets = search.DigitalObjectSearchVector().query(q) if targets.count() == 1: - target = targets.first().id + target = targets.first().slug if rubric: if target: rubrics = targets.first().rubrics.all() else: - rubrics = models.Rubric.objects.filter(id=rubric) + rubrics = models.Rubric.objects.filter(slug=rubric) else: rubrics = None if target: @@ -438,13 +441,13 @@ def get_suggestions(self): if rubrics is None or not rubrics.exists(): rubrics = models.Rubric.objects.all() if rubrics.count() == 1: - rubric = rubrics.first().id + rubric = rubrics.first().slug if project: if target: projects = targets.first().projects.all() else: - projects = models.Project.objects.filter(id=project) + projects = models.Project.objects.filter(slug=project) else: projects = None if target: @@ -452,7 +455,7 @@ def get_suggestions(self): if projects is None or not projects.exists(): projects = models.Project.objects.all() if projects.count() == 1: - project = projects.first().id + project = projects.first().slug return { 'target': target, @@ -502,7 +505,7 @@ def perform(self, request, **kwargs): if self.save_answer_forms(answer_forms): return callback_or_redirect(request, 'digital_object-detail', - pk=assessment.target.id, + slug=assessment.target.slug, ) return response.Response() diff --git a/FAIRshakeHub/templates/fairshake/assessment/element.html b/FAIRshakeHub/templates/fairshake/assessment/element.html index 61f1665..f82fb97 100644 --- a/FAIRshakeHub/templates/fairshake/assessment/element.html +++ b/FAIRshakeHub/templates/fairshake/assessment/element.html @@ -4,18 +4,18 @@
{{ model|unslugify }} - of {{ item.target.title }} - with {{ item.rubric.title }} + of {{ item.target.title }} + with {{ item.rubric.title }} {% if item.project %} - for {{ item.project.title }} + for {{ item.project.title }} {% endif %}   - + {{ model|unslugify }} - of {{ item.target.title }} - with {{ item.rubric.title }} + of {{ item.target.title }} + with {{ item.rubric.title }} {% if item.project %} - for {{ item.project.title }} + for {{ item.project.title }} {% endif %}   diff --git a/FAIRshakeHub/templates/fairshake/assessment/prepare.html b/FAIRshakeHub/templates/fairshake/assessment/prepare.html index 0c53be4..0c8831e 100644 --- a/FAIRshakeHub/templates/fairshake/assessment/prepare.html +++ b/FAIRshakeHub/templates/fairshake/assessment/prepare.html @@ -25,19 +25,19 @@
{{ form.target|bootstrap }} {% for target in suggestions.targets %} - {{ target.title }} + {{ target.title }} {% endfor %}
{{ form.rubric|bootstrap }} {% for rubric in suggestions.rubrics %} - {{ rubric.title }} + {{ rubric.title }} {% endfor %}
{{ form.project|bootstrap }} {% for project in suggestions.projects %} - {{ project.title }} + {{ project.title }} {% endfor %}
@@ -48,8 +48,8 @@