2 | <% if @prev_lesson.present? %>
3 | <%= link_to lesson_classroom_path(@classroom, lesson_id: @prev_lesson.id) do %>
4 |
5 | <% end %>
6 | <% end %>
7 |
8 |
9 |
14 | <% if @next_lesson.present? %>
15 | <%= link_to lesson_classroom_path(@classroom, lesson_id: @next_lesson.id) do %>
16 |
17 | <% end %>
18 | <% end %>
19 |
20 |
--------------------------------------------------------------------------------
/app/views/classrooms/_lesson_top_links.html.erb:
--------------------------------------------------------------------------------
1 |
2 | <%= link_to "Course page", course_path(@classroom.course) %>
3 | <% if current_user.present? && @classroom.has_access?(current_user) %>
4 | | <%= link_to "Your progress", progress_classroom_path(@classroom) %>
5 | <% if @classroom.is_admin?(current_user) %>
6 | | <%= link_to "Users", users_classroom_path(@classroom) %>
7 | <% end %>
8 | <% end %>
9 |
10 |
--------------------------------------------------------------------------------
/app/views/classrooms/_runtime_errors_details.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | <%= render partial: 'lesson_top_links' %>
6 |
7 |
8 |
Your task runs: <%= @task.title %>
9 |
10 |
11 |
12 |
13 | <%= render partial: 'task_runs' %>
14 |
15 |
16 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/app/views/classrooms/task_solution.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | <%= render partial: 'lesson_top_links' %>
6 |
7 |
8 |
Solution: <%= @task.title %>
9 |
10 |
11 |
12 |
13 |
14 |
15 | <% if @task.solution.present? %>
16 | <%= render inline: @task.solution %>
17 | <% else %>
18 | There is no solution for this task yet.
19 | <% end %>
20 |
21 |
22 |
23 |
24 |
27 |
28 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/app/views/courses/_course.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
<%= link_to course.title, course_path(course) %>
3 |
4 | <%= render inline: course.description %>
5 |
6 | <% if user_signed_in? && current_user.is_teacher? %>
7 |
16 | <% end %>
17 |
18 |
--------------------------------------------------------------------------------
/app/views/courses/_edit_visibility.html.erb:
--------------------------------------------------------------------------------
1 | <%= form_for(course_item, layout: :inline) do |f| %>
2 | <%= f.hidden_field :visible, value: !course_item.visible %>
3 | <%= button_tag class: "btn btn-sm btn-#{ course_item.visible ? 'primary' : 'default' }" do %>
4 |
5 | <% end %>
6 | <% end %>
7 |
--------------------------------------------------------------------------------
/app/views/courses/_menu.html.erb:
--------------------------------------------------------------------------------
1 |
20 |
--------------------------------------------------------------------------------
/app/views/courses/_menu_new.html.erb:
--------------------------------------------------------------------------------
1 |
30 |
--------------------------------------------------------------------------------
/app/views/courses/edit.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 |
<%= link_to @course.title, course_path(@course) %>
4 | Edit course details
5 |
6 |
7 |
8 |
9 | <%= link_to 'Edit course structure', edit_structure_course_path(@course), class: 'btn btn-primary' %>
10 | <% if @course.is_main %>
11 | <%= link_to 'Unset main', unset_main_course_path(@course), class: 'btn btn-primary', method: :post %>
12 | <% else %>
13 | <%= link_to 'Set main', set_main_course_path(@course), class: 'btn btn-primary', method: :post %>
14 | <% end %>
15 |
16 |
17 | <%= render partial: 'fields' %>
18 |
--------------------------------------------------------------------------------
/app/views/courses/index.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 | <% unless @admin_courses.empty? && @student_courses.empty? && @other_courses.empty? %>
4 | <% unless @admin_courses.empty? %>
5 |
6 |
Courses where you are an admin
7 | <%= render @admin_courses %>
8 |
9 | <% end %>
10 | <% unless @student_courses.empty? %>
11 |
12 |
Your current courses
13 | <%= render @student_courses %>
14 |
15 | <% end %>
16 | <% unless @other_courses.empty? %>
17 |
18 |
19 |
20 | <% if @admin_courses.empty? && @student_courses.empty? %>
21 | Available courses
22 | <% else %>
23 | More available courses
24 | <% end %>
25 |
26 | <%= render @other_courses %>
27 |
28 | <% end %>
29 | <% else %>
30 |
No courses are available at this time
31 | <% end %>
32 |
33 |
34 |
--------------------------------------------------------------------------------
/app/views/courses/new.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 |
Start a new course
4 |
5 |
6 |
7 | <%= render partial: 'fields' %>
8 |
--------------------------------------------------------------------------------
/app/views/devise/confirmations/new.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 |
Resend confirmation instructions
4 |
5 |
6 |
7 |
22 |
23 |
24 |
25 | <%= render "devise/shared/links" %>
26 |
27 |
28 |
--------------------------------------------------------------------------------
/app/views/devise/mailer/confirmation_instructions.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
Welcome to HiredInTech's Interview Training Camp!
5 |
6 |
To finalize your account creation please confirm your email through the link below.
7 |
8 |
9 | <%= link_to 'Confirm my account', confirmation_url(@resource, confirmation_token: @token), style: "padding: 10px 15px; background: #339933; color: #fff; text-decoration: none; font-size: 18px;" %>
10 |
11 |
12 |
--------------------------------------------------------------------------------
/app/views/devise/mailer/reset_password_instructions.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | <% if @resource.name.present? %>
7 |
Hello, <%= @resource.name %>!
8 | <% else %>
9 |
Hello!
10 | <% end %>
11 |
12 |
Someone has requested a link to change your password. You can do this through the link below.
13 |
14 |
<%= link_to 'Change my password', edit_password_url(@resource, reset_password_token: @token) %>
15 |
16 |
If you didn't request this, please ignore this email.
17 |
Your password won't change until you access the link above and create a new one.
18 |
19 |
--------------------------------------------------------------------------------
/app/views/devise/mailer/unlock_instructions.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | <% if @resource.name.present? %>
7 |
Hello, <%= @resource.name %>!
8 | <% else %>
9 |
Hello!
10 | <% end %>
11 |
12 |
Your account has been locked due to an excessive number of unsuccessful log in attempts.
13 |
14 |
Click the link below to unlock your account:
15 |
16 |
<%= link_to 'Unlock my account', unlock_url(@resource, unlock_token: @token) %>
17 |
18 |
--------------------------------------------------------------------------------
/app/views/devise/passwords/edit.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 |
Change your password
4 |
5 |
6 |
7 |
27 |
28 |
29 |
30 | <%= render "devise/shared/links" %>
31 |
32 |
33 |
--------------------------------------------------------------------------------
/app/views/devise/passwords/new.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 |
Forgot your password?
4 |
5 |
6 |
7 |
22 |
23 |
24 |
25 | <%= render "devise/shared/links" %>
26 |
27 |
28 |
--------------------------------------------------------------------------------
/app/views/devise/registrations/new.html.erb:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 |
29 |
30 | <%= render partial: "shared/social_buttons" %>
31 |
32 |
33 |
34 |
35 | <%= render "devise/shared/links" %>
36 |
37 |
38 |
--------------------------------------------------------------------------------
/app/views/devise/sessions/new.html.erb:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 |
31 |
32 | <%= render partial: "shared/social_buttons" %>
33 |
34 |
35 |
36 |
37 | <%= render "devise/shared/links" %>
38 |
39 |
40 |
--------------------------------------------------------------------------------
/app/views/devise/shared/_links.html.erb:
--------------------------------------------------------------------------------
1 | <%- if devise_mapping.registerable? && controller_name != 'registrations' %>
2 | <%= link_to "Not registered yet? Sign up", new_user_registration_path %>
3 | <% end -%>
4 |
5 | <%- if devise_mapping.recoverable? && controller_name != 'passwords' && controller_name != 'registrations' %>
6 | <%= link_to "Forgot your password?", new_password_path(resource_name) %>
7 | <% end -%>
8 |
9 | <%- if devise_mapping.confirmable? && controller_name != 'confirmations' %>
10 | <%= link_to "Didn't receive confirmation instructions?", new_confirmation_path(resource_name) %>
11 | <% end -%>
12 |
13 | <%- if devise_mapping.lockable? && resource_class.unlock_strategy_enabled?(:email) && controller_name != 'unlocks' %>
14 | <%= link_to "Didn't receive unlock instructions?", new_unlock_path(resource_name) %>
15 | <% end -%>
16 |
17 |
--------------------------------------------------------------------------------
/app/views/devise/unlocks/new.html.erb:
--------------------------------------------------------------------------------
1 |
Resend unlock instructions
2 |
3 | <%= form_for(resource, as: resource_name, url: unlock_path(resource_name), html: { method: :post }) do |f| %>
4 | <%= devise_error_messages! %>
5 |
6 |
7 | <%= f.label :email %>
8 | <%= f.email_field :email, autofocus: true %>
9 |
10 |
11 |
12 | <%= f.submit "Resend unlock instructions" %>
13 |
14 | <% end %>
15 |
16 | <%= render "devise/shared/links" %>
17 |
--------------------------------------------------------------------------------
/app/views/layouts/_footer.html.erb:
--------------------------------------------------------------------------------
1 |
12 |
--------------------------------------------------------------------------------
/app/views/layouts/_quizzes_header_item.html.erb:
--------------------------------------------------------------------------------
1 |
2 | Quizzes
3 |
8 |
9 |
--------------------------------------------------------------------------------
/app/views/layouts/_tasks_header_item.html.erb:
--------------------------------------------------------------------------------
1 |
2 | Tasks
3 |
9 |
10 |
--------------------------------------------------------------------------------
/app/views/layouts/application.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
HiredInTech's Training Camp for Coding Interviews
5 | <%= Gon::Base.render_data %>
6 | <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track' => true %>
7 | <%= javascript_include_tag 'application', 'data-turbolinks-track' => true %>
8 | <%= csrf_meta_tags %>
9 | <%= favicon_link_tag "favicon.png", type: "image/png", rel: "icon" %>
10 | <%= favicon_link_tag "favicon.ico", type: "image/x-icon", rel: "shortcut icon" %>
11 |
12 |
13 |
14 |
15 | <%= render partial: 'layouts/header' %>
16 |
17 |
18 | <% if notice.present? %>
19 |
20 | ×
21 | <%= notice %>
22 |
23 | <% end %>
24 |
25 | <% if alert.present? %>
26 |
27 | ×
28 | <%= alert %>
29 |
30 | <% end %>
31 |
32 | <%= yield %>
33 |
34 |
35 | <%= render partial: 'layouts/footer' %>
36 |
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/app/views/lessons/_attach_quizzes.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Attached quizzes to lesson
6 |
7 |
8 |
9 | <% if lesson.quizzes.present? %>
10 |
11 | <% lesson.quizzes.each do |quiz| %>
12 |
13 | <%= link_to quiz.title, quiz_path(quiz) %>
14 | <%= link_to "Detach", detach_quiz_lesson_path(lesson, quiz_id: quiz.id), method: :post, class: 'btn btn-danger btn-xs pull-right' %>
15 |
16 | <% end %>
17 |
18 | <% else %>
19 | No quizzes in lesson
20 | <% end %>
21 |
22 |
23 |
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/app/views/lessons/_attach_tasks.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Attached tasks to lesson
6 |
7 |
8 |
9 | <% if lesson.tasks.present? %>
10 |
11 | <% lesson.tasks.each do |task| %>
12 |
13 | <%= link_to task.title, task_path(task) %>
14 | <%= link_to "Detach", detach_task_lesson_path(lesson, task_id: task.id), method: :post, class: 'btn btn-danger btn-xs pull-right' %>
15 |
16 | <% end %>
17 |
18 | <% else %>
19 | No tasks in lesson
20 | <% end %>
21 |
22 |
23 |
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/app/views/lessons/_change_position.html.erb:
--------------------------------------------------------------------------------
1 |
2 | <% unless lesson.is_first? %>
3 | <%= button_to move_up_lesson_path(lesson), method: :post, class: 'btn btn-sm btn-primary' do %>
4 |
5 | <% end %>
6 | <% end %>
7 |
8 |
9 |
10 | <% unless lesson.is_last? %>
11 | <%= button_to move_down_lesson_path(lesson), method: :post, class: 'btn btn-sm btn-primary' do %>
12 |
13 | <% end %>
14 | <% end %>
15 |
16 |
--------------------------------------------------------------------------------
/app/views/lessons/_edit_title.html.erb:
--------------------------------------------------------------------------------
1 | <%= bootstrap_form_for(lesson, layout: :inline) do |f| %>
2 | <%= f.text_field :title, hide_label: true, class: "long-field input-sm" %>
3 | <%= f.submit "Update", class: "btn btn-sm btn-primary" %>
4 | <% end %>
5 |
--------------------------------------------------------------------------------
/app/views/lessons/_new.html.erb:
--------------------------------------------------------------------------------
1 |
tabindex="-1" role="dialog" aria-labelledby="new-lesson-modal-label">
2 |
3 |
4 |
8 | <%= bootstrap_form_for(Lesson.new) do |f| %>
9 |
10 |
11 | <%= f.text_field :title, class: "input-lg", placeholder: "New lesson title", hide_label: true %>
12 | <%= f.hidden_field :section_id, value: section.id %>
13 |
14 |
15 |
16 |
20 | <% end %>
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/app/views/lessons/edit.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 |
<%= link_to 'Back to course structure', edit_structure_course_path(@lesson.section.course) %>
4 | Edit lesson "<%= @lesson.title %>"
5 |
6 |
7 |
8 | <%= render partial: 'attach_tasks', locals: { lesson: @lesson } %>
9 | <%= render partial: 'attach_quizzes', locals: { lesson: @lesson } %>
10 |
11 | <%= bootstrap_form_for(@lesson) do |f| %>
12 |
13 |
14 | <%= f.text_area :markdown_content, rows: 20, label: "Lesson contents via markdown (preview doesn't support code blocks and tables)", "data-provide" => "markdown", placeholder: "Content of lesson" %>
15 |
16 |
17 |
18 |
19 |
20 | <%= f.text_area :markdown_sidebar_content, rows: 20, label: "Lesson sidebar contents via markdown (preview doesn't support code blocks and tables)", "data-provide" => "markdown", placeholder: "Sidebar content of lesson" %>
21 |
22 |
23 |
24 |
25 | <%= f.submit "Save", class: "btn btn-primary" %>
26 | <%= link_to "Cancel", edit_structure_course_path(@lesson.section.course), class: "btn btn-default" %>
27 |
28 | <% end %>
29 |
--------------------------------------------------------------------------------
/app/views/pages/contact.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | Any suggestions, comments, advice related to HiredInTech are very welcome. We may take some time to reply but we will do our best to be quick enough.
10 |
11 |
12 |
13 | Feel free to drop us a line at team@hiredintech.com .
14 |
15 |
16 |
17 | Or you could also use the contact widget at the bottom-right corner of the page.
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/app/views/quizzes/_admin_header.html.erb:
--------------------------------------------------------------------------------
1 | <%= link_to 'Quiz page', quiz_path(@quiz) %> |
2 | <%= link_to 'Edit quiz', edit_quiz_path(@quiz) %>
3 |
--------------------------------------------------------------------------------
/app/views/quizzes/_attempt.html.erb:
--------------------------------------------------------------------------------
1 | <%= bootstrap_form_tag(url: path_to_submit_quiz, method: :post) do |f| %>
2 | <% quiz.quiz_questions.shuffle.each do |quiz_question| %>
3 | <%= render partial: 'quizzes/quiz_question', locals: { quiz_question: quiz_question, f: f } %>
4 | <% end %>
5 |
6 |
7 |
8 | <%= f.submit 'Submit', class: 'btn btn-lg btn-primary' %>
9 |
10 |
11 | <% end %>
12 |
--------------------------------------------------------------------------------
/app/views/quizzes/_fields.html.erb:
--------------------------------------------------------------------------------
1 | <%= bootstrap_form_for(@quiz) do |f| %>
2 |
3 |
4 | <%= f.text_field :title, class: "input-lg", placeholder: "Quiz title", required: true %>
5 |
6 |
7 |
8 |
9 |
10 | <%= f.text_field :maximum_attempts, class: "input-lg", placeholder: "Maximum attempts" %>
11 |
12 |
13 |
14 | <%= f.text_field :wait_time_seconds, class: "input-lg", placeholder: "Wait time between attempts" %>
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 | <%= f.fields_for :quiz_questions, f.object.quiz_questions.ordered do |qqf| %>
23 | <%= render "quiz_question_fields", f: qqf %>
24 | <% end %>
25 |
26 |
27 | <%= link_to_add_field 'Add question', f, :quiz_questions %>
28 |
29 |
30 |
31 |
32 |
33 | <%= f.submit "Save", class: "btn btn-primary" %>
34 |
35 | <% end %>
36 |
--------------------------------------------------------------------------------
/app/views/quizzes/_quiz.html.erb:
--------------------------------------------------------------------------------
1 |
2 | <%= link_to quiz.title, quiz_path(quiz) %>
3 | <%= link_to quiz.creator.display_name, user_path(quiz.creator) %>
4 |
5 | <%= link_to edit_quiz_path(quiz), class: "btn btn-sm btn-warning", title: "Edit" do %>
6 |
7 | <% end %>
8 | <%= link_to quiz_path(quiz), method: :delete, class: "btn btn-sm btn-danger", data: { confirm: "Are you sure you want to delete quiz \"#{ quiz.title }\"?" } do %>
9 |
10 | <% end %>
11 |
12 |
13 |
--------------------------------------------------------------------------------
/app/views/quizzes/_quiz_answer_fields.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | <%= f.text_area :markdown_content, label: "Question answer (using markdown)", "data-provide" => "markdown", placeholder: "Answer text", required: true, class: 'quiz-markdown-editor' %>
6 |
7 |
8 | <%= f.check_box :correct %>
9 |
10 |
11 | <%= link_to_remove_field('Remove answer', f) %>
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/app/views/quizzes/_quiz_question.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | <%= render inline: quiz_question.content %>
6 |
7 |
8 | <% if quiz_question.multiple_choice? %>
9 |
10 | <% quiz_question.quiz_answers.each do |quiz_answer| %>
11 |
12 | <%= f.check_box "quiz_attempt[#{ quiz_question.id }][multiple_answers][#{ quiz_answer.id }]", label: simple_format(quiz_answer.content) %>
13 |
14 | <% end %>
15 |
16 | <% else %>
17 | <%= f.text_field "quiz_attempt[#{ quiz_question.id }][freetext_answer]", hide_label: true %>
18 | <% end %>
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/app/views/quizzes/_quiz_question_fields.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 | <%= f.text_area :markdown_content, rows: 5, label: "Question text (using markdown)", "data-provide" => "markdown", placeholder: "Question text", required: true, class: 'quiz-markdown-editor' %>
4 |
5 | <%= f.text_area :markdown_explanation, rows:5, label: "Question explanation (using markdown)", "data-provide" => "markdown", placeholder: "Question text", class: 'quiz-markdown-editor' %>
6 |
7 | <%= f.form_group :question_type, label: { text: "Type" }, help: "Multiple choice versus free text" do %>
8 | <%= f.radio_button :question_type, QuizQuestion::TYPE_MULTIPLE_CHOICE, label: "Multiple choice", class: 'question-type' %>
9 | <%= f.radio_button :question_type, QuizQuestion::TYPE_FREETEXT, label: "Freetext", class: 'question-type' %>
10 | <% end %>
11 |
12 |
13 | <%= f.text_area :freetext_regex, placeholder: 'Question freetext regex' %>
14 |
15 |
16 |
17 |
18 | <%= f.fields_for :quiz_answers do |qaf| %>
19 | <%= render "quiz_answer_fields", f: qaf %>
20 | <% end %>
21 |
22 | <%= link_to_add_field 'Add answer', f, :quiz_answers %>
23 |
24 |
25 | <%= link_to_remove_field('Remove question', f) %>
26 |
27 |
28 |
--------------------------------------------------------------------------------
/app/views/quizzes/_show_attempt.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
<%= quiz_attempt.created_at.to_s(:db) %>
7 |
8 |
9 |
10 |
11 |
14 |
15 |
<%= quiz_attempt.score.round(2) %>
16 |
17 |
18 |
19 | <% quiz.quiz_questions.each do |quiz_question| %>
20 | <%= render partial: 'quizzes/quiz_question_attempt', locals: { quiz_question: quiz_question, attempt_answers: attempt_answers } %>
21 | <% end %>
22 |
--------------------------------------------------------------------------------
/app/views/quizzes/all_attempts.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 | All attempts: <%= @all_count %>
4 |
5 |
6 | <% if @quiz_attempts.present? %>
7 | <%= paginate @quiz_attempts, theme: 'twitter-bootstrap-3' %>
8 |
9 |
10 | Time of attempt
11 | User
12 | Quiz
13 | Score
14 |
15 | <% @quiz_attempts.each do |quiz_attempt| %>
16 |
17 | <%= link_to quiz_attempt.created_at.to_s(:db), show_attempt_quiz_path(quiz_attempt.quiz, quiz_attempt_id: quiz_attempt.id) %>
18 | <%= link_to quiz_attempt.user.display_name, user_path(quiz_attempt.user) %>
19 | <%= link_to quiz_attempt.quiz.title, quiz_path(quiz_attempt.quiz) %>
20 | <%= quiz_attempt.score.round(2) %>
21 |
22 | <% end %>
23 |
24 | <%= paginate @quiz_attempts, theme: 'twitter-bootstrap-3' %>
25 | <% else %>
26 |
No attempts so far
27 | <% end %>
28 |
29 |
30 |
--------------------------------------------------------------------------------
/app/views/quizzes/attempt.html.erb:
--------------------------------------------------------------------------------
1 | <%= render partial: 'admin_header' %>
2 |
3 |
4 |
5 |
<%= @quiz.title %>
6 |
7 |
8 |
9 |
10 |
11 | <%= render partial: 'attempt', locals: { quiz: @quiz, path_to_submit_quiz: submit_quiz_path(@quiz) } %>
12 |
13 |
14 |
--------------------------------------------------------------------------------
/app/views/quizzes/edit.html.erb:
--------------------------------------------------------------------------------
1 | <%= render partial: 'admin_header' %>
2 |
3 |
4 |
5 |
Edit quiz
6 |
7 |
8 |
9 | <%= render partial: 'fields' %>
10 |
--------------------------------------------------------------------------------
/app/views/quizzes/index.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 |
Quizzes list
4 |
5 |
6 |
7 |
8 |
9 | <% if @quizzes.empty? %>
10 | No quizzes created yet
11 | <% else %>
12 |
13 |
14 | Title
15 | Creator
16 | Actions
17 |
18 | <% @quizzes.each do |quiz| %>
19 | <%= render partial: 'quiz', locals: { quiz: quiz } %>
20 | <% end %>
21 |
22 | <% end %>
23 |
24 |
25 |
--------------------------------------------------------------------------------
/app/views/quizzes/new.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 |
Create new quiz
4 |
5 |
6 |
7 | <%= render partial: 'fields' %>
8 |
--------------------------------------------------------------------------------
/app/views/quizzes/show.html.erb:
--------------------------------------------------------------------------------
1 | <%= render partial: 'admin_header' %>
2 | <%= render partial: 'main_page', locals: { quiz: @quiz } %>
3 |
--------------------------------------------------------------------------------
/app/views/quizzes/show_attempt.html.erb:
--------------------------------------------------------------------------------
1 | <%= render partial: 'admin_header' %>
2 |
3 |
4 |
5 |
<%= @quiz.title %>
6 | User: <%= link_to @quiz_attempt.user.display_name, user_path(@quiz_attempt.user) %>
7 |
8 |
9 |
10 | <%= render partial: 'show_attempt', locals: { quiz: @quiz, quiz_attempt: @quiz_attempt, attempt_answers: @attempt_answers } %>
11 |
--------------------------------------------------------------------------------
/app/views/sections/_change_position.html.erb:
--------------------------------------------------------------------------------
1 |
2 | <% unless section.is_first? %>
3 | <%= button_to move_up_section_path(section), method: :post, class: 'btn btn-sm btn-primary' do %>
4 |
5 | <% end %>
6 | <% end %>
7 |
8 |
9 |
10 | <% unless section.is_last? %>
11 | <%= button_to move_down_section_path(section), method: :post, class: 'btn btn-sm btn-primary' do %>
12 |
13 | <% end %>
14 | <% end %>
15 |
16 |
--------------------------------------------------------------------------------
/app/views/sections/_edit_title.html.erb:
--------------------------------------------------------------------------------
1 | <%= bootstrap_form_for(section, layout: :inline) do |f| %>
2 | <%= f.text_field :title, hide_label: true, class: "long-field input-sm" %>
3 | <%= f.submit "Update", class: "btn btn-sm btn-primary" %>
4 | <% end %>
5 |
--------------------------------------------------------------------------------
/app/views/sections/_new.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
8 | <%= bootstrap_form_for(Section.new) do |f| %>
9 |
10 |
11 | <%= f.text_field :title, class: "input-lg", placeholder: "New section title", hide_label: true %>
12 | <%= f.hidden_field :course_id, value: course.id %>
13 |
14 |
15 |
16 |
20 | <% end %>
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/app/views/shared/_social_buttons.html.erb:
--------------------------------------------------------------------------------
1 |
17 |
--------------------------------------------------------------------------------
/app/views/tasks/_admin_panel.html.erb:
--------------------------------------------------------------------------------
1 | <% if current_user.is_teacher? %>
2 |
3 |
4 | <%= link_to 'View', task_path(@task), class: "btn btn-primary" %>
5 | <%= link_to 'Edit', edit_task_path(@task), class: "btn btn-primary" %>
6 | <%= link_to 'Solve', solve_task_path(@task), class: "btn btn-primary" %>
7 | <% if @task.solution.present? %>
8 | <%= link_to 'Solution', solution_task_path(@task), class: "btn btn-primary" %>
9 | <% end %>
10 | <%= link_to 'Runs', runs_task_path(@task), class: "btn btn-primary" %>
11 | <%= link_to 'Run limits', runs_limits_task_path(@task), class: "btn btn-primary" %>
12 |
13 |
14 | Memory limit: <%= @task.memory_limit_kb %> KB
15 |
16 |
17 |
18 | Time limit: <%= @task.time_limit_ms %> ms
19 |
20 |
21 |
22 |
23 |
<%= @task.title %>
24 | <% end %>
25 |
--------------------------------------------------------------------------------
/app/views/tasks/_edit_runs_limit.html.erb:
--------------------------------------------------------------------------------
1 | <%= bootstrap_form_tag(url: update_runs_limit_task_path(task, user_id: task_record.user.id), method: :post, layout: :inline) do |f| %>
2 | <%= f.text_field :new_runs_limit, value: task_record.runs_limit, hide_label: true, class: "long-field input-sm" %>
3 | <%= f.submit "Update", class: "btn btn-sm btn-primary" %>
4 | <% end %>
5 |
--------------------------------------------------------------------------------
/app/views/tasks/_run.html.erb:
--------------------------------------------------------------------------------
1 |
2 | <%= task_run.id %>
3 | <%= link_to task_run.task.title, task_path(task_run.task) %>
4 | <%= link_to truncate(task_run.user.display_name, length: 15), user_path(task_run.user) if task_run.user.present? %>
5 | <%= task_run.status %>
6 | <%= task_run.message %>
7 | <%= task_run.lang %>
8 | <%= task_run.memory_limit_kb %> KB
9 | <%= task_run.time_limit_ms %> ms
10 | <%= task_run.points %>
11 | <%= task_run.created_at.to_s(:db) %>
12 | <%= render partial: 'task_run_source_code', locals: { task_run: task_run } %>
13 |
14 |
--------------------------------------------------------------------------------
/app/views/tasks/_runs.html.erb:
--------------------------------------------------------------------------------
1 | <%= paginate task_runs, theme: 'twitter-bootstrap-3' %>
2 |
3 |
4 | ID
5 | Task
6 | User
7 | Status
8 | Message
9 | Language
10 | Memory
11 | Time
12 | Points
13 | Date
14 |
15 |
16 | <% task_runs.each do |task_run| %>
17 | <%= render partial: 'run', locals: { task_run: task_run } %>
18 | <% end %>
19 |
20 | <%= paginate task_runs, theme: 'twitter-bootstrap-3' %>
21 |
--------------------------------------------------------------------------------
/app/views/tasks/_solve.html.erb:
--------------------------------------------------------------------------------
1 |
2 | <%= label_tag :lang, "Choose programming language" %>
3 | <%= select_tag :lang, options_for_select(TaskRun::PROGRAMMING_LANGS, run.nil? ? current_user.last_programming_language : run.lang) %>
4 |
Load boilerplate code
5 |
6 | Your public class must be called 'program'.
7 |
8 |
9 |
10 |
11 |
12 | <%= label_tag :source_code, "Type your source code here" %>
13 |
14 | <%= text_area_tag :source_code, nil, style: "display:none;" %>
15 |
16 |
17 |
18 | <%= check_box_tag :show_source_code, 1, true %>
19 | Show source code publicly if solution is successful?
20 |
21 |
22 |
23 | <%= form.submit 'Submit solution', class: 'btn btn-primary' %>
24 |
25 |
--------------------------------------------------------------------------------
/app/views/tasks/_successful_run_source_code.html.erb:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 |
9 |
10 |
14 |
15 |
Language: <%= task_run.lang %>
16 |
17 | <%= render inline: highlight_source_code(task_run.source_code, task_run.lang) %>
18 |
19 |
20 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/app/views/tasks/_task.html.erb:
--------------------------------------------------------------------------------
1 |
2 | <%= link_to task.title, task_path(task) %>
3 | <%= task.task_type %>
4 | <%= link_to task.creator.display_name, user_path(task.creator) %>
5 | <%= task.external_key %>
6 |
7 | <%= link_to 'Solve', solve_task_path(task), class: "btn btn-primary btn-sm" %>
8 | <%= link_to 'Runs', runs_task_path(task), class: "btn btn-primary btn-sm" %>
9 | <%= link_to edit_task_path(task), class: "btn btn-sm btn-warning", title: "Edit" do %>
10 |
11 | <% end %>
12 | <%= link_to task_path(task), method: :delete, class: "btn btn-sm btn-danger", data: { confirm: "Are you sure you want to delete task \"#{ task.title }\"?" } do %>
13 |
14 | <% end %>
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/app/views/tasks/all_runs.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 | <%= render partial: 'runs', locals: { task_runs: @task_runs } %>
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/views/tasks/create.html.erb:
--------------------------------------------------------------------------------
1 |
Tasks#create
2 |
Find me in app/views/tasks/create.html.erb
3 |
--------------------------------------------------------------------------------
/app/views/tasks/destroy.html.erb:
--------------------------------------------------------------------------------
1 |
Tasks#destroy
2 |
Find me in app/views/tasks/destroy.html.erb
3 |
--------------------------------------------------------------------------------
/app/views/tasks/edit.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
8 |
9 | <%= form_for @task, url: update_checker_task_path(@task), method: :post do |f| %>
10 | <%= render partial: 'tasks/solve', locals: { form: f, task: @task, run: nil } %>
11 | <% end %>
12 |
13 |
16 |
17 |
18 |
19 |
20 |
26 |
27 | <%= render partial: 'fields' %>
28 |
--------------------------------------------------------------------------------
/app/views/tasks/index.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 |
Tasks list
4 |
5 |
6 |
7 |
8 |
9 | <% if @tasks.empty? %>
10 | No tasks created yet
11 | <% else %>
12 |
13 |
14 | Title
15 | Type
16 | Creator
17 | Key
18 | Actions
19 |
20 | <% @tasks.each do |task| %>
21 | <%= render partial: 'task', locals: { task: task } %>
22 | <% end %>
23 |
24 | <% end %>
25 |
26 |
27 |
--------------------------------------------------------------------------------
/app/views/tasks/new.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 |
Create new task
4 |
5 |
6 |
7 | <%= render partial: 'fields' %>
8 |
--------------------------------------------------------------------------------
/app/views/tasks/runs.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 | <%= render partial: 'admin_panel' %>
4 | <%= render partial: 'runs', locals: { task_runs: @task_runs } %>
5 |
6 |
7 |
--------------------------------------------------------------------------------
/app/views/tasks/runs_limits.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 | Name
4 | Runs limit
5 |
6 | <%= @task_records.find_each do |task_record| %>
7 |
8 | <%= link_to truncate(task_record.user.display_name, length: 25), user_path(task_record.user) %>
9 |
10 | <%= render partial: 'edit_runs_limit', locals: { task: @task, task_record: task_record } %>
11 |
12 |
13 | <% end %>
14 |
15 |
--------------------------------------------------------------------------------
/app/views/tasks/show.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 | <%= render partial: 'admin_panel' %>
4 | <%= render inline: @task.description %>
5 |
6 |
7 |
--------------------------------------------------------------------------------
/app/views/tasks/solution.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 | <%= render partial: 'admin_panel' %>
4 | <%= render inline: @task.solution %>
5 |
6 |
7 |
--------------------------------------------------------------------------------
/app/views/tasks/solve.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 | <%= render partial: 'admin_panel' %>
4 | <%= form_for @task, url: do_solve_task_path(@task), method: :post do |f| %>
5 | <%= render partial: 'solve', locals: { form: f, task: @task, run: nil } %>
6 | <% end %>
7 |
8 |
9 |
--------------------------------------------------------------------------------
/app/views/tasks/stats.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 | Successfull Runs (100 points)
4 |
5 |
6 |
7 |
8 | Title
9 | all
10 | C++
11 | Java
12 | Python
13 | Ruby
14 |
15 | <% @runs_stats_by_task.each do |task_id, task_runs_stats| %>
16 |
17 | <%= task_runs_stats[:title] %>
18 | <%= task_runs_stats[:successful_runs] %> / <%= task_runs_stats[:all_runs] %> ( <%= task_runs_stats[:success_percent] %> %)
19 | <% ['cpp', 'java', 'python', 'ruby'].each do |lang| %>
20 | ">
21 | <%= task_runs_stats.fetch("#{ lang }_successful_runs".to_sym, 0) %> /
22 | <%= task_runs_stats.fetch("#{ lang }_all_runs".to_sym, 0) %> (
23 | <%= task_runs_stats.fetch("#{ lang }_success_percent".to_sym, 0) %> %)
24 |
25 | <% end %>
26 |
27 | <% end %>
28 |
29 |
30 |
--------------------------------------------------------------------------------
/app/views/tasks/update.html.erb:
--------------------------------------------------------------------------------
1 |
Tasks#update
2 |
Find me in app/views/tasks/update.html.erb
3 |
--------------------------------------------------------------------------------
/app/views/user_invitations_mailer/invitation_with_user.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
HiredInTech's Training Camp for Coding Interviews!
5 |
6 |
This is an invitation to log in HiredInTech's new training camp.
7 |
8 |
We are still in private beta and will be honoured if it's useful in your tech interview preparation.
9 |
10 |
Use the link below to go to the log in page.
11 |
12 |
You'll be able to log in with the email address at which you received this invite.
13 |
14 |
15 | <%= link_to 'Log In', new_user_session_url, style: "padding: 10px 15px; background: #339933; color: #fff; text-decoration: none; font-size: 18px;" %>
16 |
17 |
18 |
--------------------------------------------------------------------------------
/app/views/user_invitations_mailer/invitation_without_user.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
HiredInTech's Training Camp for Coding Interviews!
5 |
6 |
This is an invitation to sign up for HiredInTech's new training camp.
7 |
8 |
We are still in private beta and will be honoured if it's useful in your tech interview preparation.
9 |
10 |
Use the link below to go to the sign up page.
11 |
12 |
You'll be able to sign up with the email address at which you received this invite.
13 |
14 |
15 | <%= link_to 'Sign Up', new_user_registration_url, style: "padding: 10px 15px; background: #339933; color: #fff; text-decoration: none; font-size: 18px;" %>
16 |
17 |
18 |
--------------------------------------------------------------------------------
/app/views/users/_search_users.html.erb:
--------------------------------------------------------------------------------
1 |
2 | <%= form_tag '', method: :get do %>
3 | <%= text_field_tag :query, @user_query %>
4 | <%= submit_tag 'Search' %>
5 | <% end %>
6 |
7 |
--------------------------------------------------------------------------------
/app/views/users/_users_list.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 | <%= paginate users, theme: 'twitter-bootstrap-3' %>
4 |
5 |
6 | ID
7 | Email
8 | Name
9 | Roles
10 | Time registered
11 | Confirmed at
12 | Auth provider
13 | Action
14 |
15 | <% users.each do |user| %>
16 |
17 | <%= user.id %>
18 | <%= link_to user.email, user_path(user) %>
19 | <%= truncate(user.name, length: 25) %>
20 | <%= user.display_roles %>
21 | <%= user.created_at.to_s(:db) %>
22 | <%= user.confirmed_at.to_s(:db) if user.confirmed_at %>
23 | <%= user.provider %>
24 | <% unless user == current_user || user.has_role?(User::ROLE_TEACHER) || user.has_role?(User::ROLE_ADMIN) %>
25 | <%= link_to 'Delete', user, :class => "btn btn-xs btn-danger", method: :delete, data: {confirm: 'Are you sure?'} %>
26 | <% end %>
27 |
28 | <% end %>
29 |
30 | <%= paginate users, theme: 'twitter-bootstrap-3' %>
31 |
32 |
33 |
--------------------------------------------------------------------------------
/app/views/users/_users_top_menu.html.erb:
--------------------------------------------------------------------------------
1 |
2 | <%= link_to 'Active users', users_path %> <%= @active_users_count %> |
3 | <%= link_to 'Inactive users', inactive_users_path %> <%= @inactive_users_count %> |
4 | <%= link_to 'Invitations', user_invitations_path %> <%= @user_invitations_count %> |
5 | User limit <%= Settings.users_limit.present? ? Settings.users_limit : 'None' %>
6 |
7 |
--------------------------------------------------------------------------------
/app/views/users/edit_profile.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 |
Edit profile
4 |
5 |
6 |
7 |
8 | <%= bootstrap_form_for(@user, url: update_profile_path(@user), html: { method: :post }) do |f| %>
9 |
10 |
27 |
28 |
29 |
30 |
31 |
32 | <%= f.submit "Update profile", class: "btn btn-primary" %>
33 |
34 |
35 |
36 | <% end %>
37 |
38 |
39 |
--------------------------------------------------------------------------------
/app/views/users/inactive.html.erb:
--------------------------------------------------------------------------------
1 |
Inactive users
2 |
3 | <%= render partial: 'users_top_menu' %>
4 |
5 | <%= render partial: 'search_users' %>
6 |
7 | <%= render partial: 'users_list', locals: { users: @inactive_users } %>
8 |
--------------------------------------------------------------------------------
/app/views/users/index.html.erb:
--------------------------------------------------------------------------------
1 |
Users list
2 |
3 | <%= render partial: 'users_top_menu' %>
4 |
5 | <%= render partial: 'search_users' %>
6 |
7 | <%= render partial: 'users_list', locals: { users: @users } %>
8 |
--------------------------------------------------------------------------------
/bin/bundle:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__)
3 | load Gem.bin_path('bundler', 'bundle')
4 |
--------------------------------------------------------------------------------
/bin/delayed_job:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 |
3 | require File.expand_path(File.join(File.dirname(__FILE__), '..', 'config', 'environment'))
4 | require 'delayed/command'
5 | Delayed::Command.new(ARGV).daemonize
6 |
--------------------------------------------------------------------------------
/bin/rails:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | begin
3 | load File.expand_path("../spring", __FILE__)
4 | rescue LoadError
5 | end
6 | APP_PATH = File.expand_path('../../config/application', __FILE__)
7 | require_relative '../config/boot'
8 | require 'rails/commands'
9 |
--------------------------------------------------------------------------------
/bin/rake:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | begin
3 | load File.expand_path("../spring", __FILE__)
4 | rescue LoadError
5 | end
6 | require_relative '../config/boot'
7 | require 'rake'
8 | Rake.application.run
9 |
--------------------------------------------------------------------------------
/bin/setup:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | require 'pathname'
3 |
4 | # path to your application root.
5 | APP_ROOT = Pathname.new File.expand_path('../../', __FILE__)
6 |
7 | Dir.chdir APP_ROOT do
8 | # This script is a starting point to setup your application.
9 | # Add necessary setup steps to this file:
10 |
11 | puts "== Installing dependencies =="
12 | system "gem install bundler --conservative"
13 | system "bundle check || bundle install"
14 |
15 | # puts "\n== Copying sample files =="
16 | # unless File.exist?("config/database.yml")
17 | # system "cp config/database.yml.sample config/database.yml"
18 | # end
19 |
20 | puts "\n== Preparing database =="
21 | system "bin/rake db:setup"
22 |
23 | puts "\n== Removing old logs and tempfiles =="
24 | system "rm -f log/*"
25 | system "rm -rf tmp/cache"
26 |
27 | puts "\n== Restarting application server =="
28 | system "touch tmp/restart.txt"
29 | end
30 |
--------------------------------------------------------------------------------
/bin/spring:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 |
3 | # This file loads spring without using Bundler, in order to be fast.
4 | # It gets overwritten when you run the `spring binstub` command.
5 |
6 | unless defined?(Spring)
7 | require "rubygems"
8 | require "bundler"
9 |
10 | if match = Bundler.default_lockfile.read.match(/^GEM$.*?^ (?: )*spring \((.*?)\)$.*?^$/m)
11 | Gem.paths = { "GEM_PATH" => [Bundler.bundle_path.to_s, *Gem.path].uniq }
12 | gem "spring", match[1]
13 | require "spring/binstub"
14 | end
15 | end
16 |
--------------------------------------------------------------------------------
/config.ru:
--------------------------------------------------------------------------------
1 | # This file is used by Rack-based servers to start the application.
2 |
3 | require ::File.expand_path('../config/environment', __FILE__)
4 | run Rails.application
5 |
--------------------------------------------------------------------------------
/config/application.rb:
--------------------------------------------------------------------------------
1 | require File.expand_path('../boot', __FILE__)
2 |
3 | require 'rails/all'
4 |
5 | # Require the gems listed in Gemfile, including any gems
6 | # you've limited to :test, :development, or :production.
7 | Bundler.require(*Rails.groups)
8 |
9 | # Added when upgrading from Rails 4.2 to 5.0
10 | ActiveSupport.halt_callback_chains_on_return_false = false
11 |
12 | module Codemarathon
13 | class Application < Rails::Application
14 | # Settings in config/environments/* take precedence over those specified here.
15 | # Application configuration should go into files in config/initializers
16 | # -- all .rb files in that directory are automatically loaded.
17 |
18 | # Set Time.zone default to the specified zone and make Active Record auto-convert to this zone.
19 | # Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC.
20 | # config.time_zone = 'Central Time (US & Canada)'
21 |
22 | # The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded.
23 | # config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s]
24 | # config.i18n.default_locale = :de
25 |
26 | # Do not swallow errors in after_commit/after_rollback callbacks.
27 | # Disabled when migrating to Rails 5.0
28 | # config.active_record.raise_in_transactional_callbacks = true
29 |
30 | config.sass.preferred_syntax = :sass
31 | config.sass.line_comments = false
32 | config.sass.cache = false
33 |
34 | config.active_job.queue_adapter = :delayed_job
35 |
36 | config.action_controller.forgery_protection_origin_check = true
37 | end
38 | end
39 |
--------------------------------------------------------------------------------
/config/application.yml:
--------------------------------------------------------------------------------
1 | defaults: &defaults
2 | users_limit: 200
3 |
4 | development:
5 | <<: *defaults
6 |
7 | test:
8 | <<: *defaults
9 | users_limit: 5
10 |
11 | staging:
12 | <<: *defaults
13 |
14 | production:
15 | <<: *defaults
16 |
--------------------------------------------------------------------------------
/config/boot.rb:
--------------------------------------------------------------------------------
1 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__)
2 |
3 | require 'bundler/setup' # Set up gems listed in the Gemfile.
4 |
--------------------------------------------------------------------------------
/config/database.example.yml:
--------------------------------------------------------------------------------
1 | default: &default
2 | adapter: postgresql
3 | pool: 5
4 | encoding: unicode
5 |
6 | development:
7 | <<: *default
8 | database: codemarathon_development
9 | host: localhost
10 | username:
11 | password:
12 |
13 | # Warning: The database defined as "test" will be erased and
14 | # re-generated from your development database when you run "rake".
15 | # Do not set this db to the same as development or production.
16 | test:
17 | <<: *default
18 | database: codemarathon_test
19 | host: localhost
20 | username:
21 | password:
22 |
23 | production:
24 | <<: *default
25 | database: codemarathon_production
26 | host:
27 | username:
28 | password:
29 |
--------------------------------------------------------------------------------
/config/environment.rb:
--------------------------------------------------------------------------------
1 | # Load the Rails application.
2 | require File.expand_path('../application', __FILE__)
3 |
4 | # Initialize the Rails application.
5 | Rails.application.initialize!
6 |
--------------------------------------------------------------------------------
/config/initializers/assets.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | # Version of your assets, change this if you want to expire all your assets.
4 | Rails.application.config.assets.version = '1.0'
5 |
6 | # Add additional assets to the asset load path
7 | # Rails.application.config.assets.paths << Emoji.images_path
8 |
9 | # Precompile additional assets.
10 | # application.js, application.css, and all non-JS/CSS in app/assets folder are already added.
11 | # Rails.application.config.assets.precompile += %w( search.js )
12 |
--------------------------------------------------------------------------------
/config/initializers/backtrace_silencers.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | # You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces.
4 | # Rails.backtrace_cleaner.add_silencer { |line| line =~ /my_noisy_library/ }
5 |
6 | # You can also remove all the silencers if you're trying to debug a problem that might stem from framework code.
7 | # Rails.backtrace_cleaner.remove_silencers!
8 |
--------------------------------------------------------------------------------
/config/initializers/cookies_serializer.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | Rails.application.config.action_dispatch.cookies_serializer = :json
4 |
--------------------------------------------------------------------------------
/config/initializers/filter_parameter_logging.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | # Configure sensitive parameters which will be filtered from the log file.
4 | Rails.application.config.filter_parameters += [:password]
5 |
--------------------------------------------------------------------------------
/config/initializers/inflections.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | # Add new inflection rules using the following format. Inflections
4 | # are locale specific, and you may define rules for as many different
5 | # locales as you wish. All of these examples are active by default:
6 | # ActiveSupport::Inflector.inflections(:en) do |inflect|
7 | # inflect.plural /^(ox)$/i, '\1en'
8 | # inflect.singular /^(ox)en/i, '\1'
9 | # inflect.irregular 'person', 'people'
10 | # inflect.uncountable %w( fish sheep )
11 | # end
12 |
13 | # These inflection rules are supported but not enabled by default:
14 | # ActiveSupport::Inflector.inflections(:en) do |inflect|
15 | # inflect.acronym 'RESTful'
16 | # end
17 |
--------------------------------------------------------------------------------
/config/initializers/mime_types.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | # Add new mime types for use in respond_to blocks:
4 | # Mime::Type.register "text/richtext", :rtf
5 |
--------------------------------------------------------------------------------
/config/initializers/omniauth.rb:
--------------------------------------------------------------------------------
1 | OmniAuth.config.test_mode = true if Rails.env.test?
2 | # OmniAuth.config.logger = Rails.logger
3 |
4 | # Rails.application.config.middleware.use OmniAuth::Builder do
5 | # provider :facebook, FACEBOOK_APP_ID, FACEBOOK_SECRET,
6 | # {
7 | # image_size: :square,
8 | # secure_image_url: true,
9 | # display: :popup
10 | # }
11 | # provider :google_oauth2, GOOGLE_APP_ID, GOOGLE_SECRET,
12 | # {
13 | # image_aspect_ratio: "square",
14 | # image_size: 50,
15 | # scoe: "email, profile"
16 | # }
17 | # provider :github, ENV['GITHUB_KEY'], ENV['GITHUB_SECRET'], scope: "user:email"
18 | # provider :linkedin, LINKEDIN_API_KEY, LINKEDIN_SECRET_KEY,
19 | # :fields => ['id', 'email-address', 'first-name', 'last-name', 'picture-url']
20 | # end
21 |
--------------------------------------------------------------------------------
/config/initializers/session_store.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | Rails.application.config.session_store :cookie_store, key: '_codemarathon_session'
4 |
--------------------------------------------------------------------------------
/config/initializers/wrap_parameters.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | # This file contains settings for ActionController::ParamsWrapper which
4 | # is enabled by default.
5 |
6 | # Enable parameter wrapping for JSON. You can disable this by setting :format to an empty array.
7 | ActiveSupport.on_load(:action_controller) do
8 | wrap_parameters format: [:json] if respond_to?(:wrap_parameters)
9 | end
10 |
11 | # To enable root element in JSON for ActiveRecord objects.
12 | # ActiveSupport.on_load(:active_record) do
13 | # self.include_root_in_json = true
14 | # end
15 |
--------------------------------------------------------------------------------
/config/locales/en.yml:
--------------------------------------------------------------------------------
1 | # Files in the config/locales directory are used for internationalization
2 | # and are automatically loaded by Rails. If you want to use locales other
3 | # than English, add the necessary files in this directory.
4 | #
5 | # To use the locales, use `I18n.t`:
6 | #
7 | # I18n.t 'hello'
8 | #
9 | # In views, this is aliased to just `t`:
10 | #
11 | # <%= t('hello') %>
12 | #
13 | # To use a different locale, set it with `I18n.locale`:
14 | #
15 | # I18n.locale = :es
16 | #
17 | # This would use the information in config/locales/es.yml.
18 | #
19 | # To learn more, please read the Rails Internationalization guide
20 | # available at http://guides.rubyonrails.org/i18n.html.
21 |
22 | en:
23 | hello: "Hello world"
24 |
--------------------------------------------------------------------------------
/config/secrets.yml:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | # Your secret key is used for verifying the integrity of signed cookies.
4 | # If you change this key, all old signed cookies will become invalid!
5 |
6 | # Make sure the secret is at least 30 characters and all random,
7 | # no regular words or you'll be exposed to dictionary attacks.
8 | # You can use `rake secret` to generate a secure secret key.
9 |
10 | # Make sure the secrets in this file are kept private
11 | # if you're sharing your code publicly.
12 |
13 | development:
14 | secret_key_base: b39a3cb1da68e06e0dbe2d343dc1172a9bc9a13e33517fcfb73f516f139d45a7a072f37ac3e75ce25b7b37dfe8bcec2d190295268ac5274485de64891fe305bf
15 | grader_host: http://localhost:6543
16 | grader_email: anton@codemarathon.com
17 | grader_token: 0cbbf77d7b85d83fdaa848c654566b4b
18 |
19 | test:
20 | secret_key_base: a900722b3afcc864da57779e91997349204a90b83918604e8b1c8316293851b9d488f88b5596fb86715d6eca786e48e182dd5a743ff0dc2310720572fe39e402
21 | grader_host: http://grader
22 |
23 | # Do not keep production secrets in the repository,
24 | # instead read values from the environment.
25 | production:
26 | secret_key_base: <%= ENV["SECRET_KEY_BASE"] %>
27 | grader_host: <%= ENV["GRADER_HOST"] %>
28 | grader_email: <%= ENV["GRADER_EMAIL"] %>
29 | grader_token: <%= ENV["GRADER_TOKEN"] %>
30 | grader_use_ssl: <%= ENV["GRADER_USE_SSL"] %>
31 |
--------------------------------------------------------------------------------
/config/unicorn.rb:
--------------------------------------------------------------------------------
1 | # root = "/home/grader/applications/grader"
2 | root = "/home/hiredintech/applications/codemarathon"
3 | working_directory root
4 | pid "#{root}/tmp/pids/unicorn.pid"
5 | stderr_path "#{root}/log/unicorn.log"
6 | stdout_path "#{root}/log/unicorn.log"
7 |
8 | listen "/tmp/unicorn.codemarathon.sock"
9 | worker_processes 2
10 | timeout 30
11 |
--------------------------------------------------------------------------------
/db/migrate/20150813135216_devise_create_users.rb:
--------------------------------------------------------------------------------
1 | class DeviseCreateUsers < ActiveRecord::Migration
2 | def change
3 | create_table(:users) do |t|
4 | ## Database authenticatable
5 | t.string :email, null: false, default: ""
6 | t.string :encrypted_password, null: false, default: ""
7 |
8 | ## Recoverable
9 | t.string :reset_password_token
10 | t.datetime :reset_password_sent_at
11 |
12 | ## Rememberable
13 | t.datetime :remember_created_at
14 |
15 | ## Trackable
16 | t.integer :sign_in_count, default: 0, null: false
17 | t.datetime :current_sign_in_at
18 | t.datetime :last_sign_in_at
19 | t.string :current_sign_in_ip
20 | t.string :last_sign_in_ip
21 |
22 | ## Confirmable
23 | t.string :confirmation_token
24 | t.datetime :confirmed_at
25 | t.datetime :confirmation_sent_at
26 | t.string :unconfirmed_email # Only if using reconfirmable
27 |
28 | ## Lockable
29 | # t.integer :failed_attempts, default: 0, null: false # Only if lock strategy is :failed_attempts
30 | # t.string :unlock_token # Only if unlock strategy is :email or :both
31 | # t.datetime :locked_at
32 |
33 |
34 | t.timestamps null: false
35 | end
36 |
37 | add_index :users, :email, unique: true
38 | add_index :users, :reset_password_token, unique: true
39 | # add_index :users, :confirmation_token, unique: true
40 | # add_index :users, :unlock_token, unique: true
41 | end
42 | end
43 |
--------------------------------------------------------------------------------
/db/migrate/20150813145458_add_omniauth_to_users.rb:
--------------------------------------------------------------------------------
1 | class AddOmniauthToUsers < ActiveRecord::Migration
2 | def change
3 | add_column :users, :provider, :string
4 | add_index :users, :provider
5 | add_column :users, :uid, :string
6 | add_index :users, :uid
7 | end
8 | end
9 |
--------------------------------------------------------------------------------
/db/migrate/20150813152119_add_name_to_user.rb:
--------------------------------------------------------------------------------
1 | class AddNameToUser < ActiveRecord::Migration
2 | def change
3 | add_column :users, :name, :string
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/db/migrate/20151002053704_create_courses.rb:
--------------------------------------------------------------------------------
1 | class CreateCourses < ActiveRecord::Migration
2 | def change
3 | create_table :courses do |t|
4 | t.string :title
5 | t.text :markdown_description
6 | t.text :description
7 |
8 | t.timestamps null: false
9 | end
10 | end
11 | end
12 |
--------------------------------------------------------------------------------
/db/migrate/20151002073002_add_long_description_to_course.rb:
--------------------------------------------------------------------------------
1 | class AddLongDescriptionToCourse < ActiveRecord::Migration
2 | def change
3 | add_column :courses, :markdown_long_description, :text
4 | add_column :courses, :long_description, :text
5 | end
6 | end
7 |
--------------------------------------------------------------------------------
/db/migrate/20151002130501_modify_course_columns.rb:
--------------------------------------------------------------------------------
1 | class ModifyCourseColumns < ActiveRecord::Migration
2 | def change
3 | change_column_null :courses, :title, false
4 | change_column_null :courses, :markdown_description, false
5 | change_column_null :courses, :description, false
6 | change_column_null :courses, :markdown_long_description, false
7 | change_column_null :courses, :long_description, false
8 | end
9 | end
10 |
--------------------------------------------------------------------------------
/db/migrate/20151002134106_create_roles.rb:
--------------------------------------------------------------------------------
1 | class CreateRoles < ActiveRecord::Migration
2 | def change
3 | create_table :roles do |t|
4 | t.integer :user_id, null: false
5 | t.string :role_type, null: false
6 |
7 | t.timestamps null: false
8 | end
9 | end
10 | end
11 |
--------------------------------------------------------------------------------
/db/migrate/20151012135858_create_sections.rb:
--------------------------------------------------------------------------------
1 | class CreateSections < ActiveRecord::Migration
2 | def change
3 | create_table :sections do |t|
4 | t.integer :course_id
5 | t.string :title
6 | t.integer :position
7 |
8 | t.timestamps null: false
9 | end
10 | end
11 | end
12 |
--------------------------------------------------------------------------------
/db/migrate/20151013060709_make_section_fields_non_null.rb:
--------------------------------------------------------------------------------
1 | class MakeSectionFieldsNonNull < ActiveRecord::Migration
2 | def change
3 | change_column_null(:sections, :title, false)
4 | change_column_null(:sections, :position, false)
5 | change_column_null(:sections, :course_id, false)
6 | end
7 | end
8 |
--------------------------------------------------------------------------------
/db/migrate/20151013161035_create_lessons.rb:
--------------------------------------------------------------------------------
1 | class CreateLessons < ActiveRecord::Migration
2 | def change
3 | create_table :lessons do |t|
4 | t.string :title
5 | t.integer :position
6 | t.integer :section_id
7 |
8 | t.timestamps null: false
9 | end
10 | end
11 | end
12 |
--------------------------------------------------------------------------------
/db/migrate/20151013163723_change_lesson_field_null.rb:
--------------------------------------------------------------------------------
1 | class ChangeLessonFieldNull < ActiveRecord::Migration
2 | def change
3 | change_column_null(:lessons, :title, false)
4 | change_column_null(:lessons, :position, false)
5 | change_column_null(:lessons, :section_id, false)
6 | end
7 | end
8 |
--------------------------------------------------------------------------------
/db/migrate/20151013194516_add_content_to_lesson.rb:
--------------------------------------------------------------------------------
1 | class AddContentToLesson < ActiveRecord::Migration
2 | def change
3 | add_column :lessons, :content, :text
4 | add_column :lessons, :markdown_content, :text
5 | end
6 | end
7 |
--------------------------------------------------------------------------------
/db/migrate/20151016153923_create_classrooms.rb:
--------------------------------------------------------------------------------
1 | class CreateClassrooms < ActiveRecord::Migration
2 | def change
3 | create_table :classrooms do |t|
4 | t.string :name
5 | t.integer :course_id
6 |
7 | t.timestamps null: false
8 | end
9 | end
10 | end
11 |
--------------------------------------------------------------------------------
/db/migrate/20151016154207_make_classroom_fields_non_null.rb:
--------------------------------------------------------------------------------
1 | class MakeClassroomFieldsNonNull < ActiveRecord::Migration
2 | def change
3 | change_column_null(:classrooms, :name, false)
4 | change_column_null(:classrooms, :course_id, false)
5 | end
6 | end
7 |
--------------------------------------------------------------------------------
/db/migrate/20151016154749_create_classroom_records.rb:
--------------------------------------------------------------------------------
1 | class CreateClassroomRecords < ActiveRecord::Migration
2 | def change
3 | create_table :classroom_records do |t|
4 | t.integer :classroom_id, null: false
5 | t.integer :user_id, null: false
6 | t.string :role, null: false
7 |
8 | t.timestamps null: false
9 | end
10 | end
11 | end
12 |
--------------------------------------------------------------------------------
/db/migrate/20151023135004_add_default_to_lesson_content.rb:
--------------------------------------------------------------------------------
1 | class AddDefaultToLessonContent < ActiveRecord::Migration
2 | def change
3 | change_column_default(:lessons, :content, "")
4 | change_column_default(:lessons, :markdown_content, "")
5 |
6 | Lesson.where(content: nil).update_all(content: "")
7 | Lesson.where(markdown_content: nil).update_all(markdown_content: "")
8 |
9 | change_column_null(:lessons, :content, false)
10 | change_column_null(:lessons, :markdown_content, false)
11 | end
12 | end
13 |
--------------------------------------------------------------------------------
/db/migrate/20151025194346_add_visible_flag_to_course.rb:
--------------------------------------------------------------------------------
1 | class AddVisibleFlagToCourse < ActiveRecord::Migration
2 | def change
3 | add_column :courses, :visible, :boolean, null: false, default: false
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/db/migrate/20151026143538_add_visible_to_sections.rb:
--------------------------------------------------------------------------------
1 | class AddVisibleToSections < ActiveRecord::Migration
2 | def change
3 | add_column :sections, :visible, :boolean, null: false, default: false
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/db/migrate/20151026143549_add_visible_to_lessons.rb:
--------------------------------------------------------------------------------
1 | class AddVisibleToLessons < ActiveRecord::Migration
2 | def change
3 | add_column :lessons, :visible, :boolean, null: false, default: false
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/db/migrate/20151029063854_create_tasks.rb:
--------------------------------------------------------------------------------
1 | class CreateTasks < ActiveRecord::Migration
2 | def change
3 | create_table :tasks do |t|
4 | t.string :title, null: false
5 | t.string :task_type, null: false
6 | t.text :markdown_description, null: false
7 | t.text :description, null: false
8 | t.integer :creator_id, null: false
9 | t.boolean :visible, null: false, default: false
10 | t.string :external_key
11 | t.integer :memory_limit_kb
12 | t.integer :time_limit_ms
13 |
14 | t.timestamps null: false
15 | end
16 | end
17 | end
18 |
--------------------------------------------------------------------------------
/db/migrate/20151105093612_create_task_runs.rb:
--------------------------------------------------------------------------------
1 | class CreateTaskRuns < ActiveRecord::Migration
2 | def change
3 | create_table :task_runs do |t|
4 | t.integer :task_id, null: false
5 | t.integer :user_id, null: false
6 | t.text :source_code, null: false
7 | t.string :lang, null: false
8 | t.string :status, null: false
9 | t.string :external_key
10 | t.string :message
11 | t.text :grader_log
12 | t.integer :memory_limit_kb, null: false
13 | t.integer :time_limit_ms, null: false
14 |
15 | t.timestamps null: false
16 | end
17 | end
18 | end
19 |
--------------------------------------------------------------------------------
/db/migrate/20151105120959_add_run_type_to_task_runs.rb:
--------------------------------------------------------------------------------
1 | class AddRunTypeToTaskRuns < ActiveRecord::Migration
2 | def change
3 | add_column :task_runs, :run_type, :string
4 |
5 | TaskRun.find_each do |task_run|
6 | task_run.update_attributes(run_type: TaskRun::TYPE_RUN_TASK)
7 | end
8 |
9 | change_column_null(:task_runs, :run_type, false)
10 | end
11 | end
12 |
--------------------------------------------------------------------------------
/db/migrate/20151105122008_add_points_to_task_run.rb:
--------------------------------------------------------------------------------
1 | class AddPointsToTaskRun < ActiveRecord::Migration
2 | def change
3 | add_column :task_runs, :points, :float
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/db/migrate/20151130142452_create_table_lesson_tasks.rb:
--------------------------------------------------------------------------------
1 | class CreateTableLessonTasks < ActiveRecord::Migration
2 | def change
3 | create_table :lessons_tasks do |t|
4 | t.integer :lesson_id
5 | t.integer :task_id
6 | end
7 | end
8 | end
9 |
--------------------------------------------------------------------------------
/db/migrate/20151203141019_make_points_non_null_in_task_run.rb:
--------------------------------------------------------------------------------
1 | class MakePointsNonNullInTaskRun < ActiveRecord::Migration
2 | def change
3 | TaskRun.where(points: nil).update_all(points: 0.0)
4 | change_column_default(:task_runs, :points, 0.0)
5 | change_column_null(:task_runs, :points, false)
6 | end
7 | end
8 |
--------------------------------------------------------------------------------
/db/migrate/20151208213102_create_task_records.rb:
--------------------------------------------------------------------------------
1 | class CreateTaskRecords < ActiveRecord::Migration
2 | def change
3 | create_table :task_records do |t|
4 | t.integer :user_id, null: false
5 | t.integer :task_id, null: false
6 | t.float :best_score, default: 0.0, null: false
7 | t.integer :best_run_id
8 | t.boolean :covered, default: false, null: false
9 |
10 | t.timestamps null: false
11 | end
12 | end
13 | end
14 |
--------------------------------------------------------------------------------
/db/migrate/20151208214540_create_lesson_records.rb:
--------------------------------------------------------------------------------
1 | class CreateLessonRecords < ActiveRecord::Migration
2 | def change
3 | create_table :lesson_records do |t|
4 | t.integer :lesson_id, null: false
5 | t.integer :user_id, null: false
6 | t.integer :classroom_id, null: false
7 | t.integer :views, default: 0, null: false
8 | t.boolean :covered, default: false, null: false
9 |
10 | t.timestamps null: false
11 | end
12 | end
13 | end
14 |
--------------------------------------------------------------------------------
/db/migrate/20151210122605_make_task_fields_mandatory.rb:
--------------------------------------------------------------------------------
1 | class MakeTaskFieldsMandatory < ActiveRecord::Migration
2 | def change
3 | change_column_null(:tasks, :memory_limit_kb, false)
4 | change_column_null(:tasks, :time_limit_ms, false)
5 | end
6 | end
7 |
--------------------------------------------------------------------------------
/db/migrate/20160104161048_make_source_code_nullable_in_task.rb:
--------------------------------------------------------------------------------
1 | class MakeSourceCodeNullableInTask < ActiveRecord::Migration
2 | def change
3 | change_column_null(:task_runs, :source_code, true)
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/db/migrate/20160303075349_add_main_flag_to_courses.rb:
--------------------------------------------------------------------------------
1 | class AddMainFlagToCourses < ActiveRecord::Migration
2 | def change
3 | add_column :courses, :is_main, :boolean, null: false, default: false
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/db/migrate/20160305073957_add_unique_constraint_on_classroom_records.rb:
--------------------------------------------------------------------------------
1 | class AddUniqueConstraintOnClassroomRecords < ActiveRecord::Migration
2 | def change
3 | add_index :classroom_records, [:classroom_id, :user_id], unique: true
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/db/migrate/20160310070738_add_runs_limit_to_task_record.rb:
--------------------------------------------------------------------------------
1 | class AddRunsLimitToTaskRecord < ActiveRecord::Migration
2 | def change
3 | add_column :task_records, :runs_limit, :integer, null: false, default: TaskRecord::DEFAULT_MAX_RUNS_LIMIT
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/db/migrate/20160314071507_create_user_invitations.rb:
--------------------------------------------------------------------------------
1 | class CreateUserInvitations < ActiveRecord::Migration
2 | def change
3 | create_table :user_invitations do |t|
4 | t.string :email, null: false
5 | t.boolean :used, null: false, default: false
6 | t.datetime :used_at
7 |
8 | t.timestamps null: false
9 | end
10 |
11 | add_index :user_invitations, :email, unique: true
12 | end
13 | end
14 |
--------------------------------------------------------------------------------
/db/migrate/20160314074133_add_active_to_users.rb:
--------------------------------------------------------------------------------
1 | class AddActiveToUsers < ActiveRecord::Migration
2 | def change
3 | add_column :users, :active, :boolean, null: false, default: false
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/db/migrate/20160417163920_add_subtitle_to_course.rb:
--------------------------------------------------------------------------------
1 | class AddSubtitleToCourse < ActiveRecord::Migration
2 | def change
3 | add_column :courses, :subtitle, :string
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/db/migrate/20160418192655_add_slug_to_course.rb:
--------------------------------------------------------------------------------
1 | class AddSlugToCourse < ActiveRecord::Migration
2 | def change
3 | add_column :courses, :slug, :string
4 |
5 | Course.all.each do |course|
6 | slug = course.title.downcase.gsub(/\s/, "-").gsub(/[^a-z0-9\-]/, "")[0..15]
7 | course.update_attributes(slug: slug)
8 | end
9 |
10 | change_column_null(:courses, :slug, false)
11 | end
12 | end
13 |
--------------------------------------------------------------------------------
/db/migrate/20160418200353_add_unique_index_on_course_slug.rb:
--------------------------------------------------------------------------------
1 | class AddUniqueIndexOnCourseSlug < ActiveRecord::Migration
2 | def change
3 | add_index :courses, :slug, unique: true
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/db/migrate/20160418200506_add_slug_to_classrooms.rb:
--------------------------------------------------------------------------------
1 | class AddSlugToClassrooms < ActiveRecord::Migration
2 | def change
3 | add_column :classrooms, :slug, :string
4 |
5 | Classroom.all.each do |classroom|
6 | classroom.update_attributes(slug: classroom.course.slug)
7 | end
8 |
9 | change_column_null :classrooms, :slug, false
10 |
11 | add_index :classrooms, :slug, unique: true
12 | end
13 | end
14 |
--------------------------------------------------------------------------------
/db/migrate/20160429170700_create_delayed_jobs.rb:
--------------------------------------------------------------------------------
1 | class CreateDelayedJobs < ActiveRecord::Migration
2 | def self.up
3 | create_table :delayed_jobs, force: true do |table|
4 | table.integer :priority, default: 0, null: false # Allows some jobs to jump to the front of the queue
5 | table.integer :attempts, default: 0, null: false # Provides for retries, but still fail eventually.
6 | table.text :handler, null: false # YAML-encoded string of the object that will do work
7 | table.text :last_error # reason for last failure (See Note below)
8 | table.datetime :run_at # When to run. Could be Time.zone.now for immediately, or sometime in the future.
9 | table.datetime :locked_at # Set when a client is working on this object
10 | table.datetime :failed_at # Set when all retries have failed (actually, by default, the record is deleted instead)
11 | table.string :locked_by # Who is working on this object (if locked)
12 | table.string :queue # The name of the queue this job is in
13 | table.timestamps null: true
14 | end
15 |
16 | add_index :delayed_jobs, [:priority, :run_at], name: "delayed_jobs_priority"
17 | end
18 |
19 | def self.down
20 | drop_table :delayed_jobs
21 | end
22 | end
23 |
--------------------------------------------------------------------------------
/db/migrate/20160502194330_add_solution_to_task.rb:
--------------------------------------------------------------------------------
1 | class AddSolutionToTask < ActiveRecord::Migration
2 | def change
3 | add_column :tasks, :markdown_solution, :text
4 | add_column :tasks, :solution, :text
5 | end
6 | end
7 |
--------------------------------------------------------------------------------
/db/migrate/20160608104441_add_active_to_classroom_record.rb:
--------------------------------------------------------------------------------
1 | class AddActiveToClassroomRecord < ActiveRecord::Migration
2 | def change
3 | add_column :classroom_records, :active, :boolean
4 |
5 | ClassroomRecord.find_each do |record|
6 | record.update_attributes(active: true)
7 | end
8 |
9 | change_column_null(:classroom_records, :active, false)
10 | end
11 | end
12 |
--------------------------------------------------------------------------------
/db/migrate/20160608110642_add_user_limit_to_classroom.rb:
--------------------------------------------------------------------------------
1 | class AddUserLimitToClassroom < ActiveRecord::Migration
2 | def change
3 | add_column :classrooms, :user_limit, :integer
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/db/migrate/20160614144305_add_display_status_to_task_run.rb:
--------------------------------------------------------------------------------
1 | class AddDisplayStatusToTaskRun < ActiveRecord::Migration
2 | def change
3 | add_column :task_runs, :display_status, :string
4 |
5 | TaskRun.find_each do |task_run|
6 | task_run.update_attribute(:display_status, display_status(task_run))
7 | end
8 |
9 | change_column_null :task_runs, :display_status, false
10 | end
11 |
12 | private
13 |
14 | def display_status task_run
15 | if task_run.status == TaskRun::STATUS_SUCCESS
16 | if task_run.points == Task::TASK_MAX_POINTS
17 | "Accepted"
18 | else
19 | "Some Errors"
20 | end
21 | else
22 | task_run.status.titlecase
23 | end
24 | end
25 | end
26 |
--------------------------------------------------------------------------------
/db/migrate/20160614152702_add_compilation_log_to_task_run.rb:
--------------------------------------------------------------------------------
1 | class AddCompilationLogToTaskRun < ActiveRecord::Migration
2 | def change
3 | add_column :task_runs, :compilation_log, :text
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/db/migrate/20160614201512_add_error_details_to_task_runs.rb:
--------------------------------------------------------------------------------
1 | class AddErrorDetailsToTaskRuns < ActiveRecord::Migration
2 | def change
3 | add_column :task_runs, :has_ml, :boolean, default: false, null: false
4 | add_column :task_runs, :has_tl, :boolean, default: false, null: false
5 | add_column :task_runs, :has_wa, :boolean, default: false, null: false
6 | add_column :task_runs, :has_re, :boolean, default: false, null: false
7 | add_column :task_runs, :re_details, :text
8 |
9 | TaskRun.find_each do |task_run|
10 | has_ml = task_run.message.present? && task_run.message.include?("ml")
11 | has_tl = task_run.message.present? && task_run.message.include?("tl")
12 | has_wa = task_run.message.present? && task_run.message.include?("wa")
13 | has_re = task_run.message.present? && task_run.message.include?("re")
14 | task_run.update_attributes(has_ml: has_ml, has_tl: has_tl, has_wa: has_wa, has_re: has_re)
15 | end
16 | end
17 | end
18 |
--------------------------------------------------------------------------------
/db/migrate/20160713161017_add_wrapper_and_boilerplate_code_to_tasks.rb:
--------------------------------------------------------------------------------
1 | class AddWrapperAndBoilerplateCodeToTasks < ActiveRecord::Migration
2 | def change
3 | add_column :tasks, :cpp_boilerplate, :text
4 | add_column :tasks, :cpp_wrapper, :text
5 | add_column :tasks, :java_boilerplate, :text
6 | add_column :tasks, :java_wrapper, :text
7 | add_column :tasks, :python_boilerplate, :text
8 | add_column :tasks, :python_wrapper, :text
9 | add_column :tasks, :ruby_boilerplate, :text
10 | add_column :tasks, :ruby_wrapper, :text
11 | end
12 | end
13 |
--------------------------------------------------------------------------------
/db/migrate/20160713183600_add_last_programming_language_to_user.rb:
--------------------------------------------------------------------------------
1 | class AddLastProgrammingLanguageToUser < ActiveRecord::Migration
2 | def change
3 | add_column :users, :last_programming_language, :string
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/db/migrate/20160716163403_set_last_programming_language_based_on_submissions.rb:
--------------------------------------------------------------------------------
1 | class SetLastProgrammingLanguageBasedOnSubmissions < ActiveRecord::Migration
2 | def change
3 | User.find_each do |user|
4 | latest_task_run = user.task_runs.newest_first.first
5 | if latest_task_run.present?
6 | user.update_attributes(last_programming_language: latest_task_run.lang)
7 | end
8 | end
9 | end
10 | end
11 |
--------------------------------------------------------------------------------
/db/migrate/20160817091910_add_public_to_courses.rb:
--------------------------------------------------------------------------------
1 | class AddPublicToCourses < ActiveRecord::Migration
2 | def change
3 | add_column :courses, :public, :boolean, null: false, default: false
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/db/migrate/20160826161231_increase_runs_limit.rb:
--------------------------------------------------------------------------------
1 | class IncreaseRunsLimit < ActiveRecord::Migration
2 | def change
3 | change_column_default :task_records, :runs_limit, TaskRecord::DEFAULT_MAX_RUNS_LIMIT
4 |
5 | TaskRecord.where(runs_limit: 5).update_all(runs_limit: TaskRecord::DEFAULT_MAX_RUNS_LIMIT)
6 | end
7 | end
8 |
--------------------------------------------------------------------------------
/db/migrate/20160906111443_add_sidebar_content_to_lesson.rb:
--------------------------------------------------------------------------------
1 | class AddSidebarContentToLesson < ActiveRecord::Migration
2 | def change
3 | add_column :lessons, :sidebar_content, :text
4 | add_column :lessons, :markdown_sidebar_content, :text
5 | end
6 | end
7 |
--------------------------------------------------------------------------------
/db/migrate/20160920113459_create_quizzes.rb:
--------------------------------------------------------------------------------
1 | class CreateQuizzes < ActiveRecord::Migration
2 | def change
3 | create_table :quizzes do |t|
4 | t.string :title, null: false
5 | t.integer :creator_id, null: false
6 |
7 | t.timestamps null: false
8 | end
9 | end
10 | end
11 |
--------------------------------------------------------------------------------
/db/migrate/20160920113641_create_quiz_questions.rb:
--------------------------------------------------------------------------------
1 | class CreateQuizQuestions < ActiveRecord::Migration
2 | def change
3 | create_table :quiz_questions do |t|
4 | t.integer :quiz_id, null: false
5 | t.text :content, null: false
6 | t.string :question_type, null: false
7 | t.string :freetext_regex
8 |
9 | t.timestamps null: false
10 | end
11 | end
12 | end
13 |
--------------------------------------------------------------------------------
/db/migrate/20160920113733_create_quiz_answers.rb:
--------------------------------------------------------------------------------
1 | class CreateQuizAnswers < ActiveRecord::Migration
2 | def change
3 | create_table :quiz_answers do |t|
4 | t.integer :quiz_question_id, null: false
5 | t.text :content, null: false
6 | t.boolean :correct, null: false
7 |
8 | t.timestamps null: false
9 | end
10 | end
11 | end
12 |
--------------------------------------------------------------------------------
/db/migrate/20160928125223_add_maximum_attempts_and_time_to_wait_to_quizzes.rb:
--------------------------------------------------------------------------------
1 | class AddMaximumAttemptsAndTimeToWaitToQuizzes < ActiveRecord::Migration
2 | def change
3 | add_column :quizzes, :maximum_attempts, :integer
4 | add_column :quizzes, :wait_time_seconds, :integer
5 | end
6 | end
7 |
--------------------------------------------------------------------------------
/db/migrate/20160928140809_create_quiz_attempts.rb:
--------------------------------------------------------------------------------
1 | class CreateQuizAttempts < ActiveRecord::Migration
2 | def change
3 | create_table :quiz_attempts do |t|
4 | t.integer :quiz_id, null: false
5 | t.integer :user_id, null: false
6 | t.float :score, null: false
7 | t.text :answers_json, null: false
8 | t.text :message
9 |
10 | t.timestamps null: false
11 | end
12 | end
13 | end
14 |
--------------------------------------------------------------------------------
/db/migrate/20160929185657_add_lessons_quizzes_table.rb:
--------------------------------------------------------------------------------
1 | class AddLessonsQuizzesTable < ActiveRecord::Migration
2 | def change
3 | create_table :lessons_quizzes do |t|
4 | t.integer :lesson_id
5 | t.integer :quiz_id
6 | end
7 | end
8 | end
9 |
--------------------------------------------------------------------------------
/db/migrate/20161018120810_add_explanation_to_quiz_questions.rb:
--------------------------------------------------------------------------------
1 | class AddExplanationToQuizQuestions < ActiveRecord::Migration
2 | def change
3 | add_column :quiz_questions, :explanation, :text
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/db/migrate/20161216140911_add_markdown_to_quiz_questions.rb:
--------------------------------------------------------------------------------
1 | class AddMarkdownToQuizQuestions < ActiveRecord::Migration
2 | def change
3 | add_column :quiz_questions, :markdown_content, :text
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/db/migrate/20161220144607_add_markdown_explanation_to_quiz_questions.rb:
--------------------------------------------------------------------------------
1 | class AddMarkdownExplanationToQuizQuestions < ActiveRecord::Migration
2 | def change
3 | add_column :quiz_questions, :markdown_explanation, :text
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/db/migrate/20161220161304_add_markdown_to_quiz_answers.rb:
--------------------------------------------------------------------------------
1 | class AddMarkdownToQuizAnswers < ActiveRecord::Migration
2 | def change
3 | add_column :quiz_answers, :markdown_content, :text
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/db/migrate/20161221104754_transfer_question_content_to_markdown.rb:
--------------------------------------------------------------------------------
1 | class TransferQuestionContentToMarkdown < ActiveRecord::Migration
2 | def up
3 | QuizQuestion.find_each do |quiz_question|
4 | if quiz_question.content.present?
5 | say "Updating content of quiz questions #{ quiz_question.id }"
6 | quiz_question.update_attributes(markdown_content: quiz_question.content)
7 | else
8 | say "Error: empty quiz question content found!"
9 | end
10 |
11 | if quiz_question.explanation.present?
12 | say "Updating explanation of quiz questions #{ quiz_question.id }"
13 | quiz_question.update_attributes(markdown_explanation: quiz_question.explanation)
14 | end
15 | end
16 |
17 |
18 | change_column_null(:quiz_questions, :markdown_content, false)
19 | end
20 |
21 | def down
22 | change_column_null(:quiz_questions, :markdown_content, true)
23 |
24 | QuizQuestion.update_all(markdown_content: nil, markdown_explanation: nil)
25 | end
26 | end
27 |
--------------------------------------------------------------------------------
/db/migrate/20161226071326_transfer_quiz_answers_content_to_markdown.rb:
--------------------------------------------------------------------------------
1 | class TransferQuizAnswersContentToMarkdown < ActiveRecord::Migration
2 | def up
3 | QuizAnswer.find_each do |quiz_answer|
4 | if quiz_answer.content.present?
5 | say "Updating content of quiz answers #{ quiz_answer.id }"
6 | quiz_answer.update_attributes(markdown_content: quiz_answer.content)
7 | else
8 | say "Error: empty quiz answer content found!"
9 | end
10 | end
11 |
12 |
13 | change_column_null(:quiz_answers, :markdown_content, false)
14 | end
15 |
16 | def down
17 | change_column_null(:quiz_answers, :markdown_content, true)
18 |
19 | QuizAnswer.update_all(markdown_content: nil)
20 | end
21 | end
22 |
--------------------------------------------------------------------------------
/db/migrate/20170119113201_add_disable_task_submissions_to_courses.rb:
--------------------------------------------------------------------------------
1 | class AddDisableTaskSubmissionsToCourses < ActiveRecord::Migration
2 | def change
3 | add_column :courses, :disable_task_submissions, :boolean, default: false, null: false
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/db/migrate/20171101202536_add_public_to_task_run.rb:
--------------------------------------------------------------------------------
1 | class AddPublicToTaskRun < ActiveRecord::Migration[5.0]
2 | def change
3 | add_column :task_runs, :show_source_code, :boolean, default: false, null: false
4 | add_column :task_runs, :show_user_name, :boolean, default: false, null: false
5 |
6 | TaskRun.update_all(show_source_code: true)
7 | end
8 | end
9 |
--------------------------------------------------------------------------------
/lib/assets/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antonrd/codemarathon/0d601b1d1fa5ada715a1e567a0bd55ed8f11170f/lib/assets/.keep
--------------------------------------------------------------------------------
/lib/tasks/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antonrd/codemarathon/0d601b1d1fa5ada715a1e567a0bd55ed8f11170f/lib/tasks/.keep
--------------------------------------------------------------------------------
/lib/tasks/update_runs_status.rake:
--------------------------------------------------------------------------------
1 | namespace :runs do
2 | desc "Update runs statuses"
3 | task :update_status => :environment do
4 | api = GraderApi.new
5 |
6 | running = true
7 | puts "Ready to update statuses"
8 |
9 | last_run_id = nil
10 |
11 | while running do
12 | ["INT", "TERM"].each do |signal|
13 | Signal.trap(signal) do
14 | puts "Stopping..."
15 | running = false
16 | end
17 | end
18 |
19 | found_run = ProcessTaskRun.new(api).call
20 |
21 | sleep 1 unless found_run && found_run.id != last_run_id
22 |
23 | last_run_id = found_run.id if found_run
24 | end
25 | end
26 | end
27 |
28 |
--------------------------------------------------------------------------------
/log/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antonrd/codemarathon/0d601b1d1fa5ada715a1e567a0bd55ed8f11170f/log/.keep
--------------------------------------------------------------------------------
/provisioning/deploy_production.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - hosts: all
3 | sudo: no
4 |
5 | vars:
6 | app_root: /home/hiredintech/applications/codemarathon
7 | app_name: codemarathon
8 | git_repo: git@bitbucket.org:hiredintechteam/codemarathon.git
9 | git_branch: hiredintech
10 |
11 | roles:
12 | - deploy
13 | # - restart
14 |
--------------------------------------------------------------------------------
/provisioning/production.ini:
--------------------------------------------------------------------------------
1 | [hiredintech]
2 | 45.55.21.48 ansible_ssh_user=hiredintech
3 |
--------------------------------------------------------------------------------
/provisioning/restart_production.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - hosts: all
3 | sudo: no
4 |
5 | vars:
6 | app_name: codemarathon
7 |
8 | roles:
9 | - restart
10 |
--------------------------------------------------------------------------------
/provisioning/roles/backup/tasks/main.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: Installs the backup gem
3 | command: bash -lc "gem install backup"
4 | args:
5 | chdir: "{{ app_root }}"
6 |
7 | # Set up crontab manually, or add the gem whenever for more automation.
8 |
--------------------------------------------------------------------------------
/provisioning/roles/config/tasks/main.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: Get project code from Github
3 | git:
4 | repo="{{ git_repo }}"
5 | dest="{{ app_root }}"
6 | accept_hostkey=yes
7 | version="{{ git_branch }}"
8 | force=yes
9 |
10 | - name: Bundle install
11 | command: bash -lc "bundle install"
12 | args:
13 | chdir: "{{ app_root }}"
14 |
15 | - name: Set up database
16 | shell: bash -lc "RAILS_ENV=production bundle exec rake db:setup"
17 | args:
18 | chdir: "{{ app_root }}"
19 |
20 | - name: Create pids directory
21 | file: path="{{ app_root }}"/tmp/pids state=directory
22 |
23 | - name: Create unicorn init script
24 | become: yes
25 | become_method: sudo
26 | template: src=unicorn_init.j2 dest=/etc/init.d/unicorn_{{ app_name }} mode=0744
27 |
28 | - name: Create nginx config
29 | become: yes
30 | become_method: sudo
31 | template: src=nginx_config.j2 dest=/etc/nginx/sites-enabled/{{ app_name }} mode=0744
32 |
33 | # This one will set PORT env vars for the jobs, and this can break the links
34 | # generated in emails that are sent through delayed jobs.
35 | - name: Set up upstart for hiredintech rake task
36 | shell: bash -lc "rvmsudo foreman export upstart /etc/init -a {{ app_name }} -u hiredintech"
37 | args:
38 | chdir: "{{ app_root }}"
39 |
40 | # - name: Start runs status update rake task for the first time
41 | # become: yes
42 | # become_method: sudo
43 | # shell: bash -lc "start {{ app_name }}"
44 |
45 | # Grader rake logs will go to /var/log/codemarathon_grader/worker-1.log
46 |
--------------------------------------------------------------------------------
/provisioning/roles/config/templates/nginx_config.j2:
--------------------------------------------------------------------------------
1 | upstream codemarathon_unicorn {
2 | server unix:/tmp/unicorn.{{ app_name }}.sock fail_timeout=0;
3 | }
4 |
5 | server {
6 | listen 80;
7 | server_name {{ server_name }};
8 | return 301 https://$server_name$request_uri;
9 | }
10 |
11 | server {
12 | listen 443 ssl;
13 | server_name {{ server_name }};
14 | root {{ app_root }}/public;
15 |
16 | ssl on;
17 | ssl_certificate /etc/nginx/ssl/train.hiredintech.com.crt;
18 | ssl_certificate_key /etc/nginx/ssl/train.hiredintech.com.key;
19 |
20 | ssl_session_timeout 5m;
21 |
22 | ssl_protocols SSLv2 SSLv3 TLSv1 TLSv1.1 TLSv1.2;
23 | ssl_ciphers HIGH:!aNULL:!MD5;
24 | ssl_prefer_server_ciphers on;
25 |
26 | location ^~ /assets/ {
27 | gzip_static on;
28 | expires max;
29 | add_header Cache-Control public;
30 | }
31 |
32 | try_files $uri/index.html $uri @codemarathon_unicorn;
33 | location @codemarathon_unicorn {
34 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
35 | proxy_set_header Host $http_host;
36 | proxy_set_header X-Forwarded-Proto https;
37 | proxy_redirect off;
38 | proxy_pass http://codemarathon_unicorn;
39 | }
40 |
41 | error_page 500 502 503 504 /500.html;
42 | client_max_body_size 4G;
43 | keepalive_timeout 10;
44 | }
45 |
--------------------------------------------------------------------------------
/provisioning/roles/config/templates/nginx_config.no_ssl.j2:
--------------------------------------------------------------------------------
1 | upstream codemarathon_unicorn {
2 | server unix:/tmp/unicorn.{{ app_name }}.sock fail_timeout=0;
3 | }
4 |
5 | server {
6 | listen 80;
7 | # listen 443;
8 | server_name {{ server_name }};
9 | root {{ app_root }}/public;
10 |
11 | #ssl on;
12 | #ssl_certificate /etc/ssl/server.crt;
13 | #ssl_certificate_key /etc/ssl/server.key;
14 |
15 | #ssl_session_timeout 5m;
16 |
17 | #ssl_protocols SSLv2 SSLv3 TLSv1;
18 | #ssl_ciphers HIGH:!aNULL:!MD5;
19 | #ssl_prefer_server_ciphers on;
20 |
21 | location ^~ /assets/ {
22 | gzip_static on;
23 | expires max;
24 | add_header Cache-Control public;
25 | }
26 |
27 | try_files $uri/index.html $uri @codemarathon_unicorn;
28 | location @codemarathon_unicorn {
29 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
30 | proxy_set_header Host $http_host;
31 | proxy_redirect off;
32 | proxy_pass http://codemarathon_unicorn;
33 | }
34 |
35 | error_page 500 502 503 504 /500.html;
36 | client_max_body_size 4G;
37 | keepalive_timeout 10;
38 | }
39 |
--------------------------------------------------------------------------------
/provisioning/roles/deploy/tasks/main.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: Update project code from Github
3 | git:
4 | repo="{{ git_repo }}"
5 | dest="{{ app_root }}"
6 | accept_hostkey=yes
7 | version="{{ git_branch }}"
8 | force=yes
9 |
10 | - name: Bundle install
11 | command: bash -lc "bundle install"
12 | args:
13 | chdir: "{{ app_root }}"
14 |
15 | - name: Run migrations
16 | shell: bash -lc "RAILS_ENV=production bundle exec rake db:migrate"
17 | args:
18 | chdir: "{{ app_root }}"
19 |
20 | - name: Precompile assets
21 | shell: bash -lc "RAILS_ENV=production bundle exec rake assets:precompile"
22 | args:
23 | chdir: "{{ app_root }}"
24 |
--------------------------------------------------------------------------------
/provisioning/roles/restart/tasks/main.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: Restart unicorn
3 | become: yes
4 | become_method: sudo
5 | shell: bash -lc "/etc/init.d/unicorn_{{ app_name }} restart"
6 |
7 | - name: Restart nginx
8 | become: yes
9 | become_method: sudo
10 | service: name=nginx state=restarted
11 | # shell: bash -lc "nginx -s reload"
12 |
13 | - name: Restart runs status update rake task
14 | become: yes
15 | become_method: sudo
16 | shell: bash -lc "restart {{ app_name }}"
17 |
--------------------------------------------------------------------------------
/provisioning/roles/start/tasks/main.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: Start unicorn
3 | become: yes
4 | become_method: sudo
5 | shell: bash -lc "/etc/init.d/unicorn_{{ app_name }} start"
6 |
7 | - name: Start nginx
8 | become: yes
9 | become_method: sudo
10 | service: name=nginx state=started
11 |
12 | - name: Start runs update statuses rake task
13 | become: yes
14 | become_method: sudo
15 | shell: bash -lc "start {{ app_name }}"
16 |
--------------------------------------------------------------------------------
/provisioning/roles/stop/tasks/main.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: Stop unicorn
3 | become: yes
4 | become_method: sudo
5 | shell: bash -lc "/etc/init.d/unicorn_{{ app_name }} stop"
6 |
7 | - name: Stop nginx
8 | become: yes
9 | become_method: sudo
10 | service: name=nginx state=stopped
11 |
12 | - name: Stop runs status update rake task
13 | become: yes
14 | become_method: sudo
15 | shell: bash -lc "stop {{ app_name }}"
16 |
--------------------------------------------------------------------------------
/provisioning/setup_backups.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - hosts: all
3 | sudo: no
4 |
5 | vars:
6 | app_root: /home/hiredintech/applications/codemarathon
7 | app_name: codemarathon
8 |
9 | roles:
10 | - backup
11 | # - restart
12 |
--------------------------------------------------------------------------------
/provisioning/setup_vagrant.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - hosts: all
3 | sudo: no
4 |
5 | vars:
6 | ruby_version: 2.2.2
7 |
8 | roles:
9 | - install
10 |
--------------------------------------------------------------------------------
/provisioning/start_production.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - hosts: all
3 | sudo: no
4 |
5 | vars:
6 | app_name: codemarathon
7 |
8 | roles:
9 | - start
10 |
--------------------------------------------------------------------------------
/provisioning/stop_production.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - hosts: all
3 | sudo: no
4 |
5 | vars:
6 | app_name: codemarathon
7 |
8 | roles:
9 | - stop
10 |
--------------------------------------------------------------------------------
/public/404.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
The page you were looking for doesn't exist (404)
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
Hey, we're sorry but this page does not exist at the moment.
20 |
21 |
You could go back to the home page
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/public/500.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
The page you were looking for doesn't exist (404)
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
Hm, something seems to be broken. We'll look into it and we apologize for the inconvenience!
20 |
21 |
You could go back to the home page
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/public/css/styles.css:
--------------------------------------------------------------------------------
1 | div.dialog {
2 | width: 95%;
3 | max-width: 33em;
4 | margin: 1em auto 0;
5 | margin-top: 20%;
6 | text-align: center;
7 | font-family: medium-content-serif-font,Georgia,Cambria,"Times New Roman",Times,serif;
8 | font-weight: 400;
9 | font-style: normal;
10 | line-height: 1.58;
11 | letter-spacing: -.003em;
12 | font-size: 20px;
13 | }
14 |
--------------------------------------------------------------------------------
/public/img/hiredintech_logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antonrd/codemarathon/0d601b1d1fa5ada715a1e567a0bd55ed8f11170f/public/img/hiredintech_logo.png
--------------------------------------------------------------------------------
/public/robots.txt:
--------------------------------------------------------------------------------
1 | # See http://www.robotstxt.org/robotstxt.html for documentation on how to use the robots.txt file
2 | #
3 | # To ban all spiders from the entire site uncomment the next two lines:
4 | # User-agent: *
5 | # Disallow: /
6 |
--------------------------------------------------------------------------------
/spec/controllers/pages_controller_spec.rb:
--------------------------------------------------------------------------------
1 | describe PagesController do
2 | describe "#home" do
3 | before do
4 | get :home
5 | end
6 |
7 | it { is_expected.to respond_with(:found) }
8 | end
9 |
10 | describe "#about" do
11 | before do
12 | get :about
13 | end
14 |
15 | it { is_expected.to respond_with(:success) }
16 | end
17 |
18 | describe "#about_codemarathon" do
19 | before do
20 | get :about_codemarathon
21 | end
22 |
23 | it { is_expected.to respond_with(:success) }
24 | end
25 | end
26 |
--------------------------------------------------------------------------------
/spec/factories/classroom_records.rb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antonrd/codemarathon/0d601b1d1fa5ada715a1e567a0bd55ed8f11170f/spec/factories/classroom_records.rb
--------------------------------------------------------------------------------
/spec/factories/classrooms.rb:
--------------------------------------------------------------------------------
1 | FactoryGirl.define do
2 | factory :classroom do
3 | name "Classroom name"
4 | sequence(:slug) { |i| "classroom-slug-#{ i }" }
5 |
6 | course
7 | end
8 | end
9 |
--------------------------------------------------------------------------------
/spec/factories/courses.rb:
--------------------------------------------------------------------------------
1 | FactoryGirl.define do
2 | factory :course do
3 | title "Some course title"
4 | subtitle "Some course subtitle"
5 | sequence(:slug) { |i| "course-slug-#{ i }" }
6 | markdown_description "Hello world!"
7 | markdown_long_description "Hello *world*! And everyone *else*"
8 | visible true
9 | end
10 | end
11 |
--------------------------------------------------------------------------------
/spec/factories/lesson_records.rb:
--------------------------------------------------------------------------------
1 | FactoryGirl.define do
2 | factory :lesson_record do
3 | views 10
4 | covered false
5 |
6 | user
7 | lesson
8 | classroom
9 | end
10 | end
11 |
--------------------------------------------------------------------------------
/spec/factories/lessons.rb:
--------------------------------------------------------------------------------
1 | FactoryGirl.define do
2 | factory :lesson do
3 | title "Some lesson title"
4 | sequence(:position) { |i| i }
5 | section
6 | markdown_content "***Great lesson***"
7 | visible true
8 | end
9 | end
10 |
--------------------------------------------------------------------------------
/spec/factories/quiz_answers.rb:
--------------------------------------------------------------------------------
1 | FactoryGirl.define do
2 | factory :quiz_answer do
3 | association :quiz_question
4 | markdown_content "**Quiz answer text**"
5 | correct true
6 | end
7 | end
8 |
--------------------------------------------------------------------------------
/spec/factories/quiz_attempts.rb:
--------------------------------------------------------------------------------
1 | FactoryGirl.define do
2 | factory :quiz_attempt do
3 | association :quiz
4 | association :user
5 | score 1.5
6 | answers_json "{}"
7 | end
8 | end
9 |
--------------------------------------------------------------------------------
/spec/factories/quiz_questions.rb:
--------------------------------------------------------------------------------
1 | FactoryGirl.define do
2 | factory :quiz_question do
3 | association :quiz
4 | markdown_content "**Quiz text**"
5 | markdown_explanation "Test explanation"
6 | question_type QuizQuestion::TYPE_MULTIPLE_CHOICE
7 | end
8 | end
9 |
--------------------------------------------------------------------------------
/spec/factories/quizzes.rb:
--------------------------------------------------------------------------------
1 | FactoryGirl.define do
2 | factory :quiz do
3 | title "Some quiz title"
4 | association :creator, factory: :user
5 | maximum_attempts 10
6 | end
7 | end
8 |
--------------------------------------------------------------------------------
/spec/factories/roles.rb:
--------------------------------------------------------------------------------
1 | FactoryGirl.define do
2 | factory :role do
3 | user
4 |
5 | trait :teacher do
6 | role_type User::ROLE_TEACHER
7 | end
8 |
9 | trait :admin do
10 | role_type User::ROLE_ADMIN
11 | end
12 | end
13 | end
14 |
--------------------------------------------------------------------------------
/spec/factories/sections.rb:
--------------------------------------------------------------------------------
1 | FactoryGirl.define do
2 | factory :section do
3 | title "Some section title"
4 | sequence(:position) { |i| i }
5 | course
6 | visible true
7 | end
8 | end
9 |
--------------------------------------------------------------------------------
/spec/factories/task_records.rb:
--------------------------------------------------------------------------------
1 | FactoryGirl.define do
2 | factory :task_record do
3 | user
4 | task
5 | best_score 50.0
6 | association :best_run, factory: :task_run
7 | covered true
8 | end
9 | end
10 |
--------------------------------------------------------------------------------
/spec/factories/task_runs.rb:
--------------------------------------------------------------------------------
1 | FactoryGirl.define do
2 | factory :task_run do
3 | user
4 | task
5 | source_code "print \'hello world\'"
6 | lang "ruby"
7 | status TaskRun::STATUS_SUCCESS
8 | external_key "14"
9 | message "success"
10 | grader_log "some log"
11 | memory_limit_kb 1024
12 | time_limit_ms 1000
13 | run_type TaskRun::TYPE_RUN_TASK
14 | points 50.0
15 | display_status "Some Errors"
16 | compilation_log nil
17 | has_ml false
18 | has_tl true
19 | has_wa true
20 | has_re false
21 | re_details nil
22 | show_source_code true
23 | show_user_name false
24 | end
25 | end
26 |
--------------------------------------------------------------------------------
/spec/factories/tasks.rb:
--------------------------------------------------------------------------------
1 | FactoryGirl.define do
2 | factory :task do
3 | title "Some task title"
4 | task_type Task::TASK_TYPE_IOFILES
5 | markdown_description "**Task description**"
6 | association :creator, factory: :user
7 | visible true
8 | external_key "14"
9 | memory_limit_kb 1024
10 | time_limit_ms 1000
11 | cpp_boilerplate "int foo(int value) { // write code here }"
12 | cpp_wrapper "int main() { foo(); return 0; }"
13 | java_boilerplate "java boilerplate"
14 | java_wrapper "java wrapper"
15 | end
16 | end
17 |
--------------------------------------------------------------------------------
/spec/factories/user_invitations.rb:
--------------------------------------------------------------------------------
1 | FactoryGirl.define do
2 | factory :user_invitation do
3 | sequence(:email) { |i| "user-#{ i }@codemarathon.com" }
4 | used false
5 | end
6 | end
7 |
--------------------------------------------------------------------------------
/spec/factories/users.rb:
--------------------------------------------------------------------------------
1 | FactoryGirl.define do
2 | factory :user do
3 | sequence(:email) { |i| "user-#{ i }@codemarathon.com" }
4 | sequence(:name) { |i| "Some Name-#{ i }" }
5 | password "some_test_pass"
6 | active true
7 |
8 | trait :teacher do
9 | after(:create) do |user, evaluator|
10 | create(:role, :teacher, user: user)
11 | end
12 | end
13 |
14 | trait :admin do
15 | after(:create) do |user, evaluator|
16 | create(:role, :admin, user: user)
17 | end
18 | end
19 | end
20 | end
21 |
--------------------------------------------------------------------------------
/spec/features/oauth_sign_in_spec.rb:
--------------------------------------------------------------------------------
1 | feature "OAuth log in" do
2 |
3 | given(:mock_user_data) do
4 | { uid: '12345', info: {email: 'test@test.com', name: 'Some Name'} }
5 | end
6 |
7 | background do
8 | OmniAuth.config.add_mock(:google_oauth2, mock_user_data)
9 | OmniAuth.config.add_mock(:github, mock_user_data)
10 |
11 | visit new_user_session_path
12 | end
13 |
14 | context "when user signs up" do
15 | scenario "using Google" do
16 | click_link "Log in with Google"
17 |
18 | expect(current_path).to eq(courses_path)
19 | expect(page).to have_text(mock_user_data[:info][:name])
20 | expect(User.count).to eq(1)
21 | end
22 |
23 | scenario "using Github" do
24 | click_link "Log in with GitHub"
25 |
26 | expect(current_path).to eq(courses_path)
27 | expect(page).to have_text(mock_user_data[:info][:name])
28 | expect(User.count).to eq(1)
29 | end
30 | end
31 |
32 | context "when user logs in" do
33 | given(:user) { FactoryGirl.create(:user, email: mock_user_data[:info][:email]) }
34 |
35 | background do
36 | user.confirmed_at = Time.now
37 | user.save
38 | end
39 |
40 | scenario "using Google" do
41 | click_link "Log in with Google"
42 |
43 | expect(current_path).to eq(courses_path)
44 | expect(page).to have_text(mock_user_data[:info][:name])
45 | expect(User.count).to eq(1)
46 | end
47 |
48 | scenario "using Github" do
49 | click_link "Log in with GitHub"
50 |
51 | expect(current_path).to eq(courses_path)
52 | expect(page).to have_text(mock_user_data[:info][:name])
53 | expect(User.count).to eq(1)
54 | end
55 | end
56 |
57 | end
58 |
--------------------------------------------------------------------------------
/spec/features/user_sign_in_spec.rb:
--------------------------------------------------------------------------------
1 | feature "User log in" do
2 |
3 | given(:user) { FactoryGirl.create :user }
4 |
5 | context "user log in" do
6 | background do
7 | user.confirmed_at = Time.now
8 | user.save
9 | visit new_user_session_path
10 | end
11 |
12 | scenario "successful" do
13 | within "#new_user" do
14 | fill_in "Email", with: user.email
15 | fill_in "Password", with: user.password
16 | click_button "Log in"
17 | end
18 |
19 | expect(page).to have_text user.name
20 | end
21 |
22 | scenario "incorrect email" do
23 | within "#new_user" do
24 | fill_in "Email", with: user.email.reverse
25 | fill_in "Password", with: user.password
26 | click_button "Log in"
27 | end
28 |
29 | expect(page).to have_content (/Invalid email or password/i)
30 | end
31 |
32 | scenario "incorrect password" do
33 | within "#new_user" do
34 | fill_in "Email", with: user.email
35 | fill_in "Password", with: user.email.reverse
36 | click_button "Log in"
37 | end
38 |
39 | expect(page).to have_content (/Invalid email or password/i)
40 | end
41 | end
42 |
43 | end
44 |
--------------------------------------------------------------------------------
/spec/fixtures/quiz_attempt_answers.json:
--------------------------------------------------------------------------------
1 | {
2 | "1": {
3 | "1": {
4 | "user_answer": false,
5 | "correct_answer": false,
6 | "is_correct": true
7 | },
8 | "2": {
9 | "user_answer": true,
10 | "correct_answer": true,
11 | "is_correct": true
12 | },
13 | "3": {
14 | "user_answer": false,
15 | "correct_answer": true,
16 | "is_correct": false
17 | },
18 | "score": 0.6666666666666666
19 | },
20 | "2": {
21 | "user_answer": "sdf",
22 | "correct_answer": "\\A[a-z]+\\z",
23 | "is_correct": {},
24 | "score": 1
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/spec/models/role_spec.rb:
--------------------------------------------------------------------------------
1 | describe Role do
2 | it { is_expected.to validate_presence_of(:user) }
3 | it { is_expected.to validate_presence_of(:role_type) }
4 |
5 | it { is_expected.to belong_to(:user) }
6 | end
7 |
--------------------------------------------------------------------------------
/spec/models/user_invitation_spec.rb:
--------------------------------------------------------------------------------
1 | describe UserInvitation do
2 | let!(:user_invitation) { FactoryGirl.create(:user_invitation) }
3 |
4 | it { is_expected.to validate_presence_of(:email) }
5 | it { is_expected.to validate_uniqueness_of(:email) }
6 | end
7 |
--------------------------------------------------------------------------------
/spec/services/fetch_task_statistics_spec.rb:
--------------------------------------------------------------------------------
1 | describe FetchTaskStatistics do
2 | describe "#fetch_successful_runs_stats" do
3 | let!(:task) { FactoryGirl.create(:task) }
4 | let!(:task_run1) { FactoryGirl.create(:task_run, points: 0, lang: 'cpp', task: task) }
5 | let!(:task_run2) { FactoryGirl.create(:task_run, points: 100, lang: 'cpp', task: task) }
6 | let!(:task_run3) { FactoryGirl.create(:task_run, points: 100, lang: 'java', task: task) }
7 | let!(:task_run4) { FactoryGirl.create(:task_run, points: 0, lang: 'python', task: task) }
8 |
9 | subject { FetchTaskStatistics.new.call }
10 |
11 | it "computes total statistics" do
12 | expect(subject[task.id][:successful_runs]).to eq(2)
13 | expect(subject[task.id][:all_runs]).to eq(4)
14 | expect(subject[task.id][:success_percent]).to eq(50)
15 | end
16 |
17 | context "with a given langauge" do
18 | it "computes 100\% success when all submissions are successful" do
19 | expect(subject[task.id][:java_success_percent]).to eq(100)
20 | end
21 |
22 | it "computes partial success when there are failed submissions" do
23 | expect(subject[task.id][:cpp_success_percent]).to eq(50)
24 | end
25 |
26 | it "computes 0 percent success when there are no successful submissions" do
27 | expect(subject[task.id][:python_success_percent]).to eq(0)
28 | end
29 |
30 | it "contains no data if there are no submissions for a language" do
31 | expect(subject[task.id][:ruby_success_percent]).to be_nil
32 | end
33 | end
34 | end
35 | end
36 |
--------------------------------------------------------------------------------
/spec/services/score_quiz_attempt_spec.rb:
--------------------------------------------------------------------------------
1 | describe ScoreQuizAttempt do
2 | let(:score_quiz_attempt) { ScoreQuizAttempt.new }
3 | let(:user) { FactoryGirl.create(:user) }
4 |
5 | let(:classroom) { FactoryGirl.create(:classroom) }
6 | let(:lesson) { FactoryGirl.create(:lesson) }
7 | let(:lesson_record) { lesson.lesson_record_for(classroom, user) }
8 | let(:quiz) { FactoryGirl.create(:quiz) }
9 | let(:quiz_question1) { FactoryGirl.create(:quiz_question,
10 | question_type: QuizQuestion::TYPE_MULTIPLE_CHOICE, quiz: quiz) }
11 | let(:quiz_question2) { FactoryGirl.create(:quiz_question,
12 | question_type: QuizQuestion::TYPE_FREETEXT,
13 | freetext_regex: "\\A[a-z]+\\z", quiz: quiz) }
14 |
15 | let!(:quiz_answer1) { FactoryGirl.create(:quiz_answer,
16 | quiz_question: quiz_question1, correct: false) }
17 | let!(:quiz_answer2) { FactoryGirl.create(:quiz_answer,
18 | quiz_question: quiz_question1, correct: true) }
19 |
20 | let(:params) { generate_quiz_answers([quiz_question1, quiz_question2]) }
21 |
22 | describe "#call" do
23 | before do
24 | lesson.quizzes << quiz
25 | ScoreQuizAttempt.new(quiz, user, params["quiz_attempt"]).call
26 | end
27 |
28 | it "computes the score for one quiz attempt" do
29 | expect(QuizAttempt.last.score).to eq(1.5)
30 | end
31 |
32 | it "stores the quiz attempt answers" do
33 | answers = JSON.parse(QuizAttempt.last.answers_json)
34 | expect(answers.has_key?(quiz_question1.id.to_s)).to be_truthy
35 | end
36 | end
37 | end
38 |
--------------------------------------------------------------------------------
/spec/support/factory_girl.rb:
--------------------------------------------------------------------------------
1 | RSpec.configure do |config|
2 | # Make short `#create` or `#build` factory_girl methods available in specs
3 | config.include FactoryGirl::Syntax::Methods
4 |
5 | factories_to_lint = FactoryGirl.factories.reject do |factory|
6 | factory.name.in? [:course, :section, :lesson, :user, :role]
7 | end
8 |
9 | config.before(:suite) do
10 | begin
11 | DatabaseCleaner.start
12 | FactoryGirl.lint factories_to_lint
13 | ensure
14 | DatabaseCleaner.clean
15 | end
16 | end
17 | end
18 |
19 | # config.before(:each, js: true) do
20 | # # JS examples are run with Poltergeist which uses separate db
21 | # # connection. It's impossible to use :transaction strategy in this case
22 | # # because records shouldn't be available outside of the transaction (e.g. in
23 | # # another db connection). For such examples :truncation strategy is more
24 | # # appropriate.
25 | # DatabaseCleaner.strategy = :truncation
26 | # end
27 |
--------------------------------------------------------------------------------
/spec/support/grader_helper.rb:
--------------------------------------------------------------------------------
1 | module GraderHelper
2 | def stub_grader_calls
3 | task_response = { "task_id" => 1, "status" => 0, "message" => "success" }
4 | stub_request(:any, /http:\/\/grader\/tasks.*/).to_return(status: 200, body: task_response.to_json)
5 |
6 | run_response = { "run_id" => 1, "status" => 0, "message" => "success" }
7 | stub_request(:any, /http:\/\/grader\/runs.*/).to_return(status: 200, body: run_response.to_json)
8 | end
9 | end
10 |
--------------------------------------------------------------------------------
/spec/support/omniauth.rb:
--------------------------------------------------------------------------------
1 | module OmniauthHelpers
2 | def mock_auth_hash provider_name, email=nil
3 | OmniAuth.config.mock_auth[provider_name] = OmniAuth::AuthHash.new({
4 | provider: provider_name.to_s,
5 | uid: '123456',
6 | credentials: {
7 | token: "sample-token",
8 | expires_at: 1.hours.from_now.to_i
9 | },
10 | info: {
11 | name: "Some Name",
12 | email: email || "some@email.com"
13 | }
14 | })
15 | end
16 | end
17 |
18 | OmniAuth.config.test_mode = true
19 |
--------------------------------------------------------------------------------
/spec/support/quiz_helper.rb:
--------------------------------------------------------------------------------
1 | module QuizHelper
2 | def generate_quiz_answers quiz_questions
3 | answers = {}
4 |
5 | quiz_questions.each do |quiz_question|
6 | if quiz_question.question_type == QuizQuestion::TYPE_MULTIPLE_CHOICE
7 | answers[quiz_question.id.to_s] = {}
8 | answers[quiz_question.id.to_s]["multiple_answers"] = {}
9 |
10 | quiz_question.quiz_answers.each do |quiz_answer|
11 | answers[quiz_question.id.to_s]["multiple_answers"][quiz_answer.id.to_s] = 1
12 | end
13 |
14 | else
15 | is_correct = quiz_question.correct_freetext_answer?("abc")
16 |
17 | answers[quiz_question.id.to_s] = {}
18 | answers[quiz_question.id.to_s]["freetext_answer"] = "abc"
19 | end
20 | end
21 |
22 | { 'quiz_attempt' => answers }
23 | end
24 | end
25 |
--------------------------------------------------------------------------------
/spec/support/shared_db_connection.rb:
--------------------------------------------------------------------------------
1 | class ActiveRecord::Base
2 | mattr_accessor :shared_connection
3 | @@shared_connection = nil
4 |
5 | def self.connection
6 | @@shared_connection || retrieve_connection
7 | end
8 | end
9 |
10 | # Forces all threads to share the same connection. This works on
11 | # Capybara because it starts the web server in a thread.
12 | ActiveRecord::Base.shared_connection = ActiveRecord::Base.connection
13 |
--------------------------------------------------------------------------------
/spec/support/webmock.rb:
--------------------------------------------------------------------------------
1 | require 'webmock/rspec'
2 |
3 | WebMock.disable_net_connect!(allow_localhost: true)
4 |
--------------------------------------------------------------------------------
/vendor/assets/javascripts/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antonrd/codemarathon/0d601b1d1fa5ada715a1e567a0bd55ed8f11170f/vendor/assets/javascripts/.keep
--------------------------------------------------------------------------------
/vendor/assets/stylesheets/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antonrd/codemarathon/0d601b1d1fa5ada715a1e567a0bd55ed8f11170f/vendor/assets/stylesheets/.keep
--------------------------------------------------------------------------------