commit
2033d607ec
2
.github/workflows/build.yml
vendored
2
.github/workflows/build.yml
vendored
|
@ -430,6 +430,7 @@ jobs:
|
||||||
with:
|
with:
|
||||||
workflow: deploy.yml
|
workflow: deploy.yml
|
||||||
repo: ietf-tools/infra-k8s
|
repo: ietf-tools/infra-k8s
|
||||||
|
ref: main
|
||||||
token: ${{ secrets.GH_INFRA_K8S_TOKEN }}
|
token: ${{ secrets.GH_INFRA_K8S_TOKEN }}
|
||||||
inputs: '{ "environment":"${{ secrets.GHA_K8S_CLUSTER }}", "app":"datatracker", "appVersion":"${{ env.PKG_VERSION }}", "remoteRef":"${{ github.sha }}" }'
|
inputs: '{ "environment":"${{ secrets.GHA_K8S_CLUSTER }}", "app":"datatracker", "appVersion":"${{ env.PKG_VERSION }}", "remoteRef":"${{ github.sha }}" }'
|
||||||
wait-for-completion: true
|
wait-for-completion: true
|
||||||
|
@ -455,6 +456,7 @@ jobs:
|
||||||
with:
|
with:
|
||||||
workflow: deploy.yml
|
workflow: deploy.yml
|
||||||
repo: ietf-tools/infra-k8s
|
repo: ietf-tools/infra-k8s
|
||||||
|
ref: main
|
||||||
token: ${{ secrets.GH_INFRA_K8S_TOKEN }}
|
token: ${{ secrets.GH_INFRA_K8S_TOKEN }}
|
||||||
inputs: '{ "environment":"${{ secrets.GHA_K8S_CLUSTER }}", "app":"datatracker", "appVersion":"${{ env.PKG_VERSION }}", "remoteRef":"${{ github.sha }}" }'
|
inputs: '{ "environment":"${{ secrets.GHA_K8S_CLUSTER }}", "app":"datatracker", "appVersion":"${{ env.PKG_VERSION }}", "remoteRef":"${{ github.sha }}" }'
|
||||||
wait-for-completion: true
|
wait-for-completion: true
|
||||||
|
|
30
dev/deploy-to-container/package-lock.json
generated
30
dev/deploy-to-container/package-lock.json
generated
|
@ -11,7 +11,7 @@
|
||||||
"nanoid": "5.0.7",
|
"nanoid": "5.0.7",
|
||||||
"nanoid-dictionary": "5.0.0-beta.1",
|
"nanoid-dictionary": "5.0.0-beta.1",
|
||||||
"slugify": "1.6.6",
|
"slugify": "1.6.6",
|
||||||
"tar": "^7.1.0",
|
"tar": "^7.4.0",
|
||||||
"yargs": "^17.7.2"
|
"yargs": "^17.7.2"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
|
@ -496,9 +496,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/minipass": {
|
"node_modules/minipass": {
|
||||||
"version": "7.1.0",
|
"version": "7.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz",
|
||||||
"integrity": "sha512-oGZRv2OT1lO2UF1zUcwdTb3wqUwI0kBGTgt/T7OdSj6M6N5m3o5uPf0AIW6lVxGGoiWUR7e2AwTE+xiwK8WQig==",
|
"integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=16 || 14 >=14.17"
|
"node": ">=16 || 14 >=14.17"
|
||||||
}
|
}
|
||||||
|
@ -788,13 +788,13 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/tar": {
|
"node_modules/tar": {
|
||||||
"version": "7.1.0",
|
"version": "7.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/tar/-/tar-7.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/tar/-/tar-7.4.0.tgz",
|
||||||
"integrity": "sha512-ENhg4W6BmjYxl8GTaE7/h99f0aXiSWv4kikRZ9n2/JRxypZniE84ILZqimAhxxX7Zb8Px6pFdheW3EeHfhnXQQ==",
|
"integrity": "sha512-XQs0S8fuAkQWuqhDeCdMlJXDX80D7EOVLDPVFkna9yQfzS+PHKgfxcei0jf6/+QAWcjqrnC8uM3fSAnrQl+XYg==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@isaacs/fs-minipass": "^4.0.0",
|
"@isaacs/fs-minipass": "^4.0.0",
|
||||||
"chownr": "^3.0.0",
|
"chownr": "^3.0.0",
|
||||||
"minipass": "^7.1.0",
|
"minipass": "^7.1.2",
|
||||||
"minizlib": "^3.0.1",
|
"minizlib": "^3.0.1",
|
||||||
"mkdirp": "^3.0.1",
|
"mkdirp": "^3.0.1",
|
||||||
"yallist": "^5.0.0"
|
"yallist": "^5.0.0"
|
||||||
|
@ -1311,9 +1311,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"minipass": {
|
"minipass": {
|
||||||
"version": "7.1.0",
|
"version": "7.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz",
|
||||||
"integrity": "sha512-oGZRv2OT1lO2UF1zUcwdTb3wqUwI0kBGTgt/T7OdSj6M6N5m3o5uPf0AIW6lVxGGoiWUR7e2AwTE+xiwK8WQig=="
|
"integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw=="
|
||||||
},
|
},
|
||||||
"minizlib": {
|
"minizlib": {
|
||||||
"version": "3.0.1",
|
"version": "3.0.1",
|
||||||
|
@ -1503,13 +1503,13 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"tar": {
|
"tar": {
|
||||||
"version": "7.1.0",
|
"version": "7.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/tar/-/tar-7.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/tar/-/tar-7.4.0.tgz",
|
||||||
"integrity": "sha512-ENhg4W6BmjYxl8GTaE7/h99f0aXiSWv4kikRZ9n2/JRxypZniE84ILZqimAhxxX7Zb8Px6pFdheW3EeHfhnXQQ==",
|
"integrity": "sha512-XQs0S8fuAkQWuqhDeCdMlJXDX80D7EOVLDPVFkna9yQfzS+PHKgfxcei0jf6/+QAWcjqrnC8uM3fSAnrQl+XYg==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@isaacs/fs-minipass": "^4.0.0",
|
"@isaacs/fs-minipass": "^4.0.0",
|
||||||
"chownr": "^3.0.0",
|
"chownr": "^3.0.0",
|
||||||
"minipass": "^7.1.0",
|
"minipass": "^7.1.2",
|
||||||
"minizlib": "^3.0.1",
|
"minizlib": "^3.0.1",
|
||||||
"mkdirp": "^3.0.1",
|
"mkdirp": "^3.0.1",
|
||||||
"yallist": "^5.0.0"
|
"yallist": "^5.0.0"
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
"nanoid": "5.0.7",
|
"nanoid": "5.0.7",
|
||||||
"nanoid-dictionary": "5.0.0-beta.1",
|
"nanoid-dictionary": "5.0.0-beta.1",
|
||||||
"slugify": "1.6.6",
|
"slugify": "1.6.6",
|
||||||
"tar": "^7.1.0",
|
"tar": "^7.4.0",
|
||||||
"yargs": "^17.7.2"
|
"yargs": "^17.7.2"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
|
|
30
dev/diff/package-lock.json
generated
30
dev/diff/package-lock.json
generated
|
@ -17,7 +17,7 @@
|
||||||
"lodash-es": "^4.17.21",
|
"lodash-es": "^4.17.21",
|
||||||
"luxon": "^3.4.4",
|
"luxon": "^3.4.4",
|
||||||
"pretty-bytes": "^6.1.1",
|
"pretty-bytes": "^6.1.1",
|
||||||
"tar": "^7.1.0",
|
"tar": "^7.4.0",
|
||||||
"yargs": "^17.7.2"
|
"yargs": "^17.7.2"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
|
@ -1101,9 +1101,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/minipass": {
|
"node_modules/minipass": {
|
||||||
"version": "7.1.0",
|
"version": "7.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz",
|
||||||
"integrity": "sha512-oGZRv2OT1lO2UF1zUcwdTb3wqUwI0kBGTgt/T7OdSj6M6N5m3o5uPf0AIW6lVxGGoiWUR7e2AwTE+xiwK8WQig==",
|
"integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=16 || 14 >=14.17"
|
"node": ">=16 || 14 >=14.17"
|
||||||
}
|
}
|
||||||
|
@ -1493,13 +1493,13 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/tar": {
|
"node_modules/tar": {
|
||||||
"version": "7.1.0",
|
"version": "7.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/tar/-/tar-7.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/tar/-/tar-7.4.0.tgz",
|
||||||
"integrity": "sha512-ENhg4W6BmjYxl8GTaE7/h99f0aXiSWv4kikRZ9n2/JRxypZniE84ILZqimAhxxX7Zb8Px6pFdheW3EeHfhnXQQ==",
|
"integrity": "sha512-XQs0S8fuAkQWuqhDeCdMlJXDX80D7EOVLDPVFkna9yQfzS+PHKgfxcei0jf6/+QAWcjqrnC8uM3fSAnrQl+XYg==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@isaacs/fs-minipass": "^4.0.0",
|
"@isaacs/fs-minipass": "^4.0.0",
|
||||||
"chownr": "^3.0.0",
|
"chownr": "^3.0.0",
|
||||||
"minipass": "^7.1.0",
|
"minipass": "^7.1.2",
|
||||||
"minizlib": "^3.0.1",
|
"minizlib": "^3.0.1",
|
||||||
"mkdirp": "^3.0.1",
|
"mkdirp": "^3.0.1",
|
||||||
"yallist": "^5.0.0"
|
"yallist": "^5.0.0"
|
||||||
|
@ -2433,9 +2433,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"minipass": {
|
"minipass": {
|
||||||
"version": "7.1.0",
|
"version": "7.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz",
|
||||||
"integrity": "sha512-oGZRv2OT1lO2UF1zUcwdTb3wqUwI0kBGTgt/T7OdSj6M6N5m3o5uPf0AIW6lVxGGoiWUR7e2AwTE+xiwK8WQig=="
|
"integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw=="
|
||||||
},
|
},
|
||||||
"minizlib": {
|
"minizlib": {
|
||||||
"version": "3.0.1",
|
"version": "3.0.1",
|
||||||
|
@ -2691,13 +2691,13 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"tar": {
|
"tar": {
|
||||||
"version": "7.1.0",
|
"version": "7.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/tar/-/tar-7.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/tar/-/tar-7.4.0.tgz",
|
||||||
"integrity": "sha512-ENhg4W6BmjYxl8GTaE7/h99f0aXiSWv4kikRZ9n2/JRxypZniE84ILZqimAhxxX7Zb8Px6pFdheW3EeHfhnXQQ==",
|
"integrity": "sha512-XQs0S8fuAkQWuqhDeCdMlJXDX80D7EOVLDPVFkna9yQfzS+PHKgfxcei0jf6/+QAWcjqrnC8uM3fSAnrQl+XYg==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@isaacs/fs-minipass": "^4.0.0",
|
"@isaacs/fs-minipass": "^4.0.0",
|
||||||
"chownr": "^3.0.0",
|
"chownr": "^3.0.0",
|
||||||
"minipass": "^7.1.0",
|
"minipass": "^7.1.2",
|
||||||
"minizlib": "^3.0.1",
|
"minizlib": "^3.0.1",
|
||||||
"mkdirp": "^3.0.1",
|
"mkdirp": "^3.0.1",
|
||||||
"yallist": "^5.0.0"
|
"yallist": "^5.0.0"
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
"lodash-es": "^4.17.21",
|
"lodash-es": "^4.17.21",
|
||||||
"luxon": "^3.4.4",
|
"luxon": "^3.4.4",
|
||||||
"pretty-bytes": "^6.1.1",
|
"pretty-bytes": "^6.1.1",
|
||||||
"tar": "^7.1.0",
|
"tar": "^7.4.0",
|
||||||
"yargs": "^17.7.2"
|
"yargs": "^17.7.2"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
|
|
|
@ -19,6 +19,7 @@ from zoneinfo import ZoneInfo
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
|
from django.db.models import OuterRef
|
||||||
from django.forms import ValidationError
|
from django.forms import ValidationError
|
||||||
from django.http import Http404
|
from django.http import Http404
|
||||||
from django.template.loader import render_to_string
|
from django.template.loader import render_to_string
|
||||||
|
@ -39,7 +40,7 @@ from ietf.doc.models import TelechatDocEvent, DocumentActionHolder, EditedAuthor
|
||||||
from ietf.name.models import DocReminderTypeName, DocRelationshipName
|
from ietf.name.models import DocReminderTypeName, DocRelationshipName
|
||||||
from ietf.group.models import Role, Group, GroupFeatures
|
from ietf.group.models import Role, Group, GroupFeatures
|
||||||
from ietf.ietfauth.utils import has_role, is_authorized_in_doc_stream, is_individual_draft_author, is_bofreq_editor
|
from ietf.ietfauth.utils import has_role, is_authorized_in_doc_stream, is_individual_draft_author, is_bofreq_editor
|
||||||
from ietf.person.models import Person
|
from ietf.person.models import Email, Person
|
||||||
from ietf.review.models import ReviewWish
|
from ietf.review.models import ReviewWish
|
||||||
from ietf.utils import draft, log
|
from ietf.utils import draft, log
|
||||||
from ietf.utils.mail import parseaddr, send_mail
|
from ietf.utils.mail import parseaddr, send_mail
|
||||||
|
@ -1301,9 +1302,13 @@ class DraftAliasGenerator:
|
||||||
def get_draft_authors_emails(self, doc):
|
def get_draft_authors_emails(self, doc):
|
||||||
"""Get list of authors for the given draft."""
|
"""Get list of authors for the given draft."""
|
||||||
author_emails = set()
|
author_emails = set()
|
||||||
for author in doc.documentauthor_set.all():
|
for email in Email.objects.filter(documentauthor__document=doc):
|
||||||
if author.email and author.email.email_address():
|
if email.active:
|
||||||
author_emails.add(author.email.email_address())
|
author_emails.add(email.address)
|
||||||
|
elif email.person:
|
||||||
|
person_email = email.person.email_address()
|
||||||
|
if person_email:
|
||||||
|
author_emails.add(person_email)
|
||||||
return author_emails
|
return author_emails
|
||||||
|
|
||||||
def get_draft_notify_emails(self, doc):
|
def get_draft_notify_emails(self, doc):
|
||||||
|
@ -1336,59 +1341,82 @@ class DraftAliasGenerator:
|
||||||
notify_emails.add(email)
|
notify_emails.add(email)
|
||||||
return notify_emails
|
return notify_emails
|
||||||
|
|
||||||
|
def _yield_aliases_for_draft(self, doc)-> Iterator[tuple[str, list[str]]]:
|
||||||
|
alias = doc.name
|
||||||
|
all = set()
|
||||||
|
|
||||||
|
# no suffix and .authors are the same list
|
||||||
|
emails = self.get_draft_authors_emails(doc)
|
||||||
|
all.update(emails)
|
||||||
|
if emails:
|
||||||
|
yield alias, list(emails)
|
||||||
|
yield alias + ".authors", list(emails)
|
||||||
|
|
||||||
|
# .chairs = group chairs
|
||||||
|
emails = self.get_draft_chair_emails(doc)
|
||||||
|
if emails:
|
||||||
|
all.update(emails)
|
||||||
|
yield alias + ".chairs", list(emails)
|
||||||
|
|
||||||
|
# .ad = sponsoring AD / WG AD (WG document)
|
||||||
|
emails = self.get_draft_ad_emails(doc)
|
||||||
|
if emails:
|
||||||
|
all.update(emails)
|
||||||
|
yield alias + ".ad", list(emails)
|
||||||
|
|
||||||
|
# .notify = notify email list from the Document
|
||||||
|
emails = self.get_draft_notify_emails(doc)
|
||||||
|
if emails:
|
||||||
|
all.update(emails)
|
||||||
|
yield alias + ".notify", list(emails)
|
||||||
|
|
||||||
|
# .shepherd = shepherd email from the Document
|
||||||
|
emails = self.get_draft_shepherd_email(doc)
|
||||||
|
if emails:
|
||||||
|
all.update(emails)
|
||||||
|
yield alias + ".shepherd", list(emails)
|
||||||
|
|
||||||
|
# .all = everything from above
|
||||||
|
if all:
|
||||||
|
yield alias + ".all", list(all)
|
||||||
|
|
||||||
def __iter__(self) -> Iterator[tuple[str, list[str]]]:
|
def __iter__(self) -> Iterator[tuple[str, list[str]]]:
|
||||||
# Internet-Drafts with active status or expired within self.days
|
# Internet-Drafts with active status or expired within self.days
|
||||||
show_since = timezone.now() - datetime.timedelta(days=self.days)
|
show_since = timezone.now() - datetime.timedelta(days=self.days)
|
||||||
drafts = self.draft_queryset
|
drafts = self.draft_queryset
|
||||||
active_drafts = drafts.filter(states__slug='active')
|
|
||||||
inactive_recent_drafts = drafts.exclude(states__slug='active').filter(expires__gte=show_since)
|
|
||||||
interesting_drafts = active_drafts | inactive_recent_drafts
|
|
||||||
|
|
||||||
for this_draft in interesting_drafts.distinct().iterator():
|
# Look up the draft-active state properly. Doing this with
|
||||||
|
# states__type_id, states__slug directly in the `filter()`
|
||||||
|
# works, but it does not work as expected in `exclude()`.
|
||||||
|
active_state = State.objects.get(type_id="draft", slug="active")
|
||||||
|
active_drafts = drafts.filter(states=active_state)
|
||||||
|
for this_draft in active_drafts:
|
||||||
|
for alias, addresses in self._yield_aliases_for_draft(this_draft):
|
||||||
|
yield alias, addresses
|
||||||
|
|
||||||
|
# Annotate with the draft state slug so we can check for drafts that
|
||||||
|
# have become RFCs
|
||||||
|
inactive_recent_drafts = (
|
||||||
|
drafts.exclude(states=active_state)
|
||||||
|
.filter(expires__gte=show_since)
|
||||||
|
.annotate(
|
||||||
|
# Why _default_manager instead of objects? See:
|
||||||
|
# https://docs.djangoproject.com/en/4.2/topics/db/managers/#django.db.models.Model._default_manager
|
||||||
|
draft_state_slug=Document.states.through._default_manager.filter(
|
||||||
|
document__pk=OuterRef("pk"),
|
||||||
|
state__type_id="draft"
|
||||||
|
).values("state__slug"),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
for this_draft in inactive_recent_drafts:
|
||||||
# Omit drafts that became RFCs, unless they were published in the last DEFAULT_YEARS
|
# Omit drafts that became RFCs, unless they were published in the last DEFAULT_YEARS
|
||||||
if this_draft.get_state_slug() == "rfc":
|
if this_draft.draft_state_slug == "rfc":
|
||||||
rfc = this_draft.became_rfc()
|
rfc = this_draft.became_rfc()
|
||||||
log.assertion("rfc is not None")
|
log.assertion("rfc is not None")
|
||||||
if rfc.latest_event(type='published_rfc').time < show_since:
|
if rfc.latest_event(type='published_rfc').time < show_since:
|
||||||
continue
|
continue
|
||||||
|
for alias, addresses in self._yield_aliases_for_draft(this_draft):
|
||||||
alias = this_draft.name
|
yield alias, addresses
|
||||||
all = set()
|
|
||||||
|
|
||||||
# no suffix and .authors are the same list
|
|
||||||
emails = self.get_draft_authors_emails(this_draft)
|
|
||||||
all.update(emails)
|
|
||||||
if emails:
|
|
||||||
yield alias, list(emails)
|
|
||||||
yield alias + ".authors", list(emails)
|
|
||||||
|
|
||||||
# .chairs = group chairs
|
|
||||||
emails = self.get_draft_chair_emails(this_draft)
|
|
||||||
if emails:
|
|
||||||
all.update(emails)
|
|
||||||
yield alias + ".chairs", list(emails)
|
|
||||||
|
|
||||||
# .ad = sponsoring AD / WG AD (WG document)
|
|
||||||
emails = self.get_draft_ad_emails(this_draft)
|
|
||||||
if emails:
|
|
||||||
all.update(emails)
|
|
||||||
yield alias + ".ad", list(emails)
|
|
||||||
|
|
||||||
# .notify = notify email list from the Document
|
|
||||||
emails = self.get_draft_notify_emails(this_draft)
|
|
||||||
if emails:
|
|
||||||
all.update(emails)
|
|
||||||
yield alias + ".notify", list(emails)
|
|
||||||
|
|
||||||
# .shepherd = shepherd email from the Document
|
|
||||||
emails = self.get_draft_shepherd_email(this_draft)
|
|
||||||
if emails:
|
|
||||||
all.update(emails)
|
|
||||||
yield alias + ".shepherd", list(emails)
|
|
||||||
|
|
||||||
# .all = everything from above
|
|
||||||
if all:
|
|
||||||
yield alias + ".all", list(all)
|
|
||||||
|
|
||||||
|
|
||||||
def get_doc_email_aliases(name: Optional[str] = None):
|
def get_doc_email_aliases(name: Optional[str] = None):
|
||||||
|
|
|
@ -1,15 +1,9 @@
|
||||||
--- django_cprofile_middleware/middleware.py.old 2018-04-04 06:32:29.282187502 -0700
|
--- django_cprofile_middleware/middleware.py.old 2024-06-27 21:03:56.975128007 +0000
|
||||||
+++ django_cprofile_middleware/middleware.py 2018-04-06 10:11:18.936855634 -0700
|
+++ django_cprofile_middleware/middleware.py 2024-06-27 23:45:59.421683008 +0000
|
||||||
@@ -1,4 +1,5 @@
|
@@ -19,6 +19,16 @@
|
||||||
import pstats
|
from django_cprofile_middleware.utils import MiddlewareMixin
|
||||||
+import re
|
|
||||||
|
|
||||||
try:
|
|
||||||
import cProfile as profile
|
|
||||||
@@ -14,6 +15,15 @@
|
|
||||||
from django.utils.deprecation import MiddlewareMixin
|
|
||||||
|
|
||||||
|
|
||||||
+class Stats(pstats.Stats):
|
+class Stats(pstats.Stats):
|
||||||
+ def filter_stats(self, regex):
|
+ def filter_stats(self, regex):
|
||||||
+ oldstats = self.stats
|
+ oldstats = self.stats
|
||||||
|
@ -18,17 +12,64 @@
|
||||||
+ for func, (cc, nc, tt, ct, callers) in oldstats.iteritems():
|
+ for func, (cc, nc, tt, ct, callers) in oldstats.iteritems():
|
||||||
+ if filter.search(pstats.func_std_string(func)):
|
+ if filter.search(pstats.func_std_string(func)):
|
||||||
+ newstats[func] = (cc, nc, tt, ct, callers)
|
+ newstats[func] = (cc, nc, tt, ct, callers)
|
||||||
|
+
|
||||||
+
|
+
|
||||||
class ProfilerMiddleware(MiddlewareMixin):
|
class ProfilerMiddleware(MiddlewareMixin):
|
||||||
"""
|
"""
|
||||||
Simple profile middleware to profile django views. To run it, add ?prof to
|
Simple profile middleware to profile django views. To run it, add ?prof to
|
||||||
@@ -62,8 +72,13 @@
|
@@ -38,9 +48,11 @@
|
||||||
|
?download => Download profile file suitable for visualization. For example
|
||||||
|
in snakeviz or RunSnakeRun
|
||||||
|
|
||||||
|
- This is adapted from an example found here:
|
||||||
|
- http://www.slideshare.net/zeeg/django-con-high-performance-django-presentation.
|
||||||
|
+ Patched with https://github.com/omarish/django-cprofile-middleware/pull/23
|
||||||
|
+ for operation with Django 4.2.5+
|
||||||
|
"""
|
||||||
|
+ PROFILER_REQUEST_ATTR_NAME = '_django_cprofile_middleware_profiler'
|
||||||
|
+
|
||||||
|
def can(self, request):
|
||||||
|
requires_staff = getattr(
|
||||||
|
settings, "DJANGO_CPROFILE_MIDDLEWARE_REQUIRE_STAFF", True)
|
||||||
|
@@ -52,10 +64,11 @@
|
||||||
|
|
||||||
|
def process_view(self, request, callback, callback_args, callback_kwargs):
|
||||||
|
if self.can(request):
|
||||||
|
- self.profiler = profile.Profile()
|
||||||
|
+ profiler = profile.Profile()
|
||||||
|
+ setattr(request, self.PROFILER_REQUEST_ATTR_NAME, profiler)
|
||||||
|
args = (request,) + callback_args
|
||||||
|
try:
|
||||||
|
- return self.profiler.runcall(
|
||||||
|
+ return profiler.runcall(
|
||||||
|
callback, *args, **callback_kwargs)
|
||||||
|
except Exception:
|
||||||
|
# we want the process_exception middleware to fire
|
||||||
|
@@ -63,12 +76,13 @@
|
||||||
|
return
|
||||||
|
|
||||||
|
def process_response(self, request, response):
|
||||||
|
- if self.can(request):
|
||||||
|
- self.profiler.create_stats()
|
||||||
|
+ if hasattr(request, self.PROFILER_REQUEST_ATTR_NAME):
|
||||||
|
+ profiler = getattr(request, self.PROFILER_REQUEST_ATTR_NAME)
|
||||||
|
+ profiler.create_stats()
|
||||||
|
if 'download' in request.GET:
|
||||||
|
import marshal
|
||||||
|
|
||||||
|
- output = marshal.dumps(self.profiler.stats)
|
||||||
|
+ output = marshal.dumps(profiler.stats)
|
||||||
|
response = HttpResponse(
|
||||||
|
output, content_type='application/octet-stream')
|
||||||
|
response['Content-Disposition'] = 'attachment;' \
|
||||||
|
@@ -76,9 +90,14 @@
|
||||||
response['Content-Length'] = len(output)
|
response['Content-Length'] = len(output)
|
||||||
else:
|
else:
|
||||||
io = StringIO()
|
io = StringIO()
|
||||||
- stats = pstats.Stats(self.profiler, stream=io)
|
- stats = pstats.Stats(self.profiler, stream=io)
|
||||||
|
+ stats = Stats(profiler, stream=io)
|
||||||
|
|
||||||
- stats.strip_dirs().sort_stats(request.GET.get('sort', 'time'))
|
- stats.strip_dirs().sort_stats(request.GET.get('sort', 'time'))
|
||||||
+ stats = Stats(self.profiler, stream=io)
|
|
||||||
+ if request.GET.get('stripdirs', False):
|
+ if request.GET.get('stripdirs', False):
|
||||||
+ stats = stats.strip_dirs()
|
+ stats = stats.strip_dirs()
|
||||||
+ filter = request.GET.get('filter', None)
|
+ filter = request.GET.get('filter', None)
|
||||||
|
@ -36,5 +77,5 @@
|
||||||
+ stats.filter_stats(filter)
|
+ stats.filter_stats(filter)
|
||||||
+ stats.sort_stats(request.GET.get('psort') or 'time')
|
+ stats.sort_stats(request.GET.get('psort') or 'time')
|
||||||
stats.print_stats(int(request.GET.get('count', 100)))
|
stats.print_stats(int(request.GET.get('count', 100)))
|
||||||
|
|
||||||
response = HttpResponse('<pre>%s</pre>' % io.getvalue())
|
response = HttpResponse('<pre>%s</pre>' % io.getvalue())
|
||||||
return response
|
|
||||||
|
|
Loading…
Reference in a new issue