diff --git a/app/controllers/guides_controller.rb b/app/controllers/guides_controller.rb index 6b5467cac..6bb87c001 100644 --- a/app/controllers/guides_controller.rb +++ b/app/controllers/guides_controller.rb @@ -32,7 +32,7 @@ def create def show if current_user? - @stats = @guide.stats(current_user) + @stats = @guide.stats_for(current_user) @next_exercise = @guide.next_exercise(current_user) else @next_exercise = @guide.first_exercise diff --git a/app/controllers/paths_controller.rb b/app/controllers/paths_controller.rb new file mode 100644 index 000000000..d1ef8d8b9 --- /dev/null +++ b/app/controllers/paths_controller.rb @@ -0,0 +1,7 @@ +class PathsController < ApplicationController + before_action :authenticate! + + def show + @path = Path.find(params[:id]) + end +end diff --git a/app/controllers/submissions_controller.rb b/app/controllers/submissions_controller.rb index 13469167f..da2a22b46 100644 --- a/app/controllers/submissions_controller.rb +++ b/app/controllers/submissions_controller.rb @@ -1,6 +1,8 @@ -class SubmissionsController < ApplicationController #FIXME remove +class SubmissionsController < ApplicationController + include NestedInUser + before_action :authenticate! def index - @submissions = paginated current_user.submissions + @submissions = paginated @user.submissions.order(updated_at: :desc), 50 end end diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 35494e0e7..def15199f 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -31,15 +31,13 @@ def tab_list(tabs) end def next_guides_box(guide, options={}) + return if guide.path.blank? + suggested = guide.next_guides if suggested.empty? - nil - elsif suggested.size == 1 || options[:only_first] - link_to t(:next_guide), suggested.first, class: 'btn btn-success' + t :path_finished, path: link_to_path(guide.path) else - ('').html_safe + link_to t(:next_guide, name: suggested.first.name), suggested.first, class: 'btn btn-success' end end diff --git a/app/helpers/concerns/with_breadcrumbs.rb b/app/helpers/concerns/with_breadcrumbs.rb new file mode 100644 index 000000000..27d2986ca --- /dev/null +++ b/app/helpers/concerns/with_breadcrumbs.rb @@ -0,0 +1,23 @@ +module WithBreadcrumbs + def exercise_breadcrumb(e) + base = link_to_exercise e + if e.guide + "#{guide_breadcrumb(e.guide)}/#{base}".html_safe + else + base + end + end + + def guide_breadcrumb(g) + base = link_to_guide g + if g.path + "#{path_breadcrumb(g.path)}/#{base}".html_safe + else + base + end + end + + def path_breadcrumb(p) + link_to_path p + end +end diff --git a/app/helpers/concerns/with_links_rendering.rb b/app/helpers/concerns/with_links_rendering.rb index c7d944d68..105b6ffb5 100644 --- a/app/helpers/concerns/with_links_rendering.rb +++ b/app/helpers/concerns/with_links_rendering.rb @@ -15,4 +15,7 @@ def link_to_user(user) link_to user.name, user end + def link_to_path(path) + link_to path.name, path + end end diff --git a/app/helpers/concerns/with_stats_rendering.rb b/app/helpers/concerns/with_stats_rendering.rb index f165bd6f5..077112f11 100644 --- a/app/helpers/concerns/with_stats_rendering.rb +++ b/app/helpers/concerns/with_stats_rendering.rb @@ -1,5 +1,5 @@ module WithStatsRendering - def stats(stats, k) + def stats_html(stats, k) "#{stats.send k} #{status_icon(k)} ".html_safe end diff --git a/app/helpers/user_helper.rb b/app/helpers/user_helper.rb new file mode 100644 index 000000000..b9c35f581 --- /dev/null +++ b/app/helpers/user_helper.rb @@ -0,0 +1,3 @@ +module UserHelper + include WithBreadcrumbs +end diff --git a/app/models/category.rb b/app/models/category.rb index 9a8740c7f..d9bc615a0 100644 --- a/app/models/category.rb +++ b/app/models/category.rb @@ -6,7 +6,7 @@ class Category < ActiveRecord::Base validates_presence_of :name, :description, :image_url - markup_on :description + markup_on :description, :long_description, :links def single_path? paths.size == 1 diff --git a/app/models/concerns/with_siblings.rb b/app/models/concerns/with_siblings.rb index e9bd98b7f..521594ff5 100644 --- a/app/models/concerns/with_siblings.rb +++ b/app/models/concerns/with_siblings.rb @@ -16,5 +16,13 @@ def previous def orphan? parent.nil? end + + def contextualized_name + if parent + "#{position}. #{name}" + else + name + end + end end diff --git a/app/models/exercise.rb b/app/models/exercise.rb index 8b620864a..92fe6e983 100644 --- a/app/models/exercise.rb +++ b/app/models/exercise.rb @@ -46,14 +46,6 @@ def generate_original_id! update!(original_id: id) unless original_id end - def contextualized_title - if guide - "#{position}. #{title}" - else - title - end - end - def collaborator?(user) guide.present? && guide.authored_by?(user) end @@ -76,4 +68,8 @@ def defaults def self.default_layout layouts.keys[0] end + + def name #FIXME remove + title + end end diff --git a/app/models/guide.rb b/app/models/guide.rb index 2c41917eb..1842963b5 100644 --- a/app/models/guide.rb +++ b/app/models/guide.rb @@ -13,7 +13,8 @@ class Guide < ActiveRecord::Base WithLocale, WithCollaborators, WithPath, - WithExercises + WithExercises, + WithStats #TODO rename name to title. This helps building also generic link_to compoenetns has_many :imports, -> { order(created_at: :desc)} @@ -32,10 +33,6 @@ def search_tags exercises.flat_map(&:search_tags).uniq end - def stats(user) - Stats.from_statuses exercises.map { |it| it.status_for(user) } - end - def github_url "https://github.com/#{github_repository}" end diff --git a/app/models/language.rb b/app/models/language.rb index 7baaa98b6..994890e3c 100644 --- a/app/models/language.rb +++ b/app/models/language.rb @@ -10,7 +10,7 @@ class Language < ActiveRecord::Base validates :name, presence: true, uniqueness: {case_sensitive: false} - markup_on :test_syntax_hint + markup_on :test_syntax_hint, :description def run_tests!(request) bridge.run_tests!(request) diff --git a/app/models/path.rb b/app/models/path.rb index 228d60cdb..9f9560e95 100644 --- a/app/models/path.rb +++ b/app/models/path.rb @@ -1,9 +1,11 @@ class Path < ActiveRecord::Base - include WithGuides + include WithGuides, WithStats belongs_to :category belongs_to :language + has_many :exercises, through: :guides + def name if category.single_path? category.name diff --git a/app/models/stats.rb b/app/models/stats.rb index 8771e6c60..33a64c37f 100644 --- a/app/models/stats.rb +++ b/app/models/stats.rb @@ -35,16 +35,20 @@ def started? submitted > 0 end + def resolved_ratio + ratio resolved + end + def passed_ratio - 100 * passed / total.to_f + ratio passed end def passed_with_warnings_ratio - 100 * passed_with_warnings / total.to_f + ratio passed_with_warnings end def failed_ratio - 100 * failed / total.to_f + ratio failed end def to_h(&key) @@ -60,4 +64,10 @@ def self.from_statuses(statuses) accum end) end + + private + + def ratio(x) + (100 * x / total.to_f).round(2) + end end diff --git a/app/models/user.rb b/app/models/user.rb index f7823043b..be16d9f8d 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -18,7 +18,9 @@ class User < ActiveRecord::Base class_name: 'Exercise', source: :exercise - has_many :submitted_guides, -> { uniq.order(:position) }, through: :submitted_exercises, class_name: 'Guide', source: :guide + has_many :submitted_guides, -> { uniq }, through: :submitted_exercises, class_name: 'Guide', source: :guide + + has_many :submitted_paths, -> { uniq }, through: :submitted_guides, class_name: 'Path', source: :path has_many :solved_exercises, -> { where('submissions.status' => Status::Passed.to_i).uniq }, diff --git a/app/models/with_stats.rb b/app/models/with_stats.rb new file mode 100644 index 000000000..2cca19ed8 --- /dev/null +++ b/app/models/with_stats.rb @@ -0,0 +1,5 @@ +module WithStats + def stats_for(user) + Stats.from_statuses exercises.map { |it| it.status_for(user) } + end +end diff --git a/app/views/exercise_submissions/_results.html.erb b/app/views/exercise_submissions/_results.html.erb index 5d11b3fb2..ff9185d89 100644 --- a/app/views/exercise_submissions/_results.html.erb +++ b/app/views/exercise_submissions/_results.html.erb @@ -1,6 +1,6 @@ <% @guide = @exercise.guide - @stats = @guide.stats(current_user) if @guide + @stats = @guide.stats_for(current_user) if @guide %> @@ -56,7 +56,7 @@ class: 'text-warning warning pull-left' %> <%= next_button(@exercise) %> - <%= next_guides_box(@guide, only_first: true) if @stats.try &:done? %> + <%= next_guides_box(@guide) if @stats.try &:done? %>