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
- ('
' +
- suggested.map {|it| "- #{link_to_guide(it)}
"}.join("\n") +
- '
').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? %>