{"action":"created","comment":{"url":"https://api.github.com/repos/Stanford-Online/edx-platform/pulls/comments/23191841","id":23191841,"diff_hunk":"@@ -670,6 +670,564 @@ class AuthList\n       success: (data) -> cb?(data)\n       error: std_ajax_err => @$request_response_error.text gettext \"Error changing user's permissions.\"\n \n+class EmailSelectors\n+  constructor: (@$container, @$section, params={}) ->\n+    params = _.defaults params,\n+      label : $container.data 'label'\n+\n+    template_html = $(\"#email-list-widget-template\").html()\n+    @$container.html Mustache.render template_html, params\n+    @cur_column = 0\n+    @$table = $(\"#queryTableBody\")\n+    @labelArray = ($container.data 'selections').split '<>'\n+    @$list_selector = @$container.find 'select.single-email-selector'\n+    # populate selectors\n+    @$list_selector.empty()\n+    @$list_endpoint = $container.data 'list-endpoint'\n+    @$rolename = $container.data 'rolename'\n+    @$list_selector.append $ '<option/>'\n+    if this.$container.attr('data-label') == 'Select Section'\n+      @load_list()\n+    else if this.$container.attr('data-label') == 'Select Problem'\n+      @load_list()\n+    else\n+      for label in @labelArray\n+        @$list_selector.append $ '<option/>',\n+          text: label\n+\n+    @$list_selector.change =>\n+      $opt = @$list_selector.children('option:selected')\n+      return unless $opt.length > 0\n+\n+      if this.$container.attr('data-label') == \"Select a Type\"\n+        @chosen_class = $opt.text().trim()\n+        if (@chosen_class == \"Section\")\n+          @$section.find('.problem_specific').removeClass(\"active\")\n+          @$section.find('.section_specific').addClass(\"active\")\n+        else if (@chosen_class == \"Problem\")\n+          @$section.find('.section_specific').removeClass(\"active\")\n+          @$section.find('.problem_specific').addClass(\"active\")\n+\n+  get_list: (cb)->\n+    $.ajax\n+      dataType: 'json'\n+      url: @$list_endpoint\n+      data: rolename: 'instructor'\n+      success: (data) -> cb? null, data['data']\n+      error: std_ajax_err ->\n+        cb? gettext(\"Error fetching problem or section data\")\n+\n+  # load section/problem data\n+  load_list: ->\n+    @get_list (error, section_list) =>\n+      # abort on error\n+      return @show_errors error unless error is null\n+      _.each section_list, (section) =>\n+        @add_row(section, \"section\")\n+        _.each section.sub, (subsection) =>\n+          @add_row(subsection , \"subsection\")\n+\n+  add_row: (node, useClass) ->\n+    @idArr = [node.block_type, node.block_id]\n+    @idSt = @idArr.join(\"/\")\n+    @toDisplay = node.display_name\n+    if node.parents\n+      @toDisplay = [node.parents,@toDisplay].join(\"<>\")\n+    #indenting subsections with dashes for readability\n+    if useClass == \"subsection\"\n+      @toDisplay = \"---\" + @toDisplay\n+    if @toDisplay.length > 50\n+      #displaying the last n characters\n+      @toDisplay = \"...\" + @toDisplay.substring(@toDisplay.length-60, @toDisplay.length)\n+    @$list_selector.append $ '<option/>',\n+            text: @toDisplay\n+            class: useClass\n+            id : @idSt\n+\n+  set_cell: (text, colNumber, cellid) ->\n+    rows = $(\"#queryTableBody\")[0].rows\n+    cell = rows[rows.length - 1].children[colNumber]\n+    if cell\n+      cell.innerHTML = text\n+      if cellid != \"\"\n+        cell.id = cellid\n+\n+class EmailWidget\n+  constructor:  (@email_lists, @$section, @$email_list_containers)  ->\n+    @$query_endpoint = $(\".email-lists-management\").data('query-endpoint')\n+    @$total_endpoint = $(\".email-lists-management\")\n+      .data('total-endpoint')\n+    @$temp_queries_endpoint = $(\".email-lists-management\")\n+      .data('temp-queries-endpoint')\n+    @$delete_saved_endpoint = $(\".email-lists-management\")\n+      .data('delete-saved-endpoint')\n+    @$delete_temp_endpoint = $(\".email-lists-management\")\n+      .data('delete-temp-endpoint')\n+    @$delete_bulk_temp_endpoint = $(\".email-lists-management\")\n+      .data('delete-bulk-temp-endpoint')\n+    for email_list in @email_lists\n+      email_list.$container.addClass 'active'\n+\n+    @$get_est_btn = @$section.find(\"input[name='getest']'\")\n+    @$get_est_btn.click () =>\n+      @reload_estimated()\n+\n+    @$startover_btn = @$section.find(\"input[name='startover']'\")\n+    @$startover_btn.click () =>\n+      @delete_temporary()\n+      $(\"#queryTableBody tr\").remove()\n+      @reload_estimated()\n+\n+    @$save_query_btn = @$section.find(\"input[name='savequery']'\")\n+    @$save_query_btn.click () =>\n+      @send_save_query()\n+\n+    @$email_csv_btn = @$section.find(\"input[name='getcsv']'\")\n+    @$email_csv_btn.click () =>\n+      sending_query = []\n+      tab = $(\"#queryTableBody\")\n+      rows = tab.find(\"tr\")\n+      _.each rows, (row) ->\n+        sending_query.push(row.getAttribute('query'))\n+\n+      send_data = sending_query.join(',')\n+      url = @$email_csv_btn.data 'endpoint'\n+      # handle csv special case\n+      # redirect the document to the csv file.\n+      url += '/csv'\n+      url += \"?rolename=instructor\"\n+      url += \"&existing=\" + encodeURIComponent(send_data)\n+      location.href = url\n+\n+    @load_saved_queries()\n+    @load_saved_temp_queries()\n+\n+    #poll for query status every 15 seconds\n+    POLL_INTERVAL = 1000 * 15  # 15 seconds in ms\n+    @poller = new window.InstructorDashboard.util.IntervalManager(\n+      POLL_INTERVAL, => @load_saved_temp_queries()\n+    )\n+    @poller.start()\n+\n+    $('#addQuery').click =>\n+      selected = @$email_list_containers.find('select.single-email-selector')\n+        .children('option:selected')\n+      #check to see if stuff has been filled out\n+      if selected[1].text == \"Section\"\n+        @arr = [{'text':selected[0].text, 'id':selected[0].id},\n+                {'text':selected[1].text, 'id':selected[1].id},\n+                {'text':selected[4].text, 'id':selected[4].id},\n+                {'text':selected[5].text, 'id':selected[5].id}]\n+        @arr_text = [selected[0].text, selected[1].text,\n+                     selected[4].text, selected[5].text]\n+\n+      else\n+        @arr = [{'text':selected[0].text, 'id':selected[0].id},\n+                {'text':selected[1].text, 'id':selected[1].id},\n+                {'text':selected[2].text, 'id':selected[2].id},\n+                {'text':selected[3].text, 'id':selected[3].id}]\n+        @arr_text = [selected[0].text, selected[1].text,\n+                     selected[2].text, selected[3].text]\n+\n+      for thing in @arr\n+        if thing['text'] == \"\"\n+          $(\"#incompleteMessage\")[0].innerHTML =\n+            \"Query is incomplete. Please make all the selections.\"\n+          return\n+\n+      $(\"#incompleteMessage\")[0].innerHTML = \"\"\n+      @chosen = selected[0].text\n+      @tr = @start_row(@chosen.toLowerCase(), @arr, \"\", $(\"#queryTableBody\"))\n+      @use_query_endpoint = @$query_endpoint + \"/\" + @arr_text.slice(0,2).\n+        join(\"/\") + \"/\" + @arr[2].id\n+      @filtering = @arr[3].text\n+      @entityName = @arr[2].text\n+      @reload_students(@tr)\n+      @$email_list_containers.find('select.single-email-selector').\n+        prop('selectedIndex', 0)\n+      $(\".problem_specific\").removeClass('active')\n+      $(\".section_specific\").removeClass('active')\n+\n+  get_saved_temp_queries: (cb)->\n+    $.ajax\n+      dataType: 'json'\n+      url: @$temp_queries_endpoint\n+      data: rolename: 'instructor'\n+      success: (data) -> cb? null, data\n+      error: std_ajax_err ->\n+        cb? gettext(\"Error getting saved temp queries\")\n+\n+  #get a user's in-progress queries and load them into active queries\n+  load_saved_temp_queries: ->\n+    @get_saved_temp_queries (error, data) =>\n+      # abort on error\n+      return @show_errors error unless error is null\n+      $(\"#queryTableBody tr\").remove()\n+      queries = data['queries']\n+      # use _.each instead of 'for' so that member\n+      # is bound in the button callback.\n+      _.each queries, (query) =>\n+        query_id = query['id']\n+        block_id = query['block_id']\n+        block_type = query['block_type']\n+        state_key = block_type + \"/\" + block_id\n+        display_name = query['display_name']\n+        display_entity = {'text':display_name, 'id':state_key}\n+        filter_on = {'text':query['filter_on']}\n+        inclusion = {'text':query['inclusion']}\n+        done = query['done']\n+        type = {'text':query['type']}\n+        arr = [inclusion, type, display_entity, filter_on, done]\n+        @tr = @start_row(inclusion['text'].toLowerCase(),arr,\n+          {'class':[\"working\"],'query':query_id},  $(\"#queryTableBody\"))\n+        @check_done()\n+\n+\n+  get_saved_queries: (cb)->\n+    $.ajax\n+      dataType: 'json'\n+      url: $(\"#savedQueriesTable\").data 'endpoint'\n+      data: rolename: 'instructor'\n+      success: (data) -> cb? null, data\n+      error: std_ajax_err ->\n+        cb? gettext(\"Error getting saved queries\")\n+\n+  #get a user's saved queries and load them into saved queries\n+  load_saved_queries: ->\n+    $(\"#savedQueriesTable tr\").remove()\n+    $(\"#invisibleQueriesStorage tr\").remove()\n+    @get_saved_queries (error, data) =>\n+      # abort on error\n+      return @show_errors error unless error is null\n+      queries = data['queries']\n+      groups = new Set()\n+      _.each queries, (query) =>\n+        block_id = query['block_id']\n+        block_type = query['block_type']\n+        state_key = block_type + \"/\" + block_id\n+        display_name = query['display_name']\n+        display_entity = {'text':display_name, 'id':state_key}\n+        filter_on = {'text':query['filter_on']}\n+        inclusion = {'text':query['inclusion']}\n+        created = query['created']\n+        type = {'text':query['type']}\n+        arr = [inclusion,type, display_entity, filter_on]\n+        invisibleTable = $(\"#invisibleQueriesStorage\")\n+        @tr = @start_row(inclusion['text'],arr,\n+          {'class':[\"saved\" + query.group]}, invisibleTable)\n+        @tr[0].setAttribute('created',created)\n+        groups.add(query.group)\n+      group_arr = []\n+      iter = groups.values()\n+      val = iter.next()\n+      while (val['done'] == false)\n+        group_arr.push(val['value'])\n+        val = iter.next()\n+      group_arr.sort((a, b) ->return b-a)\n+      for group in group_arr\n+        lookup = \".saved\" + group\n+        saved_qs = $(lookup)\n+        types = []\n+        names = []\n+        time = \"\"\n+        for query in saved_qs\n+          cells = query.children\n+          types.push(cells[0].innerText)\n+          names.push(cells[2].innerText)\n+          time = query.getAttribute('created')\n+        display_st = \"\"\n+        for i in [0..types.length-1]\n+          display_st += types[i]\n+          display_st += \" \"\n+          display_st += names[i] + \" \"\n+        arr = [{\"text\": time}, {\"text\": display_st}]\n+        @start_saved_row(\"and\",arr, group, $(\"#savedQueriesTable\") )\n+\n+  #if each individual query is processed, allow the user\n+  #to download the csv and save the query\n+  check_done: ->\n+    #check if all other queries have returned, if so can get total csv\n+    row_arr = []\n+    tab = $(\"#queryTableBody\")\n+    rows = tab.find(\"tr\")\n+    _.each rows, (row) ->\n+      row_arr.push(row.getAttribute('query'))\n+    allGood = true\n+    _.each row_arr, (status) ->\n+      if status == \"working\"\n+        allGood = false\n+    if allGood\n+      @$save_query_btn.removeClass(\"disabled\")\n+      @$email_csv_btn.removeClass(\"disabled\")\n+      @$email_csv_btn[0].value = \"Download CSV\"\n+\n+  #deletes an active query from the table and the db\n+  delete_temporary:->\n+    queriesToDelete = []\n+    _.each $(\"#queryTableBody tr\"), (row) ->\n+      if row.hasAttribute('query')\n+        queryToDelete = row.getAttribute('query')\n+        queriesToDelete.push(queryToDelete)\n+    @delete_bulk_temp_query(queriesToDelete)\n+    $(\"#queryTableBody tr\").remove()\n+\n+  #adds a row to saved queries\n+  start_saved_row:(color, arr, id, table) ->\n+    #find which row to insert in\n+    rows = table[0].children\n+    row = table[0].insertRow(rows)\n+    row.setAttribute(\"groupQuery\", id)\n+    for num in [0..1]\n+      cell = row.insertCell(num)\n+      item = arr[num]\n+      cell.innerHTML = item['text']\n+      if item.hasOwnProperty('id')\n+        cell.id = item['id']\n+    $load_btn = $ _.template('<div class=\"loadQuery\"><i class=\"icon-upload\">\n+      </i> <%= label %></div>', {label: \"Load\"})\n+    $load_btn.click =>\n+      @delete_temporary()\n+      $(\"#queryTableBody tr\").remove()\n+      targ = event.target\n+      while (!targ.classList.contains('loadQuery'))\n+        targ = targ.parentNode\n+      curRow = targ.parentNode.parentNode\n+      groupedQueryId = curRow.getAttribute('groupQuery')\n+      @$email_csv_btn[0].value = \"Aggregating Queries\"\n+      $(\"#incompleteMessage\")[0].innerHTML = \"\"\n+      rowsToAdd = $(\".saved\" + groupedQueryId)\n+      for row in rowsToAdd\n+        cells = row.children\n+        @arr = [{'text':cells[0].innerText},\n+                {'text':cells[1].innerText},\n+                {'text':cells[2].innerText, 'id':cells[2].id},\n+                {'text':cells[3].innerText}]\n+\n+        @arr_text = [cells[0].innerText, cells[1].innerText,\n+                     cells[2].innerText, cells[3].innerText]\n+        @tr = @start_row(cells[0].innerText.toLowerCase(),\n+          @arr,\"\", $(\"#queryTableBody\"))\n+        #todo:this feels too hacky. suggestions?\n+        @use_query_endpoint =@$query_endpoint + \"/\" + @arr_text.slice(0,2).\n+          join(\"/\") + \"/\" + @arr[2].id\n+        @filtering = @arr[3].text\n+        @entityName = @arr[2].text\n+        @reload_students(@tr)\n+        @$email_list_containers.find('select.single-email-selector').\n+          prop('selectedIndex',0)\n+        $(\".problem_specific\").removeClass('active')\n+        $(\".section_specific\").removeClass('active')\n+    $td = $ '<td>'\n+    $td.append $load_btn\n+    row.appendChild $td[0]\n+    $delete_btn = $ _.template('<div class=\"deleteSaved\">\n+      <i class=\"icon-remove-sign\"></i> <%= label %></div>', {label: \"Delete\"})\n+    $delete_btn.click =>\n+      targ = event.target\n+      while (!targ.classList.contains('deleteSaved'))\n+        targ = targ.parentNode\n+      curRow = targ.parentNode.parentNode\n+      curRow.remove()\n+      queryToDelete = curRow.getAttribute('groupquery')\n+      @delete_saved_query(queryToDelete)\n+    $td = $ '<td>'\n+    $td.append $delete_btn\n+    row.appendChild $td[0]\n+    return $(row)\n+\n+  get_students: (cb)->\n+    tab = $(\"#queryTableBody\")\n+    rows = tab.find(\"tr\")\n+    _.each rows, (row) ->\n+      type = row.classList[0]\n+      problems = []\n+      children = row.children\n+      _.each children, (child) ->\n+        id = child.id\n+        html = child.innerHTML\n+        problems.push({\"id\":id, \"text\":html})\n+      problems = problems.slice(0,-1)\n+    send_data =\n+      filter: @filtering\n+      entityName: @entityName\n+    $.ajax\n+      dataType: 'json'\n+      url: @use_query_endpoint\n+      data: send_data\n+      success: (data) -> cb? null, data\n+      error: std_ajax_err ->\n+        cb? gettext(\"Error getting students\")\n+\n+  #make a single query to the backend. doesn't wait for\n+  #query completion as that can take awhile\n+  reload_students: (tr) ->\n+    @$save_query_btn.addClass(\"disabled\")\n+    @$email_csv_btn.addClass(\"disabled\")\n+    @$email_csv_btn[0].value = \"Aggregating Queries\"\n+    tr.addClass(\"working\")\n+    @get_students (error, students) =>\n+      if error\n+        $broken_icon = $ _.template('<div class=\"done\">\n+          <i class=\"icon-warning-sign\"></i> <%= label %></div>',\n+          {label: \"Sorry, we're having a problem with this query.\n+            Please delete this row and try again.\"})\n+        tr.children()[4].innerHTML = $broken_icon[0].outerHTML\n+      return @show_errors error unless error is null\n+\n+  #we don't care if these calls succeed or not so no wrapped callback\n+  delete_temp_query: (queryId)->\n+    send_url = @$delete_temp_endpoint + \"/\" + queryId\n+    $.ajax\n+      dataType: 'json'\n+      url: send_url\n+\n+  delete_bulk_temp_query: (queryIds)->\n+    send_url = @$delete_bulk_temp_endpoint\n+    send_data =\n+      existing: queryIds.join(',')\n+    $.ajax\n+      dataType: 'json'\n+      url: send_url\n+      data: send_data\n+\n+  delete_saved_query: (queryId)->\n+    send_url = @$delete_saved_endpoint + \"/\" + queryId\n+    $.ajax\n+      dataType: 'json'\n+      url: send_url\n+\n+  #adds a row to active queries\n+  start_row:(color, arr, rowIdClass, table) ->\n+    #find which row to insert in\n+    idx =0\n+    orIdx = 0\n+    andIdx = 0\n+    notIdx = 0\n+    useIdx = 0\n+    rows = table[0].children\n+    #figuring out where to place the new row\n+    #we want the group order to be and, or, not\n+    for curRow in rows\n+      idx += 1\n+      if curRow.classList.contains(\"or\")\n+        orIdx = idx\n+      if curRow.classList.contains(\"and\")\n+        andIdx = idx\n+      if curRow.classList.contains(\"not\")\n+        notIdx = idx\n+      if curRow.classList.contains(color)\n+        useIdx = idx\n+    if color == \"or\" and useIdx == 0\n+      useIdx = Math.max(notIdx, andIdx)\n+    if color == \"not\" and useIdx == 0\n+      useIdx =andIdx\n+    row = table[0].insertRow(useIdx)\n+    if rowIdClass.hasOwnProperty('id')\n+      row.id = rowIdClass['id']\n+    if rowIdClass.hasOwnProperty('query')\n+      row.setAttribute('query',rowIdClass['query'])\n+\n+    row.classList.add(color.toLowerCase())\n+    if rowIdClass.hasOwnProperty('class')\n+      _.each rowIdClass['class'], (addingClass) ->\n+        row.classList.add(addingClass.toLowerCase())\n+    for num in [0..3]\n+      cell = row.insertCell(num)\n+      item = arr[num]\n+      cell.innerHTML = item['text']\n+      if item.hasOwnProperty('id') and item['id'] !=\"\"\n+        cell.id = item['id']\n+    progressCell = row.insertCell(4)\n+    $progress_icon = $ _.template('<div class=\"Working\">\n+      <i class=\"icon-spinner icon-spin\"></i><%= label %></div>',\n+      {label: \"Working\"})\n+    $done_icon = $ _.template('<div class=\"done\"><i class=\"icon-check\">\n+      </i> <%= label %></div>', {label: \"Done\"})\n+    $broken_icon = $ _.template('<div class=\"done\">\n+      <i class=\"icon-warning-sign\"></i> <%= label %></div>',\n+      {label: \"Sorry, we're having a problem with this query.\n+        Please delete this row and try again.\"})\n+    if arr.length == 4\n+      progressCell.innerHTML = $progress_icon[0].outerHTML\n+    else\n+      if arr[4] == null\n+        progressCell.innerHTML = $broken_icon[0].outerHTML\n+      else if arr[4] == true\n+        progressCell.innerHTML = $done_icon[0].outerHTML\n+        row.classList.remove('working')\n+      else\n+        progressCell.innerHTML = $progress_icon[0].outerHTML\n+    $remove_btn = $ _.template('<div class=\"remove\"><i class=\"icon-remove-sign\">\n+      </i> <%= label %></div>', {label: \"Remove\"})\n+    $remove_btn.click =>\n+      targ = event.target\n+      while (!targ.classList.contains('remove'))\n+        targ = targ.parentNode\n+      curRow = targ.parentNode.parentNode\n+      curRow.remove()\n+      if curRow.hasAttribute('query')\n+        queryToDelete = curRow.getAttribute('query')\n+        @delete_temp_query(queryToDelete)\n+      @check_done()\n+    $td = $ '<td>'\n+    $td.append $remove_btn\n+    row.appendChild $td[0]\n+    return $(row)\n+\n+  save_query: (cb)->\n+    cur_queries = []\n+    tab = $(\"#queryTableBody\")\n+    rows = tab.find(\"tr\")\n+    _.each rows, (row) ->\n+      cur_queries.push(row.getAttribute('query'))\n+    send_data =\n+      existing: cur_queries.join(',')\n+    $.ajax\n+      dataType: 'json'\n+      url: @$save_query_btn.data 'endpoint'\n+      data: send_data\n+      success: (data) -> cb? null, data\n+      error: std_ajax_err ->\n+        cb? gettext(\"Error saving query\")\n+\n+  #save queries in active queries\n+  send_save_query: ->\n+    @save_query (error, students) =>\n+      return @show_errors error unless error is null\n+      @load_saved_queries()\n+\n+  get_estimated: (cb)->\n+    cur_queries = []\n+    tab = $(\"#queryTableBody\")\n+    rows = tab.find(\"tr\")\n+    _.each rows, (row) ->\n+      cur_queries.push(row.getAttribute('query'))\n+    send_data =\n+      existing: cur_queries.join(',')\n+    $.ajax\n+      dataType: 'json'\n+      url: @$total_endpoint\n+      data: send_data\n+      success: (data) -> cb? null, data\n+      error: std_ajax_err ->\n+        cb? gettext(\"Error getting estimated\")\n+\n+  #estimate the students selected\n+  reload_estimated: ->\n+    $(\"#estimated\")[0].innerHTML= \"Calculating\"\n+    @get_estimated (error, students) =>\n+      if students['success'] == false\n+        $(\"#estimated\")[0].innerHTML = '0 students selected'","path":"lms/static/coffee/src/instructor_dashboard/membership.coffee","position":560,"original_position":560,"commit_id":"ea94939cb1cf94b1e882fd85ff2b587f0432dc0c","original_commit_id":"ea94939cb1cf94b1e882fd85ff2b587f0432dc0c","user":{"login":"stvstnfrd","id":7300975,"avatar_url":"https://avatars.githubusercontent.com/u/7300975?v=3","gravatar_id":"","url":"https://api.github.com/users/stvstnfrd","html_url":"https://github.com/stvstnfrd","followers_url":"https://api.github.com/users/stvstnfrd/followers","following_url":"https://api.github.com/users/stvstnfrd/following{/other_user}","gists_url":"https://api.github.com/users/stvstnfrd/gists{/gist_id}","starred_url":"https://api.github.com/users/stvstnfrd/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/stvstnfrd/subscriptions","organizations_url":"https://api.github.com/users/stvstnfrd/orgs","repos_url":"https://api.github.com/users/stvstnfrd/repos","events_url":"https://api.github.com/users/stvstnfrd/events{/privacy}","received_events_url":"https://api.github.com/users/stvstnfrd/received_events","type":"User","site_admin":false},"body":"This text needs i18n'ed.\r\n","created_at":"2015-01-19T22:39:38Z","updated_at":"2015-01-19T22:39:38Z","html_url":"https://github.com/Stanford-Online/edx-platform/pull/169#discussion_r23191841","pull_request_url":"https://api.github.com/repos/Stanford-Online/edx-platform/pulls/169","_links":{"self":{"href":"https://api.github.com/repos/Stanford-Online/edx-platform/pulls/comments/23191841"},"html":{"href":"https://github.com/Stanford-Online/edx-platform/pull/169#discussion_r23191841"},"pull_request":{"href":"https://api.github.com/repos/Stanford-Online/edx-platform/pulls/169"}}},"pull_request":{"url":"https://api.github.com/repos/Stanford-Online/edx-platform/pulls/169","id":25466502,"html_url":"https://github.com/Stanford-Online/edx-platform/pull/169","diff_url":"https://github.com/Stanford-Online/edx-platform/pull/169.diff","patch_url":"https://github.com/Stanford-Online/edx-platform/pull/169.patch","issue_url":"https://api.github.com/repos/Stanford-Online/edx-platform/issues/169","number":169,"state":"open","locked":false,"title":"Caijim/emaillist","user":{"login":"caijim","id":461386,"avatar_url":"https://avatars.githubusercontent.com/u/461386?v=3","gravatar_id":"","url":"https://api.github.com/users/caijim","html_url":"https://github.com/caijim","followers_url":"https://api.github.com/users/caijim/followers","following_url":"https://api.github.com/users/caijim/following{/other_user}","gists_url":"https://api.github.com/users/caijim/gists{/gist_id}","starred_url":"https://api.github.com/users/caijim/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/caijim/subscriptions","organizations_url":"https://api.github.com/users/caijim/orgs","repos_url":"https://api.github.com/users/caijim/repos","events_url":"https://api.github.com/users/caijim/events{/privacy}","received_events_url":"https://api.github.com/users/caijim/received_events","type":"User","site_admin":false},"body":"Backend+Frontend code for Email List tool on instructor dashboard page (under membership tab)\r\n\r\nA few things:\r\n1) Javascript is not clean. Any pointers would be greatly and graciously appreciated\r\n2) In the urls file, I had to double up on some urls like the following just so I could call reverse(..) on them (see instructor_dashboard.py) so I could use the parameterized version in js. If I don't add the non-param'd version the page doesn't load. What is the way around this?\r\n\r\nurl(r'^get_single_query/(?P<inclusion>\\S{2,3})/(?P<queryType>(Section|Problem))/(?P<stateType>\\S+)/(?P<stateId>\\S+)$', 'instructor.views.api.get_single_query', name=\"get_single_query\"),\r\n(r'^get_single_query',\r\n  'instructor.views.api.get_single_query', name=\"get_single_query\")\r\n\r\n\r\nThanks, and sorry for the huge changelist\r\n\r\ntagging @jbau @stvstnfrd @kluo  for reviewing\r\n\r\nStyle changed applied and functionality has been tested. Still need to write unit tests and address some existing comments. Thanks so far!\r\n","created_at":"2014-12-04T01:18:20Z","updated_at":"2015-01-19T22:39:38Z","closed_at":null,"merged_at":null,"merge_commit_sha":"7dbc9d36ac33fbdfe53fda98502c3595ca283e85","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/Stanford-Online/edx-platform/pulls/169/commits","review_comments_url":"https://api.github.com/repos/Stanford-Online/edx-platform/pulls/169/comments","review_comment_url":"https://api.github.com/repos/Stanford-Online/edx-platform/pulls/comments/{number}","comments_url":"https://api.github.com/repos/Stanford-Online/edx-platform/issues/169/comments","statuses_url":"https://api.github.com/repos/Stanford-Online/edx-platform/statuses/ea94939cb1cf94b1e882fd85ff2b587f0432dc0c","head":{"label":"Stanford-Online:caijim/emaillist","ref":"caijim/emaillist","sha":"ea94939cb1cf94b1e882fd85ff2b587f0432dc0c","user":{"login":"Stanford-Online","id":2159497,"avatar_url":"https://avatars.githubusercontent.com/u/2159497?v=3","gravatar_id":"","url":"https://api.github.com/users/Stanford-Online","html_url":"https://github.com/Stanford-Online","followers_url":"https://api.github.com/users/Stanford-Online/followers","following_url":"https://api.github.com/users/Stanford-Online/following{/other_user}","gists_url":"https://api.github.com/users/Stanford-Online/gists{/gist_id}","starred_url":"https://api.github.com/users/Stanford-Online/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Stanford-Online/subscriptions","organizations_url":"https://api.github.com/users/Stanford-Online/orgs","repos_url":"https://api.github.com/users/Stanford-Online/repos","events_url":"https://api.github.com/users/Stanford-Online/events{/privacy}","received_events_url":"https://api.github.com/users/Stanford-Online/received_events","type":"Organization","site_admin":false},"repo":{"id":11616657,"name":"edx-platform","full_name":"Stanford-Online/edx-platform","owner":{"login":"Stanford-Online","id":2159497,"avatar_url":"https://avatars.githubusercontent.com/u/2159497?v=3","gravatar_id":"","url":"https://api.github.com/users/Stanford-Online","html_url":"https://github.com/Stanford-Online","followers_url":"https://api.github.com/users/Stanford-Online/followers","following_url":"https://api.github.com/users/Stanford-Online/following{/other_user}","gists_url":"https://api.github.com/users/Stanford-Online/gists{/gist_id}","starred_url":"https://api.github.com/users/Stanford-Online/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Stanford-Online/subscriptions","organizations_url":"https://api.github.com/users/Stanford-Online/orgs","repos_url":"https://api.github.com/users/Stanford-Online/repos","events_url":"https://api.github.com/users/Stanford-Online/events{/privacy}","received_events_url":"https://api.github.com/users/Stanford-Online/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/Stanford-Online/edx-platform","description":"the edX learning management system (LMS) and course authoring tool, Studio","fork":true,"url":"https://api.github.com/repos/Stanford-Online/edx-platform","forks_url":"https://api.github.com/repos/Stanford-Online/edx-platform/forks","keys_url":"https://api.github.com/repos/Stanford-Online/edx-platform/keys{/key_id}","collaborators_url":"https://api.github.com/repos/Stanford-Online/edx-platform/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/Stanford-Online/edx-platform/teams","hooks_url":"https://api.github.com/repos/Stanford-Online/edx-platform/hooks","issue_events_url":"https://api.github.com/repos/Stanford-Online/edx-platform/issues/events{/number}","events_url":"https://api.github.com/repos/Stanford-Online/edx-platform/events","assignees_url":"https://api.github.com/repos/Stanford-Online/edx-platform/assignees{/user}","branches_url":"https://api.github.com/repos/Stanford-Online/edx-platform/branches{/branch}","tags_url":"https://api.github.com/repos/Stanford-Online/edx-platform/tags","blobs_url":"https://api.github.com/repos/Stanford-Online/edx-platform/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/Stanford-Online/edx-platform/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/Stanford-Online/edx-platform/git/refs{/sha}","trees_url":"https://api.github.com/repos/Stanford-Online/edx-platform/git/trees{/sha}","statuses_url":"https://api.github.com/repos/Stanford-Online/edx-platform/statuses/{sha}","languages_url":"https://api.github.com/repos/Stanford-Online/edx-platform/languages","stargazers_url":"https://api.github.com/repos/Stanford-Online/edx-platform/stargazers","contributors_url":"https://api.github.com/repos/Stanford-Online/edx-platform/contributors","subscribers_url":"https://api.github.com/repos/Stanford-Online/edx-platform/subscribers","subscription_url":"https://api.github.com/repos/Stanford-Online/edx-platform/subscription","commits_url":"https://api.github.com/repos/Stanford-Online/edx-platform/commits{/sha}","git_commits_url":"https://api.github.com/repos/Stanford-Online/edx-platform/git/commits{/sha}","comments_url":"https://api.github.com/repos/Stanford-Online/edx-platform/comments{/number}","issue_comment_url":"https://api.github.com/repos/Stanford-Online/edx-platform/issues/comments/{number}","contents_url":"https://api.github.com/repos/Stanford-Online/edx-platform/contents/{+path}","compare_url":"https://api.github.com/repos/Stanford-Online/edx-platform/compare/{base}...{head}","merges_url":"https://api.github.com/repos/Stanford-Online/edx-platform/merges","archive_url":"https://api.github.com/repos/Stanford-Online/edx-platform/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/Stanford-Online/edx-platform/downloads","issues_url":"https://api.github.com/repos/Stanford-Online/edx-platform/issues{/number}","pulls_url":"https://api.github.com/repos/Stanford-Online/edx-platform/pulls{/number}","milestones_url":"https://api.github.com/repos/Stanford-Online/edx-platform/milestones{/number}","notifications_url":"https://api.github.com/repos/Stanford-Online/edx-platform/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/Stanford-Online/edx-platform/labels{/name}","releases_url":"https://api.github.com/repos/Stanford-Online/edx-platform/releases{/id}","created_at":"2013-07-23T19:05:46Z","updated_at":"2015-01-16T08:47:14Z","pushed_at":"2015-01-19T21:04:43Z","git_url":"git://github.com/Stanford-Online/edx-platform.git","ssh_url":"git@github.com:Stanford-Online/edx-platform.git","clone_url":"https://github.com/Stanford-Online/edx-platform.git","svn_url":"https://github.com/Stanford-Online/edx-platform","homepage":"http://code.edx.org/","size":366563,"stargazers_count":9,"watchers_count":9,"language":"Python","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":2,"mirror_url":null,"open_issues_count":51,"forks":2,"open_issues":51,"watchers":9,"default_branch":"master"}},"base":{"label":"Stanford-Online:master","ref":"master","sha":"17888bb993e7d35b322a73362d1e8e05b95d1c93","user":{"login":"Stanford-Online","id":2159497,"avatar_url":"https://avatars.githubusercontent.com/u/2159497?v=3","gravatar_id":"","url":"https://api.github.com/users/Stanford-Online","html_url":"https://github.com/Stanford-Online","followers_url":"https://api.github.com/users/Stanford-Online/followers","following_url":"https://api.github.com/users/Stanford-Online/following{/other_user}","gists_url":"https://api.github.com/users/Stanford-Online/gists{/gist_id}","starred_url":"https://api.github.com/users/Stanford-Online/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Stanford-Online/subscriptions","organizations_url":"https://api.github.com/users/Stanford-Online/orgs","repos_url":"https://api.github.com/users/Stanford-Online/repos","events_url":"https://api.github.com/users/Stanford-Online/events{/privacy}","received_events_url":"https://api.github.com/users/Stanford-Online/received_events","type":"Organization","site_admin":false},"repo":{"id":11616657,"name":"edx-platform","full_name":"Stanford-Online/edx-platform","owner":{"login":"Stanford-Online","id":2159497,"avatar_url":"https://avatars.githubusercontent.com/u/2159497?v=3","gravatar_id":"","url":"https://api.github.com/users/Stanford-Online","html_url":"https://github.com/Stanford-Online","followers_url":"https://api.github.com/users/Stanford-Online/followers","following_url":"https://api.github.com/users/Stanford-Online/following{/other_user}","gists_url":"https://api.github.com/users/Stanford-Online/gists{/gist_id}","starred_url":"https://api.github.com/users/Stanford-Online/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Stanford-Online/subscriptions","organizations_url":"https://api.github.com/users/Stanford-Online/orgs","repos_url":"https://api.github.com/users/Stanford-Online/repos","events_url":"https://api.github.com/users/Stanford-Online/events{/privacy}","received_events_url":"https://api.github.com/users/Stanford-Online/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/Stanford-Online/edx-platform","description":"the edX learning management system (LMS) and course authoring tool, Studio","fork":true,"url":"https://api.github.com/repos/Stanford-Online/edx-platform","forks_url":"https://api.github.com/repos/Stanford-Online/edx-platform/forks","keys_url":"https://api.github.com/repos/Stanford-Online/edx-platform/keys{/key_id}","collaborators_url":"https://api.github.com/repos/Stanford-Online/edx-platform/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/Stanford-Online/edx-platform/teams","hooks_url":"https://api.github.com/repos/Stanford-Online/edx-platform/hooks","issue_events_url":"https://api.github.com/repos/Stanford-Online/edx-platform/issues/events{/number}","events_url":"https://api.github.com/repos/Stanford-Online/edx-platform/events","assignees_url":"https://api.github.com/repos/Stanford-Online/edx-platform/assignees{/user}","branches_url":"https://api.github.com/repos/Stanford-Online/edx-platform/branches{/branch}","tags_url":"https://api.github.com/repos/Stanford-Online/edx-platform/tags","blobs_url":"https://api.github.com/repos/Stanford-Online/edx-platform/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/Stanford-Online/edx-platform/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/Stanford-Online/edx-platform/git/refs{/sha}","trees_url":"https://api.github.com/repos/Stanford-Online/edx-platform/git/trees{/sha}","statuses_url":"https://api.github.com/repos/Stanford-Online/edx-platform/statuses/{sha}","languages_url":"https://api.github.com/repos/Stanford-Online/edx-platform/languages","stargazers_url":"https://api.github.com/repos/Stanford-Online/edx-platform/stargazers","contributors_url":"https://api.github.com/repos/Stanford-Online/edx-platform/contributors","subscribers_url":"https://api.github.com/repos/Stanford-Online/edx-platform/subscribers","subscription_url":"https://api.github.com/repos/Stanford-Online/edx-platform/subscription","commits_url":"https://api.github.com/repos/Stanford-Online/edx-platform/commits{/sha}","git_commits_url":"https://api.github.com/repos/Stanford-Online/edx-platform/git/commits{/sha}","comments_url":"https://api.github.com/repos/Stanford-Online/edx-platform/comments{/number}","issue_comment_url":"https://api.github.com/repos/Stanford-Online/edx-platform/issues/comments/{number}","contents_url":"https://api.github.com/repos/Stanford-Online/edx-platform/contents/{+path}","compare_url":"https://api.github.com/repos/Stanford-Online/edx-platform/compare/{base}...{head}","merges_url":"https://api.github.com/repos/Stanford-Online/edx-platform/merges","archive_url":"https://api.github.com/repos/Stanford-Online/edx-platform/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/Stanford-Online/edx-platform/downloads","issues_url":"https://api.github.com/repos/Stanford-Online/edx-platform/issues{/number}","pulls_url":"https://api.github.com/repos/Stanford-Online/edx-platform/pulls{/number}","milestones_url":"https://api.github.com/repos/Stanford-Online/edx-platform/milestones{/number}","notifications_url":"https://api.github.com/repos/Stanford-Online/edx-platform/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/Stanford-Online/edx-platform/labels{/name}","releases_url":"https://api.github.com/repos/Stanford-Online/edx-platform/releases{/id}","created_at":"2013-07-23T19:05:46Z","updated_at":"2015-01-16T08:47:14Z","pushed_at":"2015-01-19T21:04:43Z","git_url":"git://github.com/Stanford-Online/edx-platform.git","ssh_url":"git@github.com:Stanford-Online/edx-platform.git","clone_url":"https://github.com/Stanford-Online/edx-platform.git","svn_url":"https://github.com/Stanford-Online/edx-platform","homepage":"http://code.edx.org/","size":366563,"stargazers_count":9,"watchers_count":9,"language":"Python","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":2,"mirror_url":null,"open_issues_count":51,"forks":2,"open_issues":51,"watchers":9,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/Stanford-Online/edx-platform/pulls/169"},"html":{"href":"https://github.com/Stanford-Online/edx-platform/pull/169"},"issue":{"href":"https://api.github.com/repos/Stanford-Online/edx-platform/issues/169"},"comments":{"href":"https://api.github.com/repos/Stanford-Online/edx-platform/issues/169/comments"},"review_comments":{"href":"https://api.github.com/repos/Stanford-Online/edx-platform/pulls/169/comments"},"review_comment":{"href":"https://api.github.com/repos/Stanford-Online/edx-platform/pulls/comments/{number}"},"commits":{"href":"https://api.github.com/repos/Stanford-Online/edx-platform/pulls/169/commits"},"statuses":{"href":"https://api.github.com/repos/Stanford-Online/edx-platform/statuses/ea94939cb1cf94b1e882fd85ff2b587f0432dc0c"}}}}