Skip to content

Commit 113dacd

Browse files
authored
Introduce logo placement API endpoint (#1849)
* Add csv file with pypi sponsors data * Create endpoint to list logo placements from Pypi * Move sponsor placement url definition to urls_api file * Add pypi sponsors csv filename to settings * Remove old script to list sponsors as a CSV file * Add minimal unit test just to make sure CI will trigger errors if we somehow delete the CSV file * Update pypi-sponsors csv * Enable authentication * Add missing migration from contract updates * Create custom permission to access sponsors API * Set up permission for the new endpoint
1 parent b19497d commit 113dacd

File tree

10 files changed

+215
-94
lines changed

10 files changed

+215
-94
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,4 @@ static/stylesheets/style.css
1818
__pycache__
1919
*.db
2020
.vscode
21+
.~lock.*

data/pypi-sponsors.csv

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
name,service,activity_markdown,link_url,color_logo_url,white_logo_url,is_active,footer,psf_sponsor,infra_sponsor,one_time,sidebar
2+
Adafruit,,Adafruit is a participating sponsor of the Python Software Foundation.,https://www.adafruit.com/circuitpython,https://storage.googleapis.com/pypi-assets/sponsorlogos/adafruit-color-logo-JDBhK7TA.png,,t,f,t,f,f,f
3+
Adimian.be SPRL,,Adimian.be SPRL is a participating sponsor of the Python Software Foundation.,https://www.adimian.com/,https://storage.googleapis.com/pypi-assets/sponsorlogos/adimian-be-sprl-color-logo-OZy1Thzt.png,,t,f,t,f,f,f
4+
Caktus Group,,Caktus Group is a partner sponsor of the Python Software Foundation.,https://www.caktusgroup.com/?utm_source=psf&utm_medium=sponsor&utm_campaign=caktus,https://storage.googleapis.com/pypi-assets/sponsorlogos/caktus-group-color-logo-wBrCQdjF.png,,t,f,t,f,f,f
5+
Capital One,,Capital One is a maintaining sponsor of the Python Software Foundation.,https://www.capitalone.com/tech/,https://storage.googleapis.com/pypi-assets/sponsorlogos/capital-one-color-logo-MzyYZC_Z.png,,t,f,t,f,f,t
6+
CircleCI,,CircleCI is a supporting sponsor of the Python Software Foundation.,http://www.circleci.com,https://storage.googleapis.com/pypi-assets/sponsorlogos/circleci-color-logo-SCDBNtqT.png,,t,f,t,f,f,f
7+
DigiCert,EV certificate,PyPI uses Digicert to secure communication and prove identity with an EV Certificate.,https://www.digicert.com/,https://storage.googleapis.com/pypi-assets/sponsorlogos/digicert-color-logo-Cc5zUp0p.png,https://storage.googleapis.com/pypi-assets/sponsorlogos/digicert-white-logo-bRtE4d-C.png,t,f,f,t,f,f
8+
Cockroach Labs,,Cockroach Labs is a contributing sponsor of the Python Software Foundation.,http://www.cockroachlabs.com/,https://storage.googleapis.com/pypi-assets/sponsorlogos/cockroach-labs-color-logo-OzhCaslQ.png,https://storage.googleapis.com/pypi-assets/sponsorlogos/cockroach-labs-white-logo-JC6h9e_O.png,t,f,t,f,f,t
9+
Chan Zuckerberg Initiative,,Chan Zuckerberg Initiative is a supporting sponsor of the Python Software Foundation.,https://chanzuckerberg.com/,https://storage.googleapis.com/pypi-assets/sponsorlogos/chan-zuckerberg-initiative-color-logo-smpclr1C.png,,t,f,t,f,f,f
10+
Huawei,,Huawei is a sustainability sponsor of the Python Software Foundation.,https://www.huawei.com/,https://storage.googleapis.com/pypi-assets/sponsorlogos/huawei-color-logo-Rznq6ItM.png,,t,f,t,f,f,t
11+
Blackfire.io,,Blackfire.io is a supporting sponsor of the Python Software Foundation.,https://www.blackfire.io/python,https://storage.googleapis.com/pypi-assets/sponsorlogos/blackfire-io-color-logo-kCOJwn_Y.png,,t,f,t,f,f,f
12+
Bloomberg,,Bloomberg is a visionary sponsor of the Python Software Foundation.,https://www.techatbloomberg.com/,https://pypi.org/static/images/sponsors/color/bloomberg.png,https://storage.googleapis.com/pypi-assets/sponsorlogos/bloomberg-white-logo-9j_a1jaq.png,t,f,t,f,f,t
13+
Corning,,Corning is a maintaining sponsor of the Python Software Foundation.,https://www.corning.com/,https://storage.googleapis.com/pypi-assets/sponsorlogos/corning-color-logo-S5olmipc.png,https://storage.googleapis.com/pypi-assets/sponsorlogos/corning-white-logo-_43wG1P7.png,t,f,t,f,f,t
14+
Cuttlesoft,,Cuttlesoft is a partner sponsor of the Python Software Foundation.,https://cuttlesoft.com,https://storage.googleapis.com/pypi-assets/sponsorlogos/cuttlesoft-color-logo-sVxxYttP.png,,t,f,t,f,f,f
15+
JetBrains,,JetBrains is a supporting sponsor of the Python Software Foundation.,https://www.jetbrains.com/pycharm,https://storage.googleapis.com/pypi-assets/sponsorlogos/jetbrains-color-logo-18v8Sij0.png,,t,f,t,f,f,f
16+
LinkedIn,,LinkedIn is a supporting sponsor of the Python Software Foundation.,https://www.linkedin.com,https://storage.googleapis.com/pypi-assets/sponsorlogos/linkedin-color-logo-C995BzFp.png,,t,f,t,f,f,f
17+
Mattermost,,Mattermost is a partner sponsor of the Python Software Foundation.,http://mattermost.com,https://storage.googleapis.com/pypi-assets/sponsorlogos/mattermost-color-logo-bpBHSexQ.png,,t,f,t,f,f,f
18+
Pingdom,Monitoring,PyPI's infrastructure volunteers use Pingdom to monitor and receive alerts about downtime and other issues affecting end-users.,https://www.pingdom.com/,https://storage.googleapis.com/pypi-assets/sponsorlogos/pingdom-color-logo-x-ZQCojg.png,https://storage.googleapis.com/pypi-assets/sponsorlogos/pingdom-white-logo-g5X1TuF6.png,t,f,f,t,f,f
19+
Mozilla,,"In late 2017 the Python Software Foundation was awarded a Mozilla Open Source Support (MOSS) award.
20+
21+
This award was used to move PyPI from its legacy codebase and deploy Warehouse - the new codebase powering PyPI.",https://www.mozilla.org,https://storage.googleapis.com/pypi-assets/sponsorlogos/mozilla-color-logo-aMh4U34w.png,,t,f,f,f,t,f
22+
Netflix,,Netflix is a partner sponsor of the Python Software Foundation.,https://about.netflix.com/,https://storage.googleapis.com/pypi-assets/sponsorlogos/netflix-color-logo-U9HJMS8W.png,,t,f,t,f,f,f
23+
OpenEDG Python Institute,,OpenEDG Python Institute is a supporting sponsor of the Python Software Foundation.,https://pythoninstitute.org/,https://storage.googleapis.com/pypi-assets/sponsorlogos/openedg-python-institute-color-logo-atIwUwdK.png,,t,f,t,f,f,f
24+
Open Technology Fund,,"In 2019 the Python Software Foundation was awarded a contract through the OTF Core Infrastructure Fund.
25+
26+
This contract included an audit and improvements to the accessibility of PyPI, internationalization and translations for PyPI user interface, and security features including two-factor authentication and API tokens for uploads.",https://www.opentech.fund,https://storage.googleapis.com/pypi-assets/sponsorlogos/open-technology-fund-color-logo-tPC8eg1y.png,,t,f,f,f,t,f
27+
Python Academy,,Python Academy is a participating sponsor of the Python Software Foundation.,https://www.python-academy.com/,https://storage.googleapis.com/pypi-assets/sponsorlogos/python-academy-color-logo-IPvBKy_1.png,,t,f,t,f,f,f
28+
Real Python,,Real Python is a participating sponsor of the Python Software Foundation.,https://realpython.com/,https://storage.googleapis.com/pypi-assets/sponsorlogos/real-python-color-logo-sWrk1UZ0.png,,t,f,t,f,f,f
29+
Red Hat,,Red Hat is a contributing sponsor of the Python Software Foundation.,https://www.redhat.com/en,https://storage.googleapis.com/pypi-assets/sponsorlogos/red-hat-color-logo-Fc_zk0Xg.png,,t,f,t,f,f,t
30+
Reuven Lerner — Python training,,Reuven Lerner is a partner sponsor of the Python Software Foundation.,https://lerner.co.il,https://storage.googleapis.com/pypi-assets/sponsorlogos/reuven-lerner-python-training-color-logo-0SzFOaeI.png,,t,f,t,f,f,f
31+
Saleor,,Saleor is a partner sponsor of the Python Software Foundation.,http://saleor.io/,https://storage.googleapis.com/pypi-assets/sponsorlogos/saleor-color-logo-HI5-JKT-.png,,t,f,t,f,f,f
32+
Scout APM,,Scout APM is a partner sponsor of the Python Software Foundation.,https://ter.li/jjv5k0,https://storage.googleapis.com/pypi-assets/sponsorlogos/scout-apm-color-logo-5Wy-dfVC.png,,t,f,t,f,f,f
33+
Slack,,Slack is a maintaining sponsor of the Python Software Foundation.,https://slack.com,https://storage.googleapis.com/pypi-assets/sponsorlogos/slack-color-logo-K8koyFLJ.png,,t,f,t,f,f,t
34+
Datadog,Monitoring,"PyPI uses Datadog to collect metrics from the applications, services, and infrastructure behind the scenes allowing for the team to measure the impact of new changes, monitor for problems, and alert when systems fail.",https://www.datadoghq.com/,https://storage.googleapis.com/pypi-assets/sponsorlogos/datadog-color-logo-qaecwJgr.png,https://storage.googleapis.com/pypi-assets/sponsorlogos/datadog-white-logo-fhdLNflo.png,t,f,f,t,f,f
35+
Facebook / Instagram,,Facebook / Instagram is a sustainability sponsor of the Python Software Foundation.,https://research.fb.com/,https://storage.googleapis.com/pypi-assets/sponsorlogos/facebook-instagram-color-logo-znA-4MDT.png,https://storage.googleapis.com/pypi-assets/sponsorlogos/facebook-instagram-white-logo-gPhjWdzr.png,t,t,t,f,f,t
36+
Latacora,,Latacora is a contributing sponsor of the Python Software Foundation.,https://www.latacora.com,https://storage.googleapis.com/pypi-assets/sponsorlogos/latacora-color-logo-r5iAsqf0.png,https://storage.googleapis.com/pypi-assets/sponsorlogos/latacora-white-logo-2bsVuZpq.png,t,f,t,f,f,t
37+
Google,Object Storage and Download Analytics,Google is a visionary sponsor of the Python Software Foundation.,https://careers.google.com/,https://storage.googleapis.com/pypi-assets/sponsorlogos/google-color-logo-2uT7IlTp.png,https://storage.googleapis.com/pypi-assets/sponsorlogos/google-white-logo-ag4BN7t3.png,t,t,t,t,f,t
38+
Salesforce,,Salesforce is a sustainability sponsor of the Python Software Foundation.,https://opensource.salesforce.com/,https://storage.googleapis.com/pypi-assets/sponsorlogos/salesforce-color-logo-jFaM31BY.png,https://storage.googleapis.com/pypi-assets/sponsorlogos/salesforce-white-logo-E9gz0Sx-.png,t,t,t,f,f,t
39+
Sentry,Error logging,"The PyPI team uses Sentry to capture, record, and respond to exceptions and errors on PyPI.",https://getsentry.com/for/python,https://storage.googleapis.com/pypi-assets/sponsorlogos/sentry-color-logo-4n0jeHxP.png,https://storage.googleapis.com/pypi-assets/sponsorlogos/sentry-white-logo-1Uh6uL2E.png,t,f,f,t,f,f
40+
"Elasticsearch, Inc.",,"Elasticsearch, Inc. is a partner sponsor of the Python Software Foundation.",https://www.elastic.co/,https://storage.googleapis.com/pypi-assets/sponsorlogos/elasticsearch-inc-color-logo-Tb33ewTv.svg,https://storage.googleapis.com/pypi-assets/sponsorlogos/elasticsearch-inc-white-logo-CzLcfxB9.png,t,f,t,f,f,f
41+
SonarSource,,SonarSource is a partner sponsor of the Python Software Foundation.,https://www.sonarsource.com/,https://storage.googleapis.com/pypi-assets/sponsorlogos/sonarsource-color-logo-BqjKyRZG.png,,t,f,t,f,f,f
42+
Tara AI,,Tara AI is a partner sponsor of the Python Software Foundation.,http://tara.ai/?utm_source=PyCon&utm_medium=Sponsorship&utm_campaign=PyCon%202021,https://storage.googleapis.com/pypi-assets/sponsorlogos/tara-ai-color-logo-xvtgzWa9.png,,t,f,t,f,f,f
43+
Tidelift,,Tidelift is a partner sponsor of the Python Software Foundation.,https://tidelift.com/,https://storage.googleapis.com/pypi-assets/sponsorlogos/tidelift-color-logo-gdZjLrcT.png,,t,f,t,f,f,f
44+
AWS,Cloud computing,"PyPI uses AWS infrastructure to host the machines that power our services, serve DNS, host our databases, and send and monitor email.",https://aws.amazon.com/,https://storage.googleapis.com/pypi-assets/sponsorlogos/aws-color-logo-AloCRR0a.png,https://storage.googleapis.com/pypi-assets/sponsorlogos/aws-white-logo-tCaTs8zC.png,t,f,f,t,f,f
45+
Fastly,CDN,"PyPI uses Fastly's CDN to quickly serve content to end-users, allowing us to minimize our hosting infrastructure and obscure possible downtime.",https://www.fastly.com/,https://storage.googleapis.com/pypi-assets/sponsorlogos/fastly-color-logo-vlmBL3eL.png,https://storage.googleapis.com/pypi-assets/sponsorlogos/fastly-white-logo-ehM0ws_o.png,t,f,f,t,f,f
46+
Microsoft,,Microsoft is a visionary sponsor of the Python Software Foundation.,https://azure.microsoft.com/en-us/develop/python/,https://storage.googleapis.com/pypi-assets/sponsorlogos/microsoft-color-logo-qdS6FbR3.png,https://storage.googleapis.com/pypi-assets/sponsorlogos/microsoft-white-logo-ZD1rhTDF.png,t,t,t,f,f,t
47+
StatusPage,Status page,"The PyPI team uses StatusPage to communicate downtime, service degradation, or maintenance windows to end-users.",https://statuspage.io,https://storage.googleapis.com/pypi-assets/sponsorlogos/statuspage-color-logo-B22Cktnk.png,https://storage.googleapis.com/pypi-assets/sponsorlogos/statuspage-white-logo-TgGljJ-P.png,t,f,f,t,f,f

pydotorg/settings/base.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,7 @@
261261
SPONSORSHIP_NOTIFICATION_TO_EMAIL = os.environ.get(
262262
"SPONSORSHIP_NOTIFICATION_TO_EMAIL", "[email protected]"
263263
)
264+
PYPI_SPONSORS_CSV = os.path.join(BASE, "data", "pypi-sponsors.csv")
264265

265266
# Mail
266267
DEFAULT_FROM_EMAIL = '[email protected]'

pydotorg/urls.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,7 @@
88
from cms.views import custom_404
99
from users.views import HoneypotSignupView, CustomPasswordChangeView
1010

11-
from . import views
12-
from .urls_api import v1_api, router
11+
from . import views, urls_api
1312

1413
handler404 = custom_404
1514

@@ -71,8 +70,9 @@
7170
url(r'^admin/', admin.site.urls),
7271

7372
# api
74-
url(r'^api/', include(v1_api.urls)),
75-
url(r'^api/v2/', include(router.urls)),
73+
url(r'^api/', include(urls_api.v1_api.urls)),
74+
url(r'^api/v2/', include(urls_api.router.urls)),
75+
url(r'^api/v2/', include(urls_api)),
7676

7777
# storage migration
7878
url(r'^m/(?P<url>.*)/$', views.MediaMigrationView.as_view(prefix='media'), name='media_migration_view'),

pydotorg/urls_api.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
1-
from rest_framework import routers
1+
from django.conf.urls import url
22

3+
from rest_framework import routers
34
from tastypie.api import Api
45

56
from downloads.api import OSResource, ReleaseResource, ReleaseFileResource
67
from downloads.api import OSViewSet, ReleaseViewSet, ReleaseFileViewSet
78
from pages.api import PageResource
89
from pages.api import PageViewSet
10+
from sponsors.api import LogoPlacementeAPIList
911

1012
v1_api = Api(api_name='v1')
1113
v1_api.register(PageResource())
@@ -18,3 +20,7 @@
1820
router.register(r'downloads/os', OSViewSet)
1921
router.register(r'downloads/release', ReleaseViewSet, base_name='release')
2022
router.register(r'downloads/release_file', ReleaseFileViewSet)
23+
24+
urlpatterns = [
25+
url(r'sponsors/logo-placement/', LogoPlacementeAPIList.as_view(), name="logo_placement_list"),
26+
]

sponsors/api.py

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
import csv
2+
3+
from django.conf import settings
4+
5+
from rest_framework import permissions
6+
from rest_framework import serializers
7+
from rest_framework.authentication import TokenAuthentication
8+
from rest_framework.views import APIView
9+
from rest_framework.response import Response
10+
from sponsors.enums import LogoPlacementChoices, PublisherChoices
11+
12+
13+
class LogoPlacementSerializer(serializers.Serializer):
14+
publisher = serializers.CharField()
15+
flight = serializers.CharField()
16+
sponsor = serializers.CharField()
17+
description = serializers.CharField()
18+
logo = serializers.URLField()
19+
start_date = serializers.DateField()
20+
end_date = serializers.DateField()
21+
sponsor_url = serializers.URLField()
22+
23+
24+
25+
class SponsorPublisherPermission(permissions.BasePermission):
26+
message = 'Must have publisher permission.'
27+
28+
def has_permission(self, request, view):
29+
user = request.user
30+
if request.user.is_superuser or request.user.is_staff:
31+
return True
32+
return user.has_perm("sponsors.sponsor_publisher")
33+
34+
35+
# TODO Currently this endpoint only lists sponsors from pypi sponsors CSV.
36+
# Once we have all sponsorship data input into pydotorg, we should be
37+
# able to change this view to fetch data from the database instead.
38+
class LogoPlacementeAPIList(APIView):
39+
authentication_classes = [TokenAuthentication]
40+
permission_classes = [SponsorPublisherPermission]
41+
serializer_class = LogoPlacementSerializer
42+
43+
def get(self, request, *args, **kwargs):
44+
placements = []
45+
46+
with open(settings.PYPI_SPONSORS_CSV, "r") as fd:
47+
for row in csv.DictReader(fd):
48+
if row["is_active"] != "t":
49+
continue
50+
51+
base_data = {
52+
"publisher": PublisherChoices.PYPI.value,
53+
"sponsor": row["name"],
54+
"description": row["activity_markdown"],
55+
"logo": row["color_logo_url"],
56+
"start_date": None,
57+
"end_date": None,
58+
"sponsor_url": row["link_url"],
59+
}
60+
61+
sponsors_page_keys = ["psf_sponsor", "infra_sponsor", "one_time"]
62+
if any([row[k] == "t" for k in sponsors_page_keys]):
63+
placement = base_data.copy()
64+
placement["flight"] = LogoPlacementChoices.SPONSORS_PAGE.value
65+
placements.append(placement)
66+
67+
if row["sidebar"] == "t":
68+
placement = base_data.copy()
69+
placement["flight"] = LogoPlacementChoices.SIDEBAR.value
70+
placement["sponsor_url"] = "https://pypi.org/sponsors/"
71+
placements.append(placement)
72+
73+
serializer = LogoPlacementSerializer(placements, many=True)
74+
return Response(serializer.data)

sponsors/management/commands/gen_sponsors_csv.py

Lines changed: 0 additions & 89 deletions
This file was deleted.

0 commit comments

Comments
 (0)