diff --git a/app/assets/javascripts/about/index.js b/app/assets/javascripts/about/index.js new file mode 100644 index 000000000..7980f45dc --- /dev/null +++ b/app/assets/javascripts/about/index.js @@ -0,0 +1,24 @@ +function loadProgressStats(){ + stats = window.progressData[window.activeProjectID] + $('#num_vulns').html(stats["num_vulns"]) + $('#perc_curated').html(stats["perc_curated"]) +} + +$( document ).ready( function() { + + $.ajax({ + url: "/api/about/progress", + dataType: 'json' + }).done(function(jsonData){ + window.progressData = jsonData; + window.activeProjectID = 0; // all projects + loadProgressStats(); + }); + + $('.project-select-pane button').click((e) => { + $('button.project-select-button').html(e.target.innerHTML); + $('#progress-project-select').foundation('close'); + window.activeProjectID = e.target.dataset.project; + loadProgressStats(); + }) +}); diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js index 2fcbde1ec..92ca0dad5 100644 --- a/app/assets/javascripts/application.js +++ b/app/assets/javascripts/application.js @@ -15,6 +15,12 @@ //= require d3 //= require modernizr //= require_tree ./global +//= require plugins/foundation.core +//= require plugins/foundation.dropdown +//= require plugins/foundation.util.keyboard +//= require plugins/foundation.util.box +//= require plugins/foundation.util.touch +//= require plugins/foundation.util.triggers //= require foundation //= require moment/moment //= require datatables.net/js/jquery.dataTables diff --git a/app/assets/javascripts/curate.js b/app/assets/javascripts/curate.js new file mode 100644 index 000000000..67aedd88e --- /dev/null +++ b/app/assets/javascripts/curate.js @@ -0,0 +1,13 @@ +function loadProgressStats(projectID){ + +} + +$( document ).ready( function() { + + + + $('.project-select-pane button').click((e) => { + let projectID = e.target.dataset.project; + + }) +}); diff --git a/app/assets/stylesheets/_settings.scss b/app/assets/stylesheets/_settings.scss index ed6ce4abb..a9492cc49 100644 --- a/app/assets/stylesheets/_settings.scss +++ b/app/assets/stylesheets/_settings.scss @@ -396,7 +396,7 @@ $dropdownmenu-arrows: true; $dropdownmenu-arrow-color: $anchor-color; $dropdownmenu-arrow-size: 6px; $dropdownmenu-arrow-padding: 1.5rem; -$dropdownmenu-min-width: 200px; +$dropdownmenu-min-width: 150px; $dropdownmenu-background: $white; $dropdownmenu-submenu-background: $dropdownmenu-background; $dropdownmenu-padding: $global-menu-padding; diff --git a/app/assets/stylesheets/about.scss b/app/assets/stylesheets/about.scss new file mode 100644 index 000000000..e69de29bb diff --git a/app/assets/stylesheets/common/icons.scss b/app/assets/stylesheets/common/icons.scss index 08078d42e..f13e3a397 100644 --- a/app/assets/stylesheets/common/icons.scss +++ b/app/assets/stylesheets/common/icons.scss @@ -96,6 +96,7 @@ $fa-font-path: "@fortawesome/fontawesome-free/webfonts"; .vhp-icon-cloud { @extend .fi-cloud; } .vhp-icon-cogs { @extend .fas; @extend .fa-cogs; } .vhp-icon-contest { @extend .fas; @extend .fa-trophy; } +.vhp-icon-curate { @extend .fas; @extend .fa-comment-medical; } .vhp-icon-default { @extend .fas; @extend .fa-clipboard-check; } .vhp-icon-dependency { @include vhp-material-icon('device_hub') } .vhp-icon-distrust-input{ @extend .fas; @extend .fa-door-closed; } diff --git a/app/assets/stylesheets/common/vhp.scss b/app/assets/stylesheets/common/vhp.scss index aa67a1190..74870a7f6 100644 --- a/app/assets/stylesheets/common/vhp.scss +++ b/app/assets/stylesheets/common/vhp.scss @@ -90,11 +90,11 @@ hr { } .dropdown.menu > li.is-dropdown-submenu-parent > a::after{ - border-top-color: white; + border-top-color: white; // down arrow } .dropdown.menu > li.is-dropdown-submenu-parent > a:hover:after{ - border-top-color: $vhp-color; + border-top-color: $vhp-color; // down arrow } .top-bar-title { @@ -111,6 +111,38 @@ hr { top: 120%; } +.project-select-button { + background-color: $light-gray; + color: $body-font-color; + font-weight: $global-weight-bold; + +} + +.project-select-pane { + cursor: pointer; + user-select: none; + display: flex; + flex-flow: row; + border: 1pt solid $medium-gray; + justify-content: center; + width: 12em; + + + button { + flex-grow: 1; + flex-shrink: 1; + flex-basis: 0; + padding: 1em; + margin: 0.25em; + width: 100%; + text-align: center; + border: 1pt solid $medium-gray; + background-color: $light-gray; + color: $body-font-color; + font-weight: $global-weight-bold; + } +} + .subheader { font-size: 2vh; } diff --git a/app/assets/stylesheets/foundation_and_overrides.scss b/app/assets/stylesheets/foundation_and_overrides.scss index 94380da5c..c4ebc809c 100644 --- a/app/assets/stylesheets/foundation_and_overrides.scss +++ b/app/assets/stylesheets/foundation_and_overrides.scss @@ -19,7 +19,7 @@ // @include foundation-flex-classes; @include foundation-typography; @include foundation-forms; -// @include foundation-button; +@include foundation-button; // @include foundation-accordion; // @include foundation-accordion-menu; // @include foundation-badge; @@ -31,7 +31,7 @@ @include foundation-menu; @include foundation-menu-icon; // @include foundation-drilldown-menu; -// @include foundation-dropdown; +@include foundation-dropdown; @include foundation-dropdown-menu; @include foundation-responsive-embed; // @include foundation-label; diff --git a/app/assets/stylesheets/progress.scss b/app/assets/stylesheets/progress.scss new file mode 100644 index 000000000..e69de29bb diff --git a/app/assets/stylesheets/projects.scss b/app/assets/stylesheets/projects.scss new file mode 100644 index 000000000..e69de29bb diff --git a/app/controllers/about_controller.rb b/app/controllers/about_controller.rb new file mode 100644 index 000000000..0475cc266 --- /dev/null +++ b/app/controllers/about_controller.rb @@ -0,0 +1,8 @@ +class AboutController < ApplicationController + + # GET /about + def index + end + + +end diff --git a/app/controllers/curate_controller.rb b/app/controllers/curate_controller.rb index 6709f301d..8eaebdcf6 100644 --- a/app/controllers/curate_controller.rb +++ b/app/controllers/curate_controller.rb @@ -1,6 +1,7 @@ class CurateController < ApplicationController def index + @projects = Project.all num_vulns = Vulnerability.count @num_vulns_report = ActiveSupport::NumberHelper. number_to_delimited(num_vulns, :delimiter => ',') diff --git a/app/controllers/progress_controller.rb b/app/controllers/progress_controller.rb new file mode 100644 index 000000000..554709899 --- /dev/null +++ b/app/controllers/progress_controller.rb @@ -0,0 +1,42 @@ +class ProgressController < ApplicationController + + # GET /about + def index + @projects = Project.all + end + + # GET /api/about/progress + def progress + stats = {} + Project.all.each do |p| + p_stats = {} + num_vulns = Vulnerability.where(project: p).count + p_stats[:num_vulns] = num_vulns + p_stats[:num_vulns_report] = ActiveSupport::NumberHelper.number_to_delimited(num_vulns, :delimiter => ',') + num_curated = Vulnerability.curated.where(project: p).count + p_stats[:num_curated] = num_curated + p_stats[:perc_curated] = 100.0 * num_curated / num_vulns.to_f + p_stats[:perc_report] = "%.1f%%" % p_stats[:perc_curated] + num_w_fixes = Fix.select(:vulnerability_id).distinct.count + p_stats[:perc_fixes] = (100.0 * num_w_fixes / num_vulns.to_f) + # @fix_report = "%.1f%%" % @perc_fixes + # @num_vccs = Vcc.count + # @num_w_vccs = Vcc.select(:vulnerability_id).distinct.count + # @perc_vccs = (100.0 * @num_w_vccs / num_vulns.to_f) + # @vcc_report = "%.1f%%" % @perc_vccs + stats[p.id] = p_stats + end + stats[0] = all_project_stats() + render_json_for_api stats + end + + private + + def all_project_stats + { + num_vulns: Vulnerability.count + } + end + + +end diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb index f5600febb..69c2faa7d 100644 --- a/app/controllers/projects_controller.rb +++ b/app/controllers/projects_controller.rb @@ -19,7 +19,7 @@ def releases private # Use callbacks to share common setup or constraints between actions. def set_project - @project = Project.find(params[:project_id]) + @project = Project.find(params[:project_id]) end # Never trust parameters from the scary internet, only allow the white list through. diff --git a/app/views/about/index.html.erb b/app/views/about/index.html.erb new file mode 100644 index 000000000..a85ca06f0 --- /dev/null +++ b/app/views/about/index.html.erb @@ -0,0 +1,3 @@ +

About Us

+ +

Stuff about us.

diff --git a/app/views/curate/_howto.html.erb b/app/views/curate/_howto.html.erb new file mode 100644 index 000000000..ebf9250dd --- /dev/null +++ b/app/views/curate/_howto.html.erb @@ -0,0 +1,15 @@ +<%= render('shared/grid', size: 8) do %> + +

About Our Curators

+ +

Most of our curators are undergraduate software engineering students at Rochester Institute of Technology. Students are required to complete a vulnerability history study, and are allowed to volunteer their submissions to this project.

+ +<% end %> + + +<%= render('shared/grid', size: 8) do %> +

How to Curate

+ +

To be written.

+ +<% end %> diff --git a/app/views/curate/_progress.html.erb b/app/views/curate/_progress.html.erb index 28f1a9e0f..f4adc7936 100644 --- a/app/views/curate/_progress.html.erb +++ b/app/views/curate/_progress.html.erb @@ -1,6 +1,24 @@ + <%= render('shared/grid', size: 8) do %> -

Chromium Curation Progress

+ + +

The data set for this project is usable at any time, and has been used in academic literature. diff --git a/app/views/curate/index.html.erb b/app/views/curate/index.html.erb index a9ca32215..919987620 100644 --- a/app/views/curate/index.html.erb +++ b/app/views/curate/index.html.erb @@ -3,21 +3,39 @@ <% end %> <%= render('shared/grid', size: 8) do %> -

- This project relies upon a massive effort to collect, correct, and annotate vulnerability history data. We call this process curating. -

- -

About Our Curators

- -

Most of our curators are undergraduate software engineering students at Rochester Institute of Technology. Students are required to complete a vulnerability history study, and are allowed to volunteer their submissions to this project.

- +

+ This project relies upon a massive effort to collect, correct, and annotate vulnerability history data. We call this process curating. +

+ + <% end %> -<%= render 'progress' %> +
+
+ <%= render 'howto' %> +
+
+ <%= render 'progress' %> +
+
-<%= render('shared/grid', size: 8) do %> -

How to Curate

- -

To be written.

- -<% end %> +<%= javascript_include_tag "curate" %> diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb index 378261143..4ff1a334f 100644 --- a/app/views/layouts/application.html.erb +++ b/app/views/layouts/application.html.erb @@ -44,19 +44,27 @@
  • <%= link_to "Vulnerabilities", :controller =>"vulnerabilities" %>
  • <%= link_to "Code", :controller =>"filepaths" %>
  • <%= link_to "Articles", :controller =>"articles" %>
  • -
  • +
  • Tags +
  • +
  • + More +
  • -
  • <%= link_to "Curate", :controller =>'curate' %>
  • diff --git a/app/views/progress/index.html.erb b/app/views/progress/index.html.erb new file mode 100644 index 000000000..4be2d5688 --- /dev/null +++ b/app/views/progress/index.html.erb @@ -0,0 +1,69 @@ +

    VHP Progress

    +<%= render('shared/grid', size: 8) do %> + + + + + +

    + The data set for this project is usable at any time, and has been used in academic literature. +

    +<% end %> + +
    +
    + Known Vulnerabilities +
    + +
    + +
    +
    + +<%= render('shared/grid', size: 8) do %> +

    + This the current number of historical vulnerabilities that this project knows about. +

    +<% end %> + +
    + +
    + Manually Curated +
    + +
    +
    + +

    +
    +
    +
    + +
    + +<%= render('shared/grid', size: 8) do %> +

    + These are the vulnerabilities that have received a curator's attention. Curation is assigned at random so that this population is representative of the whole. +

    +<% end %> diff --git a/app/views/projects/index.html.erb b/app/views/projects/index.html.erb new file mode 100644 index 000000000..a4d637f41 --- /dev/null +++ b/app/views/projects/index.html.erb @@ -0,0 +1,19 @@ +
    +

    Case Study Projects

    + +

    TODO: make this better.

    + + <% Project.all.each do |p| %> + +
    + <%= p.name %> +
    + <% end %> +
    diff --git a/app/views/projects/show.html.erb b/app/views/projects/show.html.erb new file mode 100644 index 000000000..f68c2aacd --- /dev/null +++ b/app/views/projects/show.html.erb @@ -0,0 +1,2 @@ +

    Project Show Page

    +Under construction. diff --git a/config/initializers/assets.rb b/config/initializers/assets.rb index d674ad556..74fa219c1 100644 --- a/config/initializers/assets.rb +++ b/config/initializers/assets.rb @@ -15,14 +15,14 @@ # Precompile additional assets. # application.js, application.css, and all non-JS/CSS in app/assets folder are already added. # Rails.application.config.assets.precompile += %w( search.js ) -Rails.application.config.assets.precompile += %w( foundation-select.css ) -Rails.application.config.assets.precompile += %w( foundation-select.js ) Rails.application.config.assets.precompile += %w( foundation-icons.css ) Rails.application.config.assets.precompile += %w( application.css ) Rails.application.config.assets.precompile += %w( articles.css ) Rails.application.config.assets.precompile += %w( articles.js ) Rails.application.config.assets.precompile += %w( articles/index.js ) Rails.application.config.assets.precompile += %w( articles/show.js ) +Rails.application.config.assets.precompile += %w( about/index.js ) +Rails.application.config.assets.precompile += %w( about.css ) Rails.application.config.assets.precompile += %w( commits.css ) Rails.application.config.assets.precompile += %w( commits/index.js ) Rails.application.config.assets.precompile += %w( commits/show.js ) diff --git a/config/routes.rb b/config/routes.rb index b3bebaa6b..57a87630d 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -15,9 +15,18 @@ resources :filepaths, only: [:index, :show], via: [:get], format: false, param: :filepath_id - get :curate, to: 'curate#index' + resources :projects, only: [:index, :show], format: false, param: :project_id + + get :progress, to: 'progress#index', format: false + get :curate, to: 'curate#index', format: false + get :about, to: 'about#index', format: false scope :api do + + scope :about do + get :progress, to: 'about#progress', format: false + end + resources :vulnerabilities, only: [:index, :show], :format => false do get :events end @@ -40,7 +49,7 @@ resources :articles, only: [:index, :show], :format => false - resources :projects, only: [:index, :show], :format => false do + resources :projects, only: [:index, :show], :format => false, param: :project_id do get :releases end end diff --git a/vendor/assets/javascripts/foundation-select.js b/vendor/assets/javascripts/foundation-select.js deleted file mode 100644 index 4d05fb672..000000000 --- a/vendor/assets/javascripts/foundation-select.js +++ /dev/null @@ -1,109 +0,0 @@ -(function ( $ ) { - - $.fn.foundationSelect = function() { - - // Check to see if custom dropdowns have already been drawn - if (!$('.custom-dropdown-area').length) { - - // If custom dropdowns haven't been drawn, build and insert them - return this.each(function () { - selectPrompt = ''; - selected = ''; - translateClasses = ''; - select = $(this); - selectId = select.attr('id'); - multiple = false; - multiple = select.prop('multiple') ? true : false; - options = ''; - if (select.data('prompt')) { - selectPrompt = '' + select.data('prompt') + ''; - options = '
  • ' + selectPrompt + '
  • '; - } else { - selectPrompt = 'Choose...'; - } - select.find('option').each( function () { - if ($(this).attr('selected')) { - selected = 'selected'; - selectPrompt = "
    " + $(this).html() + "
    "; - } - if( $(this).attr('class') ) { - translateClasses = $(this).attr('class') + ' '; - } - options += '
  • ' + $(this).html() + '
  • '; - selected = ''; - }); - newButton = '
    ' + selectPrompt + ' \ -
    '; - select.hide(); - select.after(newButton); - }); - }; - }; - - // setup a listener to deal with custom dropdown clicks. - $(document).on('click', '.custom-dropdown-area li', function () { - if ($(this).hasClass('disabled')) { - return false; - } - dropdown = $(this).closest('.custom-dropdown-area'); - multiple = dropdown.data('multiple') ? true : false; - text = "
    " + $(this).find('.option-title').html() + "
    "; - value = $(this).data('value'); - totalOptions = dropdown.find('li').not('.disabled').length; - origDropdown = $(dropdown.data('orig-select')); - prompt = origDropdown.data('prompt') ? origDropdown.data('prompt') : 'Choose...'; - if (multiple) { - $(this).toggleClass('selected'); - selectedOptions = []; - selectedTitles = []; - dropdown.find('.selected').each( function () { - selectedOptions.push($(this).data('value')); - selectedTitles.push($(this).find('.option-title').html()); - }); - origDropdown.val(selectedOptions).change(); - if (selectedOptions.length) { - if (selectedOptions.length > 2) { - dropdown.find('.custom-dropdown-button').html(selectedOptions.length + ' of ' + totalOptions + ' selected'); - }else{ - dropdown.find('.custom-dropdown-button').html(selectedTitles.join(', ')); - } - }else{ - dropdown.find('.custom-dropdown-button').html(prompt); - } - }else{ - dropdown.find('li').removeClass('selected'); - Foundation.libs.dropdown.close($('#'+dropdown.find('ul').attr('id'))); - origDropdown.val(value).change(); - $(this).toggleClass('selected'); - dropdown.find('.custom-dropdown-button').html(text); - } - }); - - $(document).on('reset', 'form', function () { - if ($(this).children('.custom-dropdown-area').length) { - $(this).find('.custom-dropdown-area').each( function () { - origDropdown = $($(this).data('orig-select')); - dropdown = $(this); - multiple = dropdown.data('multiple') ? true : false; - dropdown.find('li').removeClass('selected'); - if (origDropdown.data('prompt')) { - prompt = origDropdown.data('prompt'); - }else{ - origDropdown.find('option').each( function () { - if ($(this).attr('selected')) { - prompt = $(this).html(); - dropdown.find('li[data-value="' + this.value + '"]').addClass('selected'); - } - }); - if (prompt == '') { - prompt = 'Choose...'; - } - } - dropdown.find('.custom-dropdown-button').html(prompt); - }); - } - }); - -}( jQuery )); diff --git a/vendor/assets/stylesheets/foundation-select.css b/vendor/assets/stylesheets/foundation-select.css deleted file mode 100644 index c5aa17102..000000000 --- a/vendor/assets/stylesheets/foundation-select.css +++ /dev/null @@ -1,77 +0,0 @@ -.custom-dropdown-area { - display: inline-block; - margin: 0; - position:relative; - min-width: 250px; -} - -.custom-dropdown-button { - background-color: #fafafa; - background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZlcnNpb249IjEuMSIgeD0iMTJweCIgeT0iMHB4IiB3aWR0aD0iMjRweCIgaGVpZ2h0PSIzcHgiIHZpZXdCb3g9IjAgMCA2IDMiIGVuYWJsZS1iYWNrZ3JvdW5kPSJuZXcgMCAwIDYgMyIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSI+PHBvbHlnb24gcG9pbnRzPSI1Ljk5MiwwIDIuOTkyLDMgLTAuMDA4LDAgIi8+PC9zdmc+); - background-position: 100% center; - background-repeat: no-repeat; - border: 1px solid #cccccc; - padding: 0.5rem; - padding-right: 2rem; - font-size: 0.875rem; - color: rgba(0, 0, 0, 0.75); - line-height: normal; - border-radius: 0; - height: 2.3125rem; - width: 100%; - display: block; -} - -.custom-dropdown-button.radius { - border-radius: 3px; -} - -.custom-dropdown-area:hover .custom-dropdown-button { - background-color: #f3f3f3; - border-color: #999999; - color: rgba(0, 0, 0, 0.75); -} - -.custom-dropdown-area:hover .custom-dropdown-options { - background-color: #f3f3f3; - border-color: #999999; -} - -.custom-dropdown-button:disabled { - background-color: #dddddd; - cursor: default; -} - -.custom-dropdown-options { - background-color: #fafafa; - border-top: 0; - margin-top: -3px; - max-width: 100%; - width: 100% !important; -} - -.custom-dropdown-options li { - padding: 0.5rem; -} - -.custom-dropdown-options li.disabled { - color: #ccc; -} - -.custom-dropdown-options li.disabled:hover { - background: #f3f3f3; -} - -.custom-dropdown-options li.selected:after { - content: '✓'; - float: right; -} -.custom-dropdown-options:before, .custom-dropdown-options:after { - display: none; -} - -@media only screen and (max-width: 40em) { - .custom-dropdown-options { - margin-left: -8px !important; - } -} \ No newline at end of file