Specify badge by name instead of id.
This commit is contained in:
parent
709c5b1d23
commit
82df5ccd3d
23
README.md
23
README.md
|
@ -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
|
||||
|
|
|
@ -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}"
|
||||
)
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue