Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Add management command to create sponsor vouchers for PyCon 2023 #2233

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Jan 26, 2023
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
1 change: 1 addition & 0 deletions 1 .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,4 @@ __pycache__
.env
.DS_Store
.envrc
.state/
6 changes: 6 additions & 0 deletions 6 Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -50,3 +50,9 @@ shell: .state/db-initialized
clean:
docker-compose down -v
rm -f .state/docker-build-web .state/db-initialized .state/db-migrated

test: .state/db-initialized
docker-compose run --rm web ./manage.py test

docker_shell: .state/db-initialized
docker-compose run --rm web /bin/bash
133 changes: 133 additions & 0 deletions 133 sponsors/management/commands/create_pycon_vouchers_for_sponsors.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
import os
from hashlib import sha1
from calendar import timegm
from datetime import datetime
import sys
from urllib.parse import urlencode

import requests
from requests.exceptions import RequestException

from django.db.models import Q
from django.conf import settings
from django.core.management import BaseCommand

from sponsors.models import (
SponsorBenefit,
BenefitFeature,
ProvidedTextAsset,
TieredBenefit,
)

BENEFITS = {
121: {
"internal_name": "full_conference_passes_2023_code",
"voucher_type": "SPNS_COMP_",
},
139: {
"internal_name": "expo_hall_only_passes_2023_code",
"voucher_type": "SPNS_EXPO_COMP_",
},
148: {
"internal_name": "additional_full_conference_passes_2023_code",
"voucher_type": "SPNS_EXPO_DISC_",
},
166: {
"internal_name": "online_only_conference_passes_2023_code",
"voucher_type": "SPNS_ONLINE_COMP_",
},
}


def api_call(uri, query):
method = "GET"
body = ""

timestamp = timegm(datetime.utcnow().timetuple())
base_string = "".join(
(
settings.PYCON_API_SECRET,
str(timestamp),
method.upper(),
f"{uri}?{urlencode(query)}",
body,
)
)

headers = {
"X-API-Key": str(settings.PYCON_API_KEY),
"X-API-Signature": str(sha1(base_string.encode("utf-8")).hexdigest()),
"X-API-Timestamp": str(timestamp),
}
scheme = "http" if settings.DEBUG else "https"
url = f"{scheme}://{settings.PYCON_API_HOST}{uri}"
try:
return requests.get(url, headers=headers, params=query).json()
except RequestException:
raise


def generate_voucher_codes(year):
for benefit_id, code in BENEFITS.items():
for sponsorbenefit in (
SponsorBenefit.objects.filter(sponsorship_benefit_id=benefit_id)
.filter(sponsorship__status="finalized")
.all()
):
try:
quantity = BenefitFeature.objects.instance_of(TieredBenefit).get(
sponsor_benefit=sponsorbenefit
)
except BenefitFeature.DoesNotExist:
print(
f"No quantity found for {sponsorbenefit.sponsorship.sponsor.name} and {code['internal_name']}"
)
continue
try:
asset = ProvidedTextAsset.objects.filter(
sponsor_benefit=sponsorbenefit
).get(internal_name=code["internal_name"])
except ProvidedTextAsset.DoesNotExist:
print(
f"No provided asset found for {sponsorbenefit.sponsorship.sponsor.name} with internal name {code['internal_name']}"
)
continue

result = api_call(
f"/{year}/api/vouchers/",
query={
"voucher_type": code["voucher_type"],
"quantity": quantity.quantity,
"sponsor_name": sponsorbenefit.sponsorship.sponsor.name,
},
)
if result["code"] == 200:
print(
f"Fullfilling {code['internal_name']} for {sponsorbenefit.sponsorship.sponsor.name}: {quantity.quantity}"
)
promo_code = result["data"]["promo_code"]
asset.value = promo_code
asset.save()
else:
print(
f"Error from PyCon when fullfilling {code['internal_name']} for {sponsorbenefit.sponsorship.sponsor.name}: {result}"
)
print(f"Done!")


class Command(BaseCommand):
"""
Create Contract objects for existing approved Sponsorships.

Run this command as a initial data migration or to make sure
all approved Sponsorships do have associated Contract objects.
"""

help = "Create Contract objects for existing approved Sponsorships."

def add_arguments(self, parser):
parser.add_argument("year")

def handle(self, **options):
year = options["year"]
generate_voucher_codes(year)
54 changes: 54 additions & 0 deletions 54 sponsors/tests/test_management_command.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
from django.test import TestCase

from model_bakery import baker

from unittest import mock

from sponsors.models import ProvidedTextAssetConfiguration, ProvidedTextAsset
from sponsors.models.enums import AssetsRelatedTo

from sponsors.management.commands.create_pycon_vouchers_for_sponsors import (
generate_voucher_codes,
BENEFITS,
)


class CreatePyConVouchersForSponsorsTestCase(TestCase):
@mock.patch(
"sponsors.management.commands.create_pycon_vouchers_for_sponsors.api_call",
return_value={"code": 200, "data": {"promo_code": "test-promo-code"}},
)
def test_generate_voucher_codes(self, mock_api_call):
for benefit_id, code in BENEFITS.items():
sponsor = baker.make("sponsors.Sponsor", name="Foo")
sponsorship = baker.make(
"sponsors.Sponsorship", status="finalized", sponsor=sponsor
)
sponsorship_benefit = baker.make(
"sponsors.SponsorshipBenefit", id=benefit_id
)
sponsor_benefit = baker.make(
"sponsors.SponsorBenefit",
id=benefit_id,
sponsorship=sponsorship,
sponsorship_benefit=sponsorship_benefit,
)
quantity = baker.make(
"sponsors.TieredBenefit",
sponsor_benefit=sponsor_benefit,
)
config = baker.make(
ProvidedTextAssetConfiguration,
related_to=AssetsRelatedTo.SPONSORSHIP.value,
_fill_optional=True,
internal_name=code["internal_name"],
)
asset = config.create_benefit_feature(sponsor_benefit=sponsor_benefit)

generate_voucher_codes(2020)

for benefit_id, code in BENEFITS.items():
asset = ProvidedTextAsset.objects.get(
sponsor_benefit__id=benefit_id, internal_name=code["internal_name"]
)
self.assertEqual(asset.value, "test-promo-code")
Morty Proxy This is a proxified and sanitized view of the page, visit original site.