├── .gitignore
├── .project
├── .pydevproject
├── Capfile
├── DEVNOTES.md
├── Gemfile
├── README.md
├── README.rdoc
├── Rakefile
├── app
├── assets
│ ├── images
│ │ ├── bg.png
│ │ ├── curl-blue-small.png
│ │ ├── curl-gray-small.png
│ │ ├── curl-green-small.png
│ │ ├── curl-red-small.png
│ │ ├── curl-yellow-small.png
│ │ ├── curl.png
│ │ ├── landing-header-bg.png
│ │ ├── navbar-separator.png
│ │ └── snake-cap-300h.png
│ ├── javascripts
│ │ ├── activity_logs.js.coffee
│ │ ├── application.js
│ │ ├── assignment_offerings.js.coffee
│ │ ├── assignment_repositories.js.coffee
│ │ ├── assignments.js.coffee
│ │ ├── authentications.js.coffee
│ │ ├── code.js.coffee
│ │ ├── color-picker.js.coffee
│ │ ├── course_offerings.js.coffee
│ │ ├── courses.js.coffee
│ │ ├── environments.js.coffee
│ │ ├── errors.js.coffee
│ │ ├── example_repositories.js.coffee
│ │ ├── global.js.coffee
│ │ ├── highcharts-theme.js.coffee
│ │ ├── home.js.coffee
│ │ ├── internal
│ │ │ ├── builtin.js
│ │ │ ├── skulpt-uncomp.js
│ │ │ └── skulpt.js
│ │ ├── juggernaut.js
│ │ ├── landing.js.coffee
│ │ ├── media-library.js.coffee
│ │ ├── organizations.js.coffee
│ │ ├── picture_tool.js.coffee
│ │ ├── setup.js.coffee
│ │ ├── sound.js.coffee
│ │ ├── sound_tool.js.coffee
│ │ ├── system_configurations.js.coffee
│ │ ├── terms.js.coffee
│ │ ├── typeaheads.js.coffee
│ │ └── upload_roster.js.coffee
│ └── stylesheets
│ │ ├── activity_logs.css.scss
│ │ ├── application.css
│ │ ├── assignment_offerings.css.scss
│ │ ├── assignment_repositories.css.scss
│ │ ├── assignments.css.scss
│ │ ├── authentications.css.scss
│ │ ├── bootstrap_and_overrides.css.less
│ │ ├── code.css.scss
│ │ ├── course_offerings.css.scss
│ │ ├── courses.css.scss
│ │ ├── environments.css.scss
│ │ ├── errors.css.scss
│ │ ├── example_repositories.css.scss
│ │ ├── global.css.scss
│ │ ├── home.css.scss
│ │ ├── landing.css.scss
│ │ ├── organizations.css.scss
│ │ ├── scaffolds.css.scss
│ │ ├── setup.css.scss
│ │ ├── system_configurations.css.scss
│ │ └── terms.css.scss
├── controllers
│ ├── activity_logs_controller.rb
│ ├── application_controller.rb
│ ├── assignment_checks_controller.rb
│ ├── assignment_offerings_controller.rb
│ ├── assignment_repositories_controller.rb
│ ├── assignments_controller.rb
│ ├── authentications_controller.rb
│ ├── code_controller.rb
│ ├── course_enrollments_controller.rb
│ ├── course_offerings_controller.rb
│ ├── course_roles_controller.rb
│ ├── courses_controller.rb
│ ├── environments_controller.rb
│ ├── errors_controller.rb
│ ├── example_repositories_controller.rb
│ ├── friendly_url_controller.rb
│ ├── global_roles_controller.rb
│ ├── home_controller.rb
│ ├── landing_controller.rb
│ ├── media_controller.rb
│ ├── organizations_controller.rb
│ ├── proxy_controller.rb
│ ├── registrations_controller.rb
│ ├── scratchpad_repositories_controller.rb
│ ├── self_enrollment_controller.rb
│ ├── sessions_controller.rb
│ ├── setup_controller.rb
│ ├── system_configurations_controller.rb
│ ├── terms_controller.rb
│ ├── typeaheads_controller.rb
│ ├── upload_roster_controller.rb
│ └── users_controller.rb
├── helpers
│ ├── activity_logs_helper.rb
│ ├── application_helper.rb
│ ├── assignment_offerings_helper.rb
│ ├── assignments_helper.rb
│ ├── authentications_helper.rb
│ ├── code_helper.rb
│ ├── course_enrollments_helper.rb
│ ├── course_offerings_helper.rb
│ ├── courses_helper.rb
│ ├── devise_helper.rb
│ ├── environments_helper.rb
│ ├── errors_helper.rb
│ ├── example_repositories_helper.rb
│ ├── friendly_url_helper.rb
│ ├── global_roles_helper.rb
│ ├── home_helper.rb
│ ├── landing_helper.rb
│ ├── media_helper.rb
│ ├── organizations_helper.rb
│ ├── setup_helper.rb
│ ├── system_configurations_helper.rb
│ ├── terms_helper.rb
│ └── users_helper.rb
├── mailers
│ └── .gitkeep
├── models
│ ├── .gitkeep
│ ├── ability.rb
│ ├── activity_log.rb
│ ├── assignment.rb
│ ├── assignment_check.rb
│ ├── assignment_offering.rb
│ ├── assignment_reference_repository.rb
│ ├── assignment_repository.rb
│ ├── authentication.rb
│ ├── check_outcome.rb
│ ├── commit_collector.rb
│ ├── course.rb
│ ├── course_enrollment.rb
│ ├── course_offering.rb
│ ├── course_offering_scores.rb
│ ├── course_role.rb
│ ├── environment.rb
│ ├── example_repository.rb
│ ├── global_role.rb
│ ├── media_item.rb
│ ├── organization.rb
│ ├── personal_repository.rb
│ ├── repository.rb
│ ├── resource_key_methods.rb
│ ├── scratchpad_repository.rb
│ ├── system_configuration.rb
│ ├── term.rb
│ ├── uploaded_roster.rb
│ └── user.rb
├── uploaders
│ └── media_item_uploader.rb
├── validators
│ ├── changeable_validator.rb
│ └── path_validator.rb
├── views
│ ├── activity_logs
│ │ ├── _activity_log.html.haml
│ │ ├── _table.html.haml
│ │ ├── filter.js.coffee
│ │ ├── index.html.haml
│ │ └── index.js.coffee
│ ├── application
│ │ ├── _flashbar.html.haml
│ │ ├── _form_errors.html.haml
│ │ ├── _index_search.html.haml
│ │ ├── _navbar.html.haml
│ │ ├── modal_form_errors.js.coffee
│ │ └── place_flash.js.coffee
│ ├── assignment_checks
│ │ ├── _score_history_modal.html.haml
│ │ ├── index.js.coffee
│ │ └── show.js.coffee
│ ├── assignment_offerings
│ │ ├── _form.html.haml
│ │ ├── _grades.html.haml
│ │ ├── _modal.html.haml
│ │ ├── create.js.coffee
│ │ ├── edit.html.haml
│ │ ├── new.js.coffee
│ │ └── show.json.rabl
│ ├── assignment_repositories
│ │ └── show.html.haml
│ ├── assignments
│ │ ├── _form.html.haml
│ │ ├── edit.html.haml
│ │ ├── index.html.erb
│ │ ├── new.html.erb
│ │ ├── show.html.haml
│ │ └── template_picker.html.haml
│ ├── authentications
│ │ └── index.html.haml
│ ├── code
│ │ ├── _check_outcomes_modal.html.haml
│ │ ├── _check_results.html.haml
│ │ ├── _choose_environment_modal.html.haml
│ │ ├── _color_picker.haml
│ │ ├── _commit.html.haml
│ │ ├── _file_list.html.haml
│ │ ├── _picture_tool.haml
│ │ ├── _sound_tool.haml
│ │ ├── _user_list.html.haml
│ │ ├── add_history.js.coffee
│ │ ├── check.js.coffee
│ │ ├── check_results.js.coffee
│ │ ├── prompt_for_environment.js.coffee
│ │ ├── related_files
│ │ │ └── _assignment_reference_repository.html.haml
│ │ ├── show.html.haml
│ │ ├── summary
│ │ │ ├── _assignment_reference_repository.html.haml
│ │ │ ├── _assignment_repository.html.haml
│ │ │ ├── _example_repository.html.haml
│ │ │ └── _scratchpad_repository.html.haml
│ │ ├── update.js.coffee
│ │ ├── update_code.js.coffee
│ │ └── update_user_list.js.coffee
│ ├── course_enrollments
│ │ ├── _course_enrollment.html.haml
│ │ ├── _modal.html.haml
│ │ ├── _table.html.haml
│ │ ├── create.js.coffee
│ │ ├── destroy.js.coffee
│ │ ├── index.js.coffee
│ │ └── new.js.coffee
│ ├── course_offerings
│ │ ├── _form.html.haml
│ │ ├── _index.html.haml
│ │ ├── edit.html.haml
│ │ ├── index.html.haml
│ │ ├── new.html.haml
│ │ ├── show.html.haml
│ │ └── show.js.coffee
│ ├── course_roles
│ │ ├── _form.html.haml
│ │ ├── edit.html.haml
│ │ ├── index.html.haml
│ │ ├── new.html.haml
│ │ └── show.html.haml
│ ├── courses
│ │ ├── _form.html.haml
│ │ ├── _index.html.haml
│ │ ├── edit.html.haml
│ │ ├── index.html.haml
│ │ ├── new.html.haml
│ │ └── show.html.haml
│ ├── devise
│ │ ├── _links.erb
│ │ ├── confirmations
│ │ │ └── new.html.erb
│ │ ├── mailer
│ │ │ ├── confirmation_instructions.html.erb
│ │ │ ├── reset_password_instructions.html.erb
│ │ │ └── unlock_instructions.html.erb
│ │ ├── passwords
│ │ │ ├── edit.html.erb
│ │ │ └── new.html.erb
│ │ ├── registrations
│ │ │ ├── edit.html.erb
│ │ │ └── new.html.haml
│ │ └── unlocks
│ │ │ └── new.html.erb
│ ├── environments
│ │ ├── _form.html.haml
│ │ ├── edit.html.haml
│ │ ├── index.html.haml
│ │ ├── new.html.haml
│ │ └── show.html.haml
│ ├── errors
│ │ ├── _modal.html.haml
│ │ ├── error_403.html.haml
│ │ ├── error_404.html.haml
│ │ ├── error_500.html.haml
│ │ └── error_modal.js.coffee
│ ├── example_repositories
│ │ ├── _empty.html.haml
│ │ ├── _example_repository.html.haml
│ │ ├── _modal.html.haml
│ │ ├── create.js.coffee
│ │ ├── destroy.js.coffee
│ │ ├── index.js.coffee
│ │ └── new.js.coffee
│ ├── global_roles
│ │ ├── _form.html.haml
│ │ ├── edit.html.haml
│ │ ├── index.html.haml
│ │ ├── new.html.haml
│ │ └── show.html.haml
│ ├── home
│ │ ├── _course_staff_assignments.html.haml
│ │ ├── _course_staff_grades.html.haml
│ │ ├── _course_staff_offering_settings.html.haml
│ │ ├── _course_staff_settings.html.haml
│ │ ├── _course_staff_users.html.haml
│ │ ├── _instructor_assignment.html.haml
│ │ ├── _no_assignments.html.haml
│ │ ├── _no_started_assignments.html.haml
│ │ ├── _not_found.html.haml
│ │ ├── _not_started_assignment.html.haml
│ │ ├── _started_assignment.html.haml
│ │ ├── course.js.coffee
│ │ ├── course_staff.html.haml
│ │ ├── course_student.html.haml
│ │ ├── index.html.haml
│ │ ├── load_grades.js.coffee
│ │ └── refresh_examples.js.coffee
│ ├── kaminari
│ │ ├── _first_page.html.haml
│ │ ├── _gap.html.haml
│ │ ├── _last_page.html.haml
│ │ ├── _next_page.html.haml
│ │ ├── _page.html.haml
│ │ ├── _paginator.html.haml
│ │ └── _prev_page.html.haml
│ ├── landing
│ │ └── index.html.haml
│ ├── layouts
│ │ ├── code.html.haml
│ │ ├── error.html.haml
│ │ ├── landing.html.haml
│ │ ├── logged_in.html.haml
│ │ ├── no_container.html.haml
│ │ ├── not_logged_in.html.haml
│ │ └── setup.html.haml
│ ├── media
│ │ ├── _filter_item.html.haml
│ │ ├── _index.html.haml
│ │ ├── _modal.html.haml
│ │ ├── destroy.js.coffee
│ │ ├── index.html.haml
│ │ └── index.js.coffee
│ ├── organizations
│ │ ├── _form.html.haml
│ │ ├── edit.html.haml
│ │ ├── index.html.haml
│ │ ├── new.html.haml
│ │ └── show.html.haml
│ ├── registrations
│ │ ├── _new.html.haml
│ │ └── edit.html.haml
│ ├── self_enrollment
│ │ ├── _course_list.html.haml
│ │ ├── _select_organization.html.haml
│ │ ├── _select_term.html.haml
│ │ ├── select_organization.js.coffee
│ │ └── select_term.js.coffee
│ ├── sessions
│ │ ├── _sign_in.html.haml
│ │ ├── new.html.haml
│ │ └── new_initial.html.haml
│ ├── setup
│ │ └── index.html.haml
│ ├── system_configurations
│ │ ├── _form.html.haml
│ │ ├── edit.html.haml
│ │ ├── new.html.haml
│ │ └── show.html.haml
│ ├── terms
│ │ ├── _form.html.haml
│ │ ├── edit.html.haml
│ │ ├── index.html.haml
│ │ ├── new.html.haml
│ │ └── show.html.haml
│ ├── upload_roster
│ │ ├── _modal.html.haml
│ │ ├── _table.html.haml
│ │ ├── index.js.coffee
│ │ └── upload.js.coffee
│ └── users
│ │ ├── _form.html.haml
│ │ ├── _user.html.haml
│ │ ├── edit.html.haml
│ │ ├── index.html.haml
│ │ ├── index.js.coffee
│ │ ├── new.html.haml
│ │ └── show.html.haml
└── workers
│ └── check_code_worker.rb
├── code_examples
└── image_manipulation.py
├── config.ru
├── config
├── application.rb
├── boot.rb
├── deploy.rb
├── deploy
│ ├── production.rb
│ └── staging.rb
├── environment.rb
├── environments
│ ├── development.rb
│ ├── production.rb
│ ├── staging.rb
│ └── test.rb
├── initializers
│ ├── backtrace_silencers.rb
│ ├── devise.rb
│ ├── inflections.rb
│ ├── mime_types.rb
│ ├── omniauth.rb
│ ├── rabl.rb
│ ├── redis.rb
│ ├── secret_token.rb
│ ├── session_store.rb
│ └── wrap_parameters.rb
├── locales
│ ├── devise.en.yml
│ └── en.yml
├── routes.rb
└── sidekiq.yml
├── db
├── migrate
│ ├── 20120709021020_devise_create_users.rb
│ ├── 20120924132009_create_institutions.rb
│ ├── 20120924132121_create_departments.rb
│ ├── 20120924132144_create_terms.rb
│ ├── 20120924132208_create_courses.rb
│ ├── 20120924132630_create_course_offerings.rb
│ ├── 20120924132808_create_assignments.rb
│ ├── 20120924133015_create_assignment_offerings.rb
│ ├── 20120924141027_add_initial_columns_to_users.rb
│ ├── 20120927011009_create_rails_admin_histories_table.rb
│ ├── 20121114021257_create_global_roles.rb
│ ├── 20121205005020_create_authentications.rb
│ ├── 20121206145720_create_repositories.rb
│ ├── 20121212151228_create_course_roles.rb
│ ├── 20121212161741_create_course_enrollments.rb
│ ├── 20121224211905_create_activity_logs.rb
│ ├── 20130103133018_create_system_configurations.rb
│ ├── 20130109175139_create_assignment_checks.rb
│ ├── 20130111190807_create_check_outcomes.rb
│ ├── 20130518031137_create_media_items.rb
│ ├── 20130529205501_add_resource_key_to_users.rb
│ ├── 20130529205532_add_resource_key_to_assignments.rb
│ ├── 20130615112518_add_commit_sha_to_assignment_checks.rb
│ ├── 20130617144912_add_self_enrollment_allowed_to_course_offerings.rb
│ ├── 20130617145517_drop_departments_table.rb
│ ├── 20130617145542_add_institution_id_to_courses.rb
│ ├── 20130617204903_remove_institution_id_from_users.rb
│ ├── 20130617205241_rename_institutions_to_organizations.rb
│ ├── 20130619172521_merge_first_last_name_into_full_name.rb
│ ├── 20130623191637_rename_course_offering_crn_and_label.rb
│ ├── 20130625201013_create_environments.rb
│ ├── 20130625202204_add_default_environment_id_to_courses.rb
│ ├── 20130625202241_add_environment_id_to_repositories.rb
│ ├── 20131014014924_add_term_id_to_assignments.rb
│ ├── 20131119081535_split_full_name_into_first_and_last_name.rb
│ └── 20140116001823_add_current_course_and_current_term_to_users.rb
├── schema.rb
└── seeds.rb
├── doc
├── README_FOR_APP
├── other_features.md
└── todolist.md
├── erd.pdf
├── lib
├── assets
│ └── .gitkeep
├── custom_failure.rb
├── rails_extensions.rb
├── render_anywhere.rb
└── tasks
│ └── .gitkeep
├── notes.txt
├── package.json
├── public
├── 404.html
├── 422.html
├── 500.html
├── favicon.png
└── robots.txt
├── python
├── .gitignore
├── README.md
├── image
│ ├── __init__.py
│ ├── color.py
│ ├── fonts
│ │ ├── Comic_Sans_MS.ttf
│ │ ├── Comic_Sans_MS_Bold.ttf
│ │ ├── Comic_Sans_MS_Bold_Italic.ttf
│ │ ├── Comic_Sans_MS_Italic.ttf
│ │ ├── LiberationMono.ttf
│ │ ├── LiberationMono_Bold.ttf
│ │ ├── LiberationMono_Bold_Italic.ttf
│ │ ├── LiberationMono_Italic.ttf
│ │ ├── Times_New_Roman.ttf
│ │ ├── Times_New_Roman_Bold.ttf
│ │ ├── Times_New_Roman_Bold_Italic.ttf
│ │ ├── Times_New_Roman_Italic.ttf
│ │ ├── Verdana.ttf
│ │ ├── Verdana_Bold.ttf
│ │ ├── Verdana_Bold_Italic.ttf
│ │ └── Verdana_Italic.ttf
│ ├── picture.py
│ ├── pixel.py
│ └── style.py
├── media
│ └── __init__.py
├── pythy
│ ├── __init__.py
│ ├── sandbox.py
│ └── test.py
├── sound
│ ├── __init__.py
│ ├── sample.py
│ └── sound.py
├── tests
│ ├── image
│ │ ├── README.md
│ │ ├── color_test.py
│ │ ├── imgs
│ │ │ ├── addArcFilled_10_10_100_50_60_30.png
│ │ │ ├── addArcFilled_10_10_100_50_60_30_magenta.png
│ │ │ ├── addArc_10_10_100_50_60_30.png
│ │ │ ├── addArc_10_10_100_50_60_30_magenta.png
│ │ │ ├── addLine_10_10_20_20.png
│ │ │ ├── addLine_10_10_20_20_pink.png
│ │ │ ├── addOvalFilled_10_10_70_50.png
│ │ │ ├── addOvalFilled_10_10_70_50_yellow.png
│ │ │ ├── addOval_10_10_70_50.png
│ │ │ ├── addOval_10_10_70_50_orange.png
│ │ │ ├── addRectFilled_10_10_70_50.png
│ │ │ ├── addRectFilled_10_10_70_50_red.png
│ │ │ ├── addRect_10_10_70_50.png
│ │ │ ├── addRect_10_10_70_50_red.png
│ │ │ ├── addTextWithStyle_10_10_Hello_sansSerif_BOLDITALIC_10.png
│ │ │ ├── addTextWithStyle_10_10_Hello_sansSerif_BOLDITALIC_10_green.png
│ │ │ ├── addText_10_10_Hello.png
│ │ │ ├── addText_10_10_Hello_cyan.png
│ │ │ ├── copyInto.png
│ │ │ ├── orangePic.png
│ │ │ └── test.jpg
│ │ ├── picture_test.py
│ │ ├── pixel_test.py
│ │ ├── run.sh
│ │ └── style_test.py
│ ├── media
│ │ ├── README.md
│ │ ├── init_test.py
│ │ └── run.sh
│ └── sound
│ │ ├── README.md
│ │ ├── run.sh
│ │ ├── sample_test.py
│ │ ├── sound_test.py
│ │ └── sounds
│ │ ├── test_mono.wav
│ │ └── test_stereo.wav
└── unittest
│ ├── __init__.py
│ ├── __main__.py
│ ├── case.py
│ ├── loader.py
│ ├── main.py
│ ├── mock.py
│ ├── result.py
│ ├── runner.py
│ ├── signals.py
│ ├── suite.py
│ ├── test
│ ├── __init__.py
│ ├── _test_warnings.py
│ ├── dummy.py
│ ├── support.py
│ ├── test_assertions.py
│ ├── test_break.py
│ ├── test_case.py
│ ├── test_discovery.py
│ ├── test_functiontestcase.py
│ ├── test_loader.py
│ ├── test_program.py
│ ├── test_result.py
│ ├── test_runner.py
│ ├── test_setups.py
│ ├── test_skipping.py
│ ├── test_suite.py
│ └── testmock
│ │ ├── __init__.py
│ │ ├── support.py
│ │ ├── testcallable.py
│ │ ├── testhelpers.py
│ │ ├── testmagicmethods.py
│ │ ├── testmock.py
│ │ ├── testpatch.py
│ │ ├── testsentinel.py
│ │ └── testwith.py
│ └── util.py
├── script
└── rails
├── spec
├── factories
│ ├── activity_log_factory.rb
│ ├── course_factory.rb
│ ├── course_role_factory.rb
│ ├── environment_factory.rb
│ ├── global_role_factory.rb
│ ├── organization_factory.rb
│ ├── system_configuration_factory.rb
│ ├── term_factory.rb
│ └── user_factory.rb
├── javascripts
│ ├── README.md
│ ├── index.html
│ ├── sounds
│ │ ├── test_mono.wav
│ │ └── test_stereo.wav
│ ├── src
│ │ └── sound.js.coffee
│ ├── stubs
│ │ └── pythy_stubs.js
│ ├── tests
│ │ └── sound_test.js
│ └── vendor
│ │ ├── chai.js
│ │ ├── coffee-script.js
│ │ ├── mocha.css
│ │ ├── mocha.js
│ │ └── sinon.js
├── models
│ ├── activity_log_spec.rb
│ ├── course_role_spec.rb
│ ├── course_spec.rb
│ ├── coverage
│ │ ├── .last_run.json
│ │ ├── .resultset.json
│ │ ├── assets
│ │ │ └── 0.7.1
│ │ │ │ ├── application.css
│ │ │ │ ├── application.js
│ │ │ │ ├── fancybox
│ │ │ │ ├── blank.gif
│ │ │ │ ├── fancy_close.png
│ │ │ │ ├── fancy_loading.png
│ │ │ │ ├── fancy_nav_left.png
│ │ │ │ ├── fancy_nav_right.png
│ │ │ │ ├── fancy_shadow_e.png
│ │ │ │ ├── fancy_shadow_n.png
│ │ │ │ ├── fancy_shadow_ne.png
│ │ │ │ ├── fancy_shadow_nw.png
│ │ │ │ ├── fancy_shadow_s.png
│ │ │ │ ├── fancy_shadow_se.png
│ │ │ │ ├── fancy_shadow_sw.png
│ │ │ │ ├── fancy_shadow_w.png
│ │ │ │ ├── fancy_title_left.png
│ │ │ │ ├── fancy_title_main.png
│ │ │ │ ├── fancy_title_over.png
│ │ │ │ ├── fancy_title_right.png
│ │ │ │ ├── fancybox-x.png
│ │ │ │ ├── fancybox-y.png
│ │ │ │ └── fancybox.png
│ │ │ │ ├── favicon_green.png
│ │ │ │ ├── favicon_red.png
│ │ │ │ ├── favicon_yellow.png
│ │ │ │ ├── loading.gif
│ │ │ │ ├── magnify.png
│ │ │ │ └── smoothness
│ │ │ │ └── images
│ │ │ │ ├── ui-bg_flat_0_aaaaaa_40x100.png
│ │ │ │ ├── ui-bg_flat_75_ffffff_40x100.png
│ │ │ │ ├── ui-bg_glass_55_fbf9ee_1x400.png
│ │ │ │ ├── ui-bg_glass_65_ffffff_1x400.png
│ │ │ │ ├── ui-bg_glass_75_dadada_1x400.png
│ │ │ │ ├── ui-bg_glass_75_e6e6e6_1x400.png
│ │ │ │ ├── ui-bg_glass_95_fef1ec_1x400.png
│ │ │ │ ├── ui-bg_highlight-soft_75_cccccc_1x100.png
│ │ │ │ ├── ui-icons_222222_256x240.png
│ │ │ │ ├── ui-icons_2e83ff_256x240.png
│ │ │ │ ├── ui-icons_454545_256x240.png
│ │ │ │ ├── ui-icons_888888_256x240.png
│ │ │ │ └── ui-icons_cd0a0a_256x240.png
│ │ └── index.html
│ ├── environment_spec.rb
│ ├── global_role_spec.rb
│ ├── organization_spec.rb
│ ├── system_configuration_spec.rb
│ ├── term_spec.rb
│ └── user_spec.rb
└── spec_helper.rb
└── vendor
└── assets
├── javascripts
├── .gitkeep
├── cowboy
│ └── jquery-hashchange
│ │ └── jquery.ba-hashchange.min.js
├── eternicode
│ └── bootstrap-datepicker
│ │ └── bootstrap-datepicker.js
├── jherdman
│ └── javascript-relative-time-helpers
│ │ └── date.extensions.js
├── jquery
│ └── jqueryui
│ │ └── jquery-ui-1.10.3.custom.min.js
├── morr
│ └── jquery-appear
│ │ └── jquery.appear.js
├── silviomoreto
│ └── bootstrap-select
│ │ └── bootstrap-select.min.js
├── smalot
│ └── bootstrap-datetimepicker
│ │ └── bootstrap-datetimepicker.js
└── twitter
│ └── bootstrap
│ └── bootstrap.js
└── stylesheets
├── .gitkeep
├── eternicode
└── bootstrap-datepicker
│ └── datepicker.css
├── jquery
└── jqueryui
│ └── jquery-ui-1.10.3.custom.min.css
├── silviomoreto
└── bootstrap-select
│ └── bootstrap-select.min.css
├── smalot
└── bootstrap-datetimepicker
│ └── datetimepicker.css
└── twitter
└── bootstrap
├── accordion.less
├── alerts.less
├── bootstrap.less
├── breadcrumbs.less
├── button-groups.less
├── buttons.less
├── carousel.less
├── close.less
├── code.less
├── component-animations.less
├── dropdowns.less
├── forms.less
├── grid.less
├── hero-unit.less
├── labels-badges.less
├── layouts.less
├── media.less
├── mixins.less
├── modals.less
├── navbar.less
├── navs.less
├── pager.less
├── pagination.less
├── popovers.less
├── progress-bars.less
├── reset.less
├── responsive-1200px-min.less
├── responsive-767px-max.less
├── responsive-768px-979px.less
├── responsive-navbar.less
├── responsive-utilities.less
├── responsive.less
├── scaffolding.less
├── sprites.less
├── tables.less
├── thumbnails.less
├── tooltip.less
├── type.less
├── utilities.less
├── variables.less
└── wells.less
/.gitignore:
--------------------------------------------------------------------------------
1 | *.rbc
2 | *.sassc
3 | .sass-cache
4 | capybara-*.html
5 | .rspec
6 | /.bundle
7 | /vendor/bundle
8 | /log/*
9 | /tmp/*
10 | /db/*.sqlite3
11 | /public/assets/*
12 | /public/system/*
13 | /spec/tmp/*
14 | **.orig
15 | rerun.txt
16 | pickle-email-*.html
17 |
18 | *.rdb
19 | /public/m
20 | /public/uploads/tmp
21 | /storage/*
22 | /work/*
23 |
24 | # Ignore the entity relationship diagram
25 | erd.pdf
26 |
27 | # Ignore the database configuration
28 | /config/database.yml
29 |
30 | # Ignore all vim backup and swap files
31 | *~
32 | *.swp
33 |
34 | # Ignore test coverage reports
35 | /coverage/
36 |
37 | # Ignore node modules
38 | node_modules
39 |
40 | *.pyc
41 |
--------------------------------------------------------------------------------
/.project:
--------------------------------------------------------------------------------
1 |
2 |
3 | pythy
4 |
5 |
6 |
7 |
8 |
9 | org.python.pydev.PyDevBuilder
10 |
11 |
12 |
13 |
14 | com.aptana.ide.core.unifiedBuilder
15 |
16 |
17 |
18 |
19 |
20 | org.radrails.rails.core.railsnature
21 | com.aptana.ruby.core.rubynature
22 | org.python.pydev.pythonNature
23 |
24 |
25 |
--------------------------------------------------------------------------------
/.pydevproject:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Default
6 | python 2.7
7 |
8 |
--------------------------------------------------------------------------------
/Capfile:
--------------------------------------------------------------------------------
1 | load 'deploy' if respond_to?(:namespace) # cap2 differentiator
2 |
3 | # Uncomment if you are using Rails' asset pipeline
4 | load 'deploy/assets'
5 |
6 | Dir['vendor/gems/*/recipes/*.rb','vendor/plugins/*/recipes/*.rb'].each { |plugin| load(plugin) }
7 |
8 | load 'config/deploy' # remove this line to skip loading any of the default tasks
9 |
--------------------------------------------------------------------------------
/Rakefile:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env rake
2 | # Add your own tasks in files placed in lib/tasks ending in .rake,
3 | # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
4 |
5 | require File.expand_path('../config/application', __FILE__)
6 |
7 | Pythy::Application.load_tasks
8 |
--------------------------------------------------------------------------------
/app/assets/images/bg.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/web-cat/pythy/8dfcfd595e596f4d6f768ea5a86d2396dcbb1258/app/assets/images/bg.png
--------------------------------------------------------------------------------
/app/assets/images/curl-blue-small.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/web-cat/pythy/8dfcfd595e596f4d6f768ea5a86d2396dcbb1258/app/assets/images/curl-blue-small.png
--------------------------------------------------------------------------------
/app/assets/images/curl-gray-small.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/web-cat/pythy/8dfcfd595e596f4d6f768ea5a86d2396dcbb1258/app/assets/images/curl-gray-small.png
--------------------------------------------------------------------------------
/app/assets/images/curl-green-small.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/web-cat/pythy/8dfcfd595e596f4d6f768ea5a86d2396dcbb1258/app/assets/images/curl-green-small.png
--------------------------------------------------------------------------------
/app/assets/images/curl-red-small.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/web-cat/pythy/8dfcfd595e596f4d6f768ea5a86d2396dcbb1258/app/assets/images/curl-red-small.png
--------------------------------------------------------------------------------
/app/assets/images/curl-yellow-small.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/web-cat/pythy/8dfcfd595e596f4d6f768ea5a86d2396dcbb1258/app/assets/images/curl-yellow-small.png
--------------------------------------------------------------------------------
/app/assets/images/curl.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/web-cat/pythy/8dfcfd595e596f4d6f768ea5a86d2396dcbb1258/app/assets/images/curl.png
--------------------------------------------------------------------------------
/app/assets/images/landing-header-bg.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/web-cat/pythy/8dfcfd595e596f4d6f768ea5a86d2396dcbb1258/app/assets/images/landing-header-bg.png
--------------------------------------------------------------------------------
/app/assets/images/navbar-separator.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/web-cat/pythy/8dfcfd595e596f4d6f768ea5a86d2396dcbb1258/app/assets/images/navbar-separator.png
--------------------------------------------------------------------------------
/app/assets/images/snake-cap-300h.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/web-cat/pythy/8dfcfd595e596f4d6f768ea5a86d2396dcbb1258/app/assets/images/snake-cap-300h.png
--------------------------------------------------------------------------------
/app/assets/javascripts/activity_logs.js.coffee:
--------------------------------------------------------------------------------
1 | # Place all the behaviors and hooks related to the matching controller here.
2 | # All this logic will automatically be available in application.js.
3 | # You can use CoffeeScript in this file: http://jashkenas.github.com/coffee-script/
4 |
5 | $ ->
6 | $('#reset-filter').click (e) ->
7 | $form = $(this).closest('form')
8 | $form[0].reset()
9 | $form.submit()
10 | e.preventDefault()
11 |
--------------------------------------------------------------------------------
/app/assets/javascripts/assignment_offerings.js.coffee:
--------------------------------------------------------------------------------
1 | # Place all the behaviors and hooks related to the matching controller here.
2 | # All this logic will automatically be available in application.js.
3 | # You can use CoffeeScript in this file: http://jashkenas.github.com/coffee-script/
4 |
--------------------------------------------------------------------------------
/app/assets/javascripts/assignment_repositories.js.coffee:
--------------------------------------------------------------------------------
1 | google.load 'visualization', '1.0', packages: ['corechart'], callback: ->
2 |
3 | $.get(window.location.href + '.json').always (response) ->
4 | rows = ([new Date(Date.parse(row[0])), row[1]] for row in response)
5 |
6 | data = new google.visualization.DataTable
7 | data.addColumn 'date', 'Time'
8 | data.addColumn 'number', 'Score'
9 | #data.addColumn type: 'string', role: 'tooltip', p: { html: true }
10 | data.addRows rows
11 |
12 | formatter = new google.visualization.DateFormat(pattern: 'MM/dd/yyyy hh:mm aa')
13 | formatter.format data, 0
14 |
15 | options = {
16 | #width: 770,
17 | #height: 350,
18 | #tooltip: { isHtml: true },
19 | #hAxis: { title: 'Time' },
20 | vAxis: { minValue: 0 },
21 | legend: { position: 'none' },
22 | chartArea: { left: '0%', top: '0%', width: '100%', height: '88%' }
23 | }
24 |
25 | chart = new google.visualization.AreaChart($('#commit-time-chart')[0])
26 | chart.draw data, options
27 |
--------------------------------------------------------------------------------
/app/assets/javascripts/authentications.js.coffee:
--------------------------------------------------------------------------------
1 | # Place all the behaviors and hooks related to the matching controller here.
2 | # All this logic will automatically be available in application.js.
3 | # You can use CoffeeScript in this file: http://jashkenas.github.com/coffee-script/
4 |
--------------------------------------------------------------------------------
/app/assets/javascripts/course_offerings.js.coffee:
--------------------------------------------------------------------------------
1 | # Place all the behaviors and hooks related to the matching controller here.
2 | # All this logic will automatically be available in application.js.
3 | # You can use CoffeeScript in this file: http://jashkenas.github.com/coffee-script/
4 |
--------------------------------------------------------------------------------
/app/assets/javascripts/courses.js.coffee:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/web-cat/pythy/8dfcfd595e596f4d6f768ea5a86d2396dcbb1258/app/assets/javascripts/courses.js.coffee
--------------------------------------------------------------------------------
/app/assets/javascripts/environments.js.coffee:
--------------------------------------------------------------------------------
1 | $ ->
2 | # -------------------------------------------------------------
3 | # Create CodeMirror widgets on the editing page.
4 | if $('#environment_preamble').length
5 | CodeMirror.fromTextArea $('#environment_preamble')[0],
6 | mode: { name: "python", version: 3, singleLineStringErrors: false },
7 | lineNumbers: true,
8 | gutters: ["CodeMirror-linenumbers"]
9 | indentUnit: 2,
10 | tabSize: 2,
11 | indentWithTabs: false,
12 | matchBrackets: true,
13 | extraKeys: { Tab: (cm) -> cm.replaceSelection(' ', 'end') }
14 |
--------------------------------------------------------------------------------
/app/assets/javascripts/errors.js.coffee:
--------------------------------------------------------------------------------
1 | # Place all the behaviors and hooks related to the matching controller here.
2 | # All this logic will automatically be available in application.js.
3 | # You can use CoffeeScript in this file: http://jashkenas.github.com/coffee-script/
4 |
--------------------------------------------------------------------------------
/app/assets/javascripts/example_repositories.js.coffee:
--------------------------------------------------------------------------------
1 | # Place all the behaviors and hooks related to the matching controller here.
2 | # All this logic will automatically be available in application.js.
3 | # You can use CoffeeScript in this file: http://jashkenas.github.com/coffee-script/
4 |
--------------------------------------------------------------------------------
/app/assets/javascripts/landing.js.coffee:
--------------------------------------------------------------------------------
1 | # Place all the behaviors and hooks related to the matching controller here.
2 | # All this logic will automatically be available in application.js.
3 | # You can use CoffeeScript in this file: http://jashkenas.github.com/coffee-script/
4 |
--------------------------------------------------------------------------------
/app/assets/javascripts/organizations.js.coffee:
--------------------------------------------------------------------------------
1 | $ ->
2 | updateHelpText = ->
3 | val = $('#organization_abbreviation').val()
4 | if val
5 | part = pythy.url_part_safe(val)
6 | $('#url_part').text("This organization will appear in URLs like .../#{part}/...").show()
7 | else
8 | $('#url_part').hide()
9 |
10 | $('#organization_abbreviation').keyup -> updateHelpText()
11 | $('#organization_abbreviation').change -> updateHelpText()
12 |
13 | updateHelpText()
14 |
--------------------------------------------------------------------------------
/app/assets/javascripts/setup.js.coffee:
--------------------------------------------------------------------------------
1 | # Place all the behaviors and hooks related to the matching controller here.
2 | # All this logic will automatically be available in application.js.
3 | # You can use CoffeeScript in this file: http://jashkenas.github.com/coffee-script/
4 |
--------------------------------------------------------------------------------
/app/assets/javascripts/system_configurations.js.coffee:
--------------------------------------------------------------------------------
1 | # Place all the behaviors and hooks related to the matching controller here.
2 | # All this logic will automatically be available in application.js.
3 | # You can use CoffeeScript in this file: http://jashkenas.github.com/coffee-script/
4 |
--------------------------------------------------------------------------------
/app/assets/javascripts/terms.js.coffee:
--------------------------------------------------------------------------------
1 | # Place all the behaviors and hooks related to the matching controller here.
2 | # All this logic will automatically be available in application.js.
3 | # You can use CoffeeScript in this file: http://jashkenas.github.com/coffee-script/
4 |
--------------------------------------------------------------------------------
/app/assets/javascripts/upload_roster.js.coffee:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/web-cat/pythy/8dfcfd595e596f4d6f768ea5a86d2396dcbb1258/app/assets/javascripts/upload_roster.js.coffee
--------------------------------------------------------------------------------
/app/assets/stylesheets/activity_logs.css.scss:
--------------------------------------------------------------------------------
1 | // Place all the styles related to the UserLogs controller here.
2 | // They will automatically be included in application.css.
3 | // You can use Sass (SCSS) here: http://sass-lang.com/
4 |
5 | tbody#activity_logs td {
6 | font-size: 12px;
7 | line-height: 14px;
8 | }
9 |
--------------------------------------------------------------------------------
/app/assets/stylesheets/application.css:
--------------------------------------------------------------------------------
1 | /*
2 | * This is a manifest file that'll be compiled into application.css, which will include all the files
3 | * listed below.
4 | *
5 | * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
6 | * or vendor/assets/stylesheets of plugins, if any, can be referenced here using a relative path.
7 | *
8 | * You're free to add application-wide styles to this file and they'll appear at the top of the
9 | * compiled file, but it's generally better to create a new file per style scope.
10 | *
11 | *= require_self
12 | *= require codemirror
13 | *= require eternicode/bootstrap-datepicker/datepicker.css
14 | //= require smalot/bootstrap-datetimepicker/datetimepicker
15 | *= require silviomoreto/bootstrap-select/bootstrap-select.min
16 | *= require bootstrap_and_overrides
17 | *= require jquery/jqueryui/jquery-ui-1.10.3.custom.min
18 | *= require font-awesome
19 | *= require jquery.fileupload-ui
20 | *= require global
21 | */
22 |
--------------------------------------------------------------------------------
/app/assets/stylesheets/assignment_offerings.css.scss:
--------------------------------------------------------------------------------
1 | // Place all the styles related to the AssignmentOfferings controller here.
2 | // They will automatically be included in application.css.
3 | // You can use Sass (SCSS) here: http://sass-lang.com/
4 |
--------------------------------------------------------------------------------
/app/assets/stylesheets/assignment_repositories.css.scss:
--------------------------------------------------------------------------------
1 | .chart {
2 | width: 100%;
3 | height: 300px;
4 | }
5 |
--------------------------------------------------------------------------------
/app/assets/stylesheets/assignments.css.scss:
--------------------------------------------------------------------------------
1 | #assignment_brief_summary_control_group .CodeMirror {
2 | height: 120px;
3 | }
4 |
5 | #assignment_description_control_group .CodeMirror {
6 | height: 300px;
7 | }
8 |
9 | .chart.grade-histogram {
10 | width: 100%;
11 | height: 200px;
12 | }
13 |
14 | table.grade-summary {
15 | td:first-child { width: 67%; }
16 | td:last-child { width: 33% };
17 | }
18 |
--------------------------------------------------------------------------------
/app/assets/stylesheets/authentications.css.scss:
--------------------------------------------------------------------------------
1 | // Place all the styles related to the Authentications controller here.
2 | // They will automatically be included in application.css.
3 | // You can use Sass (SCSS) here: http://sass-lang.com/
4 |
--------------------------------------------------------------------------------
/app/assets/stylesheets/course_offerings.css.scss:
--------------------------------------------------------------------------------
1 | // Place all the styles related to the CourseOfferings controller here.
2 | // They will automatically be included in application.css.
3 | // You can use Sass (SCSS) here: http://sass-lang.com/
4 |
--------------------------------------------------------------------------------
/app/assets/stylesheets/courses.css.scss:
--------------------------------------------------------------------------------
1 | // Place all the styles related to the Courses controller here.
2 | // They will automatically be included in application.css.
3 | // You can use Sass (SCSS) here: http://sass-lang.com/
4 |
--------------------------------------------------------------------------------
/app/assets/stylesheets/environments.css.scss:
--------------------------------------------------------------------------------
1 | // Place all the styles related to the Environments controller here.
2 | // They will automatically be included in application.css.
3 | // You can use Sass (SCSS) here: http://sass-lang.com/
4 |
--------------------------------------------------------------------------------
/app/assets/stylesheets/errors.css.scss:
--------------------------------------------------------------------------------
1 | // Place all the styles related to the errors controller here.
2 | // They will automatically be included in application.css.
3 | // You can use Sass (SCSS) here: http://sass-lang.com/
4 |
--------------------------------------------------------------------------------
/app/assets/stylesheets/example_repositories.css.scss:
--------------------------------------------------------------------------------
1 | // Place all the styles related to the examples controller here.
2 | // They will automatically be included in application.css.
3 | // You can use Sass (SCSS) here: http://sass-lang.com/
4 |
--------------------------------------------------------------------------------
/app/assets/stylesheets/landing.css.scss:
--------------------------------------------------------------------------------
1 | // Place all the styles related to the landing controller here.
2 | // They will automatically be included in application.css.
3 | // You can use Sass (SCSS) here: http://sass-lang.com/
4 |
--------------------------------------------------------------------------------
/app/assets/stylesheets/organizations.css.scss:
--------------------------------------------------------------------------------
1 | // Place all the styles related to the Organizations controller here.
2 | // They will automatically be included in application.css.
3 | // You can use Sass (SCSS) here: http://sass-lang.com/
4 |
--------------------------------------------------------------------------------
/app/assets/stylesheets/setup.css.scss:
--------------------------------------------------------------------------------
1 | // Place all the styles related to the setup controller here.
2 | // They will automatically be included in application.css.
3 | // You can use Sass (SCSS) here: http://sass-lang.com/
4 |
--------------------------------------------------------------------------------
/app/assets/stylesheets/system_configurations.css.scss:
--------------------------------------------------------------------------------
1 | // Place all the styles related to the system_configurations controller here.
2 | // They will automatically be included in application.css.
3 | // You can use Sass (SCSS) here: http://sass-lang.com/
4 |
--------------------------------------------------------------------------------
/app/assets/stylesheets/terms.css.scss:
--------------------------------------------------------------------------------
1 | // Place all the styles related to the Terms controller here.
2 | // They will automatically be included in application.css.
3 | // You can use Sass (SCSS) here: http://sass-lang.com/
4 |
--------------------------------------------------------------------------------
/app/controllers/assignment_checks_controller.rb:
--------------------------------------------------------------------------------
1 | class AssignmentChecksController < ApplicationController
2 |
3 | before_filter :authenticate_user!
4 | load_and_authorize_resource :assignment_repository
5 | load_and_authorize_resource :assignment_check,
6 | through: :assignment_repository, shallow: true
7 |
8 |
9 | # -------------------------------------------------------------
10 | def index
11 | # FIXME Why do I have to do this? The l_a_a_r above should take
12 | # care of it.
13 | @assignment_checks = @assignment_repository.assignment_checks
14 |
15 | @scores = []
16 | @check_ids = []
17 | @assignment_checks.each do |check|
18 | @scores << [check.number.to_i, check.overall_score.to_f]
19 | @check_ids << check.id
20 | end
21 |
22 | respond_to do |format|
23 | format.js
24 | end
25 | end
26 |
27 |
28 | # -------------------------------------------------------------
29 | def show
30 | respond_to do |format|
31 | format.js
32 | end
33 | end
34 |
35 | end
36 |
--------------------------------------------------------------------------------
/app/controllers/assignment_repositories_controller.rb:
--------------------------------------------------------------------------------
1 | class AssignmentRepositoriesController < ApplicationController
2 |
3 | before_filter :authenticate_user!
4 | load_and_authorize_resource :assignment_repository
5 |
6 |
7 | # -------------------------------------------------------------
8 | def show
9 | #@assignment_checks = @assignment_repository.assignment_checks
10 | @assignment_offering = @assignment_repository.assignment_offering
11 | @assignment = @assignment_offering.assignment
12 |
13 | respond_to do |format|
14 | format.html
15 | format.json do
16 | # TODO Handle assignments that are open forever, or never open
17 | if @assignment_offering.opens_at && @assignment_offering.effectively_due_at
18 | collector = CommitCollector.new(@assignment_repository,
19 | @assignment_offering.opens_at, @assignment_offering.effectively_due_at, 1)
20 | buckets = collector.commit_time_data
21 | end
22 |
23 | render json: buckets
24 | end
25 | end
26 | end
27 |
28 | end
29 |
--------------------------------------------------------------------------------
/app/controllers/errors_controller.rb:
--------------------------------------------------------------------------------
1 | class ErrorsController < ApplicationController
2 |
3 | layout 'error'
4 |
5 |
6 | # -------------------------------------------------------------
7 | def error_404
8 | @not_found_path = params[:not_found]
9 | end
10 |
11 | end
12 |
--------------------------------------------------------------------------------
/app/controllers/landing_controller.rb:
--------------------------------------------------------------------------------
1 | class LandingController < ApplicationController
2 |
3 | layout 'landing'
4 |
5 | def index
6 | end
7 |
8 | end
9 |
--------------------------------------------------------------------------------
/app/controllers/proxy_controller.rb:
--------------------------------------------------------------------------------
1 | require 'net/http'
2 |
3 | class ProxyController < ApplicationController
4 |
5 | # -------------------------------------------------------------
6 | def get
7 | url = URI.parse(params[:url])
8 | hash = params[:hash]
9 |
10 | # TODO verify hash
11 |
12 | result = get_response_with_redirect(url)
13 | send_data result.body,
14 | type: result.content_type || 'text/plain',
15 | disposition: 'inline',
16 | status: result.code
17 | end
18 |
19 |
20 | private
21 |
22 | # -------------------------------------------------------------
23 | def get_response_with_redirect(uri)
24 | r = Net::HTTP.get_response(uri)
25 |
26 | if r.code == "301"
27 | r = Net::HTTP.get_response(URI.parse(r.header['location']))
28 | end
29 |
30 | r
31 | end
32 |
33 | end
34 |
--------------------------------------------------------------------------------
/app/controllers/scratchpad_repositories_controller.rb:
--------------------------------------------------------------------------------
1 | class ScratchpadRepositoriesController < ApplicationController
2 |
3 | before_filter :authenticate_user!
4 | load_and_authorize_resource :scratchpad_repository
5 |
6 |
7 | # -------------------------------------------------------------
8 | def update
9 | respond_to do |format|
10 | if @scratchpad_repository.update_attributes(params[:scratchpad_repository])
11 | format.html { redirect_to @scratchpad_repository, notice: 'Scratchpad repository was successfully updated.' }
12 | format.json { render json: @scratchpad_repository.as_json(include: [:environment]) }
13 | else
14 | format.html { render action: 'edit' }
15 | format.json { render json: @scratchpad_repository.errors, status: :unprocessable_entity }
16 | end
17 | end
18 | end
19 |
20 | end
21 |
--------------------------------------------------------------------------------
/app/controllers/sessions_controller.rb:
--------------------------------------------------------------------------------
1 | class SessionsController < Devise::SessionsController
2 |
3 | layout 'landing'
4 |
5 | before_filter :log_event, only: [:create, :destroy]
6 |
7 | end
8 |
--------------------------------------------------------------------------------
/app/controllers/setup_controller.rb:
--------------------------------------------------------------------------------
1 | class SetupController < ApplicationController
2 |
3 | layout 'setup'
4 |
5 | # -------------------------------------------------------------
6 | # GET /setup
7 | def index
8 | end
9 |
10 | end
11 |
--------------------------------------------------------------------------------
/app/controllers/typeaheads_controller.rb:
--------------------------------------------------------------------------------
1 | class TypeaheadsController < ApplicationController
2 |
3 | # -------------------------------------------------------------
4 | def user
5 | @search = params[:search]
6 | @users = User.search(@search)
7 |
8 | respond_to do |format|
9 | format.json { render json: @users.as_json(only: [:first_name, :last_name, :email, :id]) }
10 | end
11 | end
12 |
13 | end
14 |
--------------------------------------------------------------------------------
/app/helpers/activity_logs_helper.rb:
--------------------------------------------------------------------------------
1 | module ActivityLogsHelper
2 |
3 | # -------------------------------------------------------------
4 | def filter_form
5 | form_tag({ controller: 'activity_logs', action: 'filter' },
6 | remote: true, class: 'form-search well well-small') do
7 | yield
8 | end
9 | end
10 |
11 | end
12 |
--------------------------------------------------------------------------------
/app/helpers/assignment_offerings_helper.rb:
--------------------------------------------------------------------------------
1 | module AssignmentOfferingsHelper
2 | end
3 |
--------------------------------------------------------------------------------
/app/helpers/assignments_helper.rb:
--------------------------------------------------------------------------------
1 | module AssignmentsHelper
2 | end
3 |
--------------------------------------------------------------------------------
/app/helpers/authentications_helper.rb:
--------------------------------------------------------------------------------
1 | module AuthenticationsHelper
2 | end
3 |
--------------------------------------------------------------------------------
/app/helpers/course_enrollments_helper.rb:
--------------------------------------------------------------------------------
1 | module CourseEnrollmentsHelper
2 | end
3 |
--------------------------------------------------------------------------------
/app/helpers/course_offerings_helper.rb:
--------------------------------------------------------------------------------
1 | module CourseOfferingsHelper
2 | end
3 |
--------------------------------------------------------------------------------
/app/helpers/courses_helper.rb:
--------------------------------------------------------------------------------
1 | module CoursesHelper
2 | end
3 |
--------------------------------------------------------------------------------
/app/helpers/devise_helper.rb:
--------------------------------------------------------------------------------
1 | module DeviseHelper
2 |
3 | # -------------------------------------------------------------
4 | def devise_error_messages!
5 | return "" if resource.nil? || resource.errors.empty?
6 |
7 | messages = resource.errors.full_messages.map { |msg| content_tag(:li, msg) }.join
8 | sentence = I18n.t("errors.messages.not_saved",
9 | :count => resource.errors.count,
10 | :resource => resource_name)
11 |
12 | html = <<-HTML
13 |
14 |
#{sentence}
15 |
16 |
17 | HTML
18 |
19 | html.html_safe
20 | end
21 |
22 | end
23 |
--------------------------------------------------------------------------------
/app/helpers/environments_helper.rb:
--------------------------------------------------------------------------------
1 | module EnvironmentsHelper
2 | end
3 |
--------------------------------------------------------------------------------
/app/helpers/errors_helper.rb:
--------------------------------------------------------------------------------
1 | module ErrorsHelper
2 | end
3 |
--------------------------------------------------------------------------------
/app/helpers/example_repositories_helper.rb:
--------------------------------------------------------------------------------
1 | module ExampleRepositoriesHelper
2 | end
3 |
--------------------------------------------------------------------------------
/app/helpers/global_roles_helper.rb:
--------------------------------------------------------------------------------
1 | module GlobalRolesHelper
2 | end
3 |
--------------------------------------------------------------------------------
/app/helpers/landing_helper.rb:
--------------------------------------------------------------------------------
1 | module LandingHelper
2 | end
3 |
--------------------------------------------------------------------------------
/app/helpers/media_helper.rb:
--------------------------------------------------------------------------------
1 | module MediaHelper
2 |
3 | end
4 |
--------------------------------------------------------------------------------
/app/helpers/organizations_helper.rb:
--------------------------------------------------------------------------------
1 | module OrganizationsHelper
2 | end
3 |
--------------------------------------------------------------------------------
/app/helpers/setup_helper.rb:
--------------------------------------------------------------------------------
1 | module SetupHelper
2 | end
3 |
--------------------------------------------------------------------------------
/app/helpers/system_configurations_helper.rb:
--------------------------------------------------------------------------------
1 | module SystemConfigurationsHelper
2 | end
3 |
--------------------------------------------------------------------------------
/app/helpers/terms_helper.rb:
--------------------------------------------------------------------------------
1 | module TermsHelper
2 | end
3 |
--------------------------------------------------------------------------------
/app/helpers/users_helper.rb:
--------------------------------------------------------------------------------
1 | module UsersHelper
2 |
3 | # -------------------------------------------------------------
4 | def full_name_or_none(user, options={})
5 | if !user.first_name.blank? && !user.last_name.blank?
6 | options[:query] ? query_highlight(user.first_name + ' ' + user.last_name) : user.first_name + ' ' + user.last_name
7 | elsif options[:muted]
8 | raw(content_tag :span, '(none given)', class: 'muted')
9 | else
10 | '(none given)'
11 | end
12 | end
13 |
14 | end
15 |
--------------------------------------------------------------------------------
/app/mailers/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/web-cat/pythy/8dfcfd595e596f4d6f768ea5a86d2396dcbb1258/app/mailers/.gitkeep
--------------------------------------------------------------------------------
/app/models/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/web-cat/pythy/8dfcfd595e596f4d6f768ea5a86d2396dcbb1258/app/models/.gitkeep
--------------------------------------------------------------------------------
/app/models/authentication.rb:
--------------------------------------------------------------------------------
1 | class Authentication < ActiveRecord::Base
2 |
3 | belongs_to :user
4 |
5 | attr_accessible :provider, :uid
6 |
7 | def apply_omniauth(user, omniauth)
8 | if user.email.blank?
9 | user.email = omniauth['info']['email']
10 | end
11 |
12 | user.first_name ||= omniauth['info']['first_name']
13 | user.last_name ||= omniauth['info']['last_name']
14 |
15 | # Generate a dummy password for the user.
16 | user.password ||= Devise.friendly_token.first(20)
17 | end
18 |
19 | end
20 |
--------------------------------------------------------------------------------
/app/models/check_outcome.rb:
--------------------------------------------------------------------------------
1 | class CheckOutcome < ActiveRecord::Base
2 |
3 | belongs_to :assignment_check
4 |
5 | attr_accessible :name, :description, :category, :position, :score,
6 | :possible_score, :detail
7 |
8 | serialize :detail, Hash
9 |
10 |
11 | # -------------------------------------------------------------
12 | def percentage_score
13 | 100 * score / possible_score
14 | end
15 |
16 |
17 | # -------------------------------------------------------------
18 | def reason
19 | # Putting a $ at the end of the custom hint message for the
20 | # assertion will indicate that the rest of the message should
21 | # not be shown to the student.
22 | r = detail['reason']
23 | if r && r =~ /(.*)\$:.*/
24 | $1
25 | else
26 | r
27 | end
28 | end
29 |
30 |
31 | # -------------------------------------------------------------
32 | def hint?
33 | reason && reason =~ /Hint:/i
34 | end
35 |
36 |
37 | # -------------------------------------------------------------
38 | def hint
39 | if reason && reason =~ /Hint:\s*(.*)$/i
40 | $1
41 | end
42 | end
43 |
44 | end
--------------------------------------------------------------------------------
/app/models/course_enrollment.rb:
--------------------------------------------------------------------------------
1 | class CourseEnrollment < ActiveRecord::Base
2 |
3 | belongs_to :user
4 | belongs_to :course_offering
5 | belongs_to :course_role
6 |
7 | paginates_per 100
8 |
9 | attr_accessible :user, :course_offering, :course_role, :user_id,
10 | :course_offering_id, :course_role_id
11 |
12 | end
13 |
--------------------------------------------------------------------------------
/app/models/environment.rb:
--------------------------------------------------------------------------------
1 | class Environment < ActiveRecord::Base
2 |
3 | has_many :courses, foreign_key: 'default_environment_id'
4 | has_many :repositories
5 |
6 | attr_accessible :name, :preamble
7 |
8 | validates :name, presence: true
9 |
10 | end
11 |
--------------------------------------------------------------------------------
/app/models/personal_repository.rb:
--------------------------------------------------------------------------------
1 | class PersonalRepository < Repository
2 |
3 | end
4 |
--------------------------------------------------------------------------------
/app/models/resource_key_methods.rb:
--------------------------------------------------------------------------------
1 | require 'securerandom'
2 |
3 | module ResourceKeyMethods
4 | extend ActiveSupport::Concern
5 |
6 | included do
7 | before_save :generate_resource_key
8 | end
9 |
10 |
11 | # -------------------------------------------------------
12 | def generate_resource_key
13 | unless self.resource_key
14 | key = nil
15 |
16 | loop do
17 | key = SecureRandom.urlsafe_base64(10)
18 | break unless self.class.where(resource_key: key).exists?
19 | end
20 |
21 | self.resource_key = key
22 | end
23 | end
24 |
25 | end
26 |
--------------------------------------------------------------------------------
/app/models/system_configuration.rb:
--------------------------------------------------------------------------------
1 | class SystemConfiguration < ActiveRecord::Base
2 | attr_accessible :storage_path, :work_path
3 |
4 | with_options presence: true, path: true do |sys_config|
5 | sys_config.validates :storage_path
6 | sys_config.validates :work_path
7 | end
8 |
9 | end
10 |
--------------------------------------------------------------------------------
/app/validators/changeable_validator.rb:
--------------------------------------------------------------------------------
1 | # =============================================================================
2 | # Found at http://gist.github.com/3149393, modified for Pythy use
3 | class ChangeableValidator < ActiveModel::EachValidator
4 | # Enforce/prevent attribute change
5 | #
6 | # Example: Make attribute immutable once saved
7 | # validates :attribute, changeable: false, on: :update
8 | #
9 | # Example: Force attribute change on every save
10 | # validates :attribute, changeable: true
11 |
12 | def initialize(options)
13 | options[:changeable] = !(options[:with] === false)
14 | super
15 | end
16 |
17 | def validate_each(record, attribute, value)
18 | unless record.public_send(:"#{attribute}_changed?") == options[:changeable]
19 | record.errors.add(attribute,
20 | "#{options[:changeable] ? 'must' : 'cannot'} be modified")
21 | end
22 | end
23 | end
24 |
--------------------------------------------------------------------------------
/app/validators/path_validator.rb:
--------------------------------------------------------------------------------
1 | # Validates that the path exists and is writable by the server.
2 | class PathValidator < ActiveModel::EachValidator
3 | def validate_each(record, attribute, value)
4 | dir = find_writable_path(value)
5 |
6 | if not File.exists?(dir)
7 | record.errors.add(attribute, "#{value} must exist.")
8 | end
9 |
10 | if not File.stat(dir).writable?
11 | record.errors.add(attribute, "#{value} must be writable by the server.")
12 | end
13 |
14 | end
15 |
16 | private
17 | # Checks each path in the hierarchy to see if the path can be
18 | # written to by the user who started the server
19 | def find_writable_path(dir_path)
20 | paths = File.split(dir_path)
21 |
22 | while(!File.exists?(dir_path) ||
23 | !File.stat(dir_path).writable? &&
24 | !paths[0].eql?(paths[1])) do
25 | dir_path = paths[0]
26 | paths = File.split(dir_path)
27 | end
28 |
29 | return dir_path
30 | end
31 | end
32 |
--------------------------------------------------------------------------------
/app/views/activity_logs/_activity_log.html.haml:
--------------------------------------------------------------------------------
1 | %tr
2 | %td= link_to activity_log.user.email, activity_log.user
3 | %td= activity_log.action
4 | %td= l activity_log.created_at
5 | %td= activity_log.info
--------------------------------------------------------------------------------
/app/views/activity_logs/_table.html.haml:
--------------------------------------------------------------------------------
1 | %table.table.table-striped.table-bordered.table-condensed
2 | %thead
3 | %tr
4 | %th.span3 User
5 | %th.span2 Action
6 | %th.span2 Time
7 | %th.span5 Extra Info
8 | %tbody#activity_logs
9 | = render @activity_logs
10 |
11 | #paginator
12 | = paginate @activity_logs, remote: true
13 |
--------------------------------------------------------------------------------
/app/views/activity_logs/filter.js.coffee:
--------------------------------------------------------------------------------
1 | $('#log-entries').html('<%= escape_javascript(render partial: "table") %>')
2 |
--------------------------------------------------------------------------------
/app/views/activity_logs/index.html.haml:
--------------------------------------------------------------------------------
1 |
2 | = filter_form do
3 | %span.help-inline Filter:
4 | = typeahead_field_tag :email, nil, placeholder: 'E-mail', url: users_path
5 | = typeahead_field_tag :action_name, nil, placeholder: 'Action', url: activity_logs_path, submit: true
6 | = link_to 'Clear', '#', id: 'reset-filter', class: 'btn'
7 | = submit_tag 'Filter', class: 'btn btn-primary'
8 |
9 | #log-entries
10 | = render partial: 'table'
11 |
--------------------------------------------------------------------------------
/app/views/activity_logs/index.js.coffee:
--------------------------------------------------------------------------------
1 | $('#activity_logs').html('<%= escape_javascript render(@activity_logs) %>')
2 | $('#paginator').html('<%= escape_javascript(paginate(@activity_logs, remote: true).to_s) %>')
3 |
--------------------------------------------------------------------------------
/app/views/application/_flashbar.html.haml:
--------------------------------------------------------------------------------
1 | #flashbar
2 | - [:notice, :alert, :error].each do |level|
3 | - unless flash[level].blank?
4 | .flash{ class: flash_class(level) }
5 | .container
6 | .row
7 | = close_button_tag dismiss: 'flash'
8 | %span{ class: "tag-#{level.to_s}" }
9 | = flash[level]
10 |
--------------------------------------------------------------------------------
/app/views/application/_form_errors.html.haml:
--------------------------------------------------------------------------------
1 | #form_errors
2 | - if model.errors.any?
3 | .alert.alert-block.alert-danger
4 | %p
5 | %strong
6 | The
7 | = model.class.name.humanize
8 | could not be saved due to the following errors:
9 |
10 | %ul
11 | - model.errors.full_messages.each do |msg|
12 | %li= msg
13 |
--------------------------------------------------------------------------------
/app/views/application/_index_search.html.haml:
--------------------------------------------------------------------------------
1 | = form_tag url_for(action: 'index'), remote: true, method: :get, class: 'form-search breadcrumb-hang', autocomplete: 'off' do
2 | .input-append
3 | = search_field_tag :query, nil, class: 'input-medium input-small search-query', placeholder: 'Search...'
4 | = button_tag type: 'submit', class: 'btn' do
5 | = icon_tag('search')
6 |
--------------------------------------------------------------------------------
/app/views/application/modal_form_errors.js.coffee:
--------------------------------------------------------------------------------
1 | $('#<%= controller_name %>_modal #flashbar-placeholder').html(
2 | '<%= escape_javascript(render partial: "form_errors", locals: { model: model }) %>')
--------------------------------------------------------------------------------
/app/views/application/place_flash.js.coffee:
--------------------------------------------------------------------------------
1 | $('<%= where %>').html '<%= escape_javascript(render partial: "flashbar") %>'
2 |
--------------------------------------------------------------------------------
/app/views/assignment_checks/_score_history_modal.html.haml:
--------------------------------------------------------------------------------
1 | #score_history_modal.modal.modal-wide.hide.fade
2 | .modal-header
3 | = close_button_tag dismiss: 'modal'
4 | %h3
5 | Score History for
6 | %strong= @assignment_repository.assignment_offering.assignment.short_name
7 | %small
8 | = surround '(', ')' do
9 | = @assignment_repository.assignment_offering.course_offering.course.number
10 |
11 | .modal-body
12 | #score-history-chart{ style: 'width: 770px; height: 350px;' }
13 |
14 | .modal-footer
15 | = button_tag 'Close', class: 'btn btn-primary', data: { dismiss: 'modal' }
16 |
--------------------------------------------------------------------------------
/app/views/assignment_checks/show.js.coffee:
--------------------------------------------------------------------------------
1 | <% if @assignment_check.status == AssignmentCheck::COMPLETED %>
2 | # Append the modal to the page body.
3 | $('body').append(
4 | '<%= escape_javascript(render partial: "code/check_outcomes_modal",
5 | locals: { assignment_check: @assignment_check }) %>')
6 |
7 | # Ensure that the dialog gets removed from the DOM when it is closed.
8 | $('#check_outcomes_modal').on 'hidden', ->
9 | $('#check_outcomes_modal').remove()
10 |
11 | # Display the dialog.
12 | $('#check_outcomes_modal').modal('show')
13 | <% elsif @assignment_check.status == AssignmentCheck::FAILED %>
14 | pythy.alert 'An internal error occurred when executing your code.'
15 | <% elsif @assignment_check.status == AssignmentCheck::TIMEOUT %>
16 | pythy.alert 'Your code did not complete in the allowed amount of time.'
17 | <% end %>
18 |
--------------------------------------------------------------------------------
/app/views/assignment_offerings/_form.html.haml:
--------------------------------------------------------------------------------
1 | = pythy_form_for @assignment_offering.course_offering, @assignment_offering do |f|
2 |
3 | = f.fields_for :assignment do |assignment|
4 | = assignment.text_field :short_name, class: 'input-large' do
5 | .help-block A brief name for the assignment, such as "Project 1".
6 | = assignment.text_field :long_name, class: 'input-xxlarge' do
7 | .help-block
8 | A more descriptive name for the assignment. The short name and long name will be combined as
9 | %strong "Short Name: Long Name"
10 | in many displays.
11 | = assignment.text_area :description, rows: 10, class: 'input-xxlarge' do
12 | .help-block
13 | The full write-up or specification of the assignment. This description will be processed as
14 | = link_to 'Markdown-formatted text', 'http://daringfireball.net/projects/markdown/syntax', target: '_blank'
15 | to display to students.
16 |
17 | = f.actions do
18 | = f.submit
19 |
--------------------------------------------------------------------------------
/app/views/assignment_offerings/create.js.coffee:
--------------------------------------------------------------------------------
1 | $('#assignment_offerings').html(
2 | '<%= j render(@course_offering.assignment_offerings) %>')
3 |
4 | $('#assignment_offerings_modal').modal('hide')
5 |
--------------------------------------------------------------------------------
/app/views/assignment_offerings/edit.html.haml:
--------------------------------------------------------------------------------
1 |
2 | = render 'form'
3 |
--------------------------------------------------------------------------------
/app/views/assignment_offerings/new.js.coffee:
--------------------------------------------------------------------------------
1 | # Append the modal to the page body.
2 | $('body').append('<%= j(render partial: "modal") %>')
3 |
4 | # Ensure that the dialog gets removed from the DOM when it is closed.
5 | $('#assignment_offerings_modal').on 'hidden', ->
6 | $('#assignment_offerings_modal').remove()
7 |
8 | # Display the dialog.
9 | $('#assignment_offerings_modal').modal('show')
10 |
--------------------------------------------------------------------------------
/app/views/assignment_offerings/show.json.rabl:
--------------------------------------------------------------------------------
1 | object @assignment_offering
2 |
3 | attributes :id, :opens_at, :closes_at, :due_at
4 | node(:number_of_students) { |ao| ao.course_offering.students.count }
5 | node(:number_started) { |ao| ao.assignment_repositories_without_staff.count }
6 |
7 | child :assignment_repositories_without_staff, object_root: false do
8 | attributes :id
9 | node(:score) do |repo|
10 | check = repo.assignment_checks.most_recent
11 | check && check.overall_score || 0
12 | end
13 | end
14 |
--------------------------------------------------------------------------------
/app/views/assignment_repositories/show.html.haml:
--------------------------------------------------------------------------------
1 | %h2
2 | = @assignment.short_name
3 | %small
4 | = surround '(', ')' do
5 | = @assignment.long_name
6 | %h4
7 | %small
8 | = @assignment_repository.user.display_name
9 |
10 | .row
11 | .span6
12 | %h3 Activity Over Time
13 | #commit-time-chart.chart
14 | .span6
15 |
--------------------------------------------------------------------------------
/app/views/assignments/edit.html.haml:
--------------------------------------------------------------------------------
1 |
2 | = render 'form'
3 |
--------------------------------------------------------------------------------
/app/views/assignments/index.html.erb:
--------------------------------------------------------------------------------
1 | Listing assignments
2 |
3 |
4 |
5 | Creator |
6 | Short name |
7 | Long name |
8 | |
9 | |
10 | |
11 |
12 |
13 | <% @assignments.each do |assignment| %>
14 |
15 | <%= assignment.creator_id %> |
16 | <%= assignment.short_name %> |
17 | <%= assignment.long_name %> |
18 | <%= link_to 'Show', assignment %> |
19 | <%= link_to 'Edit', edit_assignment_path(assignment) %> |
20 | <%= link_to 'Destroy', assignment, :method => :delete, :data => { :confirm => 'Are you sure?' } %> |
21 |
22 | <% end %>
23 |
24 |
25 |
26 |
27 | <%= link_to 'New Assignment', new_assignment_path %>
28 |
--------------------------------------------------------------------------------
/app/views/assignments/new.html.erb:
--------------------------------------------------------------------------------
1 | New assignment
2 |
3 | <%= render 'form' %>
4 |
5 | <%= link_to 'Back', assignments_path %>
6 |
--------------------------------------------------------------------------------
/app/views/assignments/template_picker.html.haml:
--------------------------------------------------------------------------------
1 | %table.table.table-bordered.table-striped.table-condensed
2 | %thead
3 | %tr
4 | %th.span4 Short Name
5 | %th.span4 Full Name
6 | %th.span3 Term
7 | %th.span1
8 |
9 | %tbody
10 | - if @assignments.empty?
11 | %td{ colspan: 4 }
12 | .alert There are no past assignments that you can access in this course.
13 | - else
14 | - @assignments.each do |assignment|
15 | %tr
16 | %td= assignment.short_name
17 | %td= assignment.long_name
18 | %td= assignment.term.display_name
19 | %td= link_to "Select", simple_course_path('pick_template', @course, @term, assignment.id.to_s)
20 |
21 | - unless @assignments.empty?
22 | #assignments_paginator
23 | = paginate @assignments
24 |
--------------------------------------------------------------------------------
/app/views/authentications/index.html.haml:
--------------------------------------------------------------------------------
1 | - if @authentications
2 | - unless @authentications.empty?
3 | %p
4 | %strong You can sign in to this account using:
5 | .authentications
6 | - @authentications.each do |authentication|
7 | .authentication
8 | = image_tag "#{authentication.provider}_32.png", :size => "32x32"
9 | .provider
10 | = authentication.provider.titleize
11 | .uid
12 | = authentication.uid
13 | = link_to "X", authentication, :confirm => 'Are you sure you want to remove this authentication option?', :method => :delete, :class => "remove"
14 | .clear
15 | %p
16 | %strong Add another service to sign in with:
17 | - else
18 | %p
19 | %strong
20 | Sign in through one of these services:
21 |
22 | %a{:href => "/auth/facebook", :class => "auth_provider"}
23 | = image_tag "facebook_64.png", :size => "64x64", :alt => "Facebook"
24 | Facebook
25 |
26 | .clear
27 |
--------------------------------------------------------------------------------
/app/views/code/_check_outcomes_modal.html.haml:
--------------------------------------------------------------------------------
1 | #check_outcomes_modal.modal.hide.fade
2 | .modal-header
3 | = close_button_tag dismiss: 'modal'
4 | %h3 Assignment Check Results
5 |
6 | .modal-body
7 | .outcomes-header.clearfix
8 | .pull-left
9 | The results of your
10 | %strong= assignment_check.number.ordinalize
11 | check at
12 | %strong
13 | = succeed ':' do
14 | = l assignment_check.created_at
15 | = score_tile_label(assignment_check)
16 |
17 | %table.table.table-condensed.table-bordered.table-striped
18 | %thead
19 | %tr
20 | %th Test
21 | %th Result
22 | %tbody
23 | - assignment_check.check_outcomes.each do |outcome|
24 | %tr
25 | %td
26 | = outcome.description || outcome.name
27 | - if outcome.reason
28 | %p.hint
29 | = outcome.reason
30 | %td{ valign: 'top' }= outcome_bar outcome
31 |
32 | .modal-footer
33 | = button_tag 'Close', class: 'btn btn-primary', data: { dismiss: 'modal' }
34 |
--------------------------------------------------------------------------------
/app/views/code/_check_results.html.haml:
--------------------------------------------------------------------------------
1 | %table.table.table-bare
2 | %tbody
3 | - repository.assignment_checks.most_recent(10).each do |check|
4 | %tr
5 | %td
6 | = link_to l(check.updated_at), code_check_results_link(check), method: :post, remote: true
7 | %td{ style: 'width: 50%' }
8 | - if check.status == AssignmentCheck::COMPLETED
9 | = score_bar check.overall_score
10 | - elsif check.status == AssignmentCheck::TIMEOUT
11 | %small.text-error Timed out
12 | - elsif check.status == AssignmentCheck::FAILED
13 | %small.text-error Internal error
14 |
--------------------------------------------------------------------------------
/app/views/code/_choose_environment_modal.html.haml:
--------------------------------------------------------------------------------
1 | #choose_environment_modal.modal.hide{ data: { backdrop: 'static' } }
2 | .modal-header
3 | %h3 Choose Python Environment
4 |
5 | .modal-body.has-typeahead
6 | %p
7 | Select the Python environment that you want to use for this
8 | scratchpad. You can change it at any time later on if you wish.
9 |
10 | = select_tag :environment, options_from_collection_for_select(Environment.all, :id, :name, environment_id), prompt: '(none)', data: { width: '100%' }
11 |
12 | .modal-footer
13 | = button_tag 'Set Environment', id: 'set-environment', class: 'btn btn-primary', data: { dismiss: 'modal' }
14 |
--------------------------------------------------------------------------------
/app/views/code/_commit.html.haml:
--------------------------------------------------------------------------------
1 |
2 | - check = commit[:assignment_check]
3 | - if check
4 | %tr
5 | %td{colspan: 2}
6 | - if check.status == AssignmentCheck::COMPLETED
7 | = link_to code_check_results_link(check), method: :post, remote: true do
8 | = score_badge check.overall_score
9 | - elsif check.status == AssignmentCheck::TIMEOUT
10 | %small.text-error Timed out
11 | - elsif check.status == AssignmentCheck::FAILED
12 | %small.text-error Internal error
13 |
14 | %tr{ data: { date: commit[:date].to_i * 1000 } }
15 | %td
16 | %a{ href: "\##{commit[:sha]}" }= l commit[:date]
17 | %td
18 | = commit[:message]
19 |
--------------------------------------------------------------------------------
/app/views/code/_file_list.html.haml:
--------------------------------------------------------------------------------
1 | %ul.unstyled
2 | - @repository.ls(path).each do |e|
3 | - unless File.directory?(File.join(@repository.git_path, path, e))
4 | - relative_path = File.join(path, e)
5 | %li
6 | = icon_tag('file')
7 | - if relative_path == @filename
8 | %strong= e
9 | - else
10 | %a{ href: code_path(@repository, relative_path) }= e
11 |
--------------------------------------------------------------------------------
/app/views/code/_picture_tool.haml:
--------------------------------------------------------------------------------
1 | #mediacomp-colorpicker.modal.hide#Sk-canvasModal
2 | .modal-header
3 | = close_button_tag dismiss: 'modal'
4 | %h3
5 | Picture Tool
6 |
7 | .modal-body
8 |
9 | .modal-footer
10 | %form.form-inline.pull-left
11 | = label_tag 'canvas-x', 'X:'
12 | %input.input-mini#canvas-x{type: 'number'}
13 | = label_tag 'canvas-y', 'Y:'
14 | %input.input-mini#canvas-y{type: 'number'}
15 | %table.pull-right
16 | %tbody
17 | %tr
18 | %td.canvas-color-label R:
19 | %td#canvas-red 0
20 | %td.canvas-color-label G:
21 | %td#canvas-green 0
22 | %td.canvas-color-label B:
23 | %td#canvas-blue 0
24 | %td#canvas-color-swatch
25 |
--------------------------------------------------------------------------------
/app/views/code/_user_list.html.haml:
--------------------------------------------------------------------------------
1 | - users.each do |user|
2 | %li{ class: user_list_item_class(@repository, user) }><
3 | = gravatar_tag(user, 30, rel: 'tooltip', title: user_list_item_title(@repository, user))
4 |
--------------------------------------------------------------------------------
/app/views/code/add_history.js.coffee:
--------------------------------------------------------------------------------
1 | <% if commits.length > 0 %>
2 | $('#history-table tbody').append '<%= j render partial: "commit", collection: commits %>'
3 | <% else %>
4 | $('#history-table .next-page').hide()
5 | <% end %>
6 | window.codeController.nextHistoryPageLoaded()
7 |
--------------------------------------------------------------------------------
/app/views/code/check.js.coffee:
--------------------------------------------------------------------------------
1 | <% if @closed && !@is_instructor %>
2 | pythy.alert 'You cannot perform anymore checks because the
3 | assignment has closed.', title: 'Assignment Closed'
4 | <% elsif !@was_changed && !@is_instructor %>
5 | $('#check').button('reset')
6 | pythy.alert 'Your code hasn\'t changed since your last check,
7 | so it will not be rechecked. Please look at your previous
8 | results.', title: 'Code Unchanged'
9 | <% elsif !@was_changed && !@last_check %>
10 | pythy.alert 'There is nothing to check! Is anything saved?', title: 'Nothing to check'
11 | <% end %>
12 |
--------------------------------------------------------------------------------
/app/views/code/check_results.js.coffee:
--------------------------------------------------------------------------------
1 | $('#check').button('reset')
2 |
3 | <% if assignment_check.status == AssignmentCheck::COMPLETED %>
4 | # Append the modal to the page body.
5 | $('body').append(
6 | '<%= j render partial: "code/check_outcomes_modal", locals: { assignment_check: assignment_check } %>')
7 |
8 | # Ensure that the dialog gets removed from the DOM when it is closed.
9 | $('#check_outcomes_modal').on 'hidden', ->
10 | $('#check_outcomes_modal').remove()
11 |
12 | # Display the dialog.
13 | $('#check_outcomes_modal').modal('show')
14 |
15 | <% elsif assignment_check.status == AssignmentCheck::FAILED %>
16 | pythy.alert 'An internal error occurred when executing your code.'
17 |
18 | <% elsif assignment_check.status == AssignmentCheck::TIMEOUT %>
19 | pythy.alert 'Your code did not complete in the allowed amount of time.'
20 |
21 | <% end %>
22 |
--------------------------------------------------------------------------------
/app/views/code/related_files/_assignment_reference_repository.html.haml:
--------------------------------------------------------------------------------
1 |
2 | .section-header
3 | Starter Files
4 | .container-fluid
5 | = render partial: 'file_list', locals: { path: 'starter' }
6 |
7 | .section-header
8 | Reference Tests
9 | .container-fluid
10 | = render partial: 'file_list', locals: { path: 'test' }
11 |
12 | .section-header
13 | Solution
14 | .container-fluid
15 | = render partial: 'file_list', locals: { path: 'solution' }
16 |
17 | .section-header
18 | Student View
19 | .container-fluid
20 | %ul.unstyled
21 | - @repository.assignment.assignment_offerings.each do |ao|
22 | %li
23 | = ao.course_offering.short_label + ": " + ao.course_offering.long_label
24 | %li
25 | = icon_tag('file')
26 | = link_to "main.py", code_path(ao)
27 | %br
--------------------------------------------------------------------------------
/app/views/code/summary/_assignment_reference_repository.html.haml:
--------------------------------------------------------------------------------
1 | .section-header.big
2 | = succeed ": " do
3 | = @repository.assignment.short_name
4 | = @repository.assignment.long_name
5 | %span.label.label-important Reference repository
6 |
7 | .container-fluid
8 | This example was created by
9 | = @repository.user.display_name
10 | at
11 | = succeed '.' do
12 | %strong= l @repository.created_at
13 |
--------------------------------------------------------------------------------
/app/views/code/summary/_assignment_repository.html.haml:
--------------------------------------------------------------------------------
1 | .section-header.big
2 | = succeed ": " do
3 | = @repository.assignment_offering.assignment.short_name
4 | = @repository.assignment_offering.assignment.long_name
5 | %small
6 | - if @repository.user != current_user
7 | %span.label.label-warning= @repository.user.display_name
8 |
9 | .container-fluid
10 | .row-fluid
11 | = raw @repository.assignment_offering.assignment.brief_summary_html
12 |
13 | .section-header
14 | Important Dates
15 |
16 | .container-fluid
17 | .row-fluid
18 | - if @repository.assignment_offering.due_at
19 | This assignment is due at
20 | = succeed '.' do
21 | = live_date_tag @repository.assignment_offering.due_at
22 | - if @repository.assignment_offering.closes_at
23 | This assignment may not be checked after
24 | = succeed '.' do
25 | = l @repository.assignment_offering.closes_at
26 |
--------------------------------------------------------------------------------
/app/views/code/summary/_example_repository.html.haml:
--------------------------------------------------------------------------------
1 | .section-header.big
2 | Example:
3 | = @repository.name
4 | %small
5 | = surround '(', ')' do
6 | = @repository.course_offering.course.number
7 |
8 | .container-fluid
9 | .row-fluid
10 | This example was created by
11 | = @repository.user.display_name
12 | at
13 | = succeed '.' do
14 | %strong= l @repository.created_at
15 |
16 | - if can? :manage, @repository
17 | .section-header
18 | Users watching:
19 |
20 | .container-fluid
21 | %ul#accessing-users.gravatar-list
22 |
--------------------------------------------------------------------------------
/app/views/code/summary/_scratchpad_repository.html.haml:
--------------------------------------------------------------------------------
1 | .section-header.big
2 | Scratchpad
3 |
4 | .container-fluid
5 | You can use this coding area to do “scratch work” that
6 | isn't part of any of your courses or assignments. The code that you
7 | write here is automatically saved.
8 |
9 |
10 | /= link_to icon_tag('code-fork') + ' Save as personal repository...', 'javascript:void(0)', id: 'save-as-personal', class: 'btn btn-block'
11 |
--------------------------------------------------------------------------------
/app/views/code/update.js.coffee:
--------------------------------------------------------------------------------
1 | <% if @committed %>
2 | new_history_row = '<%= j render partial: "commit", locals: { commit: @commit_hash } %>'
3 | window.codeController.updateHistory(new_history_row, <%= @committed[:amend] %>)
4 | $('#save-state-icon').html('')
5 | $('#save-state-message').html('saved')
6 | <% end %>
7 | <% if @repository.is_a?(AssignmentRepository) && !@repository.assignment_offering.closed? %>
8 | $('#check').removeAttr('disabled')
9 | <% end %>
10 |
--------------------------------------------------------------------------------
/app/views/code/update_code.js.coffee:
--------------------------------------------------------------------------------
1 | <% if local_assigns[:environment] %>
2 | window.codeController.setPreamble '<%= j raw environment.preamble || "" %>'
3 | <% end %>
4 | <% if local_assigns[:commit] %>
5 | new_history_row = '<%= j render partial: "commit", locals: { commit: commit } %>'
6 | amend = <%= amend %>
7 | <% else %>
8 | new_history_row = null
9 | amend = false
10 | <% end %>
11 | window.codeController.updateCode '<%= j raw code %>', <%= force %>, new_history_row, amend, <%= initial %>
12 |
--------------------------------------------------------------------------------
/app/views/code/update_user_list.js.coffee:
--------------------------------------------------------------------------------
1 | $('#summary ul#accessing-users').html(
2 | "<%= j render partial: 'user_list', locals: { users: users } %>")
3 | #$('#accessing-user-count').text "(<%= users.count %>)"
4 | $('[rel=tooltip]').tooltip container: 'body'
5 |
--------------------------------------------------------------------------------
/app/views/course_enrollments/_course_enrollment.html.haml:
--------------------------------------------------------------------------------
1 | %tr
2 | %td.has_gravatar
3 | = gravatar_tag(course_enrollment.user, 28)
4 | = link_to course_enrollment.user.display_name, course_enrollment.user
5 | %td= course_enrollment.user.email
6 | %td= course_enrollment.course_role.name
7 | %td= link_to_destroy course_enrollment, remote: true
8 |
--------------------------------------------------------------------------------
/app/views/course_enrollments/_modal.html.haml:
--------------------------------------------------------------------------------
1 | #course_enrollment_modal.modal.hide.fade
2 | = pythy_form_for @course_enrollment.course_offering, @course_enrollment,
3 | remote: true, html: { class: 'modal-form' } do |f|
4 | .modal-header
5 | = close_button_tag dismiss: 'modal'
6 | %h3 Add User Manually
7 |
8 | .modal-body.has-typeahead
9 | #flashbar-placeholder
10 | = f.label :user_id, 'User' do
11 | = f.hidden_field :user_id
12 | = text_field_tag :user_name, nil, class: 'input-xlarge typeahead-user', autocomplete: 'off'
13 |
14 | = f.collection_select( :course_role_id, 'Role', CourseRole.all, :id, :name, {:selected => CourseRole::STUDENT_ID})
15 | = hidden_field_tag :type, @type
16 |
17 | .modal-footer
18 | = f.submit
19 |
--------------------------------------------------------------------------------
/app/views/course_enrollments/_table.html.haml:
--------------------------------------------------------------------------------
1 | %table.table.table-bordered.table-striped.table-condensed
2 | %thead
3 | %tr
4 | %th.span4 Full Name
5 | %th.span4 E-mail
6 | %th.span3 Role
7 | %th.span1= icon_tag('cog')
8 | %tbody#course_enrollments
9 | - if enrollments.empty?
10 | %td{ colspan: 4 }
11 | .alert There are no users currently enrolled in this course offering.
12 | - else
13 | = render enrollments
14 |
15 | - unless enrollments.empty?
16 | #course_enrollments_paginator
17 | = paginate enrollments, :param_name => "enrollments_" + enrollments.first.course_offering_id.to_s + "_page"
18 |
--------------------------------------------------------------------------------
/app/views/course_enrollments/create.js.coffee:
--------------------------------------------------------------------------------
1 | $('#course_enrollments').html(
2 | '<%= escape_javascript render(@course_offering.course_enrollments) %>')
3 |
4 | $('#course_enrollment_modal').modal('hide')
5 |
--------------------------------------------------------------------------------
/app/views/course_enrollments/destroy.js.coffee:
--------------------------------------------------------------------------------
1 | $('#course_enrollments').html(
2 | '<%= escape_javascript render(
3 | @course_enrollment.course_offering.course_enrollments.page(params[:page])) %>')
4 |
--------------------------------------------------------------------------------
/app/views/course_enrollments/index.js.coffee:
--------------------------------------------------------------------------------
1 | $('#course_enrollments').html(
2 | '<%= escape_javascript render(@course_enrollments) %>')
3 | $('#course_enrollments_paginator').html(
4 | '<%= escape_javascript(paginate(@course_enrollments, remote: true).to_s) %>')
5 |
--------------------------------------------------------------------------------
/app/views/course_enrollments/new.js.coffee:
--------------------------------------------------------------------------------
1 | # Append the course enrollments dialog to the page body.
2 | $('body').append(
3 | '<%= escape_javascript(render partial: "course_enrollments/modal") %>')
4 |
5 | window.pythy.typeaheadUser()
6 |
7 | # Ensure that the dialog gets removed from the DOM when it is closed.
8 | $('#course_enrollment_modal').on 'hidden', ->
9 | $('#course_enrollment_modal').remove()
10 |
11 | $('#course_enrollment_modal').on 'shown', ->
12 | $('#course_enrollment_user_id').focus()
13 |
14 | $('#course_enrollment_modal #enroll-users-button').button('loading')
15 |
16 | # Display the dialog.
17 | $('#course_enrollment_modal').modal('show')
18 |
--------------------------------------------------------------------------------
/app/views/course_offerings/_index.html.haml:
--------------------------------------------------------------------------------
1 | - if course_offerings.empty?
2 | %div.alert
3 | This course does not have any offerings.
4 | = link_to new_course_course_offering_path(@course) do
5 | Click here to create one.
6 | - else
7 | - course_offerings.each do |term, offerings|
8 | %h3
9 | = term.display_name
10 | Offerings
11 | %table.table.table-striped.table-bordered
12 | %thead
13 | %tr
14 | %th.span3 CRN
15 | %th.span7 Label
16 | %th.span1= icon_tag('cog')
17 | %tbody
18 | - offerings.each do |course_offering|
19 | %tr
20 | %td= link_to course_offering.short_label, course_offering
21 | %td= course_offering.long_label
22 | %td
23 | = link_to icon_tag('pencil'), edit_course_offering_path(course_offering)
24 | = link_to_destroy course_offering
25 |
--------------------------------------------------------------------------------
/app/views/course_offerings/edit.html.haml:
--------------------------------------------------------------------------------
1 |
2 | = render 'form'
3 |
--------------------------------------------------------------------------------
/app/views/course_offerings/index.html.haml:
--------------------------------------------------------------------------------
1 | .pull-right
2 | = link_to icon_tag('plus') + ' New...', new_course_course_offering_path(@course), class: 'btn'
3 |
4 | = render partial: 'course_offerings/index', locals: { course_offerings: @grouped_offerings }
5 |
--------------------------------------------------------------------------------
/app/views/course_offerings/new.html.haml:
--------------------------------------------------------------------------------
1 |
2 | = render 'form'
3 |
--------------------------------------------------------------------------------
/app/views/course_offerings/show.html.haml:
--------------------------------------------------------------------------------
1 | .pull-right
2 | = link_to icon_tag('pencil') + ' Edit', edit_course_offering_path(@course_offering), class: 'btn'
3 |
4 | %h2.page-header
5 | = @course_offering.course.number
6 | = surround '(', ')' do
7 | = @course_offering.short_label
8 | %small
9 | - if @course_offering.long_label.blank?
10 | = @course_offering.term.display_name
11 | - else
12 | = succeed ',' do
13 | = @course_offering.term.display_name
14 | = @course_offering.long_label
15 |
16 | .clearfix
17 | %h3.pull-left Course Staff and Enrolled Students
18 | .pull-right.dropdown
19 | = dropdown_button_tag 'Add Users', class: 'btn btn-primary'
20 | %ul.dropdown-menu
21 | %li
22 | = link_to 'Manually...', new_course_offering_course_enrollment_path(@course_offering), remote: true
23 | %li
24 | = link_to 'Upload a roster...', upload_roster_path(@course_offering), remote: true
25 |
26 | #staff-enrollments-table
27 | = render partial: 'course_enrollments/table', locals: { enrollments: @course_enrollments }
28 |
--------------------------------------------------------------------------------
/app/views/course_offerings/show.js.coffee:
--------------------------------------------------------------------------------
1 | $('#course_enrollments').html(
2 | '<%= escape_javascript render(@course_enrollments) %>')
3 | $('#course_enrollments_paginator').html(
4 | '<%= escape_javascript(paginate(@course_enrollments, remote: true).to_s) %>')
5 |
--------------------------------------------------------------------------------
/app/views/course_roles/_form.html.haml:
--------------------------------------------------------------------------------
1 | = twitter_bootstrap_form_for @course_role, html: { class: 'form-horizontal' } do |f|
2 | = f.text_field :name, 'Name'
3 |
4 | = f.label 'Permissions' do |controls|
5 | = controls.check_box :can_manage_course, 'Modify course', disabled: @course_role.builtin?
6 | = controls.check_box :can_manage_assignments, 'Create and edit assignments', disabled: @course_role.builtin?
7 | = controls.check_box :can_grade_submissions, 'Grade other students\' work', disabled: @course_role.builtin?
8 | = controls.check_box :can_view_other_submissions, 'View other students\' work', disabled: @course_role.builtin?
9 | - if @course_role.builtin?
10 | %span.help-block
11 | Permissions cannot be changed for built-in roles.
12 |
13 | = f.actions do
14 | = f.submit
15 |
--------------------------------------------------------------------------------
/app/views/course_roles/edit.html.haml:
--------------------------------------------------------------------------------
1 |
2 | = render 'form'
3 |
--------------------------------------------------------------------------------
/app/views/course_roles/new.html.haml:
--------------------------------------------------------------------------------
1 |
2 | = render 'form'
3 |
--------------------------------------------------------------------------------
/app/views/course_roles/show.html.haml:
--------------------------------------------------------------------------------
1 | = render :partial => "flashbar"
2 | = link_to 'Edit', edit_course_role_path(@course_role)
3 | = link_to 'Back', course_roles_path
--------------------------------------------------------------------------------
/app/views/courses/_form.html.haml:
--------------------------------------------------------------------------------
1 | = pythy_form_for @course.organization, @course do |f|
2 |
3 | = f.collection_select :organization_id, 'Organization', Organization.all, :id, :display_name, prompt: '(none)'
4 |
5 | = f.text_field :number do
6 | %span.help-block
7 | The course number prefixed by its departmental abbreviation (for example, "CS 110"). There are no restrictions on the format of this string so different types of organizations can use it differently (for example, "Sandbox" or "Playground" might be appropriate).
8 |
9 | = f.text_field :name, class: 'span6' do
10 | %span.help-block
11 | The full course title (for example, "Introduction to Python").
12 |
13 | = f.collection_select :default_environment_id, 'Default environment', Environment.all, :id, :name, prompt: '(none)'
14 |
15 | = f.actions do
16 | = f.submit
17 |
--------------------------------------------------------------------------------
/app/views/courses/_index.html.haml:
--------------------------------------------------------------------------------
1 | - if courses.empty?
2 | %div.alert
3 | This organization does not have any courses.
4 | = link_to new_organization_course_path(@organization) do
5 | Click here to create one.
6 | - else
7 | %table.table.table-striped.table-bordered
8 | %thead
9 | %tr
10 | %th.span3 Course Number
11 | %th.span8 Title
12 | %th.span1= icon_tag('cog')
13 | %tbody
14 | - courses.each do |course|
15 | %tr
16 | %td= link_to course.number, course
17 | %td= course.name
18 | %td
19 | = link_to icon_tag('pencil'), edit_course_path(course)
20 | = link_to_destroy course
21 |
--------------------------------------------------------------------------------
/app/views/courses/edit.html.haml:
--------------------------------------------------------------------------------
1 |
2 | = render 'form'
3 |
--------------------------------------------------------------------------------
/app/views/courses/index.html.haml:
--------------------------------------------------------------------------------
1 | .pull-right
2 | = link_to icon_tag('plus') + ' New...', new_organization_course_path(@organization), class: 'btn'
3 |
4 | = render partial: 'courses/index', locals: { courses: @courses }
5 |
--------------------------------------------------------------------------------
/app/views/courses/new.html.haml:
--------------------------------------------------------------------------------
1 |
2 | = render 'form'
3 |
--------------------------------------------------------------------------------
/app/views/courses/show.html.haml:
--------------------------------------------------------------------------------
1 | .pull-right
2 | = link_to icon_tag('pencil') + ' Edit', edit_course_path(@course), class: 'btn'
3 |
4 | %h2.page-header
5 | = @course.number
6 | %small
7 | = @course.name
8 |
9 | %p
10 | = link_to 'Create a new offering of this course...', new_course_course_offering_path(@course)
11 |
12 | = render partial: 'course_offerings/index', locals: { course_offerings: @grouped_offerings }
13 |
--------------------------------------------------------------------------------
/app/views/devise/confirmations/new.html.erb:
--------------------------------------------------------------------------------
1 | Resend confirmation instructions
2 |
3 | <%= form_for(resource, :as => resource_name, :url => confirmation_path(resource_name), :html => { :method => :post }) do |f| %>
4 | <%= devise_error_messages! %>
5 |
6 | <%= f.label :email %>
7 | <%= f.email_field :email %>
8 |
9 | <%= f.submit "Resend confirmation instructions" %>
10 | <% end %>
11 |
12 | <%= render "links" %>
--------------------------------------------------------------------------------
/app/views/devise/mailer/confirmation_instructions.html.erb:
--------------------------------------------------------------------------------
1 | Welcome <%= @resource.email %>!
2 |
3 | You can confirm your account email through the link below:
4 |
5 | <%= link_to 'Confirm my account', confirmation_url(@resource, :confirmation_token => @resource.confirmation_token) %>
6 |
--------------------------------------------------------------------------------
/app/views/devise/mailer/reset_password_instructions.html.erb:
--------------------------------------------------------------------------------
1 | Hello <%= @resource.email %>!
2 |
3 | Someone has requested a link to change your password, and you can do this through the link below.
4 |
5 | <%= link_to 'Change my password', edit_password_url(@resource, :reset_password_token => @resource.reset_password_token) %>
6 |
7 | If you didn't request this, please ignore this email.
8 | Your password won't change until you access the link above and create a new one.
9 |
--------------------------------------------------------------------------------
/app/views/devise/mailer/unlock_instructions.html.erb:
--------------------------------------------------------------------------------
1 | Hello <%= @resource.email %>!
2 |
3 | Your account has been locked due to an excessive amount of unsuccessful sign in attempts.
4 |
5 | Click the link below to unlock your account:
6 |
7 | <%= link_to 'Unlock my account', unlock_url(@resource, :unlock_token => @resource.unlock_token) %>
8 |
--------------------------------------------------------------------------------
/app/views/devise/passwords/edit.html.erb:
--------------------------------------------------------------------------------
1 | Change your password
2 |
3 | <%= form_for(resource, :as => resource_name, :url => password_path(resource_name), :html => { :method => :put }) do |f| %>
4 | <%= devise_error_messages! %>
5 | <%= f.hidden_field :reset_password_token %>
6 |
7 | <%= f.label :password, "New password" %>
8 | <%= f.password_field :password %>
9 |
10 | <%= f.label :password_confirmation, "Confirm new password" %>
11 | <%= f.password_field :password_confirmation %>
12 |
13 | <%= f.submit "Change my password" %>
14 | <% end %>
15 |
16 | <%= render "links" %>
--------------------------------------------------------------------------------
/app/views/devise/passwords/new.html.erb:
--------------------------------------------------------------------------------
1 | Forgot your password?
2 |
3 | <%= form_for(resource, :as => resource_name, :url => password_path(resource_name), :html => { :method => :post }) do |f| %>
4 | <%= devise_error_messages! %>
5 |
6 | <%= f.label :email %>
7 | <%= f.email_field :email %>
8 |
9 | <%= f.submit "Send me reset password instructions" %>
10 | <% end %>
11 |
12 | <%= render "links" %>
13 |
--------------------------------------------------------------------------------
/app/views/devise/registrations/edit.html.erb:
--------------------------------------------------------------------------------
1 | Edit <%= resource_name.to_s.humanize %>
2 |
3 | <%= form_for(resource, :as => resource_name, :url => registration_path(resource_name), :html => { :method => :put }) do |f| %>
4 | <%= devise_error_messages! %>
5 |
6 | <%= f.label :email %>
7 | <%= f.email_field :email %>
8 |
9 | <%= f.label :password %> (leave blank if you don't want to change it)
10 | <%= f.password_field :password, :autocomplete => "off" %>
11 |
12 | <%= f.label :password_confirmation %>
13 | <%= f.password_field :password_confirmation %>
14 |
15 | <%= f.label :current_password %> (we need your current password to confirm your changes)
16 | <%= f.password_field :current_password %>
17 |
18 | <%= f.submit "Update" %>
19 | <% end %>
20 |
21 | Cancel my account
22 |
23 | Unhappy? <%= link_to "Cancel my account", registration_path(resource_name), :confirm => "Are you sure?", :method => :delete %>.
24 |
25 | <%= link_to "Back", :back %>
26 |
--------------------------------------------------------------------------------
/app/views/devise/registrations/new.html.haml:
--------------------------------------------------------------------------------
1 | %h2 Sign up
2 |
3 | = twitter_bootstrap_form_for resource, :as => resource_name, :url => registration_path(resource_name) do |f|
4 | = devise_error_messages!
5 |
6 | = f.email_field :email
7 | = f.password_field :password
8 | = f.password_field :password_confirmation
9 | = f.text_field :first_name
10 | = f.text_field :last_name
11 |
12 | = f.actions do
13 | = f.submit 'Sign up'
14 |
15 | = render 'links'
16 |
--------------------------------------------------------------------------------
/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 | <%= f.label :email %>
7 | <%= f.email_field :email %>
8 |
9 | <%= f.submit "Resend unlock instructions" %>
10 | <% end %>
11 |
12 | <%= render "links" %>
--------------------------------------------------------------------------------
/app/views/environments/_form.html.haml:
--------------------------------------------------------------------------------
1 | = pythy_form_for @environment do |f|
2 |
3 | = f.text_field :name do
4 | %span.help-block
5 | The human-readable name of the environment.
6 |
7 | = f.text_area :preamble, rows: 5, class: 'input-xxlarge' do
8 | .help-block
9 | Any code required to execute before student code (for example,
10 | additional import statements).
11 |
12 | = f.actions do
13 | = f.submit
14 |
--------------------------------------------------------------------------------
/app/views/environments/edit.html.haml:
--------------------------------------------------------------------------------
1 |
2 | = render 'form'
3 |
--------------------------------------------------------------------------------
/app/views/environments/index.html.haml:
--------------------------------------------------------------------------------
1 | .pull-right
2 | = link_to icon_tag('plus') + ' New...', new_environment_path, class: 'btn'
3 |
4 | %table.table.table-striped.table-bordered
5 | %thead
6 | %tr
7 | %th Name
8 | %th= icon_tag('cog')
9 | %tbody
10 | - @environments.each do |environment|
11 | %tr
12 | %td= link_to environment.name, environment
13 | %td
14 | = link_to icon_tag('pencil'), edit_environment_path(environment)
15 | = link_to_destroy environment
16 |
--------------------------------------------------------------------------------
/app/views/environments/new.html.haml:
--------------------------------------------------------------------------------
1 |
2 | = render 'form'
3 |
--------------------------------------------------------------------------------
/app/views/environments/show.html.haml:
--------------------------------------------------------------------------------
1 | .pull-right
2 | = link_to icon_tag('pencil') + ' Edit', edit_environment_path(@environment), class: 'btn'
3 |
4 | %h2
5 | = @environment.name
6 |
7 | %h3 Preamble
8 | %p
9 | The Python statements below are inserted at the top of any code executed
10 | by Pythy.
11 | %pre= @environment.preamble
12 |
--------------------------------------------------------------------------------
/app/views/errors/_modal.html.haml:
--------------------------------------------------------------------------------
1 | #error_modal.modal.modal-wide.hide
2 | .modal-body
3 | = render template: "errors/error_#{status}"
4 | .modal-footer
5 | = button_tag 'Close', class: 'btn btn-primary', data: { dismiss: 'modal' }
6 |
--------------------------------------------------------------------------------
/app/views/errors/error_403.html.haml:
--------------------------------------------------------------------------------
1 | %h2 Are You Supposed to Be Here?
2 | %div
3 | %p
4 | Unfortunately, you've ended up on a page that you are not
5 | authorized to view. If you think this
6 | is in error, please let the developers know!
7 |
8 | %p Sorry!
9 |
10 | = link_to 'Home', root_url, class: 'btn btn-primary'
11 |
--------------------------------------------------------------------------------
/app/views/errors/error_404.html.haml:
--------------------------------------------------------------------------------
1 | - bc = ActiveSupport::BacktraceCleaner.new
2 | - bc.add_filter { |line| line.gsub(Rails.root.to_s, '') }
3 | - bc.add_silencer { |line| line =~ /\/gems\// }
4 | - backtrace = $! && bc.clean($!.backtrace)
5 |
6 | %h2 Resource Not Found
7 | %div
8 | %p
9 | The resource that you requested could not be found.
10 |
11 | - if current_user && current_user.global_role.can_edit_system_configuration
12 | %hr
13 | - if $!
14 | %h4 Exception
15 | %pre.alert.alert-danger
16 | = $!.message
17 | %h4 Backtrace
18 | %pre{ style: 'overflow: auto; white-space: nowrap' }
19 | - backtrace.each do |frame|
20 | = frame
21 | %br
22 |
--------------------------------------------------------------------------------
/app/views/errors/error_500.html.haml:
--------------------------------------------------------------------------------
1 | - bc = ActiveSupport::BacktraceCleaner.new
2 | - bc.add_filter { |line| line.gsub(Rails.root.to_s, '') }
3 | - bc.add_silencer { |line| line =~ /\/gems\// }
4 | - backtrace = bc.clean($!.backtrace)
5 |
6 | %h2 We've Got a Problem ...
7 | %p
8 | Unfortunately, something went wrong.
9 | There are a lot of possible reasons why this might have happened,
10 | but we've logged the problem so the developers can look at it.
11 |
12 | %p Sorry!
13 |
14 | = link_to 'Home', root_url, class: 'btn btn-primary'
15 |
16 | - if current_user && current_user.global_role.can_edit_system_configuration
17 | %hr
18 | %h4 Exception
19 | %pre.alert.alert-danger
20 | = $!.message
21 | %h4 Backtrace
22 | %pre{ style: 'overflow: auto; white-space: nowrap' }
23 | - backtrace.each do |frame|
24 | = frame
25 | %br
26 |
--------------------------------------------------------------------------------
/app/views/errors/error_modal.js.coffee:
--------------------------------------------------------------------------------
1 | # Append the course enrollments dialog to the page body.
2 | $('body').append(
3 | '<%= escape_javascript(render partial: "errors/modal", locals: { status: status }) %>')
4 |
5 | # Ensure that the dialog gets removed from the DOM when it is closed.
6 | $('#error_modal').on 'hidden', ->
7 | $('#error_modal').remove()
8 |
9 | # Display the dialog.
10 | $('#error_modal').modal('show')
11 |
--------------------------------------------------------------------------------
/app/views/example_repositories/_empty.html.haml:
--------------------------------------------------------------------------------
1 | %tr
2 | %td{ colspan: 2 }
3 | %div.alert.alert-info
4 | The course instructor hasn't made any examples available yet.
5 |
--------------------------------------------------------------------------------
/app/views/example_repositories/_example_repository.html.haml:
--------------------------------------------------------------------------------
1 | %tr
2 | %td= link_to example_repository.name, code_path(example_repository)
3 | %td
4 | = l example_repository.created_at, format: :date_only
5 |
6 | - if can?(:destroy, example_repository)
7 | = link_to_destroy example_repository
8 |
--------------------------------------------------------------------------------
/app/views/example_repositories/_modal.html.haml:
--------------------------------------------------------------------------------
1 | #example_repositories_modal.modal.hide.fade
2 | = pythy_form_for @example_repository.course_offering, @example_repository,
3 | remote: true, html: { class: 'modal-form' } do |f|
4 | .modal-header
5 | = close_button_tag dismiss: 'modal'
6 | %h3 New Example
7 |
8 | .modal-body
9 | #flashbar-placeholder
10 |
11 | = f.text_field :name, class: 'input-xlarge'
12 | = f.text_area :description, rows: 5, class: 'input-xlarge'
13 |
14 | .control-group
15 | .controls
16 | %label.checkbox
17 | = check_box_tag :add_to_all_offerings
18 | Share across all offerings in the term
19 |
20 | .modal-footer
21 | = f.submit
22 |
--------------------------------------------------------------------------------
/app/views/example_repositories/create.js.coffee:
--------------------------------------------------------------------------------
1 | $('#example_repositories').html(
2 | '<%= j render(@course_offering.example_repositories.sort! { |a, b| b.created_at <=> a.created_at }) %>')
3 |
4 | $('#example_repositories_modal').modal('hide')
5 |
--------------------------------------------------------------------------------
/app/views/example_repositories/destroy.js.coffee:
--------------------------------------------------------------------------------
1 | Examples#destroy
2 | Find me in app/views/examples/destroy.html.erb
3 |
--------------------------------------------------------------------------------
/app/views/example_repositories/index.js.coffee:
--------------------------------------------------------------------------------
1 | $('#example_repositories').html(
2 | '<%= escape_javascript render(@example_repositories) %>')
3 | $('#example_repositories_paginator').html(
4 | '<%= escape_javascript(paginate(@example_repositories, remote: true).to_s) %>')
5 |
--------------------------------------------------------------------------------
/app/views/example_repositories/new.js.coffee:
--------------------------------------------------------------------------------
1 | # Append the modal to the page body.
2 | $('body').append(
3 | '<%= escape_javascript(render partial: "modal") %>')
4 |
5 | # Ensure that the dialog gets removed from the DOM when it is closed.
6 | $('#example_repositories_modal').on 'hidden', ->
7 | $('#example_repositories_modal').remove()
8 |
9 | # Display the dialog.
10 | $('#example_repositories_modal').modal('show')
11 |
--------------------------------------------------------------------------------
/app/views/global_roles/_form.html.haml:
--------------------------------------------------------------------------------
1 | = pythy_form_for @global_role do |f|
2 |
3 | = f.text_field :name, 'Name'
4 |
5 | = f.label 'Permissions' do |controls|
6 | = controls.check_box :can_create_courses, 'Create courses', disabled: @global_role.builtin?
7 | = controls.check_box :can_manage_all_courses, 'Manage all courses', disabled: @global_role.builtin?
8 | = controls.check_box :can_edit_system_configuration, 'Edit system configuration', disabled: @global_role.builtin?
9 | - if @global_role.builtin?
10 | %span.help-block
11 | Permissions cannot be changed for built-in roles.
12 |
13 | = f.actions do
14 | = f.submit
15 |
--------------------------------------------------------------------------------
/app/views/global_roles/edit.html.haml:
--------------------------------------------------------------------------------
1 |
2 | = render 'form'
3 |
--------------------------------------------------------------------------------
/app/views/global_roles/index.html.haml:
--------------------------------------------------------------------------------
1 | .pull-right
2 | = link_to icon_tag('plus') + ' New...', new_global_role_path, class: 'btn'
3 |
4 | %h2 Global Roles
5 | %p
6 | Global roles are used to control the permissions that users have
7 | system-wide.
8 |
9 | %table.table.table-striped.table-bordered
10 | %thead
11 | %tr
12 | %th.span5 Name
13 | %th.span2 Can edit system configuration?
14 | %th.span2 Can manage all courses?
15 | %th.span2 Can create courses?
16 | %th.span1= icon_tag('cog')
17 | %tbody
18 | - @global_roles.each do |role|
19 | %tr
20 | %td
21 | = link_to role.name, role
22 | - if role.builtin?
23 | %span.muted (built-in)
24 | %td= checkmark_if role.can_edit_system_configuration?
25 | %td= checkmark_if role.can_manage_all_courses?
26 | %td= checkmark_if role.can_create_courses?
27 | %td
28 | = link_to icon_tag('pencil'), edit_global_role_path(role)
29 | - unless role.builtin?
30 | = link_to_destroy role
31 |
--------------------------------------------------------------------------------
/app/views/global_roles/new.html.haml:
--------------------------------------------------------------------------------
1 |
2 | = render 'form'
3 |
--------------------------------------------------------------------------------
/app/views/global_roles/show.html.haml:
--------------------------------------------------------------------------------
1 | = render :partial => "flashbar"
2 | = link_to 'Edit', edit_global_role_path(@global_role)
3 | = link_to 'Back', global_roles_path
--------------------------------------------------------------------------------
/app/views/home/_course_staff_assignments.html.haml:
--------------------------------------------------------------------------------
1 | .container
2 | .row
3 | .span7
4 | .btn-header-container.clearfix
5 | %h3.pull-left.slim.btn-line-height Assignments
6 | - if @offerings.any? { |o| o.role_for_user(current_user).can_manage_assignments? }
7 | .pull-right
8 | = link_to icon_tag('plus') + ' New...', new_course_offering_assignment_offering_path(@offerings.first), class: 'btn', remote: true
9 |
10 | #assignments
11 | = render(partial: 'home/instructor_assignment', collection: @assignments) || render(partial: 'home/no_assignments')
12 |
13 | .span5
14 | .btn-header-container.clearfix
15 | %h3.pull-left.slim.btn-line-height Instructor Examples
16 | - if @offerings.any? { |o| o.role_for_user(current_user).can_manage_assignments? }
17 | .pull-right
18 | = link_to icon_tag('plus') + ' New...', new_course_offering_example_repository_path(@offerings.first), class: 'btn', remote: true
19 |
20 | %table.examples
21 | %tbody#example_repositories
22 | = render(@examples) || render(partial: 'example_repositories/empty')
23 |
--------------------------------------------------------------------------------
/app/views/home/_course_staff_grades.html.haml:
--------------------------------------------------------------------------------
1 |
2 | .container
3 | - @course_scores.each do |scores|
4 | %h4
5 | = scores.course_offering.full_label
6 |
7 | %table#grades-table.table.table-condensed.table-striped{'style' => 'border-collapse: inherit;'}
8 | %thead
9 | %tr
10 | %th Name
11 | - scores.assignment_offerings.each do |offering|
12 | %th= offering.assignment.short_name
13 |
14 | %tbody
15 | - scores.users.each do |user|
16 | %tr
17 | %td.has_gravatar
18 | = gravatar_tag(user, 28)
19 | = user.display_name
20 | - scores.assignment_offerings.each do |offering|
21 | %td
22 | - info = scores.info_for_user_and_assignment_offering(user, offering)
23 | - if info && info[:score]
24 | = link_to percentage(info[:score]), "/code/#{info[:repository_id]}"
25 | - else
26 | –
27 |
--------------------------------------------------------------------------------
/app/views/home/_course_staff_settings.html.haml:
--------------------------------------------------------------------------------
1 | .container
2 | = pythy_form_for @offerings.first.course.organization, @offerings.first.course do |f|
3 |
4 | = f.collection_select :organization_id, 'Organization', Organization.all, :id, :display_name, prompt: '(none)'
5 |
6 | = f.text_field :number do
7 | %span.help-block
8 | The course number prefixed by its departmental abbreviation (for example, "CS 110"). There are no restrictions on the format of this string so different types of organizations can use it differently (for example, "Sandbox" or "Playground" might be appropriate).
9 |
10 | = f.text_field :name, class: 'span6' do
11 | %span.help-block
12 | The full course title (for example, "Introduction to Python").
13 |
14 | = f.collection_select :default_environment_id, 'Default environment', Environment.all, :id, :name, prompt: '(none)'
15 |
16 | = hidden_field_tag :term, @term.id.to_s
17 |
18 | = f.actions do
19 | = f.submit
20 |
--------------------------------------------------------------------------------
/app/views/home/_course_staff_users.html.haml:
--------------------------------------------------------------------------------
1 | .container
2 | %h3 Course Staff and Enrolled Students
3 |
4 | - @offerings.each do |offering|
5 | .btn-header-container.clearfix
6 | %h4.slim.btn-line-height.pull-left
7 | = offering.full_label
8 |
9 | .pull-right.dropdown
10 | = dropdown_button_tag icon_tag('plus') + ' Add users', class: 'btn'
11 | %ul.dropdown-menu
12 | %li
13 | = link_to 'Manually...', new_course_offering_course_enrollment_path(offering), remote: true
14 | %li
15 | = link_to 'Upload a roster...', upload_roster_path(offering), remote: true
16 |
17 | #course-enrollments-table
18 | = render partial: 'course_enrollments/table', locals: { enrollments: Kaminari.paginate_array(offering.course_enrollments).page(params["enrollments_" + offering.id.to_s + "_page"]) }
19 |
--------------------------------------------------------------------------------
/app/views/home/_instructor_assignment.html.haml:
--------------------------------------------------------------------------------
1 | .assignment-tile-wrapper
2 | .assignment-tile.front{ href: assignment_url(instructor_assignment) }
3 | .assignment-short-name><= instructor_assignment.short_name
4 | .assignment-long-name><= instructor_assignment.long_name
5 | .assignment-tile.back
6 | = link_to assignment_path(instructor_assignment, anchor: 'code') do
7 | = icon_tag('laptop')
8 | Code
9 | = link_to instructor_assignment do
10 | = icon_tag('list-ol')
11 | Description
12 | = link_to assignment_path(instructor_assignment, anchor: 'grades') do
13 | = icon_tag('tasks')
14 | Grades
15 | = link_to assignment_path(instructor_assignment, anchor: 'edit') do
16 | = icon_tag('pencil')
17 | Edit
18 |
--------------------------------------------------------------------------------
/app/views/home/_no_assignments.html.haml:
--------------------------------------------------------------------------------
1 | %div.alert.alert-info
2 | The course instructor hasn't made any new assignments available yet.
3 |
--------------------------------------------------------------------------------
/app/views/home/_no_started_assignments.html.haml:
--------------------------------------------------------------------------------
1 | %div.alert.alert-info
2 | You haven't started on any work yet in this course. As you work on
3 | assignments, they will be listed here with the most recent work shown
4 | at the top.
5 |
--------------------------------------------------------------------------------
/app/views/home/_not_found.html.haml:
--------------------------------------------------------------------------------
1 | .row-fluid
2 | .span3.offset1
3 | = image_tag 'snake-cap-300h.png'
4 | .span7.alert.alert-danger
5 | The course you are looking for does not exist.
6 |
--------------------------------------------------------------------------------
/app/views/home/_not_started_assignment.html.haml:
--------------------------------------------------------------------------------
1 | .assignment-tile-wrapper
2 | .assignment-tile.front{ href: assignment_url(not_started_assignment.assignment) }
3 | = assignment_date_tag(not_started_assignment)
4 | .assignment-short-name><= not_started_assignment.assignment.short_name
5 | .assignment-long-name><= not_started_assignment.assignment.long_name
6 | .assignment-tile.back
7 | = link_to code_path(not_started_assignment) do
8 | = icon_tag('laptop')
9 | Code
10 | = link_to not_started_assignment.assignment do
11 | = icon_tag('list-ol')
12 | Description
13 |
--------------------------------------------------------------------------------
/app/views/home/_started_assignment.html.haml:
--------------------------------------------------------------------------------
1 | - repository = started_assignment.repository_for_user(current_user)
2 | - most_recent_check = repository.assignment_checks.most_recent
3 | .assignment-tile-wrapper.student
4 | .assignment-tile.front{ href: assignment_url(started_assignment.assignment) }
5 | = assignment_date_tag(started_assignment)
6 | .assignment-short-name><= started_assignment.assignment.short_name
7 | .assignment-long-name><= started_assignment.assignment.long_name
8 | .assignment-tile.back
9 | = link_to code_path(started_assignment) do
10 | = icon_tag('laptop')
11 | Code
12 | = link_to started_assignment.assignment do
13 | = icon_tag('list-ol')
14 | Description
15 | = score_tile(most_recent_check)
--------------------------------------------------------------------------------
/app/views/home/course.js.coffee:
--------------------------------------------------------------------------------
1 | $('#course_enrollments').html(
2 | '<%= j render(@course_enrollments) %>')
3 | $('#course_enrollments_paginator').html(
4 | '<%= j paginate(@course_enrollments, remote: true).to_s %>')
5 |
--------------------------------------------------------------------------------
/app/views/home/course_staff.html.haml:
--------------------------------------------------------------------------------
1 | .jumbo-title
2 | .container
3 | .row
4 | .span8
5 | %h1.slim
6 | = @course.number
7 | %p.lead
8 | = @course.name
9 |
10 | = render partial: 'flashbar'
11 |
12 | .container
13 | %ul.nav.nav-tabs
14 | = tab_tag 'assignments-tab', icon_tag('laptop') + ' Assignments', active: true
15 | = tab_tag 'users-tab', icon_tag('group') + ' Users'
16 | = tab_tag 'grades-tab', icon_tag('tasks') + ' Grades'
17 | - @offerings.each do |offering|
18 | - if can? :edit, offering
19 | = tab_tag 'settings-tab', icon_tag('cog') + ' Settings'
20 | - break
21 |
22 | .tab-content
23 | #assignments-tab.tab-pane.active
24 | = render partial: 'course_staff_assignments'
25 | #users-tab.tab-pane
26 | = render partial: 'course_staff_users'
27 | #grades-tab.tab-pane
28 | = render partial: 'course_staff_grades'
29 | #settings-tab.tab-pane
30 | = render partial: 'course_staff_settings'
31 | - @offerings.each do |offering|
32 | - if can? :edit, offering
33 | = render partial: 'course_staff_offering_settings', locals: { offering: offering }
34 |
35 |
--------------------------------------------------------------------------------
/app/views/home/load_grades.js.coffee:
--------------------------------------------------------------------------------
1 | $('#grades-tab').html '<%= j render partial: "home/course_staff_grades" %>'
2 |
--------------------------------------------------------------------------------
/app/views/home/refresh_examples.js.coffee:
--------------------------------------------------------------------------------
1 | $('#example_repositories').html(
2 | "<%= j render(@examples) || render(partial: 'example_repositories/empty') %>")
3 |
--------------------------------------------------------------------------------
/app/views/kaminari/_first_page.html.haml:
--------------------------------------------------------------------------------
1 | %li{ class: ('active' if current_page.first?) }
2 | - if current_page.first?
3 | %span= raw(t 'views.pagination.first')
4 | - else
5 | = link_to raw(t 'views.pagination.first'), url, remote: remote
6 |
--------------------------------------------------------------------------------
/app/views/kaminari/_gap.html.haml:
--------------------------------------------------------------------------------
1 | %li
2 | %span= raw(t 'views.pagination.truncate')
3 |
--------------------------------------------------------------------------------
/app/views/kaminari/_last_page.html.haml:
--------------------------------------------------------------------------------
1 | %li{ class: ('active' if current_page.last?) }
2 | - if current_page.last?
3 | %span= raw(t 'views.pagination.last')
4 | - else
5 | = link_to raw(t 'views.pagination.last'), url, remote: remote
6 |
--------------------------------------------------------------------------------
/app/views/kaminari/_next_page.html.haml:
--------------------------------------------------------------------------------
1 | %li{ class: ('active' if current_page.last?) }
2 | - if current_page.last?
3 | %span= raw(t 'views.pagination.next')
4 | - else
5 | = link_to raw(t 'views.pagination.next'), url, rel: 'next', remote: remote
6 |
--------------------------------------------------------------------------------
/app/views/kaminari/_page.html.haml:
--------------------------------------------------------------------------------
1 | %li{ class: ('active' if page.current?) }
2 | - if page.current?
3 | %span= page
4 | - else
5 | = link_to page, url, remote: remote, rel: page.next? ? 'next' : page.prev? ? 'prev' : nil
6 |
--------------------------------------------------------------------------------
/app/views/kaminari/_paginator.html.haml:
--------------------------------------------------------------------------------
1 | = paginator.render do
2 | .pagination
3 | %ul
4 | = first_page_tag
5 | = prev_page_tag
6 | - each_page do |page|
7 | - if page.left_outer? || page.right_outer? || page.inside_window?
8 | = page_tag page
9 | - elsif !page.was_truncated?
10 | = gap_tag
11 | = next_page_tag
12 | = last_page_tag
13 |
--------------------------------------------------------------------------------
/app/views/kaminari/_prev_page.html.haml:
--------------------------------------------------------------------------------
1 | %li{ class: ('active' if current_page.first?) }
2 | - if current_page.first?
3 | %span= raw(t 'views.pagination.previous')
4 | - else
5 | = link_to raw(t 'views.pagination.previous'), url, rel: 'prev', remote: remote
6 |
--------------------------------------------------------------------------------
/app/views/landing/index.html.haml:
--------------------------------------------------------------------------------
1 | = render template: 'sessions/new'
2 |
--------------------------------------------------------------------------------
/app/views/layouts/code.html.haml:
--------------------------------------------------------------------------------
1 | !!!
2 | %html
3 | %head
4 | %title!= content_for?(:title) ? 'Pythy – ' + content_for(:title) : 'Pythy'
5 | %meta{ name: 'viewport', content: 'width=device-width, initial-scale=1.0' }
6 | = stylesheet_link_tag 'application', media: 'all'
7 | = controller_stylesheet_link_tag
8 | = javascript_include_tag 'application'
9 | = google_api_javascript_include_tag
10 | = juggernaut_javascript_include_tag
11 | = controller_javascript_include_tag
12 | = skulpt_javascript_include_tags
13 | = csrf_meta_tags
14 | = favicon_link_tag '/favicon.png', type: 'image/png'
15 | = body_tag do
16 | = render partial: 'navbar'
17 | = render partial: 'flashbar'
18 | = yield
19 |
--------------------------------------------------------------------------------
/app/views/layouts/error.html.haml:
--------------------------------------------------------------------------------
1 | !!!
2 | %html
3 | %head
4 | %title!= 'Pythy – Error'
5 | = stylesheet_link_tag 'application', media: 'all'
6 | = stylesheet_link_tag 'errors', media: 'all'
7 | = javascript_include_tag 'application'
8 | = javascript_include_tag 'errors'
9 | = csrf_meta_tags
10 | = favicon_link_tag '/favicon.png', type: 'image/png'
11 | %body
12 | = render partial: 'navbar'
13 | .container
14 | #main-container-inner
15 | .row
16 | .span10.offset1
17 | .well
18 | = yield
19 |
--------------------------------------------------------------------------------
/app/views/layouts/landing.html.haml:
--------------------------------------------------------------------------------
1 | !!!
2 | %html
3 | %head
4 | %title!= 'Welcome to Pythy'
5 | %meta{ name: 'viewport', content: 'width=device-width, initial-scale=1.0' }
6 | = stylesheet_link_tag 'application', media: 'all'
7 | = controller_stylesheet_link_tag
8 | = javascript_include_tag 'application'
9 | = controller_javascript_include_tag
10 | = csrf_meta_tags
11 | = favicon_link_tag '/favicon.png', type: 'image/png'
12 | %body.landing
13 | .jumbo-title
14 | .container
15 | %h1
16 | Pythy
17 | %small the online Python learning environment
18 | = render partial: 'flashbar'
19 | = yield
20 |
--------------------------------------------------------------------------------
/app/views/layouts/logged_in.html.haml:
--------------------------------------------------------------------------------
1 | !!!
2 | %html
3 | %head
4 | %title!= content_for?(:title) ? 'Pythy – ' + content_for(:title) : 'Pythy'
5 | %meta{ name: 'viewport', content: 'width=device-width, initial-scale=1.0' }
6 | = stylesheet_link_tag 'application', media: 'all'
7 | = controller_stylesheet_link_tag
8 | = javascript_include_tag 'application'
9 | = google_api_javascript_include_tag
10 | = juggernaut_javascript_include_tag
11 | = controller_javascript_include_tag
12 | = csrf_meta_tags
13 | = favicon_link_tag '/favicon.png', type: 'image/png'
14 | = body_tag do
15 | = render partial: 'navbar'
16 | = render partial: 'flashbar'
17 | .container
18 | = yield
19 |
--------------------------------------------------------------------------------
/app/views/layouts/no_container.html.haml:
--------------------------------------------------------------------------------
1 | !!!
2 | %html
3 | %head
4 | %title!= content_for?(:title) ? 'Pythy – ' + content_for(:title) : 'Pythy'
5 | %meta{ name: 'viewport', content: 'width=device-width, initial-scale=1.0' }
6 | = stylesheet_link_tag 'application', media: 'all'
7 | = controller_stylesheet_link_tag
8 | = javascript_include_tag 'application'
9 | = google_api_javascript_include_tag
10 | = juggernaut_javascript_include_tag
11 | = controller_javascript_include_tag
12 | = csrf_meta_tags
13 | = favicon_link_tag '/favicon.png', type: 'image/png'
14 | = body_tag do
15 | = render partial: 'navbar'
16 | = yield
17 |
--------------------------------------------------------------------------------
/app/views/layouts/not_logged_in.html.haml:
--------------------------------------------------------------------------------
1 | !!!
2 | %html
3 | %head
4 | %title!= 'Pythy – Sign In'
5 | = stylesheet_link_tag 'application', media: 'all'
6 | = controller_stylesheet_link_tag
7 | = javascript_include_tag 'application'
8 | = controller_javascript_include_tag
9 | = csrf_meta_tags
10 | = favicon_link_tag '/favicon.png', type: 'image/png'
11 | %body.landing
12 | = render partial: 'flashbar'
13 | .container
14 | = yield
15 |
--------------------------------------------------------------------------------
/app/views/layouts/setup.html.haml:
--------------------------------------------------------------------------------
1 | !!!
2 | %html
3 | %head
4 | %title!= 'Pythy – Initial Setup'
5 | = stylesheet_link_tag 'application', media: 'all'
6 | = controller_stylesheet_link_tag
7 | = javascript_include_tag 'application'
8 | = controller_javascript_include_tag
9 | = csrf_meta_tags
10 | = favicon_link_tag '/favicon.png', type: 'image/png'
11 | %body.setup
12 | .container
13 | = yield
14 |
--------------------------------------------------------------------------------
/app/views/media/_filter_item.html.haml:
--------------------------------------------------------------------------------
1 | %li
2 | %a{ href: '#', data: { type: type } }
3 | %i{ class: "fa fa-#{icon}" }
4 | = icon_tag('chevron-right')
5 | = title
6 |
--------------------------------------------------------------------------------
/app/views/media/_index.html.haml:
--------------------------------------------------------------------------------
1 | #media-drop-zone
2 | .container-fluid
3 | .row-fluid
4 | .span3
5 | %ul.filter-list.nav.nav-list
6 | = render partial: 'filter_item', locals: { icon: 'cloud', title: 'All Media', type: '*/*' }
7 | = render partial: 'filter_item', locals: { icon: 'picture', title: 'Pictures', type: 'image/*' }
8 | = render partial: 'filter_item', locals: { icon: 'music', title: 'Sounds', type: 'audio/*' }
9 | = render partial: 'filter_item', locals: { icon: 'file-alt', title: 'Text', type: 'text/*' }
10 | %p.clearfix
11 | %span.btn.btn-block.btn-success.fileinput-button
12 | = icon_tag('plus')
13 | %span Add files...
14 | %input{ type: 'file', id: 'media-upload', name: 'files[]', multiple: 'multiple', data: { url: @upload_url } }
15 | #media-progress.progress.progress-striped
16 | .bar
17 | .span9
18 | #media-area.media-area
19 |
--------------------------------------------------------------------------------
/app/views/media/_modal.html.haml:
--------------------------------------------------------------------------------
1 | #media_library_modal.modal.modal-wide.hide
2 | .modal-header
3 | = close_button_tag dismiss: 'modal'
4 | %h3
5 | Media Library
6 |
7 | .modal-body
8 | = render partial: 'index'
9 |
10 | .modal-footer
11 | = button_tag 'Close', class: 'btn btn-primary', data: { dismiss: 'modal' }
12 |
--------------------------------------------------------------------------------
/app/views/media/destroy.js.coffee:
--------------------------------------------------------------------------------
1 | window.pythy.mediaLibrary.refreshList()
2 |
--------------------------------------------------------------------------------
/app/views/media/index.html.haml:
--------------------------------------------------------------------------------
1 | = render partial: 'index'
2 |
--------------------------------------------------------------------------------
/app/views/media/index.js.coffee:
--------------------------------------------------------------------------------
1 | # Append the modal to the page body.
2 | $('body').append '<%= j render partial: "media/modal" %>'
3 |
4 | # Ensure that the dialog gets removed from the DOM when it is closed.
5 | $('#media_library_modal').on 'hidden', ->
6 | $('#media_library_modal').remove()
7 |
8 | # Display the dialog.
9 | $('#media_library_modal').modal('show')
10 |
--------------------------------------------------------------------------------
/app/views/organizations/_form.html.haml:
--------------------------------------------------------------------------------
1 | = pythy_form_for @organization do |f|
2 |
3 | = f.text_field :display_name do
4 | %span.help-block
5 | The full displayable name of the organization.
6 |
7 | = f.text_field :abbreviation do
8 | %span.help-block
9 | A short abbreviation that will be used in URLs.
10 |
11 | .controls
12 | .alert.alert-info#url_part
13 |
14 | = f.text_field :domain do
15 | %span.help-inline (Optional)
16 | %span.help-block
17 | The e-mail domain used by members of this organization.
18 | If present, it can be used to restrict courses in an
19 | organization only to users within that domain.
20 |
21 | = f.actions do
22 | = f.submit
23 |
--------------------------------------------------------------------------------
/app/views/organizations/edit.html.haml:
--------------------------------------------------------------------------------
1 |
2 | = render 'form'
3 |
--------------------------------------------------------------------------------
/app/views/organizations/index.html.haml:
--------------------------------------------------------------------------------
1 | .pull-right
2 | = link_to icon_tag('plus') + ' New...', new_organization_path, class: 'btn'
3 |
4 | %table.table.table-striped.table-bordered
5 | %thead
6 | %tr
7 | %th Display Name
8 | %th Domain
9 | %th= icon_tag('cog')
10 | %tbody
11 | - @organizations.each do |organization|
12 | %tr
13 | %td
14 | = link_to organization.display_name, organization
15 | = "(#{organization.abbreviation})"
16 | %td= organization.domain
17 | %td
18 | = link_to icon_tag('pencil'), edit_organization_path(organization)
19 | = link_to_destroy organization
20 |
--------------------------------------------------------------------------------
/app/views/organizations/new.html.haml:
--------------------------------------------------------------------------------
1 |
2 | = render 'form'
3 |
--------------------------------------------------------------------------------
/app/views/organizations/show.html.haml:
--------------------------------------------------------------------------------
1 | .pull-right
2 | = link_to icon_tag('pencil') + ' Edit', edit_organization_path(@organization), class: 'btn'
3 |
4 | %h2
5 | = @organization.display_name
6 | %small= "(#{@organization.domain})"
7 |
8 | -# Table listing the courses belonging to the organization (and allowing
9 | -# them to be modified
10 | %h3
11 | = link_to 'Courses', organization_courses_path(@organization)
12 |
13 | = render partial: 'courses/index', locals: { courses: @organization.courses }
14 | .pull-right
15 | = link_to 'Create a new course...', new_organization_course_path(@organization), class: 'btn btn-success'
16 |
--------------------------------------------------------------------------------
/app/views/registrations/_new.html.haml:
--------------------------------------------------------------------------------
1 | = twitter_bootstrap_form_for(resource, :as => resource_name, :url => registration_path(resource_name), html: { class: 'form-horizontal' }) do |f|
2 |
3 | = f.email_field :email, class: 'input-medium'
4 | = f.password_field :password, class: 'input-medium'
5 | = f.password_field :password_confirmation, class: 'input-medium'
6 | = f.text_field :first_name, class: 'input-medium'
7 | = f.text_field :last_name, class: 'input-medium'
8 |
9 | = f.actions do
10 | = f.submit 'Sign up'
11 |
--------------------------------------------------------------------------------
/app/views/self_enrollment/_course_list.html.haml:
--------------------------------------------------------------------------------
1 | - if courses.any?
2 | - courses.each do |course, offerings|
3 | %h3.slim
4 | = course.number
5 | %small
6 | = course.name
7 | %table.table.table-condensed
8 | %tbody
9 | - offerings.each do |offering|
10 | %tr
11 | %td= link_to_if link_to_offerings, offering.short_label, home_path(offering)
12 | %td= offering.long_label
13 | %td.text-right
14 | - if offering.user_enrolled?(current_user)
15 | %span.muted
16 | - enrollment = offering.course_enrollments.where(user_id: current_user.id).first
17 | = enrollment.course_role.name
18 | - else
19 | = form_tag '/self_enroll/enroll', class: 'form-basic form-inline' do
20 | = hidden_field_tag :course_offering, offering.id
21 | = submit_tag 'Enroll', class: 'btn btn-mini'
22 |
23 | - else
24 | This organization does not have any courses that allow student
25 | self-enrollment at the moment.
26 | Please contact your instructor to be added to your course.
--------------------------------------------------------------------------------
/app/views/self_enrollment/_select_organization.html.haml:
--------------------------------------------------------------------------------
1 | .well.well-small
2 | %p Which school or organization is hosting the course?
3 | - if organizations.any?
4 | = select_tag :organization, options_for_select(organizations), { id: 'self-enroll-organization', prompt: '(select an organization)', data: { width: '100%' } }
5 | - else
6 | %div.alert
7 | There are no registered organizations at the moment.
8 | - if can? :create, Organization
9 | = link_to new_organization_path do
10 | Add a new organization.
11 |
12 | #select-term
13 |
14 | #enroll-course-list
15 |
--------------------------------------------------------------------------------
/app/views/self_enrollment/_select_term.html.haml:
--------------------------------------------------------------------------------
1 | %p What term is the course offered?
2 | - if terms.any?
3 | = select_tag :term, options_for_select(terms), { id: 'self-enroll-term', prompt: '(select a term)', data: { width: '100%' } }
4 | - else
5 | %div.alert
6 | There are no terms to choose from at the moment.
7 | - if can? :create, Term
8 | = link_to new_term_path do
9 | Add a new term.
--------------------------------------------------------------------------------
/app/views/self_enrollment/select_organization.js.coffee:
--------------------------------------------------------------------------------
1 | <% if @organization %>
2 | $('#select-term').html(
3 | "<%= j render partial: 'self_enrollment/select_term', locals: { terms: @term_list } %>")
4 | $('select').selectpicker()
5 | $('#enroll-course-list').html('')
6 | <% else %>
7 | $('#select-term').html('')
8 | $('#enroll-course-list').html('')
9 | <% end %>
10 |
--------------------------------------------------------------------------------
/app/views/self_enrollment/select_term.js.coffee:
--------------------------------------------------------------------------------
1 | <% if @courses %>
2 | $('#enroll-course-list').html(
3 | "<%= j render partial: 'self_enrollment/course_list', locals: { courses: @courses, link_to_offerings: false } %>")
4 | <% else %>
5 | $('#enroll-course-list').html('')
6 | <% end %>
7 |
--------------------------------------------------------------------------------
/app/views/sessions/_sign_in.html.haml:
--------------------------------------------------------------------------------
1 | = twitter_bootstrap_form_for(resource, as: resource_name, url: session_path(resource), html: { class: 'form-horizontal' }) do |f|
2 | %fieldset
3 | = f.email_field :email, class: 'input-medium'
4 | = f.password_field :password, class: 'input-medium' do
5 | %span.help-block
6 | Forgot your password?
7 | = link_to 'Click here to reset it.', new_password_path(resource_name)
8 | = f.label nil do |controls|
9 | = controls.check_box :remember_me, 'Remember me?'
10 | = f.actions do
11 | = f.submit "Sign In"
12 |
--------------------------------------------------------------------------------
/app/views/sessions/new.html.haml:
--------------------------------------------------------------------------------
1 | .container
2 | .row
3 | .span6
4 | %h2.page-header Already have an account?
5 | = render partial: 'sessions/sign_in'
6 | .span6
7 | %h2.page-header New user?
8 | = render partial: 'registrations/new'
9 |
--------------------------------------------------------------------------------
/app/views/sessions/new_initial.html.haml:
--------------------------------------------------------------------------------
1 | %h2 Welcome to Pythy!
2 | %p
3 | This is the first time the application is being started,
4 | so please log-in and your account will be used as the application's
5 | administrator user.
6 |
7 | = twitter_bootstrap_form_for resource, :as => resource_name, :url => session_path(resource_name), :html => { :class => 'form-horizontal' } do |f|
8 | = devise_error_messages!
9 |
10 | = f.text_field :email
11 | = f.password_field :password
12 |
13 | = f.actions do
14 | = f.submit 'Sign in', :class => 'btn btn-primary'
15 |
16 | = link_to "Sign up", new_registration_path(resource_name)
17 |
--------------------------------------------------------------------------------
/app/views/setup/index.html.haml:
--------------------------------------------------------------------------------
1 | .row
2 | .span8.offset2
3 | .well
4 | %h2 Welcome to Pythy!
5 | %p
6 | This is the first time the application is being started,
7 | so please log-in and your account will be used as the application's
8 | administrator user.
9 |
10 | = twitter_bootstrap_form_for resource, :as => resource_name, :url => registration_path(resource_name), :html => { :class => 'form-horizontal' } do |f|
11 | = devise_error_messages!
12 |
13 | = f.email_field :email
14 | = f.password_field :password
15 | = f.password_field :password_confirmation
16 | = f.text_field :first_name
17 | = f.text_field :last_name
18 |
19 | = f.actions do
20 | = f.submit 'Sign in'
21 |
--------------------------------------------------------------------------------
/app/views/system_configurations/_form.html.haml:
--------------------------------------------------------------------------------
1 | = pythy_form_for @system_configuration, url: system_configuration_path do |f|
2 |
3 | = f.text_field :storage_path, class: 'input-xxlarge' do
4 | .help-block
5 | The path on the server where user data files (such as repositories for
6 | saved code) are stored.
7 | %span.text-error
8 | Be careful if you change this after the system has already been in
9 | use.
10 | You will need to move the old storage location to the new one manually.
11 |
12 | = f.text_field :work_path, class: 'input-xxlarge' do
13 | .help-block
14 | The path on the server where user code is copied when it is executed
15 | to check it against the instructor's reference tests. Putting this in
16 | a separate, small partition can help prevent run-away code from
17 | adversely affecting the performance of the rest of the system.
18 |
19 | = f.actions do
20 | = f.submit
21 |
--------------------------------------------------------------------------------
/app/views/system_configurations/edit.html.haml:
--------------------------------------------------------------------------------
1 |
2 | = render 'form'
3 |
--------------------------------------------------------------------------------
/app/views/system_configurations/new.html.haml:
--------------------------------------------------------------------------------
1 |
2 | = render 'form'
3 |
--------------------------------------------------------------------------------
/app/views/system_configurations/show.html.haml:
--------------------------------------------------------------------------------
1 | .pull-right
2 | = link_to icon_tag('pencil') + ' Edit', edit_system_configuration_path(@system_configuration), class: 'btn'
3 |
4 | %table.table.table-bordered.table-striped
5 | %tr
6 | %th Storage path
7 | %td
8 | %tt= @system_configuration.storage_path
9 | %tr
10 | %th Working area
11 | %td
12 | %tt= @system_configuration.work_path
13 |
--------------------------------------------------------------------------------
/app/views/terms/_form.html.haml:
--------------------------------------------------------------------------------
1 | = pythy_form_for @term do |f|
2 |
3 | = f.label 'Season and Year' do |controls|
4 | = controls.select :season, Term::SEASONS, {}, class: 'span2'
5 | = controls.number_field :year, delimiter: '', class: 'span2'
6 |
7 | = f.date_field :starts_on, class: 'span2'
8 |
9 | = f.date_field :ends_on, class: 'span2'
10 |
11 | = f.actions do
12 | = f.submit
13 |
--------------------------------------------------------------------------------
/app/views/terms/edit.html.haml:
--------------------------------------------------------------------------------
1 |
2 | = render 'form'
3 |
--------------------------------------------------------------------------------
/app/views/terms/index.html.haml:
--------------------------------------------------------------------------------
1 | .pull-right
2 | = link_to icon_tag('plus') + ' New...', new_term_path, class: 'btn'
3 |
4 | - if @terms.empty?
5 | %div.alert
6 | You have not yet created any terms.
7 | = link_to new_term_path do
8 | Click here to create one.
9 | - else
10 | %table.table.table-striped.table-bordered
11 | %thead
12 | %tr
13 | %th.span6 Season and Year
14 | %th.span5 Time Period
15 | %th.span1= icon_tag('cog')
16 | %tbody
17 | - @terms.each do |term|
18 | %tr
19 | %td
20 | - if term.contains_now?
21 | %strong
22 | = link_to term.display_name, term
23 | (current)
24 | - else
25 | = link_to term.display_name, term
26 | %td
27 | = l term.starts_on
28 | to
29 | = l term.ends_on
30 | %td
31 | = link_to icon_tag('pencil'), edit_term_path(term)
32 | = link_to_destroy term
33 |
--------------------------------------------------------------------------------
/app/views/terms/new.html.haml:
--------------------------------------------------------------------------------
1 |
2 | = render 'form'
3 |
--------------------------------------------------------------------------------
/app/views/terms/show.html.haml:
--------------------------------------------------------------------------------
1 | .pull-right
2 | = link_to icon_tag('pencil') + ' Edit', edit_term_path(@term), class: 'btn'
3 |
4 | %h2
5 | = @term.display_name
6 | %small= "(#{l @term.starts_on} to #{l @term.ends_on})"
7 |
--------------------------------------------------------------------------------
/app/views/upload_roster/_table.html.haml:
--------------------------------------------------------------------------------
1 | - if @uploaded_roster.valid?
2 | %table#roster-preview.table.table-bordered.table-striped.table-condensed
3 | %thead
4 | %tr
5 | - (0...@uploaded_roster.column_count).each do |index|
6 | %th
7 | = select_tag "columns[#{index}]", options_for_select(UploadedRoster::COLUMNS, @uploaded_roster.column_mapping[index])
8 | %tbody
9 | - @uploaded_roster.preview_rows.each do |row|
10 | %tr
11 | - row.each do |value|
12 | %td= value
13 |
--------------------------------------------------------------------------------
/app/views/upload_roster/index.js.coffee:
--------------------------------------------------------------------------------
1 | # Append the course enrollments dialog to the page body.
2 | $('body').append(
3 | '<%= j render partial: "upload_roster/modal" %>')
4 |
5 | # Ensure that the dialog gets removed from the DOM when it is closed.
6 | $('#upload_roster_modal').on 'hidden', ->
7 | $('#upload_roster_modal').remove()
8 |
9 | $('#upload_roster_modal').on 'shown', ->
10 | $('#upload_roster_modal select').selectpicker()
11 |
12 | $('#upload_roster_modal #roster').change ->
13 | $('#upload_roster_modal #has_csv').val(0)
14 | $(this).closest('form').submit()
15 |
16 | # Display the dialog.
17 | $('#upload_roster_modal').modal 'show'
18 |
--------------------------------------------------------------------------------
/app/views/upload_roster/upload.js.coffee:
--------------------------------------------------------------------------------
1 | <%= remotipart_response do %>
2 | <% if params[:commit] %>
3 | # This submit came from clicking the submit button, so dismiss
4 | # the modal.
5 | $('#upload_roster_modal').modal 'hide'
6 | <% else %>
7 | # This submit came from the file upload control, so update and
8 | # display the preview table.
9 | $('#upload_roster_modal #roster-preview-wrapper').html(
10 | '<%= j render partial: "table" %>')
11 | $('#upload_roster_modal #roster-section2').slideDown()
12 | $('#upload_roster_modal select').selectpicker()
13 | <% end %>
14 | <% end %>
15 |
--------------------------------------------------------------------------------
/app/views/users/_form.html.haml:
--------------------------------------------------------------------------------
1 | = pythy_form_for @user do |f|
2 |
3 | = f.text_field :email
4 | = f.text_field :first_name
5 | = f.text_field :last_name
6 | = f.collection_select :global_role_id , 'Global Role', GlobalRole.all, :id, :name , :prompt => true
7 |
8 | = f.actions do
9 | = f.submit
10 |
--------------------------------------------------------------------------------
/app/views/users/_user.html.haml:
--------------------------------------------------------------------------------
1 | %tr
2 | %td.has_gravatar
3 | = gravatar_tag(user, 28)
4 | = full_name_or_none(user, muted: true, query: true)
5 | %td
6 | = link_to user do
7 | = query_highlight(user.email)
8 | %td= user.global_role.name
9 | %td
10 | %span.dropdown
11 | = link_to icon_tag('cog'), '#', data: { toggle: 'dropdown' }
12 | %ul.dropdown-menu.pull-right
13 | %li= link_to icon_tag('pencil') + ' Edit...', edit_user_path(user)
14 | %li= link_to_destroy user, text: true
15 | %li= link_to icon_tag('user') + ' Impersonate...', impersonate_user_path(user)
16 |
--------------------------------------------------------------------------------
/app/views/users/edit.html.haml:
--------------------------------------------------------------------------------
1 |
2 | = render 'form'
3 |
--------------------------------------------------------------------------------
/app/views/users/index.html.haml:
--------------------------------------------------------------------------------
1 | .row
2 | .pull-right
3 | = index_search_form
4 |
5 | %table.table.table-striped.table-bordered.table-condensed
6 | %thead
7 | %tr
8 | %th.span4 Full Name
9 | %th.span4 E-mail
10 | %th.span3 Role
11 | %th.span1= icon_tag('cog')
12 | %tbody#users
13 | - if @users.empty?
14 | %td{ colspan: 3 }
15 | .alert There are no users.
16 | - else
17 | = render @users
18 |
19 | - unless @users.empty?
20 | #users_paginator
21 | = paginate @users, remote: true
22 |
--------------------------------------------------------------------------------
/app/views/users/index.js.coffee:
--------------------------------------------------------------------------------
1 | $('#users').html(
2 | '<%= escape_javascript render(@users) %>')
3 | $('#users_paginator').html(
4 | '<%= escape_javascript(paginate(@users, remote: true).to_s) %>')
5 |
--------------------------------------------------------------------------------
/app/views/users/new.html.haml:
--------------------------------------------------------------------------------
1 |
2 | = render 'form'
3 |
--------------------------------------------------------------------------------
/app/views/users/show.html.haml:
--------------------------------------------------------------------------------
1 | .pull-right
2 | = link_to icon_tag('pencil') + ' Edit', edit_user_path(@user), class: 'btn'
3 |
4 | .row
5 | .span3
6 | = gravatar_tag(@user, 210)
7 |
8 | .span9
9 | %h2= full_name_or_none(@user)
10 | %table.table
11 | %tbody
12 | %tr
13 | %th E-mail
14 | %td= mail_to @user.email
15 | %tr
16 | %th Global Role
17 | %td= @user.global_role.name
18 |
19 | %h3 Course Enrollments
20 | %table.table
21 | %tbody
22 | - @user.course_enrollments.each do |ce|
23 | %tr
24 | %td
25 | = succeed ':' do
26 | = link_to_if_can :show, ce.course_offering.course do
27 | = ce.course_offering.course.number
28 | = ce.course_offering.course.name
29 | = link_to_if_can :show, ce.course_offering do
30 | = surround '(', ')' do
31 | = ce.course_offering.short_label
32 | %td= ce.course_offering.term.display_name
33 | %td= ce.course_role.name
--------------------------------------------------------------------------------
/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 Pythy::Application
5 |
--------------------------------------------------------------------------------
/config/boot.rb:
--------------------------------------------------------------------------------
1 | require 'rubygems'
2 |
3 | # Set up gems listed in the Gemfile.
4 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__)
5 |
6 | require 'bundler/setup' if File.exists?(ENV['BUNDLE_GEMFILE'])
7 |
--------------------------------------------------------------------------------
/config/deploy/production.rb:
--------------------------------------------------------------------------------
1 | default_run_options[:pty] = true
2 |
3 | set :user, 'pythy'
4 | set :db_user, 'pythy'
5 |
6 | set :branch, 'stable'
7 | set :rails_env, 'production'
8 | set :deploy_to, "/home/#{user}/rails"
9 |
10 | after 'uploads:symlink', 'deploy:symlink_db'
11 |
12 | namespace :deploy do
13 | desc "Symlinks the database.yml"
14 | task :symlink_db, :roles => :app do
15 | run "ln -nfs #{deploy_to}/shared/config/database.yml #{release_path}/config/database.yml"
16 | end
17 | end
18 |
--------------------------------------------------------------------------------
/config/deploy/staging.rb:
--------------------------------------------------------------------------------
1 | default_run_options[:pty] = true
2 |
3 | set :user, 'pythystaging'
4 | set :db_user, 'pythystaging'
5 |
6 | set :branch, 'master'
7 | set :rails_env, 'staging'
8 | set :deploy_to, "/home/#{user}/rails"
9 |
10 | after 'uploads:symlink', 'deploy:symlink_db'
11 |
12 | namespace :deploy do
13 | desc "Symlinks the database.yml"
14 | task :symlink_db, :roles => :app do
15 | run "ln -nfs #{deploy_to}/shared/config/database.yml #{release_path}/config/database.yml"
16 | end
17 | end
18 |
--------------------------------------------------------------------------------
/config/environment.rb:
--------------------------------------------------------------------------------
1 | # Load the rails application
2 | require File.expand_path('../application', __FILE__)
3 | require 'rails_extensions'
4 |
5 | # Generate non-pretty-printed HTML even in development (it's faster, and
6 | # with tools like Firebug and the Webkit inspector, we don't need to look
7 | # directly at the source)
8 | Haml::Template.options[:ugly] = true
9 |
10 | # Initialize the rails application
11 | Pythy::Application.initialize!
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/inflections.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | # We use the word "staff" to refer to users who are teachers or
4 | # graders on a course, so we add the inflection here to make sure
5 | # that singular/plural automated conversions do the right thing
6 | # (we don't want to have to write "staffs").
7 | ActiveSupport::Inflector.inflections do |inflect|
8 | inflect.irregular 'staff', 'staff'
9 | end
10 |
--------------------------------------------------------------------------------
/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 | # Mime::Type.register_alias "text/html", :iphone
6 |
--------------------------------------------------------------------------------
/config/initializers/omniauth.rb:
--------------------------------------------------------------------------------
1 | Rails.application.config.middleware.use OmniAuth::Builder do
2 | provider :facebook, '204740312977274', 'c5315ec75271f0030534cdd27cfaa4a4'
3 | end
4 |
--------------------------------------------------------------------------------
/config/initializers/rabl.rb:
--------------------------------------------------------------------------------
1 | Rabl.configure do |config|
2 | config.include_json_root = false
3 | end
4 |
--------------------------------------------------------------------------------
/config/initializers/redis.rb:
--------------------------------------------------------------------------------
1 | # TODO We may want to allow this to be configured through VERY advanced system
2 | # configuration options.
3 | $raw_redis = Redis.new(host: 'localhost', port: 6379)
4 |
5 | # We want any Redis key access to be properly namespaced by the application
6 | # name, in case we're running multiple apps on the server that access the
7 | # same Redis instance. In addition to that, we include the name of the
8 | # current environment as part of the key prefix, so that doing work under
9 | # development/staging instances does not pollute the production keyspace.
10 | $redis_namespace = "pythy:#{Rails.env}"
11 | $redis = Redis::Namespace.new($redis_namespace, redis: $raw_redis)
12 |
13 | # Configure Sidekiq's background job processor to use the same namespace.
14 | # This must match what is in config/sidekiq.yml.
15 | Sidekiq.configure_server do |config|
16 | config.redis = { namespace: "#{$redis_namespace}:sidekiq" }
17 | end
18 |
19 | Sidekiq.configure_client do |config|
20 | config.redis = { namespace: "#{$redis_namespace}:sidekiq" }
21 | end
22 |
--------------------------------------------------------------------------------
/config/initializers/secret_token.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | # Your secret key for verifying the integrity of signed cookies.
4 | # If you change this key, all old signed cookies will become invalid!
5 | # Make sure the secret is at least 30 characters and all random,
6 | # no regular words or you'll be exposed to dictionary attacks.
7 | Pythy::Application.config.secret_token = 'a0e3c651211d9a2e88b4e51cb20bd2002f75c7e2234d41b44ff1bc8c5382d5958fdaa28b0ecfc622941cc9f3a037904c992bb173637ae08a493019854405be9e'
8 | Pythy::Application.config.secret_key_base = 'xxa0e3c651211d9a2e88b4e51cb20bd2002f75c7e2234d41b44ff1bc8c5382d5958fdaa28b0ecfc622941cc9f3a037904c992bb173637ae08a493019854405be9e'
9 |
--------------------------------------------------------------------------------
/config/initializers/session_store.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | Pythy::Application.config.session_store :cookie_store, :key => '_pythy_session'
4 |
5 | # Use the database for sessions instead of the cookie-based default,
6 | # which shouldn't be used to store highly confidential information
7 | # (create the session table with "rails generate session_migration")
8 | # Pythy::Application.config.session_store :active_record_store
9 |
--------------------------------------------------------------------------------
/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]
9 | end
10 |
11 | # Disable root element in JSON by default.
12 | ActiveSupport.on_load(:active_record) do
13 | self.include_root_in_json = false
14 | end
15 |
--------------------------------------------------------------------------------
/config/locales/en.yml:
--------------------------------------------------------------------------------
1 | # Localizations for US English.
2 |
3 | en:
4 | date:
5 | input:
6 | formats:
7 | - :default
8 | formats:
9 | default: "%m/%d/%Y"
10 | time:
11 | input:
12 | formats:
13 | - :default
14 | formats:
15 | default: "%m/%d/%Y %H:%M"
16 | date_only: "%m/%d/%Y"
17 | time_only: "%H:%M"
18 | am: "am"
19 | pm: "pm"
20 |
21 | activerecord:
22 | attributes:
23 | course_offering:
24 | url: "URL"
25 |
26 | user:
27 | email: 'E-mail address'
28 | password_confirmation: 'Confirm password'
--------------------------------------------------------------------------------
/config/sidekiq.yml:
--------------------------------------------------------------------------------
1 | :verbose: false
2 | :pidfile: ./tmp/pids/sidekiq.pid
3 | :namespace: pythy:<%= ENV['RAILS_ENV'] %>:sidekiq
4 | :concurrency: 25
5 | :queues:
6 | - [default, 5]
7 |
--------------------------------------------------------------------------------
/db/migrate/20120924132009_create_institutions.rb:
--------------------------------------------------------------------------------
1 | class CreateInstitutions < ActiveRecord::Migration
2 |
3 | def change
4 | create_table :institutions do |t|
5 | t.string :domain
6 | t.string :display_name
7 | t.string :abbreviation
8 | t.string :url_part
9 | t.timestamps
10 | end
11 |
12 | add_index :institutions, :abbreviation, unique: true
13 | add_index :institutions, :domain, unique: true
14 | add_index :institutions, :url_part, unique: true
15 | end
16 |
17 | end
18 |
--------------------------------------------------------------------------------
/db/migrate/20120924132121_create_departments.rb:
--------------------------------------------------------------------------------
1 | class CreateDepartments < ActiveRecord::Migration
2 | def change
3 | create_table :departments do |t|
4 | t.integer :institution_id
5 | t.string :name
6 | t.string :abbreviation
7 | t.string :url_part
8 | t.timestamps
9 | end
10 | end
11 | end
12 |
--------------------------------------------------------------------------------
/db/migrate/20120924132144_create_terms.rb:
--------------------------------------------------------------------------------
1 | class CreateTerms < ActiveRecord::Migration
2 | def change
3 | create_table :terms do |t|
4 | t.integer :year
5 | t.integer :season
6 | t.date :starts_on
7 | t.date :ends_on
8 |
9 | t.timestamps
10 | end
11 | end
12 | end
13 |
--------------------------------------------------------------------------------
/db/migrate/20120924132208_create_courses.rb:
--------------------------------------------------------------------------------
1 | class CreateCourses < ActiveRecord::Migration
2 | def change
3 | create_table :courses do |t|
4 | t.string :name
5 | t.string :number
6 | t.integer :department_id
7 |
8 | t.timestamps
9 | end
10 | end
11 | end
12 |
--------------------------------------------------------------------------------
/db/migrate/20120924132630_create_course_offerings.rb:
--------------------------------------------------------------------------------
1 | class CreateCourseOfferings < ActiveRecord::Migration
2 | def change
3 | create_table :course_offerings do |t|
4 | t.integer :course_id
5 | t.integer :term_id
6 | t.integer :crn
7 | t.string :label
8 | t.string :url
9 |
10 | t.timestamps
11 | end
12 | end
13 | end
14 |
--------------------------------------------------------------------------------
/db/migrate/20120924132808_create_assignments.rb:
--------------------------------------------------------------------------------
1 | class CreateAssignments < ActiveRecord::Migration
2 | def change
3 | create_table :assignments do |t|
4 | t.integer :creator_id
5 | t.integer :course_id
6 | t.string :short_name
7 | t.string :long_name
8 | t.text :brief_summary
9 | t.text :description
10 | t.string :url_part
11 |
12 | t.timestamps
13 | end
14 | end
15 | end
16 |
--------------------------------------------------------------------------------
/db/migrate/20120924133015_create_assignment_offerings.rb:
--------------------------------------------------------------------------------
1 | class CreateAssignmentOfferings < ActiveRecord::Migration
2 | def change
3 | create_table :assignment_offerings do |t|
4 | t.integer :assignment_id
5 | t.integer :course_offering_id
6 | t.datetime :opens_at
7 | t.datetime :closes_at
8 | t.datetime :due_at
9 | t.timestamps
10 | end
11 | end
12 | end
13 |
--------------------------------------------------------------------------------
/db/migrate/20120924141027_add_initial_columns_to_users.rb:
--------------------------------------------------------------------------------
1 | class AddInitialColumnsToUsers < ActiveRecord::Migration
2 | def change
3 | add_column :users, :institution_id, :integer
4 | add_column :users, :first_name, :string
5 | add_column :users, :last_name, :string
6 | add_column :users, :global_role_id, :integer
7 | end
8 | end
9 |
--------------------------------------------------------------------------------
/db/migrate/20120927011009_create_rails_admin_histories_table.rb:
--------------------------------------------------------------------------------
1 | class CreateRailsAdminHistoriesTable < ActiveRecord::Migration
2 | def self.up
3 | create_table :rails_admin_histories do |t|
4 | t.text :message # title, name, or object_id
5 | t.string :username
6 | t.integer :item
7 | t.string :table
8 | t.integer :month, :limit => 2
9 | t.integer :year, :limit => 5
10 | t.timestamps
11 | end
12 | add_index(:rails_admin_histories, [:item, :table, :month, :year], :name => 'index_rails_admin_histories' )
13 | end
14 |
15 | def self.down
16 | drop_table :rails_admin_histories
17 | end
18 | end
19 |
--------------------------------------------------------------------------------
/db/migrate/20121114021257_create_global_roles.rb:
--------------------------------------------------------------------------------
1 | class CreateGlobalRoles < ActiveRecord::Migration
2 | def change
3 | create_table :global_roles do |t|
4 | t.string :name, :unique => true, :null => false
5 | t.boolean :can_create_courses, :null => false, :default => false
6 | t.boolean :can_manage_all_courses, :null => false, :default => false
7 | t.boolean :can_edit_system_configuration, :null => false, :default => false
8 | t.boolean :builtin, :null => false, :default => false
9 | end
10 | end
11 | end
12 |
--------------------------------------------------------------------------------
/db/migrate/20121205005020_create_authentications.rb:
--------------------------------------------------------------------------------
1 | class CreateAuthentications < ActiveRecord::Migration
2 | def change
3 | create_table :authentications do |t|
4 | t.integer :user_id
5 | t.string :provider
6 | t.string :uid
7 |
8 | t.timestamps
9 | end
10 | end
11 | end
12 |
--------------------------------------------------------------------------------
/db/migrate/20121206145720_create_repositories.rb:
--------------------------------------------------------------------------------
1 | class CreateRepositories < ActiveRecord::Migration
2 | def change
3 | create_table :repositories do |t|
4 | t.string :type
5 | t.integer :user_id
6 | t.integer :term_id
7 | t.timestamps
8 |
9 | # when type == 'AssignmentRepository'
10 | t.integer :assignment_offering_id
11 |
12 | # when type == 'ExampleRepository'
13 | t.integer :course_offering_id
14 | t.text :description
15 | t.integer :source_repository_id
16 |
17 | # when type == 'PersonalRepository' or 'ExampleRepository'
18 | t.string :name
19 |
20 | # when type == 'AssignmentReferenceRepository'
21 | t.integer :assignment_id
22 |
23 | # when type == 'ScratchpadRepository', no extra columns yet
24 | end
25 | end
26 | end
27 |
--------------------------------------------------------------------------------
/db/migrate/20121212151228_create_course_roles.rb:
--------------------------------------------------------------------------------
1 | class CreateCourseRoles < ActiveRecord::Migration
2 | def change
3 | create_table :course_roles do |t|
4 | t.string :name, :unique => true, :null => false
5 | t.boolean :can_manage_course, :null => false, :default => false
6 | t.boolean :can_manage_assignments, :null => false, :default => false
7 | t.boolean :can_grade_submissions, :null => false, :default => false
8 | t.boolean :can_view_other_submissions, :null => false, :default => false
9 | t.boolean :builtin, :null => false, :default => false
10 | end
11 | end
12 | end
13 |
--------------------------------------------------------------------------------
/db/migrate/20121212161741_create_course_enrollments.rb:
--------------------------------------------------------------------------------
1 | class CreateCourseEnrollments < ActiveRecord::Migration
2 | def change
3 | create_table :course_enrollments do |t|
4 | t.references :user
5 | t.references :course_offering
6 | t.references :course_role
7 | end
8 | add_index :course_enrollments, :user_id
9 | add_index :course_enrollments, :course_offering_id
10 | add_index :course_enrollments, :course_role_id
11 |
12 | # disallow duplicate enrollments
13 | add_index :course_enrollments, [:user_id, :course_offering_id], :unique => true
14 | end
15 | end
16 |
--------------------------------------------------------------------------------
/db/migrate/20121224211905_create_activity_logs.rb:
--------------------------------------------------------------------------------
1 | class CreateActivityLogs < ActiveRecord::Migration
2 |
3 | def change
4 | create_table :activity_logs do |t|
5 | t.integer :user_id
6 | t.string :action
7 | t.text :info
8 | t.timestamps
9 | end
10 | end
11 |
12 | end
13 |
--------------------------------------------------------------------------------
/db/migrate/20130103133018_create_system_configurations.rb:
--------------------------------------------------------------------------------
1 | class CreateSystemConfigurations < ActiveRecord::Migration
2 |
3 | def change
4 | create_table :system_configurations do |t|
5 | t.string :storage_path
6 | t.string :work_path
7 | t.timestamps
8 | end
9 | end
10 |
11 | end
12 |
--------------------------------------------------------------------------------
/db/migrate/20130109175139_create_assignment_checks.rb:
--------------------------------------------------------------------------------
1 | class CreateAssignmentChecks < ActiveRecord::Migration
2 |
3 | def change
4 | create_table :assignment_checks do |t|
5 | t.integer :assignment_repository_id
6 | t.integer :number
7 | t.integer :status
8 | t.decimal :overall_score, precision: 16, scale: 8
9 | t.text :extra
10 | t.timestamps
11 | end
12 | end
13 |
14 | end
15 |
--------------------------------------------------------------------------------
/db/migrate/20130111190807_create_check_outcomes.rb:
--------------------------------------------------------------------------------
1 | class CreateCheckOutcomes < ActiveRecord::Migration
2 |
3 | def change
4 | create_table :check_outcomes do |t|
5 | t.integer :assignment_check_id
6 | t.string :name
7 | t.string :description
8 | t.string :category
9 | t.integer :position
10 | t.decimal :score, precision: 16, scale: 8
11 | t.decimal :possible_score, precision: 16, scale: 8
12 | t.text :detail
13 | t.timestamps
14 | end
15 | end
16 |
17 | end
18 |
--------------------------------------------------------------------------------
/db/migrate/20130518031137_create_media_items.rb:
--------------------------------------------------------------------------------
1 | class CreateMediaItems < ActiveRecord::Migration
2 |
3 | def change
4 | create_table :media_items do |t|
5 | t.integer :user_id
6 | t.integer :assignment_id
7 | t.string :file
8 | t.string :content_type
9 | t.integer :file_size
10 | t.text :info
11 |
12 | t.timestamps
13 | end
14 | end
15 |
16 | end
17 |
--------------------------------------------------------------------------------
/db/migrate/20130529205501_add_resource_key_to_users.rb:
--------------------------------------------------------------------------------
1 | class AddResourceKeyToUsers < ActiveRecord::Migration
2 |
3 | def change
4 | add_column :users, :resource_key, :string
5 | add_index :users, :resource_key
6 | end
7 |
8 | end
9 |
--------------------------------------------------------------------------------
/db/migrate/20130529205532_add_resource_key_to_assignments.rb:
--------------------------------------------------------------------------------
1 | class AddResourceKeyToAssignments < ActiveRecord::Migration
2 |
3 | def change
4 | add_column :assignments, :resource_key, :string
5 | add_index :assignments, :resource_key
6 | end
7 |
8 | end
9 |
--------------------------------------------------------------------------------
/db/migrate/20130615112518_add_commit_sha_to_assignment_checks.rb:
--------------------------------------------------------------------------------
1 | class AddCommitShaToAssignmentChecks < ActiveRecord::Migration
2 |
3 | def change
4 | add_column :assignment_checks, :commit_sha, :string
5 | end
6 |
7 | end
8 |
--------------------------------------------------------------------------------
/db/migrate/20130617144912_add_self_enrollment_allowed_to_course_offerings.rb:
--------------------------------------------------------------------------------
1 | class AddSelfEnrollmentAllowedToCourseOfferings < ActiveRecord::Migration
2 |
3 | def change
4 | add_column :course_offerings, :self_enrollment_allowed, :boolean
5 | end
6 |
7 | end
8 |
--------------------------------------------------------------------------------
/db/migrate/20130617145517_drop_departments_table.rb:
--------------------------------------------------------------------------------
1 | class DropDepartmentsTable < ActiveRecord::Migration
2 |
3 | def up
4 | drop_table :departments
5 | remove_column :courses, :department_id
6 | end
7 |
8 | def down
9 | raise ActiveRecord::IrreversibleMigration
10 | end
11 |
12 | end
13 |
--------------------------------------------------------------------------------
/db/migrate/20130617145542_add_institution_id_to_courses.rb:
--------------------------------------------------------------------------------
1 | class AddInstitutionIdToCourses < ActiveRecord::Migration
2 |
3 | def change
4 | add_column :courses, :institution_id, :integer
5 | add_column :courses, :url_part, :string
6 | end
7 |
8 | end
9 |
--------------------------------------------------------------------------------
/db/migrate/20130617204903_remove_institution_id_from_users.rb:
--------------------------------------------------------------------------------
1 | class RemoveInstitutionIdFromUsers < ActiveRecord::Migration
2 |
3 | def up
4 | remove_column :users, :institution_id
5 | end
6 |
7 | def down
8 | raise ActiveRecord::IrreversibleMigration
9 | end
10 |
11 | end
12 |
--------------------------------------------------------------------------------
/db/migrate/20130617205241_rename_institutions_to_organizations.rb:
--------------------------------------------------------------------------------
1 | class RenameInstitutionsToOrganizations < ActiveRecord::Migration
2 |
3 | def change
4 | rename_table :institutions, :organizations
5 | rename_column :courses, :institution_id, :organization_id
6 | end
7 |
8 | end
9 |
--------------------------------------------------------------------------------
/db/migrate/20130619172521_merge_first_last_name_into_full_name.rb:
--------------------------------------------------------------------------------
1 | class MergeFirstLastNameIntoFullName < ActiveRecord::Migration
2 |
3 | def up
4 | add_column :users, :full_name, :string
5 |
6 | # Before removing the old columns, concatenate the users' first and last
7 | # names into the single full_name column.
8 | execute 'update users set full_name = concat_ws(\' \', first_name, last_name)'
9 |
10 | remove_column :users, :first_name
11 | remove_column :users, :last_name
12 | end
13 |
14 | def down
15 | raise ActiveRecord::IrreversibleMigration
16 | end
17 |
18 | end
19 |
--------------------------------------------------------------------------------
/db/migrate/20130623191637_rename_course_offering_crn_and_label.rb:
--------------------------------------------------------------------------------
1 | class RenameCourseOfferingCrnAndLabel < ActiveRecord::Migration
2 |
3 | def up
4 | rename_column :course_offerings, :crn, :short_label
5 | change_column :course_offerings, :short_label, :string
6 |
7 | rename_column :course_offerings, :label, :long_label
8 | end
9 |
10 | def down
11 | raise ActiveRecord::IrreversibleMigration
12 | end
13 |
14 | end
15 |
--------------------------------------------------------------------------------
/db/migrate/20130625201013_create_environments.rb:
--------------------------------------------------------------------------------
1 | class CreateEnvironments < ActiveRecord::Migration
2 |
3 | def change
4 | create_table :environments do |t|
5 | t.string :name
6 | t.text :preamble
7 | t.timestamps
8 | end
9 | end
10 |
11 | end
12 |
--------------------------------------------------------------------------------
/db/migrate/20130625202204_add_default_environment_id_to_courses.rb:
--------------------------------------------------------------------------------
1 | class AddDefaultEnvironmentIdToCourses < ActiveRecord::Migration
2 |
3 | def change
4 | add_column :courses, :default_environment_id, :integer
5 | end
6 |
7 | end
8 |
--------------------------------------------------------------------------------
/db/migrate/20130625202241_add_environment_id_to_repositories.rb:
--------------------------------------------------------------------------------
1 | class AddEnvironmentIdToRepositories < ActiveRecord::Migration
2 |
3 | def change
4 | add_column :repositories, :environment_id, :integer
5 | end
6 |
7 | end
8 |
--------------------------------------------------------------------------------
/db/migrate/20131014014924_add_term_id_to_assignments.rb:
--------------------------------------------------------------------------------
1 | class AddTermIdToAssignments < ActiveRecord::Migration
2 | def change
3 | add_column :assignments, :term_id, :integer
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/db/migrate/20131119081535_split_full_name_into_first_and_last_name.rb:
--------------------------------------------------------------------------------
1 | class SplitFullNameIntoFirstAndLastName < ActiveRecord::Migration
2 |
3 | def up
4 | add_column :users, :first_name, :string
5 | add_column :users, :last_name, :string
6 |
7 | execute 'update users set last_name = substring_index(full_name, \' \', -1)'
8 | execute 'update users set first_name = left(full_name, length(full_name) - locate(\' \', reverse(full_name)))'
9 |
10 | remove_column :users, :full_name
11 | end
12 |
13 | def down
14 | add_column :users, :full_name, :string
15 |
16 | # Before removing the old columns, concatenate the users' first and last
17 | # names into the single full_name column.
18 | execute 'update users set full_name = concat_ws(\' \', first_name, last_name)'
19 |
20 | remove_column :users, :first_name
21 | remove_column :users, :last_name
22 | end
23 |
24 | end
25 |
--------------------------------------------------------------------------------
/db/migrate/20140116001823_add_current_course_and_current_term_to_users.rb:
--------------------------------------------------------------------------------
1 | class AddCurrentCourseAndCurrentTermToUsers < ActiveRecord::Migration
2 | def change
3 | add_column :users, :current_course_id, :integer
4 | add_column :users, :current_term_id, :integer
5 | end
6 | end
7 |
--------------------------------------------------------------------------------
/doc/README_FOR_APP:
--------------------------------------------------------------------------------
1 | Use this README file to introduce your application and point to useful places in the API for learning more.
2 | Run "rake doc:app" to generate API documentation for your models, controllers, helpers, and libraries.
3 |
--------------------------------------------------------------------------------
/doc/other_features.md:
--------------------------------------------------------------------------------
1 | Other Features
2 | --------------
3 |
4 | 1. Lack of repl and functions like help.
5 | 2. turtle graphics support.
6 |
--------------------------------------------------------------------------------
/erd.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/web-cat/pythy/8dfcfd595e596f4d6f768ea5a86d2396dcbb1258/erd.pdf
--------------------------------------------------------------------------------
/lib/assets/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/web-cat/pythy/8dfcfd595e596f4d6f768ea5a86d2396dcbb1258/lib/assets/.gitkeep
--------------------------------------------------------------------------------
/lib/custom_failure.rb:
--------------------------------------------------------------------------------
1 | class CustomFailure < Devise::FailureApp
2 |
3 | def redirect_url
4 | #return super unless [:worker, :employer, :user].include?(scope)
5 | #make it specific to a scope
6 | needs_initial_setup? ? root_url : super
7 | end
8 |
9 | # You need to override respond to eliminate recall
10 | def respond
11 | http_auth? ? http_auth : redirect
12 | end
13 |
14 | end
15 |
--------------------------------------------------------------------------------
/lib/tasks/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/web-cat/pythy/8dfcfd595e596f4d6f768ea5a86d2396dcbb1258/lib/tasks/.gitkeep
--------------------------------------------------------------------------------
/notes.txt:
--------------------------------------------------------------------------------
1 |
2 | To change the file structure of the reference repositories to the current version:
3 |
4 | - Create an "assignments" folder inside each term.
5 |
6 | - For each Assignment:
7 | - Assign a term_id to the assignment.
8 | - Move the reference repo folder (has the url_part as its name) to inside the corresponding "assignments" folder in the term folder.
9 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Pythy",
3 | "version": "0.1.0",
4 | "description": "An online IDE for novice Python environment",
5 | "dependencies": {
6 | "juggernaut": "2.1.1"
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/public/404.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | The page you were looking for doesn't exist (404)
5 |
17 |
18 |
19 |
20 |
21 |
22 |
The page you were looking for doesn't exist.
23 |
You may have mistyped the address or the page may have moved.
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/public/422.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | The change you wanted was rejected (422)
5 |
17 |
18 |
19 |
20 |
21 |
22 |
The change you wanted was rejected.
23 |
Maybe you tried to change something you didn't have access to.
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/public/500.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | We're sorry, but something went wrong (500)
5 |
17 |
18 |
19 |
20 |
21 |
22 |
We're sorry, but something went wrong.
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/public/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/web-cat/pythy/8dfcfd595e596f4d6f768ea5a86d2396dcbb1258/public/favicon.png
--------------------------------------------------------------------------------
/public/robots.txt:
--------------------------------------------------------------------------------
1 | # See http://www.robotstxt.org/wc/norobots.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 |
--------------------------------------------------------------------------------
/python/.gitignore:
--------------------------------------------------------------------------------
1 | __pycache__
2 |
--------------------------------------------------------------------------------
/python/README.md:
--------------------------------------------------------------------------------
1 | This folder contains Python support code that Pythy uses during
2 | server-side checks.
3 |
--------------------------------------------------------------------------------
/python/image/__init__.py:
--------------------------------------------------------------------------------
1 | """
2 | Pythy server-side image module.
3 | """
4 |
--------------------------------------------------------------------------------
/python/image/fonts/Comic_Sans_MS.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/web-cat/pythy/8dfcfd595e596f4d6f768ea5a86d2396dcbb1258/python/image/fonts/Comic_Sans_MS.ttf
--------------------------------------------------------------------------------
/python/image/fonts/Comic_Sans_MS_Bold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/web-cat/pythy/8dfcfd595e596f4d6f768ea5a86d2396dcbb1258/python/image/fonts/Comic_Sans_MS_Bold.ttf
--------------------------------------------------------------------------------
/python/image/fonts/Comic_Sans_MS_Bold_Italic.ttf:
--------------------------------------------------------------------------------
1 | Comic_Sans_MS_Bold.ttf
--------------------------------------------------------------------------------
/python/image/fonts/Comic_Sans_MS_Italic.ttf:
--------------------------------------------------------------------------------
1 | Comic_Sans_MS.ttf
--------------------------------------------------------------------------------
/python/image/fonts/LiberationMono.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/web-cat/pythy/8dfcfd595e596f4d6f768ea5a86d2396dcbb1258/python/image/fonts/LiberationMono.ttf
--------------------------------------------------------------------------------
/python/image/fonts/LiberationMono_Bold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/web-cat/pythy/8dfcfd595e596f4d6f768ea5a86d2396dcbb1258/python/image/fonts/LiberationMono_Bold.ttf
--------------------------------------------------------------------------------
/python/image/fonts/LiberationMono_Bold_Italic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/web-cat/pythy/8dfcfd595e596f4d6f768ea5a86d2396dcbb1258/python/image/fonts/LiberationMono_Bold_Italic.ttf
--------------------------------------------------------------------------------
/python/image/fonts/LiberationMono_Italic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/web-cat/pythy/8dfcfd595e596f4d6f768ea5a86d2396dcbb1258/python/image/fonts/LiberationMono_Italic.ttf
--------------------------------------------------------------------------------
/python/image/fonts/Times_New_Roman.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/web-cat/pythy/8dfcfd595e596f4d6f768ea5a86d2396dcbb1258/python/image/fonts/Times_New_Roman.ttf
--------------------------------------------------------------------------------
/python/image/fonts/Times_New_Roman_Bold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/web-cat/pythy/8dfcfd595e596f4d6f768ea5a86d2396dcbb1258/python/image/fonts/Times_New_Roman_Bold.ttf
--------------------------------------------------------------------------------
/python/image/fonts/Times_New_Roman_Bold_Italic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/web-cat/pythy/8dfcfd595e596f4d6f768ea5a86d2396dcbb1258/python/image/fonts/Times_New_Roman_Bold_Italic.ttf
--------------------------------------------------------------------------------
/python/image/fonts/Times_New_Roman_Italic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/web-cat/pythy/8dfcfd595e596f4d6f768ea5a86d2396dcbb1258/python/image/fonts/Times_New_Roman_Italic.ttf
--------------------------------------------------------------------------------
/python/image/fonts/Verdana.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/web-cat/pythy/8dfcfd595e596f4d6f768ea5a86d2396dcbb1258/python/image/fonts/Verdana.ttf
--------------------------------------------------------------------------------
/python/image/fonts/Verdana_Bold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/web-cat/pythy/8dfcfd595e596f4d6f768ea5a86d2396dcbb1258/python/image/fonts/Verdana_Bold.ttf
--------------------------------------------------------------------------------
/python/image/fonts/Verdana_Bold_Italic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/web-cat/pythy/8dfcfd595e596f4d6f768ea5a86d2396dcbb1258/python/image/fonts/Verdana_Bold_Italic.ttf
--------------------------------------------------------------------------------
/python/image/fonts/Verdana_Italic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/web-cat/pythy/8dfcfd595e596f4d6f768ea5a86d2396dcbb1258/python/image/fonts/Verdana_Italic.ttf
--------------------------------------------------------------------------------
/python/media/__init__.py:
--------------------------------------------------------------------------------
1 | # Order is important here
2 |
3 | from image.style import *
4 | from image.color import *
5 | from image.pixel import *
6 | from image.picture import *
7 | from image import *
8 | from sound import *
9 | from sound.sample import *
10 | from sound.sound import *
11 |
12 | _picked_files = []
13 |
14 | def setPickedFile(filename): _picked_files.append(filename)
15 |
16 | def pickAFile():
17 | if(len(_picked_files)):
18 | return _picked_files.pop(0)
19 | else:
20 | raise IndexError('Please set atleast one picked file using ' +
21 | 'setPickedFile(filename) before calling this method')
22 |
23 | def setMediaPath(path): pass
24 |
25 | def getMediaPath(filename=''): return filename
26 |
--------------------------------------------------------------------------------
/python/pythy/__init__.py:
--------------------------------------------------------------------------------
1 | """
2 | Pythy server-side support module.
3 |
4 | This module contains core classes used by Pythy when student code is
5 | executed on the server (such as when reference tests are being checked).
6 | """
7 |
8 |
9 | __all__ = ['TestCase', 'TestRunner', 'runAllTests']
10 |
11 | __pythy = True
12 |
13 | from .test import TestCase, TestRunner, runAllTests
14 |
--------------------------------------------------------------------------------
/python/sound/__init__.py:
--------------------------------------------------------------------------------
1 | """
2 | Pythy server-side sound module.
3 | """
4 |
--------------------------------------------------------------------------------
/python/sound/sample.py:
--------------------------------------------------------------------------------
1 | def getSound(sample):
2 | return sample.sound
3 |
4 | def getSampleValue(sample):
5 | return sample.sound.getLeftSample(sample.index)
6 |
7 | def setSampleValue(sample, value):
8 | sample.sound.setLeftSample(sample.index, value)
9 |
10 | class Sample:
11 | def __init__(self, sound, index):
12 | self.sound = sound
13 | self.index = index
14 |
15 | def __str__(self):
16 | return 'Sample at {} with value {}'.format(str(self.index), str(self.getSampleValue()))
17 |
18 | Sample.getSound = getSound
19 | Sample.getSampleValue = getSampleValue
20 | Sample.setSampleValue = setSampleValue
21 |
--------------------------------------------------------------------------------
/python/tests/image/README.md:
--------------------------------------------------------------------------------
1 | Instructions
2 | ------------
3 |
4 | 1. Start a SimpleHTTPServer `python -m SimpleHTTPServer 9000`
5 | 2. Run the tests using ./run.sh
6 |
7 | An http server is need to avoid cross-origin tainting of the canvas/sound when testing.
8 | The source code is referenced through symlinks so that they can be accessed by the http server.
9 |
--------------------------------------------------------------------------------
/python/tests/image/imgs/addArcFilled_10_10_100_50_60_30.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/web-cat/pythy/8dfcfd595e596f4d6f768ea5a86d2396dcbb1258/python/tests/image/imgs/addArcFilled_10_10_100_50_60_30.png
--------------------------------------------------------------------------------
/python/tests/image/imgs/addArcFilled_10_10_100_50_60_30_magenta.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/web-cat/pythy/8dfcfd595e596f4d6f768ea5a86d2396dcbb1258/python/tests/image/imgs/addArcFilled_10_10_100_50_60_30_magenta.png
--------------------------------------------------------------------------------
/python/tests/image/imgs/addArc_10_10_100_50_60_30.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/web-cat/pythy/8dfcfd595e596f4d6f768ea5a86d2396dcbb1258/python/tests/image/imgs/addArc_10_10_100_50_60_30.png
--------------------------------------------------------------------------------
/python/tests/image/imgs/addArc_10_10_100_50_60_30_magenta.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/web-cat/pythy/8dfcfd595e596f4d6f768ea5a86d2396dcbb1258/python/tests/image/imgs/addArc_10_10_100_50_60_30_magenta.png
--------------------------------------------------------------------------------
/python/tests/image/imgs/addLine_10_10_20_20.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/web-cat/pythy/8dfcfd595e596f4d6f768ea5a86d2396dcbb1258/python/tests/image/imgs/addLine_10_10_20_20.png
--------------------------------------------------------------------------------
/python/tests/image/imgs/addLine_10_10_20_20_pink.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/web-cat/pythy/8dfcfd595e596f4d6f768ea5a86d2396dcbb1258/python/tests/image/imgs/addLine_10_10_20_20_pink.png
--------------------------------------------------------------------------------
/python/tests/image/imgs/addOvalFilled_10_10_70_50.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/web-cat/pythy/8dfcfd595e596f4d6f768ea5a86d2396dcbb1258/python/tests/image/imgs/addOvalFilled_10_10_70_50.png
--------------------------------------------------------------------------------
/python/tests/image/imgs/addOvalFilled_10_10_70_50_yellow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/web-cat/pythy/8dfcfd595e596f4d6f768ea5a86d2396dcbb1258/python/tests/image/imgs/addOvalFilled_10_10_70_50_yellow.png
--------------------------------------------------------------------------------
/python/tests/image/imgs/addOval_10_10_70_50.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/web-cat/pythy/8dfcfd595e596f4d6f768ea5a86d2396dcbb1258/python/tests/image/imgs/addOval_10_10_70_50.png
--------------------------------------------------------------------------------
/python/tests/image/imgs/addOval_10_10_70_50_orange.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/web-cat/pythy/8dfcfd595e596f4d6f768ea5a86d2396dcbb1258/python/tests/image/imgs/addOval_10_10_70_50_orange.png
--------------------------------------------------------------------------------
/python/tests/image/imgs/addRectFilled_10_10_70_50.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/web-cat/pythy/8dfcfd595e596f4d6f768ea5a86d2396dcbb1258/python/tests/image/imgs/addRectFilled_10_10_70_50.png
--------------------------------------------------------------------------------
/python/tests/image/imgs/addRectFilled_10_10_70_50_red.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/web-cat/pythy/8dfcfd595e596f4d6f768ea5a86d2396dcbb1258/python/tests/image/imgs/addRectFilled_10_10_70_50_red.png
--------------------------------------------------------------------------------
/python/tests/image/imgs/addRect_10_10_70_50.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/web-cat/pythy/8dfcfd595e596f4d6f768ea5a86d2396dcbb1258/python/tests/image/imgs/addRect_10_10_70_50.png
--------------------------------------------------------------------------------
/python/tests/image/imgs/addRect_10_10_70_50_red.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/web-cat/pythy/8dfcfd595e596f4d6f768ea5a86d2396dcbb1258/python/tests/image/imgs/addRect_10_10_70_50_red.png
--------------------------------------------------------------------------------
/python/tests/image/imgs/addTextWithStyle_10_10_Hello_sansSerif_BOLDITALIC_10.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/web-cat/pythy/8dfcfd595e596f4d6f768ea5a86d2396dcbb1258/python/tests/image/imgs/addTextWithStyle_10_10_Hello_sansSerif_BOLDITALIC_10.png
--------------------------------------------------------------------------------
/python/tests/image/imgs/addTextWithStyle_10_10_Hello_sansSerif_BOLDITALIC_10_green.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/web-cat/pythy/8dfcfd595e596f4d6f768ea5a86d2396dcbb1258/python/tests/image/imgs/addTextWithStyle_10_10_Hello_sansSerif_BOLDITALIC_10_green.png
--------------------------------------------------------------------------------
/python/tests/image/imgs/addText_10_10_Hello.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/web-cat/pythy/8dfcfd595e596f4d6f768ea5a86d2396dcbb1258/python/tests/image/imgs/addText_10_10_Hello.png
--------------------------------------------------------------------------------
/python/tests/image/imgs/addText_10_10_Hello_cyan.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/web-cat/pythy/8dfcfd595e596f4d6f768ea5a86d2396dcbb1258/python/tests/image/imgs/addText_10_10_Hello_cyan.png
--------------------------------------------------------------------------------
/python/tests/image/imgs/copyInto.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/web-cat/pythy/8dfcfd595e596f4d6f768ea5a86d2396dcbb1258/python/tests/image/imgs/copyInto.png
--------------------------------------------------------------------------------
/python/tests/image/imgs/orangePic.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/web-cat/pythy/8dfcfd595e596f4d6f768ea5a86d2396dcbb1258/python/tests/image/imgs/orangePic.png
--------------------------------------------------------------------------------
/python/tests/image/imgs/test.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/web-cat/pythy/8dfcfd595e596f4d6f768ea5a86d2396dcbb1258/python/tests/image/imgs/test.jpg
--------------------------------------------------------------------------------
/python/tests/image/run.sh:
--------------------------------------------------------------------------------
1 | export PYTHONPATH=../..
2 | python3 -m unittest discover . '*_test.py'
3 |
--------------------------------------------------------------------------------
/python/tests/media/README.md:
--------------------------------------------------------------------------------
1 | Instructions
2 | ------------
3 |
4 | 1. Run the tests using ./run.sh
5 |
--------------------------------------------------------------------------------
/python/tests/media/init_test.py:
--------------------------------------------------------------------------------
1 | import unittest
2 | from media import *
3 |
4 | class ImageTest(unittest.TestCase):
5 | def test_pickAFile(self):
6 | with self.assertRaises(IndexError): fileURL = pickAFile()
7 | setPickedFile('http://localhost:9000/imgs/test.jpg')
8 | fileURL = pickAFile()
9 | self.assertEqual('http://localhost:9000/imgs/test.jpg', fileURL)
10 |
11 | def test_setMediaPath(self):
12 | setMediaPath('abc')
13 |
14 | def test_getMediaPath(self):
15 | self.assertEqual(getMediaPath(), '')
16 | self.assertEqual(getMediaPath('filename'), 'filename')
17 |
18 |
--------------------------------------------------------------------------------
/python/tests/media/run.sh:
--------------------------------------------------------------------------------
1 | export PYTHONPATH=../..
2 | python3 -m unittest discover . '*_test.py'
3 |
--------------------------------------------------------------------------------
/python/tests/sound/README.md:
--------------------------------------------------------------------------------
1 | Instructions
2 | ------------
3 |
4 | 1. Start a SimpleHTTPServer `python -m SimpleHTTPServer 9000`
5 | 2. Run the tests using ./run.sh
6 |
7 | An http server is need to avoid cross-origin tainting of the canvas/sound when testing.
8 | The source code is referenced through symlinks so that they can be accessed by the http server.
9 |
--------------------------------------------------------------------------------
/python/tests/sound/run.sh:
--------------------------------------------------------------------------------
1 | export PYTHONPATH=../..
2 | python3 -m unittest discover . '*_test.py'
3 |
--------------------------------------------------------------------------------
/python/tests/sound/sounds/test_mono.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/web-cat/pythy/8dfcfd595e596f4d6f768ea5a86d2396dcbb1258/python/tests/sound/sounds/test_mono.wav
--------------------------------------------------------------------------------
/python/tests/sound/sounds/test_stereo.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/web-cat/pythy/8dfcfd595e596f4d6f768ea5a86d2396dcbb1258/python/tests/sound/sounds/test_stereo.wav
--------------------------------------------------------------------------------
/python/unittest/__main__.py:
--------------------------------------------------------------------------------
1 | """Main entry point"""
2 |
3 | import sys
4 | if sys.argv[0].endswith("__main__.py"):
5 | sys.argv[0] = "python -m unittest"
6 |
7 | __unittest = True
8 |
9 | from .main import main, TestProgram, USAGE_AS_MAIN
10 | TestProgram.USAGE = USAGE_AS_MAIN
11 |
12 | main(module=None)
13 |
--------------------------------------------------------------------------------
/python/unittest/test/__init__.py:
--------------------------------------------------------------------------------
1 | import os
2 | import sys
3 | import unittest
4 |
5 |
6 | here = os.path.dirname(__file__)
7 | loader = unittest.defaultTestLoader
8 |
9 | def suite():
10 | suite = unittest.TestSuite()
11 | for fn in os.listdir(here):
12 | if fn.startswith("test") and fn.endswith(".py"):
13 | modname = "unittest.test." + fn[:-3]
14 | __import__(modname)
15 | module = sys.modules[modname]
16 | suite.addTest(loader.loadTestsFromModule(module))
17 | suite.addTest(loader.loadTestsFromName('unittest.test.testmock'))
18 | return suite
19 |
20 |
21 | if __name__ == "__main__":
22 | unittest.main(defaultTest="suite")
23 |
--------------------------------------------------------------------------------
/python/unittest/test/dummy.py:
--------------------------------------------------------------------------------
1 | # Empty module for testing the loading of modules
2 |
--------------------------------------------------------------------------------
/python/unittest/test/testmock/__init__.py:
--------------------------------------------------------------------------------
1 | import os
2 | import sys
3 | import unittest
4 |
5 |
6 | here = os.path.dirname(__file__)
7 | loader = unittest.defaultTestLoader
8 |
9 | def load_tests(*args):
10 | suite = unittest.TestSuite()
11 | for fn in os.listdir(here):
12 | if fn.startswith("test") and fn.endswith(".py"):
13 | modname = "unittest.test.testmock." + fn[:-3]
14 | __import__(modname)
15 | module = sys.modules[modname]
16 | suite.addTest(loader.loadTestsFromModule(module))
17 | return suite
18 |
--------------------------------------------------------------------------------
/python/unittest/test/testmock/support.py:
--------------------------------------------------------------------------------
1 | import sys
2 |
3 | def is_instance(obj, klass):
4 | """Version of is_instance that doesn't access __class__"""
5 | return issubclass(type(obj), klass)
6 |
7 |
8 | class SomeClass(object):
9 | class_attribute = None
10 |
11 | def wibble(self):
12 | pass
13 |
14 |
15 | class X(object):
16 | pass
17 |
18 |
19 | def examine_warnings(func):
20 | def wrapper():
21 | with catch_warnings(record=True) as ws:
22 | func(ws)
23 | return wrapper
24 |
--------------------------------------------------------------------------------
/python/unittest/test/testmock/testsentinel.py:
--------------------------------------------------------------------------------
1 | import unittest
2 | from unittest.mock import sentinel, DEFAULT
3 |
4 |
5 | class SentinelTest(unittest.TestCase):
6 |
7 | def testSentinels(self):
8 | self.assertEqual(sentinel.whatever, sentinel.whatever,
9 | 'sentinel not stored')
10 | self.assertNotEqual(sentinel.whatever, sentinel.whateverelse,
11 | 'sentinel should be unique')
12 |
13 |
14 | def testSentinelName(self):
15 | self.assertEqual(str(sentinel.whatever), 'sentinel.whatever',
16 | 'sentinel name incorrect')
17 |
18 |
19 | def testDEFAULT(self):
20 | self.assertTrue(DEFAULT is sentinel.DEFAULT)
21 |
22 | def testBases(self):
23 | # If this doesn't raise an AttributeError then help(mock) is broken
24 | self.assertRaises(AttributeError, lambda: sentinel.__bases__)
25 |
26 |
27 | if __name__ == '__main__':
28 | unittest.main()
29 |
--------------------------------------------------------------------------------
/script/rails:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | # This command will automatically be run when you run "rails" with Rails 3 gems installed from the root of your application.
3 |
4 | APP_PATH = File.expand_path('../../config/application', __FILE__)
5 | require File.expand_path('../../config/boot', __FILE__)
6 | require 'rails/commands'
7 |
--------------------------------------------------------------------------------
/spec/factories/activity_log_factory.rb:
--------------------------------------------------------------------------------
1 | FactoryGirl.define do
2 | factory :activity_log1, class: ActivityLog do
3 | user
4 | action "Test Log1"
5 | info location: "Factory", type: "Test"
6 | end
7 | factory :activity_log2, class: ActivityLog do
8 | user
9 | action "Test Log2"
10 | info location: "Factory", type: "Test"
11 | end
12 | end
13 |
--------------------------------------------------------------------------------
/spec/factories/course_factory.rb:
--------------------------------------------------------------------------------
1 | FactoryGirl.define do
2 | factory :course, class: Course do
3 | name "Introduction to Media Computation"
4 | number "CS 1124"
5 | default_environment_id Environment.first.id
6 | organization
7 | end
8 | end
9 |
--------------------------------------------------------------------------------
/spec/factories/course_role_factory.rb:
--------------------------------------------------------------------------------
1 | FactoryGirl.define do
2 | factory :course_role, class: CourseRole do
3 | name "Teaching Assistant"
4 | builtin false
5 | end
6 | end
7 |
--------------------------------------------------------------------------------
/spec/factories/environment_factory.rb:
--------------------------------------------------------------------------------
1 | FactoryGirl.define do
2 | factory :environment, class: Environment do
3 | name "Python v3.0"
4 | preamble "Sample code goes in here"
5 | end
6 | end
7 |
--------------------------------------------------------------------------------
/spec/factories/global_role_factory.rb:
--------------------------------------------------------------------------------
1 | FactoryGirl.define do
2 | factory :global_role, class: GlobalRole do
3 | name "Teaching Assistant"
4 | builtin false
5 | end
6 | end
7 |
--------------------------------------------------------------------------------
/spec/factories/organization_factory.rb:
--------------------------------------------------------------------------------
1 | FactoryGirl.define do
2 | factory :organization, class: Organization do
3 | display_name "Virginia Tech"
4 | domain "vt.edu"
5 | abbreviation "VT"
6 | end
7 | end
8 |
--------------------------------------------------------------------------------
/spec/factories/system_configuration_factory.rb:
--------------------------------------------------------------------------------
1 | FactoryGirl.define do
2 | factory :sys_config, class: SystemConfiguration do
3 | storage_path Rails.root.join('spec', 'test_storage_path').to_s
4 | work_path Rails.root.join('spec', 'test_work_path').to_s
5 | end
6 | end
7 |
--------------------------------------------------------------------------------
/spec/factories/term_factory.rb:
--------------------------------------------------------------------------------
1 | FactoryGirl.define do
2 | factory :summer1_term, class: Term do
3 | starts_on Date.new(2012, 5, 28)
4 | ends_on Date.new(2012, 7, 1)
5 | season Term::SEASONS['Summer I']
6 | year 2012
7 | end
8 | factory :spring_term, class: Term do
9 | starts_on Date.new(2012, 1, 28)
10 | ends_on Date.new(2012, 5, 10)
11 | season Term::SEASONS['Spring']
12 | year 2012
13 | end
14 | factory :summer2_term, class: Term do
15 | starts_on Date.new(2012, 7, 1)
16 | ends_on Date.new(2012, 8, 10)
17 | season Term::SEASONS['Summer II']
18 | year 2012
19 | end
20 | factory :fall_term, class: Term do
21 | starts_on Date.new(2012, 8, 23)
22 | ends_on Date.new(2012, 12, 10)
23 | season Term::SEASONS['Fall']
24 | year 2012
25 | end
26 | factory :winter_term, class: Term do
27 | starts_on Date.new(2012, 12, 15)
28 | ends_on Date.new(2013, 1, 20)
29 | season Term::SEASONS['Winter']
30 | year 2012
31 | end
32 | end
33 |
--------------------------------------------------------------------------------
/spec/javascripts/README.md:
--------------------------------------------------------------------------------
1 | Instructions
2 | ------------
3 |
4 | 1. Start a SimpleHTTPServer `python -m SimpleHTTPServer 9000`
5 | 2. Visit the url `http://127.0.0.1:9000/`
6 |
7 | An http server is need to avoid cross-origin tainting of the canvas/sound when testing.
8 | The source code is referenced through symlinks so that they can be accessed by the http server.
9 |
--------------------------------------------------------------------------------
/spec/javascripts/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Pythy Sound API tests
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/spec/javascripts/sounds/test_mono.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/web-cat/pythy/8dfcfd595e596f4d6f768ea5a86d2396dcbb1258/spec/javascripts/sounds/test_mono.wav
--------------------------------------------------------------------------------
/spec/javascripts/sounds/test_stereo.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/web-cat/pythy/8dfcfd595e596f4d6f768ea5a86d2396dcbb1258/spec/javascripts/sounds/test_stereo.wav
--------------------------------------------------------------------------------
/spec/javascripts/src/sound.js.coffee:
--------------------------------------------------------------------------------
1 | ../../../app/assets/javascripts/sound.js.coffee
--------------------------------------------------------------------------------
/spec/javascripts/stubs/pythy_stubs.js:
--------------------------------------------------------------------------------
1 | window.pythy = {
2 | uploadFileFromBlob: function () {}
3 | };
4 | window.mediaffi = {
5 | customizeMediaURL: function (url) { return url; }
6 | };
7 | window.CodeController = {
8 | transformUrl : function (url) { return url; }
9 | };
10 |
--------------------------------------------------------------------------------
/spec/models/coverage/.last_run.json:
--------------------------------------------------------------------------------
1 | {
2 | "result": {
3 | "covered_percent": 0.0
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/spec/models/coverage/.resultset.json:
--------------------------------------------------------------------------------
1 | {
2 | "RSpec": {
3 | "coverage": {
4 | },
5 | "timestamp": 1395849858
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/spec/models/coverage/assets/0.7.1/fancybox/blank.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/web-cat/pythy/8dfcfd595e596f4d6f768ea5a86d2396dcbb1258/spec/models/coverage/assets/0.7.1/fancybox/blank.gif
--------------------------------------------------------------------------------
/spec/models/coverage/assets/0.7.1/fancybox/fancy_close.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/web-cat/pythy/8dfcfd595e596f4d6f768ea5a86d2396dcbb1258/spec/models/coverage/assets/0.7.1/fancybox/fancy_close.png
--------------------------------------------------------------------------------
/spec/models/coverage/assets/0.7.1/fancybox/fancy_loading.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/web-cat/pythy/8dfcfd595e596f4d6f768ea5a86d2396dcbb1258/spec/models/coverage/assets/0.7.1/fancybox/fancy_loading.png
--------------------------------------------------------------------------------
/spec/models/coverage/assets/0.7.1/fancybox/fancy_nav_left.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/web-cat/pythy/8dfcfd595e596f4d6f768ea5a86d2396dcbb1258/spec/models/coverage/assets/0.7.1/fancybox/fancy_nav_left.png
--------------------------------------------------------------------------------
/spec/models/coverage/assets/0.7.1/fancybox/fancy_nav_right.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/web-cat/pythy/8dfcfd595e596f4d6f768ea5a86d2396dcbb1258/spec/models/coverage/assets/0.7.1/fancybox/fancy_nav_right.png
--------------------------------------------------------------------------------
/spec/models/coverage/assets/0.7.1/fancybox/fancy_shadow_e.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/web-cat/pythy/8dfcfd595e596f4d6f768ea5a86d2396dcbb1258/spec/models/coverage/assets/0.7.1/fancybox/fancy_shadow_e.png
--------------------------------------------------------------------------------
/spec/models/coverage/assets/0.7.1/fancybox/fancy_shadow_n.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/web-cat/pythy/8dfcfd595e596f4d6f768ea5a86d2396dcbb1258/spec/models/coverage/assets/0.7.1/fancybox/fancy_shadow_n.png
--------------------------------------------------------------------------------
/spec/models/coverage/assets/0.7.1/fancybox/fancy_shadow_ne.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/web-cat/pythy/8dfcfd595e596f4d6f768ea5a86d2396dcbb1258/spec/models/coverage/assets/0.7.1/fancybox/fancy_shadow_ne.png
--------------------------------------------------------------------------------
/spec/models/coverage/assets/0.7.1/fancybox/fancy_shadow_nw.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/web-cat/pythy/8dfcfd595e596f4d6f768ea5a86d2396dcbb1258/spec/models/coverage/assets/0.7.1/fancybox/fancy_shadow_nw.png
--------------------------------------------------------------------------------
/spec/models/coverage/assets/0.7.1/fancybox/fancy_shadow_s.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/web-cat/pythy/8dfcfd595e596f4d6f768ea5a86d2396dcbb1258/spec/models/coverage/assets/0.7.1/fancybox/fancy_shadow_s.png
--------------------------------------------------------------------------------
/spec/models/coverage/assets/0.7.1/fancybox/fancy_shadow_se.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/web-cat/pythy/8dfcfd595e596f4d6f768ea5a86d2396dcbb1258/spec/models/coverage/assets/0.7.1/fancybox/fancy_shadow_se.png
--------------------------------------------------------------------------------
/spec/models/coverage/assets/0.7.1/fancybox/fancy_shadow_sw.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/web-cat/pythy/8dfcfd595e596f4d6f768ea5a86d2396dcbb1258/spec/models/coverage/assets/0.7.1/fancybox/fancy_shadow_sw.png
--------------------------------------------------------------------------------
/spec/models/coverage/assets/0.7.1/fancybox/fancy_shadow_w.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/web-cat/pythy/8dfcfd595e596f4d6f768ea5a86d2396dcbb1258/spec/models/coverage/assets/0.7.1/fancybox/fancy_shadow_w.png
--------------------------------------------------------------------------------
/spec/models/coverage/assets/0.7.1/fancybox/fancy_title_left.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/web-cat/pythy/8dfcfd595e596f4d6f768ea5a86d2396dcbb1258/spec/models/coverage/assets/0.7.1/fancybox/fancy_title_left.png
--------------------------------------------------------------------------------
/spec/models/coverage/assets/0.7.1/fancybox/fancy_title_main.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/web-cat/pythy/8dfcfd595e596f4d6f768ea5a86d2396dcbb1258/spec/models/coverage/assets/0.7.1/fancybox/fancy_title_main.png
--------------------------------------------------------------------------------
/spec/models/coverage/assets/0.7.1/fancybox/fancy_title_over.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/web-cat/pythy/8dfcfd595e596f4d6f768ea5a86d2396dcbb1258/spec/models/coverage/assets/0.7.1/fancybox/fancy_title_over.png
--------------------------------------------------------------------------------
/spec/models/coverage/assets/0.7.1/fancybox/fancy_title_right.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/web-cat/pythy/8dfcfd595e596f4d6f768ea5a86d2396dcbb1258/spec/models/coverage/assets/0.7.1/fancybox/fancy_title_right.png
--------------------------------------------------------------------------------
/spec/models/coverage/assets/0.7.1/fancybox/fancybox-x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/web-cat/pythy/8dfcfd595e596f4d6f768ea5a86d2396dcbb1258/spec/models/coverage/assets/0.7.1/fancybox/fancybox-x.png
--------------------------------------------------------------------------------
/spec/models/coverage/assets/0.7.1/fancybox/fancybox-y.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/web-cat/pythy/8dfcfd595e596f4d6f768ea5a86d2396dcbb1258/spec/models/coverage/assets/0.7.1/fancybox/fancybox-y.png
--------------------------------------------------------------------------------
/spec/models/coverage/assets/0.7.1/fancybox/fancybox.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/web-cat/pythy/8dfcfd595e596f4d6f768ea5a86d2396dcbb1258/spec/models/coverage/assets/0.7.1/fancybox/fancybox.png
--------------------------------------------------------------------------------
/spec/models/coverage/assets/0.7.1/favicon_green.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/web-cat/pythy/8dfcfd595e596f4d6f768ea5a86d2396dcbb1258/spec/models/coverage/assets/0.7.1/favicon_green.png
--------------------------------------------------------------------------------
/spec/models/coverage/assets/0.7.1/favicon_red.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/web-cat/pythy/8dfcfd595e596f4d6f768ea5a86d2396dcbb1258/spec/models/coverage/assets/0.7.1/favicon_red.png
--------------------------------------------------------------------------------
/spec/models/coverage/assets/0.7.1/favicon_yellow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/web-cat/pythy/8dfcfd595e596f4d6f768ea5a86d2396dcbb1258/spec/models/coverage/assets/0.7.1/favicon_yellow.png
--------------------------------------------------------------------------------
/spec/models/coverage/assets/0.7.1/loading.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/web-cat/pythy/8dfcfd595e596f4d6f768ea5a86d2396dcbb1258/spec/models/coverage/assets/0.7.1/loading.gif
--------------------------------------------------------------------------------
/spec/models/coverage/assets/0.7.1/magnify.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/web-cat/pythy/8dfcfd595e596f4d6f768ea5a86d2396dcbb1258/spec/models/coverage/assets/0.7.1/magnify.png
--------------------------------------------------------------------------------
/spec/models/coverage/assets/0.7.1/smoothness/images/ui-bg_flat_0_aaaaaa_40x100.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/web-cat/pythy/8dfcfd595e596f4d6f768ea5a86d2396dcbb1258/spec/models/coverage/assets/0.7.1/smoothness/images/ui-bg_flat_0_aaaaaa_40x100.png
--------------------------------------------------------------------------------
/spec/models/coverage/assets/0.7.1/smoothness/images/ui-bg_flat_75_ffffff_40x100.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/web-cat/pythy/8dfcfd595e596f4d6f768ea5a86d2396dcbb1258/spec/models/coverage/assets/0.7.1/smoothness/images/ui-bg_flat_75_ffffff_40x100.png
--------------------------------------------------------------------------------
/spec/models/coverage/assets/0.7.1/smoothness/images/ui-bg_glass_55_fbf9ee_1x400.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/web-cat/pythy/8dfcfd595e596f4d6f768ea5a86d2396dcbb1258/spec/models/coverage/assets/0.7.1/smoothness/images/ui-bg_glass_55_fbf9ee_1x400.png
--------------------------------------------------------------------------------
/spec/models/coverage/assets/0.7.1/smoothness/images/ui-bg_glass_65_ffffff_1x400.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/web-cat/pythy/8dfcfd595e596f4d6f768ea5a86d2396dcbb1258/spec/models/coverage/assets/0.7.1/smoothness/images/ui-bg_glass_65_ffffff_1x400.png
--------------------------------------------------------------------------------
/spec/models/coverage/assets/0.7.1/smoothness/images/ui-bg_glass_75_dadada_1x400.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/web-cat/pythy/8dfcfd595e596f4d6f768ea5a86d2396dcbb1258/spec/models/coverage/assets/0.7.1/smoothness/images/ui-bg_glass_75_dadada_1x400.png
--------------------------------------------------------------------------------
/spec/models/coverage/assets/0.7.1/smoothness/images/ui-bg_glass_75_e6e6e6_1x400.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/web-cat/pythy/8dfcfd595e596f4d6f768ea5a86d2396dcbb1258/spec/models/coverage/assets/0.7.1/smoothness/images/ui-bg_glass_75_e6e6e6_1x400.png
--------------------------------------------------------------------------------
/spec/models/coverage/assets/0.7.1/smoothness/images/ui-bg_glass_95_fef1ec_1x400.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/web-cat/pythy/8dfcfd595e596f4d6f768ea5a86d2396dcbb1258/spec/models/coverage/assets/0.7.1/smoothness/images/ui-bg_glass_95_fef1ec_1x400.png
--------------------------------------------------------------------------------
/spec/models/coverage/assets/0.7.1/smoothness/images/ui-bg_highlight-soft_75_cccccc_1x100.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/web-cat/pythy/8dfcfd595e596f4d6f768ea5a86d2396dcbb1258/spec/models/coverage/assets/0.7.1/smoothness/images/ui-bg_highlight-soft_75_cccccc_1x100.png
--------------------------------------------------------------------------------
/spec/models/coverage/assets/0.7.1/smoothness/images/ui-icons_222222_256x240.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/web-cat/pythy/8dfcfd595e596f4d6f768ea5a86d2396dcbb1258/spec/models/coverage/assets/0.7.1/smoothness/images/ui-icons_222222_256x240.png
--------------------------------------------------------------------------------
/spec/models/coverage/assets/0.7.1/smoothness/images/ui-icons_2e83ff_256x240.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/web-cat/pythy/8dfcfd595e596f4d6f768ea5a86d2396dcbb1258/spec/models/coverage/assets/0.7.1/smoothness/images/ui-icons_2e83ff_256x240.png
--------------------------------------------------------------------------------
/spec/models/coverage/assets/0.7.1/smoothness/images/ui-icons_454545_256x240.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/web-cat/pythy/8dfcfd595e596f4d6f768ea5a86d2396dcbb1258/spec/models/coverage/assets/0.7.1/smoothness/images/ui-icons_454545_256x240.png
--------------------------------------------------------------------------------
/spec/models/coverage/assets/0.7.1/smoothness/images/ui-icons_888888_256x240.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/web-cat/pythy/8dfcfd595e596f4d6f768ea5a86d2396dcbb1258/spec/models/coverage/assets/0.7.1/smoothness/images/ui-icons_888888_256x240.png
--------------------------------------------------------------------------------
/spec/models/coverage/assets/0.7.1/smoothness/images/ui-icons_cd0a0a_256x240.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/web-cat/pythy/8dfcfd595e596f4d6f768ea5a86d2396dcbb1258/spec/models/coverage/assets/0.7.1/smoothness/images/ui-icons_cd0a0a_256x240.png
--------------------------------------------------------------------------------
/spec/models/environment_spec.rb:
--------------------------------------------------------------------------------
1 | require 'spec_helper'
2 |
3 | describe Environment do
4 | let(:environment) { FactoryGirl.build(:environment) }
5 |
6 | subject { environment }
7 |
8 | # Attribute testing
9 | it { should respond_to(:name) }
10 | it { should respond_to(:preamble) }
11 |
12 | # Association testing
13 | it { should have_many(:courses).with_foreign_key('default_environment_id') }
14 | it { should have_many(:repositories) }
15 |
16 | # Validation testing
17 | it { should be_valid }
18 |
19 | describe "when name is not present" do
20 | before { environment.name = '' }
21 |
22 | it { should be_invalid }
23 | end
24 |
25 | end
26 |
--------------------------------------------------------------------------------
/spec/models/system_configuration_spec.rb:
--------------------------------------------------------------------------------
1 | require 'spec_helper'
2 |
3 | describe SystemConfiguration do
4 | let(:sys_config) { FactoryGirl.build(:sys_config) }
5 | subject { sys_config }
6 |
7 | it { should be_valid }
8 | it { should respond_to(:storage_path) }
9 | it { should respond_to(:work_path) }
10 |
11 | describe "when storage_path is empty" do
12 | before { sys_config.storage_path = ''}
13 | it { should_not be_valid }
14 | end
15 |
16 | describe "when work_path is empty" do
17 | before { sys_config.work_path = ''}
18 | it { should_not be_valid }
19 | end
20 |
21 | describe "when the rails server doesn't have permission
22 | to write to the storage_path" do
23 | before { sys_config.storage_path = '/' }
24 | it { should_not be_valid }
25 | end
26 |
27 | describe "when the rails server doesn't have permission
28 | to write to the work_path" do
29 | before { sys_config.work_path = '/' }
30 | it { should_not be_valid }
31 | end
32 |
33 | end
34 |
--------------------------------------------------------------------------------
/vendor/assets/javascripts/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/web-cat/pythy/8dfcfd595e596f4d6f768ea5a86d2396dcbb1258/vendor/assets/javascripts/.gitkeep
--------------------------------------------------------------------------------
/vendor/assets/stylesheets/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/web-cat/pythy/8dfcfd595e596f4d6f768ea5a86d2396dcbb1258/vendor/assets/stylesheets/.gitkeep
--------------------------------------------------------------------------------
/vendor/assets/stylesheets/twitter/bootstrap/accordion.less:
--------------------------------------------------------------------------------
1 | //
2 | // Accordion
3 | // --------------------------------------------------
4 |
5 |
6 | // Parent container
7 | .accordion {
8 | margin-bottom: @baseLineHeight;
9 | }
10 |
11 | // Group == heading + body
12 | .accordion-group {
13 | margin-bottom: 2px;
14 | border: 1px solid #e5e5e5;
15 | .border-radius(@baseBorderRadius);
16 | }
17 | .accordion-heading {
18 | border-bottom: 0;
19 | }
20 | .accordion-heading .accordion-toggle {
21 | display: block;
22 | padding: 8px 15px;
23 | }
24 |
25 | // General toggle styles
26 | .accordion-toggle {
27 | cursor: pointer;
28 | }
29 |
30 | // Inner needs the styles because you can't animate properly with any styles on the element
31 | .accordion-inner {
32 | padding: 9px 15px;
33 | border-top: 1px solid #e5e5e5;
34 | }
35 |
--------------------------------------------------------------------------------
/vendor/assets/stylesheets/twitter/bootstrap/breadcrumbs.less:
--------------------------------------------------------------------------------
1 | //
2 | // Breadcrumbs
3 | // --------------------------------------------------
4 |
5 |
6 | .breadcrumb {
7 | padding: 8px 15px;
8 | margin: 0 0 @baseLineHeight;
9 | list-style: none;
10 | background-color: #f5f5f5;
11 | .border-radius(@baseBorderRadius);
12 | > li {
13 | display: inline-block;
14 | .ie7-inline-block();
15 | text-shadow: 0 1px 0 @white;
16 | > .divider {
17 | padding: 0 5px;
18 | color: #ccc;
19 | }
20 | }
21 | > .active {
22 | color: @grayLight;
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/vendor/assets/stylesheets/twitter/bootstrap/close.less:
--------------------------------------------------------------------------------
1 | //
2 | // Close icons
3 | // --------------------------------------------------
4 |
5 |
6 | .close {
7 | float: right;
8 | font-size: 20px;
9 | font-weight: bold;
10 | line-height: @baseLineHeight;
11 | color: @black;
12 | text-shadow: 0 1px 0 rgba(255,255,255,1);
13 | .opacity(20);
14 | &:hover {
15 | color: @black;
16 | text-decoration: none;
17 | cursor: pointer;
18 | .opacity(40);
19 | }
20 | }
21 |
22 | // Additional properties for button version
23 | // iOS requires the button element instead of an anchor tag.
24 | // If you want the anchor version, it requires `href="#"`.
25 | button.close {
26 | padding: 0;
27 | cursor: pointer;
28 | background: transparent;
29 | border: 0;
30 | -webkit-appearance: none;
31 | }
--------------------------------------------------------------------------------
/vendor/assets/stylesheets/twitter/bootstrap/component-animations.less:
--------------------------------------------------------------------------------
1 | //
2 | // Component animations
3 | // --------------------------------------------------
4 |
5 |
6 | .fade {
7 | opacity: 0;
8 | .transition(opacity .15s linear);
9 | &.in {
10 | opacity: 1;
11 | }
12 | }
13 |
14 | .collapse {
15 | position: relative;
16 | height: 0;
17 | overflow: hidden;
18 | .transition(height .35s ease);
19 | &.in {
20 | height: auto;
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/vendor/assets/stylesheets/twitter/bootstrap/grid.less:
--------------------------------------------------------------------------------
1 | //
2 | // Grid system
3 | // --------------------------------------------------
4 |
5 |
6 | // Fixed (940px)
7 | #grid > .core(@gridColumnWidth, @gridGutterWidth);
8 |
9 | // Fluid (940px)
10 | #grid > .fluid(@fluidGridColumnWidth, @fluidGridGutterWidth);
11 |
12 | // Reset utility classes due to specificity
13 | [class*="span"].hide,
14 | .row-fluid [class*="span"].hide {
15 | display: none;
16 | }
17 |
18 | [class*="span"].pull-right,
19 | .row-fluid [class*="span"].pull-right {
20 | float: right;
21 | }
22 |
--------------------------------------------------------------------------------
/vendor/assets/stylesheets/twitter/bootstrap/hero-unit.less:
--------------------------------------------------------------------------------
1 | //
2 | // Hero unit
3 | // --------------------------------------------------
4 |
5 |
6 | .hero-unit {
7 | padding: 60px;
8 | margin-bottom: 30px;
9 | font-size: 18px;
10 | font-weight: 200;
11 | line-height: @baseLineHeight * 1.5;
12 | color: @heroUnitLeadColor;
13 | background-color: @heroUnitBackground;
14 | .border-radius(6px);
15 | h1 {
16 | margin-bottom: 0;
17 | font-size: 60px;
18 | line-height: 1;
19 | color: @heroUnitHeadingColor;
20 | letter-spacing: -1px;
21 | }
22 | li {
23 | line-height: @baseLineHeight * 1.5; // Reset since we specify in type.less
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/vendor/assets/stylesheets/twitter/bootstrap/layouts.less:
--------------------------------------------------------------------------------
1 | //
2 | // Layouts
3 | // --------------------------------------------------
4 |
5 |
6 | // Container (centered, fixed-width layouts)
7 | .container {
8 | .container-fixed();
9 | }
10 |
11 | // Fluid layouts (left aligned, with sidebar, min- & max-width content)
12 | .container-fluid {
13 | padding-right: @gridGutterWidth;
14 | padding-left: @gridGutterWidth;
15 | .clearfix();
16 | }
--------------------------------------------------------------------------------
/vendor/assets/stylesheets/twitter/bootstrap/media.less:
--------------------------------------------------------------------------------
1 | // Media objects
2 | // Source: http://stubbornella.org/content/?p=497
3 | // --------------------------------------------------
4 |
5 |
6 | // Common styles
7 | // -------------------------
8 |
9 | // Clear the floats
10 | .media,
11 | .media-body {
12 | overflow: hidden;
13 | *overflow: visible;
14 | zoom: 1;
15 | }
16 |
17 | // Proper spacing between instances of .media
18 | .media,
19 | .media .media {
20 | margin-top: 15px;
21 | }
22 | .media:first-child {
23 | margin-top: 0;
24 | }
25 |
26 | // For images and videos, set to block
27 | .media-object {
28 | display: block;
29 | }
30 |
31 | // Reset margins on headings for tighter default spacing
32 | .media-heading {
33 | margin: 0 0 5px;
34 | }
35 |
36 |
37 | // Media image alignment
38 | // -------------------------
39 |
40 | .media .pull-left {
41 | margin-right: 10px;
42 | }
43 | .media .pull-right {
44 | margin-left: 10px;
45 | }
46 |
47 |
48 | // Media list variation
49 | // -------------------------
50 |
51 | // Undo default ul/ol styles
52 | .media-list {
53 | margin-left: 0;
54 | list-style: none;
55 | }
56 |
--------------------------------------------------------------------------------
/vendor/assets/stylesheets/twitter/bootstrap/pager.less:
--------------------------------------------------------------------------------
1 | //
2 | // Pager pagination
3 | // --------------------------------------------------
4 |
5 |
6 | .pager {
7 | margin: @baseLineHeight 0;
8 | list-style: none;
9 | text-align: center;
10 | .clearfix();
11 | }
12 | .pager li {
13 | display: inline;
14 | }
15 | .pager li > a,
16 | .pager li > span {
17 | display: inline-block;
18 | padding: 5px 14px;
19 | background-color: #fff;
20 | border: 1px solid #ddd;
21 | .border-radius(15px);
22 | }
23 | .pager li > a:hover {
24 | text-decoration: none;
25 | background-color: #f5f5f5;
26 | }
27 | .pager .next > a,
28 | .pager .next > span {
29 | float: right;
30 | }
31 | .pager .previous > a,
32 | .pager .previous > span {
33 | float: left;
34 | }
35 | .pager .disabled > a,
36 | .pager .disabled > a:hover,
37 | .pager .disabled > span {
38 | color: @grayLight;
39 | background-color: #fff;
40 | cursor: default;
41 | }
--------------------------------------------------------------------------------
/vendor/assets/stylesheets/twitter/bootstrap/responsive-1200px-min.less:
--------------------------------------------------------------------------------
1 | //
2 | // Responsive: Large desktop and up
3 | // --------------------------------------------------
4 |
5 |
6 | @media (min-width: 1200px) {
7 |
8 | // Fixed grid
9 | #grid > .core(@gridColumnWidth1200, @gridGutterWidth1200);
10 |
11 | // Fluid grid
12 | #grid > .fluid(@fluidGridColumnWidth1200, @fluidGridGutterWidth1200);
13 |
14 | // Input grid
15 | #grid > .input(@gridColumnWidth1200, @gridGutterWidth1200);
16 |
17 | // Thumbnails
18 | .thumbnails {
19 | margin-left: -@gridGutterWidth1200;
20 | }
21 | .thumbnails > li {
22 | margin-left: @gridGutterWidth1200;
23 | }
24 | .row-fluid .thumbnails {
25 | margin-left: 0;
26 | }
27 |
28 | }
29 |
--------------------------------------------------------------------------------
/vendor/assets/stylesheets/twitter/bootstrap/responsive-768px-979px.less:
--------------------------------------------------------------------------------
1 | //
2 | // Responsive: Tablet to desktop
3 | // --------------------------------------------------
4 |
5 |
6 | @media (min-width: 768px) and (max-width: 979px) {
7 |
8 | // Fixed grid
9 | #grid > .core(@gridColumnWidth768, @gridGutterWidth768);
10 |
11 | // Fluid grid
12 | #grid > .fluid(@fluidGridColumnWidth768, @fluidGridGutterWidth768);
13 |
14 | // Input grid
15 | #grid > .input(@gridColumnWidth768, @gridGutterWidth768);
16 |
17 | // No need to reset .thumbnails here since it's the same @gridGutterWidth
18 |
19 | }
20 |
--------------------------------------------------------------------------------
/vendor/assets/stylesheets/twitter/bootstrap/scaffolding.less:
--------------------------------------------------------------------------------
1 | //
2 | // Scaffolding
3 | // --------------------------------------------------
4 |
5 |
6 | // Body reset
7 | // -------------------------
8 |
9 | body {
10 | margin: 0;
11 | font-family: @baseFontFamily;
12 | font-size: @baseFontSize;
13 | line-height: @baseLineHeight;
14 | color: @textColor;
15 | background-color: @bodyBackground;
16 | }
17 |
18 |
19 | // Links
20 | // -------------------------
21 |
22 | a {
23 | color: @linkColor;
24 | text-decoration: none;
25 | }
26 | a:hover {
27 | color: @linkColorHover;
28 | text-decoration: underline;
29 | }
30 |
31 |
32 | // Images
33 | // -------------------------
34 |
35 | // Rounded corners
36 | .img-rounded {
37 | .border-radius(6px);
38 | }
39 |
40 | // Add polaroid-esque trim
41 | .img-polaroid {
42 | padding: 4px;
43 | background-color: #fff;
44 | border: 1px solid #ccc;
45 | border: 1px solid rgba(0,0,0,.2);
46 | .box-shadow(0 1px 3px rgba(0,0,0,.1));
47 | }
48 |
49 | // Perfect circle
50 | .img-circle {
51 | .border-radius(500px); // crank the border-radius so it works with most reasonably sized images
52 | }
53 |
--------------------------------------------------------------------------------
/vendor/assets/stylesheets/twitter/bootstrap/utilities.less:
--------------------------------------------------------------------------------
1 | //
2 | // Utility classes
3 | // --------------------------------------------------
4 |
5 |
6 | // Quick floats
7 | .pull-right {
8 | float: right;
9 | }
10 | .pull-left {
11 | float: left;
12 | }
13 |
14 | // Toggling content
15 | .hide {
16 | display: none;
17 | }
18 | .show {
19 | display: block;
20 | }
21 |
22 | // Visibility
23 | .invisible {
24 | visibility: hidden;
25 | }
26 |
27 | // For Affix plugin
28 | .affix {
29 | position: fixed;
30 | }
31 |
--------------------------------------------------------------------------------
/vendor/assets/stylesheets/twitter/bootstrap/wells.less:
--------------------------------------------------------------------------------
1 | //
2 | // Wells
3 | // --------------------------------------------------
4 |
5 |
6 | // Base class
7 | .well {
8 | min-height: 20px;
9 | padding: 19px;
10 | margin-bottom: 20px;
11 | background-color: @wellBackground;
12 | border: 1px solid darken(@wellBackground, 7%);
13 | .border-radius(@baseBorderRadius);
14 | .box-shadow(inset 0 1px 1px rgba(0,0,0,.05));
15 | blockquote {
16 | border-color: #ddd;
17 | border-color: rgba(0,0,0,.15);
18 | }
19 | }
20 |
21 | // Sizes
22 | .well-large {
23 | padding: 24px;
24 | .border-radius(@borderRadiusLarge);
25 | }
26 | .well-small {
27 | padding: 9px;
28 | .border-radius(@borderRadiusSmall);
29 | }
30 |
--------------------------------------------------------------------------------