Verified Commit a75a79dc authored by Agate's avatar Agate 💬

Can now fetch contributions from OpenCollective

parent 654cef13
# Generated by Django 2.1.2 on 2018-10-18 19:41
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('core', '0001_initial'),
]
operations = [
migrations.AlterModelOptions(
name='contribution',
options={'ordering': ('-creation_date',)},
),
migrations.AlterModelOptions(
name='contributor',
options={'ordering': ('-creation_date',)},
),
migrations.AlterField(
model_name='contribution',
name='type',
field=models.CharField(choices=[('dev', 'Development'), ('dev:issue', 'Development/Issue'), ('i18n', 'Translations'), ('network', 'Network'), ('donation', 'Donations'), ('communication', 'Communication'), ('other', 'Other')], max_length=50),
),
migrations.AlterField(
model_name='contribution',
name='url',
field=models.URLField(null=True),
),
]
......@@ -38,7 +38,7 @@ class Contribution(models.Model):
import_date = models.DateTimeField(default=timezone.now)
is_visible = models.BooleanField(default=True)
external_id = models.CharField(max_length=250, unique=True)
url = models.URLField()
url = models.URLField(null=True)
metadata = JSONField()
class Meta:
......
......@@ -28,7 +28,9 @@ def retrieve_issue_page(url):
def import_contributor_from_author(payload):
contributor = None
try:
contributor = core_models.Contributor.objects.get(username=payload["username"])
contributor = core_models.Contributor.objects.get(
username__iexact=payload["username"]
)
except core_models.Contributor.DoesNotExist:
return core_models.Contributor.objects.create(
username=payload["username"],
......
import datetime
import requests
from django.utils import timezone
from contributions.core import models as core_models
ENDPOINT = "https://opencollective.com/api/graphql"
DATE_FORMAT = "%a %b %d %Y %H:%M:%S GMT%z (%Z)"
TRANSACTIONS_QUERY = {
"operationName": "Transactions",
"query": """
query Transactions($CollectiveId: Int!, $type: String, $limit: Int, $offset: Int, $dateFrom: String, $dateTo: String) {
allTransactions(CollectiveId: $CollectiveId, type: $type, limit: $limit, offset: $offset, dateFrom: $dateFrom, dateTo: $dateTo) {
id
uuid
description
createdAt
type
amount
currency
hostCurrency
hostCurrencyFxRate
fromCollective {
id
name
slug
path
image
__typename
}
... on Expense {
category
attachment
__typename
}
... on Order {
createdAt
subscription {
interval
__typename
}
__typename
}
__typename
}
}""",
}
def retrieve_transactions(collective_id, limit=100, offset=0):
query = TRANSACTIONS_QUERY.copy()
query["variables"] = {
"CollectiveId": collective_id,
"limit": limit,
"offset": offset,
}
response = requests.post(ENDPOINT, json=query)
response.raise_for_status()
return response.json()["data"]["allTransactions"]
def import_contributor(payload):
contributor = None
payload["web_url"] = f"https://opencollective.com/{payload['slug']}"
try:
contributor = core_models.Contributor.objects.get(
username__iexact=payload["slug"]
)
except core_models.Contributor.DoesNotExist:
return core_models.Contributor.objects.create(
username=payload["slug"],
name=payload["name"],
metadata={"opencollective": payload},
)
contributor.metadata["opencollective"] = payload
contributor.save(update_fields=["metadata"])
return contributor
def import_transaction_as_contribution(payload, collective):
contributor = import_contributor(payload["fromCollective"].copy())
creation_date = datetime.datetime.strptime(payload["createdAt"], DATE_FORMAT)
defaults = {
"summary": payload["description"],
"contributor": contributor,
"type": "donation",
"creation_date": creation_date,
"import_date": timezone.now(),
"is_visible": True,
"url": None,
"external_id": payload["id"],
"metadata": payload,
}
defaults["metadata"]["amount"] = payload["amount"]
defaults["metadata"]["currency"] = payload["currency"]
defaults["metadata"]["project_url"] = f"https://opencollective.com/{collective}"
defaults["metadata"]["collective"] = collective
return core_models.Contribution.objects.update_or_create(
external_id=payload["id"], defaults=defaults
)[0]
......@@ -74,8 +74,8 @@ def test_import_contributor_update_metadata(factories):
payload = {"id": 130, "name": "Alice", "username": "Alice42"}
contributor = gitlab.import_contributor_from_author(payload)
contributor == existing
assert contributor == existing
assert contributor.name == existing.name
assert contributor.username == existing.username
assert contributor.metadata == {"gitlab": payload, "hello": "world"}
......
from contributions.sources import opencollective
import datetime
def test_retrieve_transactions(requests_mock):
expected_query = opencollective.TRANSACTIONS_QUERY.copy()
expected_query["variables"] = {"CollectiveId": 42, "limit": 5, "offset": 3}
graphql = requests_mock.post(
opencollective.ENDPOINT, json={"data": {"allTransactions": {"hello": "world"}}}
)
result = opencollective.retrieve_transactions(collective_id=42, limit=5, offset=3)
request = graphql.request_history[0]
assert result == {"hello": "world"}
assert request.json() == expected_query
def test_import_transaction_as_contribution(now, db):
transaction_payload = {
"__typename": "Order",
"amount": 100,
"createdAt": "Mon Oct 15 2018 22:49:53 GMT+0000 (UTC)",
"currency": "EUR",
"description": "Monthly donation to Funkwhale (Backer)",
"fromCollective": {
"__typename": "User",
"id": 22538,
"image": "https://www.gravatar.com/avatar/1bf34eec3e0e8a1b6a818103ee6619e1?default=404",
"name": "Alice",
"path": "/alice",
"slug": "alice",
},
"hostCurrency": "EUR",
"hostCurrencyFxRate": 1,
"hostFeeInHostCurrency": -5,
"id": 125_616,
"netAmountInCollectiveCurrency": 64,
"paymentProcessorFeeInHostCurrency": -26,
"platformFeeInHostCurrency": -5,
"subscription": {"__typename": "Subscription", "interval": "month"},
"type": "CREDIT",
}
contribution = opencollective.import_transaction_as_contribution(
transaction_payload, collective="funkwhale"
)
contributor = contribution.contributor
author_metadata = transaction_payload["fromCollective"].copy()
author_metadata["web_url"] = f"https://opencollective.com/{author_metadata['slug']}"
assert contributor.name == transaction_payload["fromCollective"]["name"]
assert contributor.username == transaction_payload["fromCollective"]["slug"]
assert contributor.metadata == {"opencollective": author_metadata}
assert contribution.summary == transaction_payload["description"]
assert contribution.type == "donation"
assert contribution.creation_date == datetime.datetime.strptime(
transaction_payload["createdAt"], opencollective.DATE_FORMAT
)
assert contribution.import_date == now
assert contribution.is_visible is True
assert contribution.external_id == transaction_payload["id"]
assert contribution.url is None
expected_metadata = transaction_payload.copy()
expected_metadata.update(
{
"id": transaction_payload["id"],
"amount": transaction_payload["amount"],
"currency": transaction_payload["currency"],
"collective": "funkwhale",
"project_url": f"https://opencollective.com/funkwhale",
"subscription": transaction_payload["subscription"],
}
)
assert contribution.metadata == expected_metadata
def test_import_contributor_create(db):
payload = {
"__typename": "User",
"id": 22538,
"image": "https://www.gravatar.com/avatar/1bf34eec3e0e8a1b6a818103ee6619e1?default=404",
"name": "Alice",
"path": "/alice",
"slug": "alice",
}
contributor = opencollective.import_contributor(payload)
payload["web_url"] = f"https://opencollective.com/{payload['slug']}"
assert contributor.name == payload["name"]
assert contributor.username == payload["slug"]
assert contributor.metadata == {"opencollective": payload}
def test_import_contributor_update_metadata(factories):
existing = factories.Contributor(username="Alice42", metadata={"hello": "world"})
payload = {
"__typename": "User",
"id": 22538,
"image": "https://www.gravatar.com/avatar/1bf34eec3e0e8a1b6a818103ee6619e1?default=404",
"name": "Alice",
"path": "/alice",
"slug": "alice42",
}
contributor = opencollective.import_contributor(payload)
payload["web_url"] = f"https://opencollective.com/{payload['slug']}"
assert contributor == existing
assert contributor.name == existing.name
assert contributor.username == existing.username
assert contributor.metadata == {"opencollective": payload, "hello": "world"}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment