Programatically enroll or unenroll students

I would like to enroll and unenroll students programmatically, outside the user interface. I thought of a manage.py command, or an exposed API. Do you know if it is implemented?

1 Like

Hello @Andres.Aulasneo,

localhost:18000/api/bulk_enroll/v1/bulk_enroll

You can use the above POST API endpoint to enroll multiple users in one or more courses and the same can be used for unenrollment. You have to enable ENABLE_BULK_ENROLLMENT_VIEW this feature flag in order to make the above API endpoint available in Open edX.

Reference:

Great! Thanks!

Now, I was able to get a JWT token, however when I try to make a request I get a 500 error and the following log tail:

  File "/edx/app/edxapp/venvs/edxapp/local/lib/python2.7/site-packages/edx_rest_framework_extensions/auth/jwt/decoder.py", line 189, in _get_signing_jwk_key_set
key_set.load_jwks(signing_jwk_set)
File "/edx/app/edxapp/venvs/edxapp/local/lib/python2.7/site-packages/jwkest/jwk.py", line 776, in load_jwks
self.load_dict(json.loads(jwks))
File "/usr/lib/python2.7/json/__init__.py", line 339, in loads
return _default_decoder.decode(s)
File "/usr/lib/python2.7/json/decoder.py", line 364, in decode
obj, end = self.raw_decode(s, idx=_w(s, 0).end())
File "/usr/lib/python2.7/json/decoder.py", line 382, in raw_decode
raise ValueError("No JSON object could be decoded")
ValueError: No JSON object could be decoded

I am doing this to test:

curl -X GET -H "Authorization: JWT eyJhbG.........LmNvbSJ9" https://my.lms/api/bulk_enroll/v1/bulk_enroll/

(When I do a complete request with data from python I get the same 500 error)

I was following this instructions to make the call.

Any idea what I may be doing wrong?

I don’t have any idea about your error but some pointers.

Usually, I don’t try curl to test APIs, instead of it I test the APIs in the Postman.

In the Postman, I was able to call this bulk enrollment API successfully. One thing I did was that I have passed parameters (auto_enroll, email_students, action, courses, identifiers) in the body of the request as form-data inside Postman.

And I have tested this with the OAuth2 token instead of the JWT token.

One last thing is that this API endpoint is POST not GET.

Thanks for these excellent guidelines @jramnai. Two questions: a) how do you create (or find) the exact JWT string value? and b) did you need to do anything with CSRF configuration in order to get open edx to accept requests from Postman?

@lpm0073, I do not use JWT for this, using OAuth2 for it, which requires access_token. In my DOT (Django OAuth Toolkit) application I have Resource owner password-based as Authorization grant type. (FYI)

No. I just passed access_token in Postman headers like this:

Authorization: Bearer <access_token>

And enabled Mobile Application Features.

Hi, I lost a lot of time trying to get this working and I’m still struggling probably with some small things…

Would appreciate your help…

This is how I’m tryiong to do it in postman:

and

but I keep getting:

{
“detail”: “Authentication credentials were not provided.”
}

what am I missing?

As @jramnai wrote in the second post you need to send a POST request, not a GET. When you will use the POST you will need to move all dynamic parameters from the Headers section to Body section of Postman.

**Example Request**

        POST /api/bulk_enroll/v1/bulk_enroll/ {
            "auto_enroll": true,
            "email_students": true,
            "action": "enroll",
            "courses": "course-v1:edX+Demo+123,course-v1:edX+Demo2+456",
            "cohorts": "cohortA,cohortA",
            "identifiers": "brandon@example.com,yamilah@example.com"
        }
1 Like

Thanks.
Just did it but the sam error…what am I doing wrongly?

I see that you did provide ‘Authorization’ header, you did use PostMan UI for doing this.

How did you receive the Bearer token that you use?

Try to use the approach described in the next topic for receiving the JWT or Bearer token.
https://course-catalog-api-guide.readthedocs.io/en/latest/authentication/

The ‘token_type’ in request from the topic can be OR ‘JWT’ OR ‘Bearer’

thanks that is exactly what I did…

The problem seems to be related either to some configuration on the server or something else as I did the same steps on my server and on another demo server where all works as expected.
I use Bitnami edx stack…

Any idea how I could troubleshoot further? Any logs I could check?

I have finally figured out what the problem was…

it is related to bitnami edx configuration of apache 2 - by adding this
WSGIPassAuthorization On

to the end of the httpd.conf, it solved the issue of authorization…

I’m running into the same issue that mslyon was describing.

I can hit the API with Postman and retrieve tokens but when I try to POST to
http://studio.local.overhang.io:8001/api/v1/course_runs/
I receive {“detail”:“Authentication credentials were not provided.”}

I’m using a tutor/docker from https://docs.tutor.overhang.io/
and looks like I don’t have the httpd.conf anywhere on my system.

Is there a way to set WSGIPassAuthorization
or is there something else I should be looking at?

The additional important point to be familiar with is to check that the endpoint ends with / character.
The next example is correct for the KOA version.

When I did POST request to /api/ccx/v0/ccx code redirected me to GET /api/ccx/v0/ccx/
The GET /api/ccx/v0/ccx/ wrote in response that the request is not authenticated when it had the proper token.

20.202.20.105 - 10.40.0.106 - - https [19/Jul/2023:04:03:30 +0000]  "POST /api/ccx/v0/ccx HTTP/1.1" 301 0 0.006 "-" "python-requests/2.28.1" 127.0.0.1:8000 0.004
20.202.20.105 - 10.40.0.106 - - https [19/Jul/2023:04:03:30 +0000]  "GET /api/ccx/v0/ccx/ HTTP/1.1" 403 90 0.116 "-" "python-requests/2.28.1" 127.0.0.1:8000 0.116

To repair it I was need add the / to the end of the URL.

  • POST to /api/ccx/v0/ccx not works
  • POST to /api/ccx/v0/ccx/ works