Specify badge by name instead of id.

This commit is contained in:
Julien Palard 2023-03-27 18:43:30 +02:00
parent 709c5b1d23
commit 82df5ccd3d
Signed by: mdk
GPG Key ID: 0EFC1AC1006886F8
2 changed files with 77 additions and 21 deletions

View File

@ -8,7 +8,9 @@ This works in two distinct steps: first fetch HelloAsso data, then sync with Dis
pip install .
## Fetching HelloAsso data
## Using
### 1 — Fetch HelloAsso data
Use the `fetch` subcommand, I use it as is:
@ -17,22 +19,27 @@ Use the `fetch` subcommand, I use it as is:
this fetches the data of the given organization, here named `afpy`, it creates an `./afpy` file.
## Choosing what to sync
### 2 — Choose what to sync
The goal is to sync an HelloAsso event (they call it `forms`) to a Discourse Badge.
First let's discover which events we can use:
First let's discover which HelloAsso 'forms' we can use:
$ helloasso-to-discourse list-forms ./afpy
this will list names that can be used for the next step.
Then let's discover which Discourse badges we can use:
$ helloasso-to-discourse list-badges https://discuss.afpy.org "$(pass discuss.afpy.org-api-key)"
## Syncing with Discourse
### 3 — Sync
This step actually assigns badges to Discourse users:
As an example to assign badge number 114 to HelloAsso users having paid for the form named `adhesion-2023-a-l-afpy`:
As an example to assign badge "membre" to HelloAsso users having paid for the form named `adhesion-2023-a-l-afpy`:
$ helloasso-to-discourse sync https://discuss.afpy.org "$(pass discuss.afpy.org-api-key)" ./afpy adhesion-2023-a-l-afpy 114
$ helloasso-to-discourse sync https://discuss.afpy.org "$(pass discuss.afpy.org-api-key)" ./afpy pyconfr-2023 113
$ helloasso-to-discourse sync https://discuss.afpy.org "$(pass discuss.afpy.org-api-key)" ./afpy adhesion-2023-a-l-afpy membre
And an exemple to assign Discourse badge `pyconfr-2023` to members having registered for the `pyconfr-2023` event on HelloAsso:
$ helloasso-to-discourse sync https://discuss.afpy.org "$(pass discuss.afpy.org-api-key)" ./afpy pyconfr-2023 pyconfr-2023

View File

@ -1,6 +1,7 @@
import argparse
import json
import re
import sys
from itertools import count, groupby
from pathlib import Path
from typing import Any, Dict, Set
@ -33,7 +34,7 @@ def parse_args():
"form_slug",
help="See the `list-forms` subcommand to learn which one you can use.",
)
sync_parser.add_argument("badge", type=int)
sync_parser.add_argument("badge_slug")
sync_parser.set_defaults(func=main_sync)
list_form_parser = subparsers.add_parser(
@ -42,7 +43,18 @@ def parse_args():
list_form_parser.set_defaults(func=main_list_form)
list_form_parser.add_argument("helloasso_backup_file")
return parser.parse_args()
list_badges_parser = subparsers.add_parser(
"list-badges", help="List Discourse badges, to use with `sync`"
)
list_badges_parser.set_defaults(func=main_list_badges)
list_badges_parser.add_argument("discourse_url")
list_badges_parser.add_argument("discourse_api_key")
args = parser.parse_args()
if not hasattr(args, "func"):
parser.print_help()
sys.exit(1)
return args
class Discourse:
@ -73,6 +85,21 @@ class Discourse:
def get_badge(self, badge_id):
return self.get(f"/user_badges.json?badge_id={badge_id}")
def get_badges(self):
badges_info = self.get(f"/badges.json")
badge_types = {
badge_type["id"]: badge_type for badge_type in badges_info["badge_types"]
}
badge_groups = {
badge_group["id"]: badge_group
for badge_group in badges_info["badge_groupings"]
}
badges = badges_info["badges"]
for badge in badges:
badge["type"] = badge_types[badge["badge_type_id"]]
badge["group"] = badge_groups[badge["badge_grouping_id"]]
return {badge["slug"]: badge for badge in badges}
def users(self, flag="active"):
all_users = []
for page in count(1):
@ -129,11 +156,32 @@ def main_list_form(args):
)
print(tabulate(table, headers=("Type", "Name", "Members")))
print()
if table:
print("Use the `name` for the `sync` command, like:")
print(
f'helloasso-to-discourse sync https://discuss.afpy.org "$(pass discuss.afpy.org-api-key)" ./afpy {table[0][1]} 114'
)
print("Use the `name` for the `sync` command, like:")
print(
f'helloasso-to-discourse sync https://discuss.afpy.org "$(pass discuss.afpy.org-api-key)" ./afpy form-slug badge-slug'
)
def main_list_badges(args):
discourse = Discourse(args.discourse_url, args.discourse_api_key)
table = []
with discourse:
for slug, badge in discourse.get_badges().items():
table.append(
(
badge["group"]["name"],
badge["type"]["name"],
slug,
badge["grant_count"],
)
)
table.sort()
print(tabulate(table, headers=("Group", "Type", "Slug", "Grant count")))
print()
print("Use the tag `slug` for the `sync` command, like:")
print(
f'helloasso-to-discourse sync https://discuss.afpy.org "$(pass discuss.afpy.org-api-key)" ./afpy form-slug badge-slug'
)
def main_sync(args):
@ -151,9 +199,10 @@ def main_sync(args):
and "email" in item["payer"]
}
print(f"Found {len(from_helloasso)} emails in HelloAsso")
badge = discourse.get_badge(args.badge)
badge_name = badge["badges"][0]["name"]
already_assigned = {user["username"] for user in badge["users"]}
badges = discourse.get_badges()
badge = badges[args.badge_slug]
badge_users = discourse.get_badge(badges[args.badge_slug]["id"])["users"]
already_assigned = {user["username"] for user in badge_users}
print(f"Found {len(discourse.email_to_user_map)} emails in Discourse")
common_emails = set(discourse.email_to_user_map) & from_helloasso
print(f"Found {len(common_emails)} in common")
@ -163,10 +212,10 @@ def main_sync(args):
if discourse_user["username"] in already_assigned:
already_assigned_count += 1
continue
print(f"Assigning {badge_name!r} to {discourse_user['username']!r}")
discourse.assign_badge(args.badge, discourse_user["username"])
print(f"Assigning {badge['name']!r} to {discourse_user['username']!r}")
discourse.assign_badge(badge["id"], discourse_user["username"])
print(
f"{already_assigned_count} Discourse users already have the badge {badge_name!r}"
f"{already_assigned_count} Discourse users already have the badge {badge['name']!r}"
)