Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 19 additions & 4 deletions ietf/ipr/admin.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,22 @@
# Copyright The IETF Trust 2010-2020, All Rights Reserved
# Copyright The IETF Trust 2010-2025, All Rights Reserved
# -*- coding: utf-8 -*-


from django import forms
from django.contrib import admin
from ietf.name.models import DocRelationshipName
from ietf.ipr.models import (IprDisclosureBase, IprDocRel, IprEvent,
RelatedIpr, HolderIprDisclosure, ThirdPartyIprDisclosure, GenericIprDisclosure,
NonDocSpecificIprDisclosure, LegacyMigrationIprEvent)
from ietf.ipr.models import (
IprDisclosureBase,
IprDocRel,
IprEvent,
RelatedIpr,
HolderIprDisclosure,
RemovedIprDisclosure,
ThirdPartyIprDisclosure,
GenericIprDisclosure,
NonDocSpecificIprDisclosure,
LegacyMigrationIprEvent,
)

# ------------------------------------------------------
# ModelAdmins
Expand Down Expand Up @@ -110,3 +119,9 @@ class LegacyMigrationIprEventAdmin(admin.ModelAdmin):
list_filter = ['time', 'type', 'response_due']
raw_id_fields = ['by', 'disclosure', 'message', 'in_reply_to']
admin.site.register(LegacyMigrationIprEvent, LegacyMigrationIprEventAdmin)

class RemovedIprDisclosureAdmin(admin.ModelAdmin):
pass


admin.site.register(RemovedIprDisclosure, RemovedIprDisclosureAdmin)
28 changes: 28 additions & 0 deletions ietf/ipr/migrations/0005_removediprdisclosure.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# Copyright The IETF Trust 2025, All Rights Reserved

from django.db import migrations, models


class Migration(migrations.Migration):
dependencies = [
("ipr", "0004_holderiprdisclosure_is_blanket_disclosure"),
]

operations = [
migrations.CreateModel(
name="RemovedIprDisclosure",
fields=[
(
"id",
models.AutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("removed_id", models.PositiveBigIntegerField(unique=True)),
("reason", models.TextField()),
],
),
]
24 changes: 24 additions & 0 deletions ietf/ipr/migrations/0006_already_removed_ipr.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Copyright The IETF Trust 2025, All Rights Reserved
from django.db import migrations


def forward(apps, schema_editor):
RemovedIprDisclosure = apps.get_model("ipr", "RemovedIprDisclosure")
for id in (6544, 6068):
RemovedIprDisclosure.objects.create(
removed_id=id,
reason="This IPR disclosure was removed as objectively false.",
)


def reverse(apps, schema_editor):
RemovedIprDisclosure = apps.get_model("ipr", "RemovedIprDisclosure")
RemovedIprDisclosure.objects.all().delete()


class Migration(migrations.Migration):
dependencies = [
("ipr", "0005_removediprdisclosure"),
]

operations = [migrations.RunPython(forward, reverse)]
6 changes: 5 additions & 1 deletion ietf/ipr/models.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Copyright The IETF Trust 2007-2023, All Rights Reserved
# Copyright The IETF Trust 2007-2025, All Rights Reserved
# -*- coding: utf-8 -*-


Expand Down Expand Up @@ -270,3 +270,7 @@ class LegacyMigrationIprEvent(IprEvent):
"""A subclass of IprEvent specifically for capturing contents of legacy_url_0,
the text of a disclosure submitted by email"""
pass

class RemovedIprDisclosure(models.Model):
removed_id = models.PositiveBigIntegerField(unique=True)
reason = models.TextField()
19 changes: 17 additions & 2 deletions ietf/ipr/resources.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Copyright The IETF Trust 2015-2019, All Rights Reserved
# Copyright The IETF Trust 2015-2025, All Rights Reserved
# -*- coding: utf-8 -*-
# Autogenerated by the mkresources management command 2015-03-21 14:05 PDT

Expand All @@ -11,7 +11,7 @@

from ietf import api

from ietf.ipr.models import ( IprDisclosureBase, IprDocRel, HolderIprDisclosure, ThirdPartyIprDisclosure,
from ietf.ipr.models import ( IprDisclosureBase, IprDocRel, HolderIprDisclosure, RemovedIprDisclosure, ThirdPartyIprDisclosure,
RelatedIpr, NonDocSpecificIprDisclosure, GenericIprDisclosure, IprEvent, LegacyMigrationIprEvent )

from ietf.person.resources import PersonResource
Expand Down Expand Up @@ -295,3 +295,18 @@ class Meta:
}
api.ipr.register(LegacyMigrationIprEventResource())



class RemovedIprDisclosureResource(ModelResource):
class Meta:
queryset = RemovedIprDisclosure.objects.all()
serializer = api.Serializer()
cache = SimpleCache()
#resource_name = 'removediprdisclosure'
ordering = ['id', ]
filtering = {
"id": ALL,
"removed_id": ALL,
"reason": ALL,
}
api.ipr.register(RemovedIprDisclosureResource())
22 changes: 21 additions & 1 deletion ietf/ipr/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
from ietf.ipr.forms import DraftForm, HolderIprDisclosureForm
from ietf.ipr.mail import (process_response_email, get_reply_to, get_update_submitter_emails,
get_pseudo_submitter, get_holders, get_update_cc_addrs, UndeliverableIprResponseError)
from ietf.ipr.models import (IprDisclosureBase, GenericIprDisclosure, HolderIprDisclosure,
from ietf.ipr.models import (IprDisclosureBase, GenericIprDisclosure, HolderIprDisclosure, RemovedIprDisclosure,
ThirdPartyIprDisclosure, IprEvent)
from ietf.ipr.templatetags.ipr_filters import no_revisions_message
from ietf.ipr.utils import get_genitive, get_ipr_summary, ingest_response_email
Expand Down Expand Up @@ -125,6 +125,26 @@ def test_showlist(self):
self.assertContains(r, "removed as objectively false")
ipr.delete()

def test_show_delete(self):
ipr = HolderIprDisclosureFactory()
removed = RemovedIprDisclosure.objects.create(
removed_id=ipr.pk, reason="Removed for reasons"
)
url = urlreverse("ietf.ipr.views.show", kwargs=dict(id=removed.removed_id))
r = self.client.get(url)
self.assertContains(r, "Removed for reasons")
q = PyQuery(r.content)
self.assertEqual(len(q("#deletion_warning")), 0)
self.client.login(username="secretary", password="secretary+password")
r = self.client.get(url)
self.assertContains(r, "Removed for reasons")
q = PyQuery(r.content)
self.assertEqual(len(q("#deletion_warning")), 1)
ipr.delete()
r = self.client.get(url)
self.assertContains(r, "Removed for reasons")
q = PyQuery(r.content)
self.assertEqual(len(q("#deletion_warning")), 0)

def test_show_posted(self):
ipr = HolderIprDisclosureFactory()
Expand Down
11 changes: 9 additions & 2 deletions ietf/ipr/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
AddCommentForm, AddEmailForm, NotifyForm, StateForm, NonDocSpecificIprDisclosureForm,
GenericIprDisclosureForm)
from ietf.ipr.models import (IprDisclosureStateName, IprDisclosureBase,
HolderIprDisclosure, GenericIprDisclosure, ThirdPartyIprDisclosure,
HolderIprDisclosure, GenericIprDisclosure, RemovedIprDisclosure, ThirdPartyIprDisclosure,
NonDocSpecificIprDisclosure, IprDocRel,
RelatedIpr,IprEvent)
from ietf.ipr.utils import (get_genitive, get_ipr_summary,
Expand Down Expand Up @@ -817,7 +817,14 @@ def get_details_tabs(ipr, selected):

def show(request, id):
"""View of individual declaration"""
ipr = get_object_or_404(IprDisclosureBase, id=id).get_child()
ipr = IprDisclosureBase.objects.filter(id=id)
removed = RemovedIprDisclosure.objects.filter(removed_id=id)
if removed.exists():
return render(request, "ipr/deleted.html", {"removed": removed.get(), "ipr": ipr})
Comment thread
rjsparks marked this conversation as resolved.
if not ipr.exists():
raise Http404
else:
ipr = ipr.get().get_child()
if not has_role(request.user, 'Secretariat'):
if ipr.state.slug in ['removed', 'removed_objfalse']:
return render(request, "ipr/removed.html", {
Expand Down
16 changes: 16 additions & 0 deletions ietf/templates/ipr/deleted.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{% extends "base.html" %}
{# Copyright The IETF Trust 2015-2023, All Rights Reserved #}
{% load ietf_filters origin %}
{% block title %}Removed IPR Disclosure{% endblock %}
{% block content %}
{% origin %}
<h1>Removed IPR disclosure</h1>
<p class="alert alert-info my-3">
{{ removed.reason }}
</p>
{% if user|has_role:"Secretariat" and ipr.exists %}
<p class="alert alert-warn my-3" id="deletion_warning">
This disclosure has not yet been deleted and parts of its content is available through, e.g, the history view and the /api/v1 views.
</p>
{% endif %}
{% endblock %}
Loading