Creating badge via API query works, but returns 422

AI-generated summary

Creating Badge via API Query Works, but Returns 422

pfaffman is trying to create badges via API query using a Python script, but is receiving a 422 error, despite the badge being created successfully. The script is used to create multiple badges with different criteria (bronze, silver, and gold). pfaffman added various headers to the request, but they did not resolve the issue.

pfaffman hypothesized that the error might occur when trying to create a badge with a name that already exists.

I want a way to make groups of badges:

  • bronze → submitted with certain tag
  • silver → submitted tag, liked by me
  • gold → submitted tag, liked by me and 3 other people

I need to make a bunch of them and it’s tedious doing it from the web interface. One day I’ll write a plugin, but until then, I thought I’d do a quick Python script.

I had given up, as it fails with

urllib.error.HTTPError: HTTP Error 422: Unprocessable Entity

but when I glanced again at the badges admin page, I found that my badge had indeed been created. I guess maybe I don’t care, as it does work, but any ideas on why I get this error?

I added a bunch of headers thinking that might somehow help. It didn’t seem to (but they don’t seem to have hurt, either).

Code

#!/usr/bin/python3
from urllib.request import Request, urlopen
from urllib.error import URLError
import urllib.parse
API_USERNAME = 'pfaffman'
API_KEY = 'KEY'
BADGE = 'API BADGE2.2'

url = 'https://literatecomputing.com/admin/badges'

values = {'allow_title' : 'true',
          'multiple_grant' : 'true',
          'listable' : 'true',
          'auto_revoke' : 'false',
          'enabled' : 'false',
          'show_posts' : 'true',
          'target_posts' : 'true',
          'icon' : 'fa-certificate',
          'image' : '',
          'name' : BADGE,
          'description' : 'testing 1, 2, 3',
          'query' : """SELECT p.user_id, min(p.created_at) granted_at, MIN(p.id) post_id
FROM badge_posts p
JOIN topics t ON t.id = p.topic_id
JOIN topic_custom_fields tcf on t.id = tcf.topic_id
JOIN post_actions pa ON pa.post_id = p.id AND 
      post_action_type_id = (
                SELECT id FROM post_action_types WHERE name_key = 'like'
       ) AND 
       pa.user_id IN (
           SELECT gu.user_id
           FROM group_users gu
           WHERE gu.group_id = ( SELECT id FROM groups WHERE name ilike 'Leader' ) 
       )
WHERE category_id = ANY (
  SELECT id FROM categories WHERE name ilike '%completions%'
) AND p.post_number = 1
AND p.like_count > 0
AND tcf.name LIKE 'tags' and tcf.value LIKE '%wordpress-basics%'
and (:backfill OR ( p.id IN (:post_ids) ))
GROUP BY p.user_id
""",
'badge_grouping_id' : '7',
'trigger' : '2',
'badge_type_id' : '1',
'api_username' : API_USERNAME,
'api_key' : API_KEY
}

headers = {'content-type' : 'application/x-www-form-urlencoded; charset=UTF-8',
           'x-requested-with' : 'XMLHttpRequest',
           'referer' :'https://literatecomputing.com/admin/badges/new',
           'origin' : 'https://literatecomputing.com',
           'user-agent' : 'discourseBadgeCreator',
           'referer' : 'https://literatecomputing.com/admin/badges/new',
           'content-type' : 'application/x-www-form-urlencoded; charset=UTF-8'}


data = urllib.parse.urlencode(values)
data = data.encode('ascii') 
req = urllib.request.Request(url, data, headers)

print("\n\nvalues: ", data)

try: urllib.request.urlopen(req)
except URLError as e:    
    print ("\n\n--------------------YO!--------------------\n\n" , e.reason)
    print ("\n\nHeaders:\n\n ", e.headers)

with urllib.request.urlopen(req) as response:
    if response.code == '200':
        print ("It worked!")
    else:
        print ("Darn.")

You get this error if you try to create a badge that has a name that already exists.