Skip to content

TNL-5621 Fix discussion topics in MIT course. - #13662

Merged
attiyaIshaque merged 1 commit into
masterfrom
atiya/TNL-5621-Duplicate-discussion
Nov 9, 2016
Merged

TNL-5621 Fix discussion topics in MIT course.#13662
attiyaIshaque merged 1 commit into
masterfrom
atiya/TNL-5621-Duplicate-discussion

Conversation

@attiyaIshaque

@attiyaIshaque attiyaIshaque commented Oct 6, 2016

Copy link
Copy Markdown

TNL-5621

Description

Problem: Courses has many discussion topic duplicates. On loading the discussion topics, it could not find which is a category and which is a subcategory.
Fix: Add entry and subcategory to differentiate the topics either its category or not.

Sandbox

tnl-5621-duplicate.sandbox.edx.org

Reviewers

If you've been tagged for review, please check your corresponding box once you've given the 👍.

FYI: @awaisdar001

@attiyaIshaque
attiyaIshaque force-pushed the atiya/TNL-5621-Duplicate-discussion branch 6 times, most recently from 8115376 to f4c5ce6 Compare October 13, 2016 07:14
@adampalay

Copy link
Copy Markdown
Contributor

Hey @attiyaIshaque , may you please provide a paragraph about what the original problem was and how this fix fixes it? It's not clear to me just from reading the code.

@attiyaIshaque

Copy link
Copy Markdown
Author

@adampalay I have updated the comment.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for tracking this down @attiyaIshaque. I imagine this is the main purpose of adding the type.

Are there any uses of this type in the JavaScript? If so, could you point it out? The reason I ask, is because:
a) The array of tuples in Python gives a slightly more awkward JavaScript data-structure of array of arrays.
b) It may greatly simplify this PR to not have to touch the JavaScript if there is a simple way to separate the array required by Python from the data sent to JavaScript.

Also, was the only problem one of entry vs subcategory? If topic names are repeated at multiple levels of subcategories, will we get a similar type problem, or is this ok?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@robrap Yes, this was the only problem of entry and subcategory.
You can also test this on sandbox: topic names are repeated at multiple levels of subcategories.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be using the new Python constant.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Based on my other comment, this change may not be necessary. However, if we decide it is needed, I think nameType should be renamed to child, and you could possibly add the comment:

// child[0] is the category name, child[1] is the type (i.e. 'entry' or 'subcategory')

@attiyaIshaque attiyaIshaque Oct 14, 2016

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@robrap yeah, it looks good: if we decide type is needed in the javascript.
But my point is here, who is the right person which will be decided type is required or not in the javascript?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right now I don't see type used in JavaScript. However, rather than removing type, would it be more correct to include the same fix? See the following (untested) code:

var type = child[1];
...
if (_.has(map.entries, name) && type == "entry") {
   ...

I'm not clear how this is already working without the above.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note: I don't love the data-structure of a meaningful 2x array for JavaScript, but maybe @andy-armstrong or @bjacobel could weigh in. I guess the alternatives are:

  1. Separate child_name and child_type arrays of equal length, which isn't much better, or
  2. (my preference): a child array of objects/dicts (rather than 2x arrays), with {name: "...", type: "..."}
    I think Fix js that prevented single step OE problems (ie only self assessment) ... #2 would look cleaner in JavaScript, but I know it would also affect a lot of js tests.

This is food for thought, unless and until the front-end devs weigh-in.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hard to say that one data structure is always better than another in all cases, but yes @robrap I think your #2 sounds better:

[
  {
    name: 'foo',
    type: 'bar',
  },
  {
    name: 'bizz',
    type: 'buzz'
  }
]

That's more JavaScript-y than two arrays, or a 2-D array.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@bjacobel: Thanks. This would result in a lot of changes to test data (see actual review). Could you state whether this should be a requirement for thumbs, or if we should leave this as-is, and simply let it be a lesson learned for the future?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not a requirement for thumbs (at least from me).

@attiyaIshaque attiyaIshaque Oct 18, 2016

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@robrap Are you suggesting we add a TODO here and get this PR going as is?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had a lot of different comments. My recommendations would be:

  1. Rename nameType to child in all code similar to this code (this seems to be repeated).
  2. Add the child[0] and child[1] comment I detailed above.
  3. Add a check for the type after _.has(map.entries, name) as I documented above.
  4. Forget about changing the data structure. I don't think it is worth adding a TODO that will always be ignored. If you don't do it now, it will not be done.

Hopefully this is clear.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@robrap I have addressed the comments. Kindly review again.
Also, I have updated the sandbox.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FYI: @andy-armstrong, @bjacobel: You might have reason to actually want additional data sent to JavaScript for bread-crumbing purposes, and maybe there is a way to solve both issues at once. I'm also curious about our best practices around sending JavaScript exactly what it needs vs the ease of sending everything that is needed either by JavaScript or by Mako.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use the new constants for 'entry' here, and anywhere server side.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are converting this to List of Lists here and in lms/djangoapps/django_comment_client/tests/test_utils.py:399 you are making list of tuples. Please use same verywhere.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@awaisdar001: I think the problem here is that tuples make more sense in Python, but get translated to arrays in JavaScript. Switching to a dict would make more sense in both Python and JavaScript, but that would be a larger change. Switching to an array in Python would make this more consistent, but would make less sense in Python. So, if I were going to hold thumbs for consistency, I'd rather see this move to:

children: [
    {type: 'entry', name: 'Test Topic'}, 
    {type: 'entry', name: 'Other Topic'}]
],
  1. @awaisdar001: I'm ok with this staying as-is, even though I would prefer to see dict/json used as discussed elsewhere. I'll leave it to you to determine if you want to push for the cleaner code.
  2. If we get the cleaner code (which would read much nicer), I think it would be nice to have type first, as I did above, but that's a nice to have.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@robrap Thank you for following up on the suggestion, I agree that would require a lot of code changes which will go beyond the scope of this change. As it is not the requirement for this change I agree we should move forward as-is.

@attiyaIshaque
attiyaIshaque force-pushed the atiya/TNL-5621-Duplicate-discussion branch 2 times, most recently from fac61e1 to 08f2f47 Compare October 19, 2016 09:16
@attiyaIshaque

Copy link
Copy Markdown
Author

@robrap ping.

// child[0] is the category name, child[1] is the type (i.e. 'entry' or 'subcategory')
var name = child[0],
entry = entries[name];
return subCategoryTemplate({

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's something odd about the names used here. Once you help clarify, it would be great to either fix the names and/or add a comment that provides clarity.

In the other loop over children (see common/static/common/js/discussion/views/discussion_topic_menu_view.js), we use entryTemplate() for entries and categoryTemplate() for subcategories. Here, it looks like these are entries because you are pulling from an entries list, but then you are using a subCategoryTemplate. Can you explain explain this?

Additionally, are all of these children guaranteed to be entries? If so, you should add a comment stating so, and possibly clarify why. If not, then type should be used and you should determine what needs to be done if child[1] is 'subcategory'.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@robrap I have fixed the name from subCategoryTemplate to entryTemplate.
Yes, all of these children would be entries.


return HtmlUtils.joinHtml.apply(this, _.map(children, function(name) {
return HtmlUtils.joinHtml.apply(this, _.map(children, function(nameType) {
var name = nameType[0];

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should have the same child rename, and below we should check the `type'.

if entry["sort_key"] is None and sort_alpha:
entry["sort_key"] = title
things.append((title, entry))
things.append((title, entry, 'entry'))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know I didn't mention this earlier, but it would be nice to use constants for these.

@robrap

robrap commented Oct 20, 2016

Copy link
Copy Markdown
Contributor

@attiyaIshaque: I completed another pass. Sorry, I thought I had completed this already.

@attiyaIshaque
attiyaIshaque force-pushed the atiya/TNL-5621-Duplicate-discussion branch from 08f2f47 to 10ca542 Compare October 21, 2016 09:28
@attiyaIshaque

Copy link
Copy Markdown
Author

@robrap I have addressed the comments.
@adampalay and @robrap Can you please review?

if name in course_wide_entries:
course_wide_children.append(name)
for name, c_type in discussion_category_map['children']:
if name in course_wide_entries and c_type == "entry":

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As discussed, add lms/djangoapps/django_comment_client/constants.py for constants and use them in places like this as well. Add a TODO comment near lms import here that all of course_groups should probably move to lms out of openedx/core.

topicsJson = {
course_wide_discussions: {
children: ['Topic_C_1'],
children: [['Topic_C_1', 'entry']],

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You could even use the constant in tests. Should just be search/replace.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@robrap I will add the constants in JS tests also but can you please determine the file in which we can add the constants.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was thinking about the Python tests.

@andy-armstrong or @bjacobel would be better at suggesting the appropriate place for constants in JavaScript.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't have any one defined place for them as far as I know. If you're sharing them between two files a constants.js at the root of whatever directory tree both files share sounds good to me.

*/
getCourseWideDiscussionsHtml: function(courseWideDiscussions) {
var subCategoryTemplate = HtmlUtils.template($('#cohort-discussions-subcategory-tpl').html()),
var entryTemplate = HtmlUtils.template($('#cohort-discussions-subcategory-tpl').html()),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As discussed, we shouldn't use both entryTemplate (entry) and #cohort-discussions-subcategory-tpl (subcategory). I think you should discuss with @muzaffaryousaf to better understand the naming of the underscore templates. Maybe there is a special reason that entries are being treated as subcategories in this case.

First clarify understand. Then possibly update names. Maybe entryTemplate is better as subCategoryTemplate even if it contains entries? I don't know at this point.

Once all is clarified, add clarifying comments where appropriate. Possible both in the underscore template(?) as well as here.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would go for subCategoryTemplate given that structure of discussions category map and reusability only if we don't change the name of template.

The other way is to rename the template name and use entryTemplate for course wide discussions but keep in mind we're using same template in inline template.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It may make sense to go with subCategoryTemplate, but it would be great if someone could help define category, subcategory, and entry. I see from @muzaffaryousaf's link that my attempt to define these was wrong. Are entries leaf subcategories? Other? I'm just not clear on what the names mean at this time.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we would go for subCategoryTemplate.
In the inline discussion Type can be "entry" or "subcategory", is actually the category type. So "category" means either an "entry" or "subcategory".
I am hesitant because I do not have the root knowledge about this so I will defer to you in this regard what is the right naming convention can be.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The underlying tree structure of the discussion topics is bit confusing, for course wide topics entries are sub categories when we compare them with inline but on other hand they're categories too since they don't have parent.
I would go for comments or tree structure as an example that can help someone to understand the conventions.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@muzaffaryousaf @attiyaIshaque: Thanks for your patience with this. Hopefully we can help once we are all clear.

@muzaffaryousaf: Can you carefully read the following notes and determine if you think anything is inaccurate?

Course wide discussions:
- children are all entries (leaf nodes)

Inline discussions:
- contains top-level container named subcategories
  - children can be mix of deeper subcategories or entries (leaf nodes) (in any order?)

Other details:
- Entries always have an id and represent a discussion topic.
- Entries are always leaf nodes, and never have children.
- Categories and subcategories are also names used in the UI to differentiate between top-level versus nested categories in inline discussions. 
  - In the UI (and Read the Docs), top-level categories are actually represented as the top-level subcategories data-structure.
  - In the UI (and Read the Docs), either a category or a subcategory may actually be an entry (leaf node) in the data-structure.

The most confusing term is subcategory, because:
- A subcategory is sometimes a container of subcategories (everywhere).
- A subcategory is sometimes a top-level container (in the UI code and the data-structure, but not the UI or Read the Docs).
- A subcategory is sometimes an entry or topic (in the UI code, the UI, and Read the Docs, but not in the data-structure).

Unfortunately, it is out-of-scope to fix all of this confusion as part of this PR.

Here's what I think we should do:

  1. Once @muzaffaryousaf fixes or signs off on my comments above, I will try to document it in Confluence so it is captured somewhere. I will also need to update the Glossary in Confluence which is currently inaccurate.
  2. I would leave the above rename to entryTemplate as-is, which matches the other usage.
  3. I would add the following comment into cohort-discussions-subcategory.underscore:
<%
// TODO: This underscore template is a template for entries (leaf nodes), and not for subcategories.
// We should rename uses of the term subcategory in this template, since subcategory can mean too
// many different things.
%>
  1. I would rename cohort-discussions-subcategory.underscore to cohort-discussions-entry.underscore if it doesn't cause much of a problem, since it seems to just be used in 2 places.

Let me know your thoughts.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@muzaffaryousaf: I changed and moved the comment above to a Glossary in Confluence on a related page. Feel free to comment/edit there instead of here.

@attiyaIshaque: This move shouldn't affect my recommendations above. I just got started on bullet 1.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm on it.

@muzaffaryousaf muzaffaryousaf Oct 31, 2016

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@attiyaIshaque I'll comment on confluence if anything comes up about the comment that @robrap made, i think that has nothing to do with this PR.

return subCategoryTemplate({
return HtmlUtils.joinHtml.apply(this, _.map(children, function(child) {
// child[0] is the category name, child[1] is the type (which is always 'entry')
var name = child[0],

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If these must only be entries, please add a code comment describing that, and possibly why.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe something more like this:

// child[0] is the category name
// for course wide discussions, the type stored in child[1] will always be 'entry'.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Slightly adjusted comment:

// child[0] is the category name, child[1] is the type.
// For course wide discussions, the type is always 'entry'.

@attiyaIshaque
attiyaIshaque force-pushed the atiya/TNL-5621-Duplicate-discussion branch from 10ca542 to 5afd614 Compare October 31, 2016 10:29
@attiyaIshaque

Copy link
Copy Markdown
Author

@robrap Can you please review again ?

@robrap robrap left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor fixes requested. Did you decide against js constants because you couldn't make it happen, or because the PR has been going too long, or other?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

# A leaf node in a category hierarchy.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

# A non-leaf node in a category hierarchy.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be using the new Python constant.

@attiyaIshaque
attiyaIshaque force-pushed the atiya/TNL-5621-Duplicate-discussion branch from 5afd614 to 337001b Compare November 1, 2016 16:28
@attiyaIshaque

Copy link
Copy Markdown
Author

@robrap I don't know where to add constant.js file and how to load the new js files.
I think we can leave it as-is.

@robrap

robrap commented Nov 1, 2016

Copy link
Copy Markdown
Contributor

Looks good once quality tests are passing.
UPDATE:
I give thumbs to the code, but I removed thumbs only because I never reviewed on the sandbox. I will not be around until next week, so you may need/want someone else to review on the sandbox. Thanks.

@attiyaIshaque
attiyaIshaque force-pushed the atiya/TNL-5621-Duplicate-discussion branch 2 times, most recently from 17c3001 to f14dd92 Compare November 3, 2016 07:18
@attiyaIshaque

Copy link
Copy Markdown
Author

@adampalay , @Qubad786 can you please review it?

course_wide_children.append(name)
for name, c_type in discussion_category_map['children']:
if name in course_wide_entries and c_type == TYPE_ENTRY:
course_wide_children.append([name, c_type])

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@attiyaIshaque , you also need address this pattern in doc string.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Qubad786 I will update the doc string. thanks for pointing this out.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@attiyaIshaque , also please see if any other doc string needs same addressing too.

@Qubad786

Qubad786 commented Nov 9, 2016

Copy link
Copy Markdown
Contributor

Looks good on sandbox too. 👍 after tests pass.

@robrap

robrap commented Nov 9, 2016

Copy link
Copy Markdown
Contributor

👍

@attiyaIshaque
attiyaIshaque force-pushed the atiya/TNL-5621-Duplicate-discussion branch from f14dd92 to f9497e8 Compare November 9, 2016 16:31
@attiyaIshaque
attiyaIshaque force-pushed the atiya/TNL-5621-Duplicate-discussion branch from f9497e8 to 76e1d4a Compare November 9, 2016 17:27
@attiyaIshaque
attiyaIshaque merged commit 9728759 into master Nov 9, 2016
@attiyaIshaque
attiyaIshaque deleted the atiya/TNL-5621-Duplicate-discussion branch November 9, 2016 18:30
@alisan617

Copy link
Copy Markdown

I am seeing js error (Cannot read property 'children' of undefined in discussion_topic_menu_view.js) in Editing Post view in Stage. Could someone verify?

@andy-armstrong

Copy link
Copy Markdown
Contributor

@alisan617 I see the same issue. Please report this as a bug and tag the release room that this is a blocker.

@adampalay

adampalay commented Nov 14, 2016

Copy link
Copy Markdown
Contributor

@attiyaIshaque , can you please make a PR against release-candidate to revert this PR? Thanks for catching this, @andy-armstrong and @alisan617 !

@alisan617

Copy link
Copy Markdown

Unfortunately, I think the problem is from my PR #13843. I am in process of reverting to release-candidate.

@attiyaIshaque

Copy link
Copy Markdown
Author

@adampalay, @andy-armstrong This error TypeError: Cannot read property 'children' of undefined
is already reported https://openedx.atlassian.net/browse/TNL-5713 before my PR merged.

@adampalay

Copy link
Copy Markdown
Contributor

My bad!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

9 participants