Thank you. I wanted to propose two small changes to the PR which might make it substantially more future-proof. First, to motivate the changes, the issues with the PR are:
1) The version from Stanford presumes a static set of fields matching what we currently have in edx-platform, and that they will be used in a specific way.
In a little more detail:
- When you look at something like the edX Insider course and the Profile XBlock (or Novoed), the set of fields is flexible and course-specific. This provides great pedagogical value.
- If you look at different LMSes, they collect different sets of profile information (edX, as an international platform, uses a full legal name, which handles non-US name formats, while more US-centric platforms will have first/last name split). If we want XBlocks to be used outside of edX platform, the service cannot presume the edX fields exist or are identical.
- Different LMSes (and edX as it evolves) may want to change how it uses these fields. We may want semantic abstractions for those use cases, which may not map 1:1 to what we have in the back-end. I expect this might be something like:
- "Give me the user's name, as we would show to other users." Depending on LMS, this may be username, e-mail, real name, etc.
- "Give me the user's name, as I would use to address the user." Depending on LMS, this may be full name, first name, or username.
- "Give me the user's contact info to show to other users"
- "Contact the user" (a.k.a. notifications)
2) The caller of the service also does not advertise what they need. An e-mail, for example, is more sensitive than a username. An LMS might want to allow untrusted XBlocks to have a username, but not an e-mail.
3) There isn't a clear set of use cases. For example, before putting in e-mail, I'd consider why we want that here. We have a notifications framework for sending e-mails (without knowing usernames) coming down the line. Is what we're looking for e-mail, or the user's contact information? It may be e-mail, but there should be a clear explanation of use case and why (which would, in turn, drive what we call the field, how we document it, etc).
With that background, I wanted to propose a long-term architectural direction, as well as a minor change to the patch which puts us on that direction.
As a proposal, we would split semantic information (e.g. displayname for showing to other users) from the source information. The XBlocks framework would guarantee that the semantic information was there, but it would not guarantee any particular set of source information. The semantic information would be explicit variables in the service, while the source information would be in a dict-like object:
- xblock_user.display_name -- Returns the user's name, as shown to peers on the platform. This might be a username on edX MOOCs, and the real name in residential classes.
- xblock_user.address_name -- Returns the user's name, as used when addressing the user. This could be a first name, a username, a title+last name, or a full legal name.
- xblock_user["edx-platfrom.user_id"] -- Returns the user ID, as per edX' internal representation. Either None or KeyError it doesn't exist.
- xblock_user["edx-platfrom.legal_name"] -- Returns the user's legal name, as per edX' internal representation. Either None or KeyError it doesn't exist.
- xblock_user["udacity.first_name"] -- Returns the user's first name, as per Udacity's internal representation. Either None or KeyError it doesn't exist.
- xblock_user["profile.country"] -- Returns the user's country, as registered with the Profile XBlock. Either None or KeyError it doesn't exist.
If someone can come up with cleaner names, that would be better.
In addition (but less importantly), it'd be nice if the constructor of the service took an optional argument which listed the set of data required (won't work without) and requested (will work better with). Right now, this could be ignored, or it could raise an exception if the block asks for something not on the list. I think we'll probably get it wrong on the first shot, but a first pass would be a good starting point for a discussion.
If we wanted to go in this direction, the required changes to the PR would be modest:
- Defining a clear set of use-cases for the user service.
- Changing the variable names in __init__ to cover those use cases. So instead of self.username=kwargs.get('username'), the code would have self.displayname=kwargs.get('username')
- Adding appropriate documentation around what those fields mean.
In addition, as nice-to-haves:
- Adding a __getitem__ that always returns None.
- Adding a __contains__ that always returns False.
- Make a first pass at how we declare what data the XBlock will want during operation, to get the discussion going.
I'd suggest we build out the standard fields as specific use cases come up. So the initial PR would add the specific fields which Stanford needs, and we would add additional fields on an as-needed basis. In the PR, we could either add the full set of edX data to __getitem__ and __contains__, or just leave them blank until the need arises.
Thoughts?
Piotr