├── log └── .keep ├── .rspec ├── app ├── mailers │ ├── .keep │ ├── user_mailer.rb │ ├── admin │ │ └── user_mailer.rb │ └── game_mailer.rb ├── assets │ ├── fonts │ │ └── .keep │ ├── images │ │ ├── .keep │ │ ├── logo.png │ │ ├── favicon.ico │ │ ├── logo-2x.png │ │ ├── bg-texture.gif │ │ ├── logo-smaller.png │ │ ├── logo-smaller-2x.png │ │ └── mailer │ │ │ ├── play-button.jpg │ │ │ └── sembl-logo.jpg │ ├── javascripts │ │ ├── models │ │ │ ├── user.js.coffee │ │ │ ├── node.js.coffee │ │ │ ├── result.js.coffee │ │ │ ├── player.js.coffee │ │ │ ├── board.js.coffee │ │ │ ├── board_node.js.coffee │ │ │ ├── board_link.js.coffee │ │ │ └── link.js.coffee │ │ ├── active_admin.js.coffee │ │ ├── es5-shims.js │ │ ├── collections │ │ │ ├── nodes.js.coffee │ │ │ ├── boards.js.coffee │ │ │ ├── links.js.coffee │ │ │ ├── board_nodes.js.coffee │ │ │ ├── players.js.coffee │ │ │ ├── results.js.coffee │ │ │ ├── board_links.js.coffee │ │ │ └── moves.js.coffee │ │ └── views │ │ │ ├── utils │ │ │ ├── page_title.js.coffee │ │ │ ├── masthead.js.coffee │ │ │ ├── utils.js.coffee │ │ │ └── animation_item.js.jsx.coffee │ │ │ ├── components │ │ │ ├── flash_message.js.jsx.coffee │ │ │ ├── tooltip.js.jsx.coffee │ │ │ ├── graph │ │ │ │ ├── nodes.js.jsx.coffee │ │ │ │ ├── links.js.jsx.coffee │ │ │ │ └── game_midpoint.js.jsx.coffee │ │ │ ├── flash.js.jsx.coffee │ │ │ └── toggle_component.js.jsx.coffee │ │ │ ├── games │ │ │ ├── move │ │ │ │ ├── placement_modal.js.jsx.coffee │ │ │ │ ├── gallery_thing_modal.js.jsx.coffee │ │ │ │ └── upload_modal.js.jsx.coffee │ │ │ ├── gameboard │ │ │ │ ├── resemblance_factory.js.jsx.coffee │ │ │ │ ├── game_header_view.js.jsx.coffee │ │ │ │ ├── placement_factory.js.jsx.coffee │ │ │ │ └── links_view.js.jsx.coffee │ │ │ ├── index.js.jsx.coffee │ │ │ ├── setup │ │ │ │ ├── steps │ │ │ │ │ ├── step_seed_thing_modal.js.jsx.coffee │ │ │ │ │ └── step_description.js.jsx.coffee │ │ │ │ ├── edit_view.js.jsx.coffee │ │ │ │ ├── new_view.js.jsx.coffee │ │ │ │ ├── thumb_board_graph.js.jsx.coffee │ │ │ │ └── overview │ │ │ │ │ └── overview_graph_placement.js.jsx.coffee │ │ │ └── rate │ │ │ │ ├── resemblance.js.jsx.coffee │ │ │ │ └── placement.js.jsx.coffee │ │ │ └── board │ │ │ └── board_link_view.js.coffee │ └── stylesheets │ │ ├── patterns │ │ ├── _font-size.scss │ │ ├── _touch.scss │ │ ├── _smooth-font-loading.scss │ │ ├── _type.scss │ │ ├── _accessibility.scss │ │ ├── _animation.scss │ │ └── _clearing.scss │ │ ├── _common.css.sass │ │ ├── turn-off-animations.css.scss │ │ ├── components │ │ ├── animations.css.scss │ │ └── _pagination.css.scss │ │ ├── active_admin.css.scss │ │ └── _forms.css.sass ├── controllers │ ├── concerns │ │ └── .keep │ ├── home_controller.rb │ ├── registrations_controller.rb │ ├── sessions_controller.rb │ ├── transloadit_signatures_controller.rb │ └── api │ │ ├── results_controller.rb │ │ ├── moves_controller.rb │ │ └── ratings_controller.rb ├── views │ ├── api │ │ ├── moves │ │ │ ├── show.json.jbuilder │ │ │ ├── round.json.jbuilder │ │ │ ├── _node.json.jbuilder │ │ │ ├── _resemblance.json.jbuilder │ │ │ ├── _link.json.jbuilder │ │ │ └── _move.json.jbuilder │ │ ├── games │ │ │ ├── create.json.jbuilder │ │ │ ├── join.json.jbuilder │ │ │ ├── end_rating.json.jbuilder │ │ │ ├── end_turn.json.jbuilder │ │ │ ├── show.json.jbuilder │ │ │ ├── update.json.jbuilder │ │ │ └── _game.json.jbuilder │ │ ├── players │ │ │ ├── create.json.jbuilder │ │ │ ├── show.json.jbuilder │ │ │ ├── index.json.jbuilder │ │ │ ├── _player.json.jbuilder │ │ │ └── _invited_player.json.jbuilder │ │ ├── things │ │ │ ├── show.json.jbuilder │ │ │ ├── create.json.jbuilder │ │ │ ├── random.json.jbuilder │ │ │ ├── index.json.jbuilder │ │ │ └── _thing.json.jbuilder │ │ ├── search │ │ │ ├── _user.json.jbuilder │ │ │ ├── _thing_query.json.jbuilder │ │ │ └── index.json.jbuilder │ │ ├── ratings │ │ │ ├── index.json.jbuilder │ │ │ └── _move.json.jbuilder │ │ ├── results │ │ │ ├── show.json.jbuilder │ │ │ ├── awards.json.jbuilder │ │ │ ├── _award.json.jbuilder │ │ │ └── _result.json.jbuilder │ │ ├── links │ │ │ └── _link.json.jbuilder │ │ ├── nodes │ │ │ └── _node.json.jbuilder │ │ ├── users │ │ │ └── _user.json.jbuilder │ │ ├── resemblances │ │ │ └── _resemblance.json.jbuilder │ │ └── placements │ │ │ └── _placement.json.jbuilder │ ├── contributions │ │ ├── crop.html.slim │ │ ├── edit.html.slim │ │ ├── _form.html.slim │ │ ├── index.html.slim │ │ └── show.html.slim │ ├── home │ │ └── show.html.slim │ ├── admin │ │ ├── user_mailer │ │ │ ├── email_message.text.slim │ │ │ └── email_message.html.slim │ │ └── users │ │ │ └── _email_form.html.slim │ ├── games │ │ ├── _form.html.slim │ │ ├── new.html.slim │ │ ├── edit.html.slim │ │ ├── _player_fields.html.slim │ │ ├── show.html.slim │ │ └── _seed_node.html.slim │ ├── devise │ │ ├── mailer │ │ │ ├── confirmation_instructions.html.slim │ │ │ ├── unlock_instructions.html.slim │ │ │ └── reset_password_instructions.html.slim │ │ ├── unlocks │ │ │ └── new.html.slim │ │ ├── confirmations │ │ │ └── new.html.slim │ │ ├── passwords │ │ │ ├── new.html.slim │ │ │ └── edit.html.slim │ │ ├── sessions │ │ │ └── new.html.slim │ │ ├── registrations │ │ │ ├── edit.html.slim │ │ │ └── new.html.slim │ │ └── _links.html.slim │ ├── game_mailer │ │ ├── game_started.text.erb │ │ ├── game_completed.text.erb │ │ ├── player_invitation.text.erb │ │ └── game_stale_and_incomplete_player_set.text.erb │ ├── user_mailer │ │ └── welcome.text.erb │ ├── profiles │ │ └── show.html.slim │ └── layouts │ │ └── react.html.slim ├── helpers │ ├── things_helper.rb │ └── application_helper.rb ├── responders │ └── api_responder.rb ├── jobs │ └── deliver_email_job.rb ├── policies │ ├── profile_policy.rb │ ├── move_policy.rb │ ├── thing_policy.rb │ ├── medal_awarder_policy.rb │ ├── board_policy.rb │ ├── placement_policy.rb │ ├── rating_policy.rb │ ├── resemblance_policy.rb │ ├── player_policy.rb │ ├── application_policy.rb │ └── game_policy.rb ├── models │ ├── thing_search_null_fallback.rb │ ├── profile.rb │ ├── board.rb │ ├── concerns │ │ └── random_fixed_orderable.rb │ ├── thing_search_fallback.rb │ ├── link.rb │ ├── rating.rb │ ├── resemblance.rb │ └── placement.rb ├── admin │ ├── player.rb │ └── board.rb ├── inputs │ └── image_file_input.rb └── uploaders │ ├── avatar_uploader.rb │ └── image_uploader.rb ├── lib ├── assets │ └── .keep ├── tasks │ ├── .keep │ └── game_reminders.rake ├── admin_constraint.rb ├── templates │ └── slim │ │ └── scaffold │ │ └── _form.html.slim └── process_csv.rb ├── public ├── favicon.ico └── robots.txt ├── prov ├── vagrant.retry ├── local ├── vagrant.yml ├── rails │ ├── tasks │ │ ├── main.yml │ │ ├── update_locale.yml │ │ ├── packages.yml │ │ └── ruby.yml │ └── defaults │ │ └── main.yml ├── vagrant └── vagrant-guest │ └── tasks │ └── main.yml ├── vendor └── assets │ ├── javascripts │ ├── .keep │ └── viewloader.js │ └── stylesheets │ ├── .keep │ ├── bourbon │ ├── css3 │ │ ├── _appearance.scss │ │ ├── _user-select.scss │ │ ├── _box-sizing.scss │ │ ├── _inline-block.scss │ │ ├── _perspective.scss │ │ ├── _backface-visibility.scss │ │ ├── _image-rendering.scss │ │ ├── _hidpi-media-query.scss │ │ ├── _transform.scss │ │ ├── _placeholder.scss │ │ ├── _border-radius.scss │ │ └── _font-face.scss │ ├── addons │ │ ├── _hide-text.scss │ │ ├── _font-family.scss │ │ ├── _clearfix.scss │ │ ├── _position.scss │ │ ├── _retina-image.scss │ │ ├── _size.scss │ │ └── _triangle.scss │ ├── functions │ │ ├── _compact.scss │ │ ├── _px-to-em.scss │ │ ├── _tint-shade.scss │ │ ├── _linear-gradient.scss │ │ ├── _grid-width.scss │ │ ├── _transition-property-name.scss │ │ ├── _radial-gradient.scss │ │ └── _modular-scale.scss │ ├── helpers │ │ ├── _shape-size-stripper.scss │ │ ├── _gradient-positions-parser.scss │ │ ├── _radial-positions-parser.scss │ │ └── _render-gradients.scss │ └── _bourbon-deprecated-upcoming.scss │ └── image_area_select.css.scss ├── sembl.dump ├── config ├── initializers │ ├── skim.rb │ ├── que.rb │ ├── session_store.rb │ ├── bugsnag.rb │ ├── filter_parameter_logging.rb │ ├── mime_types.rb │ ├── backtrace_silencers.rb │ ├── wrap_parameters.rb │ ├── secret_token.rb │ ├── inflections.rb │ └── carrierwave.rb ├── environment.rb ├── boot.rb ├── database.yml ├── sunspot.yml ├── database.example.yml ├── transloadit.yml ├── locales │ └── simple_form.en.yml ├── application.rb └── unicorn.rb ├── spec ├── models │ ├── user_spec.rb │ ├── thing_spec.rb │ ├── board_spec.rb │ ├── rating_spec.rb │ ├── placement_spec.rb │ └── resemblance_spec.rb ├── support │ ├── images │ │ └── monkey.jpg │ ├── devise_acceptance_helper.rb │ ├── pundit_matcher.rb │ ├── controller_helpers.rb │ └── database_cleaner.rb ├── controllers │ ├── contributions_controller_spec.rb │ ├── home_controller_spec.rb │ └── games_controller_spec.rb ├── factories │ ├── links.rb │ ├── ratings.rb │ ├── placements.rb │ ├── resemblances.rb │ ├── players.rb │ ├── things.rb │ ├── users.rb │ ├── nodes.rb │ └── boards.rb ├── features │ ├── creating_games_spec.rb │ ├── home_page_spec.rb │ ├── admin │ │ └── authentication_spec.rb │ └── viewing_and_joining_games_spec.rb └── policies │ └── player_policy_spec.rb ├── bin ├── bundle ├── ri ├── fog ├── pry ├── rake ├── rdoc ├── sass ├── scss ├── sdoc ├── thor ├── tilt ├── tt ├── guard ├── byebug ├── dotenv ├── erubis ├── ldiff ├── listen ├── rackup ├── rails ├── rspec ├── slimrb ├── bundler ├── coderay ├── launchy ├── unicorn ├── autospec ├── htmldiff ├── newrelic ├── nokogiri ├── nrdebug ├── premailer ├── sdoc-merge ├── sprockets ├── restclient ├── sass-convert ├── mongrel_rpm ├── unicorn_rails ├── newrelic_cmd └── setup ├── Procfile ├── db └── migrate │ ├── 20131015051929_add_image_to_things.rb │ ├── 20131217042024_add_email_to_players.rb │ ├── 20131120045237_add_title_to_placement.rb │ ├── 20140318231306_add_score_to_placements.rb │ ├── 20131018051741_add_state_to_games.rb │ ├── 20131121040600_add_access_via_to_things.rb │ ├── 20140828004519_add_stale_to_games.rb │ ├── 20131015002355_add_admin_to_users.rb │ ├── 20131022055830_add_current_round_to_games.rb │ ├── 20131030040144_add_state_to_players.rb │ ├── 20131205035026_add_number_of_players_to_games.rb │ ├── 20131121002730_change_attributes_on_things.rb │ ├── 20131204035049_change_score_on_players.rb │ ├── 20131204052618_change_state_on_players.rb │ ├── 20131210034401_add_suggested_seed_to_things.rb │ ├── 20131127045113_add_positions_to_nodes.rb │ ├── 20131204234506_remove_default_states.rb │ ├── 20140625005906_change_name_of_link_description_column.rb │ ├── 20131121032603_add_seed_and_row_id_to_things.rb │ ├── 20140429051556_add_game_to_thing.rb │ ├── 20131017060345_add_game_attributes_to_board.rb │ ├── 20140625001441_add_link_descriptions_to_resemblances.rb │ ├── 20131017231832_create_players.rb │ ├── 20131017044432_create_nodes.rb │ ├── 20131017045458_create_ratings.rb │ ├── 20131017044440_create_links.rb │ ├── 20141014031053_add_que.rb │ ├── 20141125225629_add_moderated_flag_to_things.rb │ ├── 20140226011705_add_move_state_to_players.rb │ ├── 20141126002824_alter_column_for_thing_moderation.rb │ ├── 20131017044451_create_placements.rb │ ├── 20131015025606_create_things.rb │ ├── 20131015070339_create_boards.rb │ ├── 20131127020914_add_random_seed_to_games.rb │ ├── 20131017044414_create_games.rb │ ├── 20131127230252_change_coordinates_on_node.rb │ ├── 20131017045438_create_resemblances.rb │ ├── 20131120045222_add_attributes_to_things.rb │ ├── 20140415064148_create_profiles.rb │ ├── 20141012220934_add_state_changed_at_to_games.rb │ ├── 20131127020944_change_random_seed_on_things.rb │ ├── 20141013000902_add_state_changed_at_to_players.rb │ ├── 20131018043025_add_config_options_to_games.rb │ ├── 20140224031647_add_source_and_target_to_resemblance.rb │ ├── 20141014013558_add_reminder_count_for_state_to_games.rb │ ├── 20141013004024_add_reminder_count_for_state_to_players.rb │ ├── 20140430080056_add_mature_and_sensitive_to_things.rb │ ├── 20131029040046_split_board_game_attributes_into_nodes_and_links.rb │ ├── 20141210235416_create_active_admin_comments.rb │ ├── 20131212030054_add_role_to_users.rb │ ├── 20140211225733_change_filter_content_by_on_games.rb │ ├── 20150126221244_make_thing_meta_fields_proper_attributes.rb │ ├── 20141126215119_change_general_attributes_default_to_empty_object.rb │ └── 20140205010520_alter_json_format_of_things_attributes.rb ├── config.ru ├── Procfile.dev ├── .gitignore ├── Rakefile ├── .env.example ├── Vagrantfile └── Guardfile /log/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.rspec: -------------------------------------------------------------------------------- 1 | --color 2 | -------------------------------------------------------------------------------- /app/mailers/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lib/assets/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lib/tasks/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/assets/fonts/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/assets/images/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/controllers/concerns/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /prov/vagrant.retry: -------------------------------------------------------------------------------- 1 | vagrant 2 | -------------------------------------------------------------------------------- /vendor/assets/javascripts/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /vendor/assets/stylesheets/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/views/api/moves/show.json.jbuilder: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/views/contributions/crop.html.slim: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/views/contributions/edit.html.slim: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/views/contributions/_form.html.slim: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/views/home/show.html.slim: -------------------------------------------------------------------------------- 1 | p Welcome to Sembl. 2 | -------------------------------------------------------------------------------- /prov/local: -------------------------------------------------------------------------------- 1 | localhost ansible_connection=local 2 | -------------------------------------------------------------------------------- /app/helpers/things_helper.rb: -------------------------------------------------------------------------------- 1 | module ThingsHelper 2 | end 3 | -------------------------------------------------------------------------------- /app/assets/javascripts/models/user.js.coffee: -------------------------------------------------------------------------------- 1 | class Sembl.User 2 | -------------------------------------------------------------------------------- /sembl.dump: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hughevans/sembl/master/sembl.dump -------------------------------------------------------------------------------- /app/assets/javascripts/active_admin.js.coffee: -------------------------------------------------------------------------------- 1 | #= require active_admin/base 2 | -------------------------------------------------------------------------------- /app/views/admin/user_mailer/email_message.text.slim: -------------------------------------------------------------------------------- 1 | = @message_content 2 | -------------------------------------------------------------------------------- /app/views/api/games/create.json.jbuilder: -------------------------------------------------------------------------------- 1 | json.partial! 'api/games/game', game: @game -------------------------------------------------------------------------------- /app/views/api/games/join.json.jbuilder: -------------------------------------------------------------------------------- 1 | json.partial! 'api/games/game', game: @game -------------------------------------------------------------------------------- /config/initializers/skim.rb: -------------------------------------------------------------------------------- 1 | Skim::Engine.default_options[:use_asset] = true 2 | -------------------------------------------------------------------------------- /app/views/api/games/end_rating.json.jbuilder: -------------------------------------------------------------------------------- 1 | json.partial! 'api/games/game', game: @game -------------------------------------------------------------------------------- /app/views/api/games/end_turn.json.jbuilder: -------------------------------------------------------------------------------- 1 | json.partial! 'api/games/game', game: @game -------------------------------------------------------------------------------- /app/views/api/games/show.json.jbuilder: -------------------------------------------------------------------------------- 1 | json.partial! 'api/games/game', game: @game 2 | -------------------------------------------------------------------------------- /app/views/api/games/update.json.jbuilder: -------------------------------------------------------------------------------- 1 | json.partial! 'api/games/game', game: @game 2 | -------------------------------------------------------------------------------- /spec/models/user_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe User do 4 | end 5 | -------------------------------------------------------------------------------- /app/views/api/players/create.json.jbuilder: -------------------------------------------------------------------------------- 1 | json.partial! 'api/players/player', player: @player -------------------------------------------------------------------------------- /app/views/api/players/show.json.jbuilder: -------------------------------------------------------------------------------- 1 | json.partial! 'api/players/player', player: @player -------------------------------------------------------------------------------- /app/views/api/things/show.json.jbuilder: -------------------------------------------------------------------------------- 1 | json.partial! "api/things/thing", thing: @thing 2 | -------------------------------------------------------------------------------- /spec/models/thing_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe Thing do 4 | 5 | end 6 | -------------------------------------------------------------------------------- /app/assets/javascripts/es5-shims.js: -------------------------------------------------------------------------------- 1 | //= require es5-shim/es5-shim 2 | //= require es5-shim/es5-sham 3 | -------------------------------------------------------------------------------- /app/views/api/search/_user.json.jbuilder: -------------------------------------------------------------------------------- 1 | json.array! users do |u| 2 | json.(u, :email, :role) 3 | end -------------------------------------------------------------------------------- /prov/vagrant.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: all 3 | 4 | roles: 5 | - rails 6 | - vagrant-guest 7 | -------------------------------------------------------------------------------- /app/assets/images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hughevans/sembl/master/app/assets/images/logo.png -------------------------------------------------------------------------------- /app/views/admin/user_mailer/email_message.html.slim: -------------------------------------------------------------------------------- 1 | = @message_content.gsub(/\n/, "
").html_safe 2 | -------------------------------------------------------------------------------- /app/assets/images/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hughevans/sembl/master/app/assets/images/favicon.ico -------------------------------------------------------------------------------- /app/assets/images/logo-2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hughevans/sembl/master/app/assets/images/logo-2x.png -------------------------------------------------------------------------------- /app/views/api/things/create.json.jbuilder: -------------------------------------------------------------------------------- 1 | json.partial! "api/things/thing", thing: @thing 2 | json.id @thing.id -------------------------------------------------------------------------------- /app/views/api/things/random.json.jbuilder: -------------------------------------------------------------------------------- 1 | json.partial! "api/things/thing", thing: @thing 2 | json.id @thing.id -------------------------------------------------------------------------------- /spec/support/images/monkey.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hughevans/sembl/master/spec/support/images/monkey.jpg -------------------------------------------------------------------------------- /app/assets/images/bg-texture.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hughevans/sembl/master/app/assets/images/bg-texture.gif -------------------------------------------------------------------------------- /app/controllers/home_controller.rb: -------------------------------------------------------------------------------- 1 | class HomeController < ApplicationController 2 | def show 3 | end 4 | end 5 | -------------------------------------------------------------------------------- /app/assets/images/logo-smaller.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hughevans/sembl/master/app/assets/images/logo-smaller.png -------------------------------------------------------------------------------- /app/views/api/players/index.json.jbuilder: -------------------------------------------------------------------------------- 1 | json.players @players, partial: 'api/players/invited_player', as: :player 2 | -------------------------------------------------------------------------------- /app/assets/images/logo-smaller-2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hughevans/sembl/master/app/assets/images/logo-smaller-2x.png -------------------------------------------------------------------------------- /app/views/api/moves/round.json.jbuilder: -------------------------------------------------------------------------------- 1 | json.array! ( 2 | json.moves @moves, partial: 'api/moves/move', as: :move 3 | ) 4 | -------------------------------------------------------------------------------- /app/views/api/things/index.json.jbuilder: -------------------------------------------------------------------------------- 1 | json.array! ( 2 | json.things @things, partial: 'api/things/thing', as: :thing 3 | ) -------------------------------------------------------------------------------- /app/assets/images/mailer/play-button.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hughevans/sembl/master/app/assets/images/mailer/play-button.jpg -------------------------------------------------------------------------------- /app/assets/images/mailer/sembl-logo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hughevans/sembl/master/app/assets/images/mailer/sembl-logo.jpg -------------------------------------------------------------------------------- /app/views/api/ratings/index.json.jbuilder: -------------------------------------------------------------------------------- 1 | json.array! ( 2 | json.moves @moves, partial: 'api/ratings/move', as: :move 3 | ) 4 | -------------------------------------------------------------------------------- /spec/controllers/contributions_controller_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe ContributionsController do 4 | 5 | end 6 | -------------------------------------------------------------------------------- /app/views/games/_form.html.slim: -------------------------------------------------------------------------------- 1 | div data-view="gamesSetup" data-game="#{render(template: "api/games/show", formats: :json, object: @game)}" 2 | -------------------------------------------------------------------------------- /app/views/games/new.html.slim: -------------------------------------------------------------------------------- 1 | div data-view="setupNew" data-game="#{render(template: "api/games/show", formats: :json, object: @game)}" 2 | -------------------------------------------------------------------------------- /config/initializers/que.rb: -------------------------------------------------------------------------------- 1 | # We run a pool of worker threads inside the web server process. See 2 | # config/unicorn.rb. 3 | Que.mode = :off 4 | -------------------------------------------------------------------------------- /spec/models/board_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe Board do 4 | pending "add some examples to (or delete) #{__FILE__}" 5 | end 6 | -------------------------------------------------------------------------------- /bin/bundle: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__) 3 | load Gem.bin_path('bundler', 'bundle') 4 | -------------------------------------------------------------------------------- /prov/rails/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # - include: update_locale.yml 3 | # - include: packages.yml 4 | # - include: ruby.yml 5 | - include: postgres.yml 6 | -------------------------------------------------------------------------------- /spec/models/rating_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe Rating do 4 | pending "add some examples to (or delete) #{__FILE__}" 5 | end 6 | -------------------------------------------------------------------------------- /spec/models/placement_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe Placement do 4 | pending "add some examples to (or delete) #{__FILE__}" 5 | end 6 | -------------------------------------------------------------------------------- /spec/models/resemblance_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe Resemblance do 4 | pending "add some examples to (or delete) #{__FILE__}" 5 | end 6 | -------------------------------------------------------------------------------- /vendor/assets/stylesheets/bourbon/css3/_appearance.scss: -------------------------------------------------------------------------------- 1 | @mixin appearance ($value) { 2 | @include prefixer(appearance, $value, webkit moz ms o spec); 3 | } 4 | -------------------------------------------------------------------------------- /vendor/assets/stylesheets/bourbon/css3/_user-select.scss: -------------------------------------------------------------------------------- 1 | @mixin user-select($arg: none) { 2 | @include prefixer(user-select, $arg, webkit moz ms spec); 3 | } 4 | -------------------------------------------------------------------------------- /app/views/games/edit.html.slim: -------------------------------------------------------------------------------- 1 | div data-view="setupEdit" data-game="#{render(template: "api/games/show", formats: :json, object: @game)}" data-header="Edit Game" 2 | -------------------------------------------------------------------------------- /spec/factories/links.rb: -------------------------------------------------------------------------------- 1 | # Read about factories at https://github.com/thoughtbot/factory_girl 2 | 3 | FactoryGirl.define do 4 | factory :link do 5 | end 6 | end 7 | -------------------------------------------------------------------------------- /app/views/api/results/show.json.jbuilder: -------------------------------------------------------------------------------- 1 | json.array! ( 2 | json.results @moves do |json, move| 3 | json.partial! 'api/results/result', move: move 4 | end 5 | ) 6 | -------------------------------------------------------------------------------- /app/views/games/_player_fields.html.slim: -------------------------------------------------------------------------------- 1 | .player-fields 2 | = f.input :email 3 | = f.hidden_field :user_id 4 | = f.hidden_field :_destroy, class: 'destroy-player' -------------------------------------------------------------------------------- /spec/factories/ratings.rb: -------------------------------------------------------------------------------- 1 | # Read about factories at https://github.com/thoughtbot/factory_girl 2 | 3 | FactoryGirl.define do 4 | factory :rating do 5 | end 6 | end 7 | -------------------------------------------------------------------------------- /Procfile: -------------------------------------------------------------------------------- 1 | web: bundle exec unicorn -c ./config/unicorn.rb 2 | 3 | # Enable this if we move to a dedicated process for the Que worker 4 | # worker: bundle exec rake que:work 5 | -------------------------------------------------------------------------------- /app/assets/javascripts/models/node.js.coffee: -------------------------------------------------------------------------------- 1 | class Sembl.Node extends Backbone.Model 2 | initialize: (options) -> 3 | @game = options?.game or @collection?.game 4 | 5 | -------------------------------------------------------------------------------- /app/assets/stylesheets/patterns/_font-size.scss: -------------------------------------------------------------------------------- 1 | // Assumes 1rem = 10px 2 | @mixin font-size($size) { 3 | font-size: #{$size}px; 4 | font-size: #{$size / 10}rem; 5 | } 6 | -------------------------------------------------------------------------------- /app/responders/api_responder.rb: -------------------------------------------------------------------------------- 1 | class ApiResponder < ActionController::Responder 2 | def json_resource_errors 3 | { errors: resource.errors.full_messages } 4 | end 5 | end -------------------------------------------------------------------------------- /app/views/api/results/awards.json.jbuilder: -------------------------------------------------------------------------------- 1 | json.array! ( 2 | json.awards @awards.all do |json, award| 3 | json.partial! 'api/results/award', award: award 4 | end 5 | ) -------------------------------------------------------------------------------- /spec/factories/placements.rb: -------------------------------------------------------------------------------- 1 | # Read about factories at https://github.com/thoughtbot/factory_girl 2 | 3 | FactoryGirl.define do 4 | factory :placement do 5 | end 6 | end 7 | -------------------------------------------------------------------------------- /db/migrate/20131015051929_add_image_to_things.rb: -------------------------------------------------------------------------------- 1 | class AddImageToThings < ActiveRecord::Migration 2 | def change 3 | add_column :things, :image, :string 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20131217042024_add_email_to_players.rb: -------------------------------------------------------------------------------- 1 | class AddEmailToPlayers < ActiveRecord::Migration 2 | def change 3 | add_column :players, :email, :string 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /lib/admin_constraint.rb: -------------------------------------------------------------------------------- 1 | AdminConstraint = lambda do |request| 2 | request.env["warden"].authenticate!(scope: :user) and 3 | request.env["warden"].user(:user).admin? 4 | end 5 | -------------------------------------------------------------------------------- /spec/factories/resemblances.rb: -------------------------------------------------------------------------------- 1 | # Read about factories at https://github.com/thoughtbot/factory_girl 2 | 3 | FactoryGirl.define do 4 | factory :resemblance do 5 | end 6 | end 7 | -------------------------------------------------------------------------------- /vendor/assets/stylesheets/bourbon/addons/_hide-text.scss: -------------------------------------------------------------------------------- 1 | @mixin hide-text { 2 | color: transparent; 3 | font: 0/0 a; 4 | text-shadow: none; 5 | } 6 | -------------------------------------------------------------------------------- /app/views/api/moves/_node.json.jbuilder: -------------------------------------------------------------------------------- 1 | json.(node, :id, :round, :x, :y, :state) 2 | json.viewable_placement do 3 | json.partial! 'api/placements/placement', placement: placement 4 | end -------------------------------------------------------------------------------- /config/initializers/session_store.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | Sembl::Application.config.session_store :cookie_store, key: '_Sembl_session' 4 | -------------------------------------------------------------------------------- /config/environment.rb: -------------------------------------------------------------------------------- 1 | # Load the Rails application. 2 | require File.expand_path('../application', __FILE__) 3 | 4 | # Initialize the Rails application. 5 | Sembl::Application.initialize! 6 | -------------------------------------------------------------------------------- /db/migrate/20131120045237_add_title_to_placement.rb: -------------------------------------------------------------------------------- 1 | class AddTitleToPlacement < ActiveRecord::Migration 2 | def change 3 | add_column :placements, :title, :string 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20140318231306_add_score_to_placements.rb: -------------------------------------------------------------------------------- 1 | class AddScoreToPlacements < ActiveRecord::Migration 2 | def change 3 | add_column :placements, :score, :float 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20131018051741_add_state_to_games.rb: -------------------------------------------------------------------------------- 1 | class AddStateToGames < ActiveRecord::Migration 2 | def change 3 | add_column :games, :state, :string, default: "draft" 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20131121040600_add_access_via_to_things.rb: -------------------------------------------------------------------------------- 1 | class AddAccessViaToThings < ActiveRecord::Migration 2 | def change 3 | add_column :things, :access_via, :string 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20140828004519_add_stale_to_games.rb: -------------------------------------------------------------------------------- 1 | class AddStaleToGames < ActiveRecord::Migration 2 | def change 3 | add_column :games, :stale, :boolean, default: false 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /vendor/assets/stylesheets/bourbon/css3/_box-sizing.scss: -------------------------------------------------------------------------------- 1 | @mixin box-sizing ($box) { 2 | // content-box | border-box | inherit 3 | @include prefixer(box-sizing, $box, webkit moz spec); 4 | } 5 | -------------------------------------------------------------------------------- /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 | use Rack::Deflater 5 | run Rails.application 6 | -------------------------------------------------------------------------------- /db/migrate/20131015002355_add_admin_to_users.rb: -------------------------------------------------------------------------------- 1 | class AddAdminToUsers < ActiveRecord::Migration 2 | def change 3 | add_column :users, :admin, :boolean, null: false, default: false 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /app/views/api/players/_player.json.jbuilder: -------------------------------------------------------------------------------- 1 | json.(player, :id, :state, :move_state, :score) 2 | 3 | if player.user 4 | json.user do 5 | json.partial! 'api/users/user', user: player.user 6 | end 7 | end -------------------------------------------------------------------------------- /db/migrate/20131022055830_add_current_round_to_games.rb: -------------------------------------------------------------------------------- 1 | class AddCurrentRoundToGames < ActiveRecord::Migration 2 | def change 3 | add_column :games, :current_round, :integer, default: 1 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20131030040144_add_state_to_players.rb: -------------------------------------------------------------------------------- 1 | class AddStateToPlayers < ActiveRecord::Migration 2 | def change 3 | add_column :players, :state, :string, default: "completing_turn" 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20131205035026_add_number_of_players_to_games.rb: -------------------------------------------------------------------------------- 1 | class AddNumberOfPlayersToGames < ActiveRecord::Migration 2 | def change 3 | add_column :games, :number_of_players, :integer 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /app/assets/javascripts/models/result.js.coffee: -------------------------------------------------------------------------------- 1 | class Sembl.Result extends Backbone.Model 2 | url: -> 3 | null 4 | 5 | initialize: (options) -> 6 | @game = options?.game or @collection?.game 7 | 8 | 9 | -------------------------------------------------------------------------------- /app/assets/stylesheets/patterns/_touch.scss: -------------------------------------------------------------------------------- 1 | %no-tap-delay { 2 | .touch & { 3 | -webkit-tap-highlight-color: rgba(0,0,0,0); 4 | -webkit-user-select: none; 5 | -webkit-touch-callout: none; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /app/jobs/deliver_email_job.rb: -------------------------------------------------------------------------------- 1 | class DeliverEmailJob < Que::Job 2 | def run(mailer_class, mailer_method, *method_args) 3 | mailer_class.constantize.send(mailer_method, *method_args).deliver 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20131121002730_change_attributes_on_things.rb: -------------------------------------------------------------------------------- 1 | class ChangeAttributesOnThings < ActiveRecord::Migration 2 | def change 3 | rename_column :things, :attributes, :general_attributes 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20131204035049_change_score_on_players.rb: -------------------------------------------------------------------------------- 1 | class ChangeScoreOnPlayers < ActiveRecord::Migration 2 | def change 3 | change_column :players, :score, :float, null: false, default: 0 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20131204052618_change_state_on_players.rb: -------------------------------------------------------------------------------- 1 | class ChangeStateOnPlayers < ActiveRecord::Migration 2 | def change 3 | change_column :players, :state, :string, null: false, default: "" 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /prov/vagrant: -------------------------------------------------------------------------------- 1 | [webservers] 2 | vagrant 3 | 4 | [webservers:vars] 5 | 6 | ansible_ssh_host=sembl.dev 7 | ansible_ssh_user=vagrant 8 | ansible_ssh_private_key_file=.vagrant/machines/default/virtualbox/private_key 9 | -------------------------------------------------------------------------------- /Procfile.dev: -------------------------------------------------------------------------------- 1 | web: bundle exec unicorn -c ./config/unicorn.rb 2 | solr: bundle exec rake sunspot:solr:run 3 | 4 | # Enable this if we move to a dedicated process for the Que worker 5 | # worker: bundle exec rake que:work 6 | -------------------------------------------------------------------------------- /app/assets/javascripts/collections/nodes.js.coffee: -------------------------------------------------------------------------------- 1 | #= require models/node 2 | 3 | class Sembl.Nodes extends Backbone.Collection 4 | model: Sembl.Node 5 | 6 | initialize: (models, options) -> 7 | @game = options?.game -------------------------------------------------------------------------------- /app/assets/javascripts/models/player.js.coffee: -------------------------------------------------------------------------------- 1 | class Sembl.Player extends Backbone.Model 2 | initialize: (options) -> 3 | @game = @collection.game 4 | 5 | formatted_score: -> 6 | Math.floor(@get('score')*100) 7 | -------------------------------------------------------------------------------- /app/views/contributions/index.html.slim: -------------------------------------------------------------------------------- 1 | h1 My Contributions 2 | 3 | = link_to 'Upload New Thing', new_contribution_path 4 | 5 | ul 6 | - @things.each do |thing| 7 | li= link_to thing.title, contribution_path(thing) 8 | -------------------------------------------------------------------------------- /db/migrate/20131210034401_add_suggested_seed_to_things.rb: -------------------------------------------------------------------------------- 1 | class AddSuggestedSeedToThings < ActiveRecord::Migration 2 | def change 3 | add_column :things, :suggested_seed, :boolean, default: false 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /spec/controllers/home_controller_spec.rb: -------------------------------------------------------------------------------- 1 | require "spec_helper" 2 | 3 | describe HomeController do 4 | describe "GET 'show'" do 5 | it "returns http success" do 6 | pending 7 | end 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /app/assets/javascripts/collections/boards.js.coffee: -------------------------------------------------------------------------------- 1 | #= require models/board 2 | 3 | class Sembl.Boards extends Backbone.Collection 4 | model: Sembl.Board 5 | 6 | initialize: (models, options) -> 7 | 8 | comparator: 'title' -------------------------------------------------------------------------------- /app/assets/javascripts/views/utils/page_title.js.coffee: -------------------------------------------------------------------------------- 1 | class PageTitle 2 | baseTitle: "— Sembl" 3 | set: (pageTitle) -> 4 | document.title = "#{pageTitle} #{@baseTitle}" 5 | 6 | @Sembl.Utils.PageTitle = new PageTitle() 7 | -------------------------------------------------------------------------------- /app/policies/profile_policy.rb: -------------------------------------------------------------------------------- 1 | class ProfilePolicy < ApplicationPolicy 2 | 3 | def edit? 4 | !!user && record.user == user 5 | end 6 | 7 | def update? 8 | !!user && record.user == user 9 | end 10 | 11 | end -------------------------------------------------------------------------------- /db/migrate/20131127045113_add_positions_to_nodes.rb: -------------------------------------------------------------------------------- 1 | class AddPositionsToNodes < ActiveRecord::Migration 2 | def change 3 | add_column :nodes, :position_x, :float 4 | add_column :nodes, :position_y, :float 5 | end 6 | end 7 | -------------------------------------------------------------------------------- /app/policies/move_policy.rb: -------------------------------------------------------------------------------- 1 | class MovePolicy < ApplicationPolicy 2 | 3 | def create? 4 | if record.placement.valid? 5 | record.placement.node.available_to?(user) 6 | else 7 | true 8 | end 9 | end 10 | end -------------------------------------------------------------------------------- /app/views/api/moves/_resemblance.json.jbuilder: -------------------------------------------------------------------------------- 1 | json.(resemblance, :id, :description, :score, :source_description, :target_description) 2 | 3 | if include_rating 4 | json.rating resemblance.rating_by(current_user).try(:rating) 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20131204234506_remove_default_states.rb: -------------------------------------------------------------------------------- 1 | class RemoveDefaultStates < ActiveRecord::Migration 2 | def change 3 | change_column_default :games, :state, nil 4 | change_column_default :players, :state, nil 5 | end 6 | end 7 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /app/assets/javascripts/views/components/flash_message.js.jsx.coffee: -------------------------------------------------------------------------------- 1 | #= require jquery 2 | 3 | @Sembl.views.flashMessage = ($el, el) -> 4 | $el.on "click", "button", (e) -> 5 | e.preventDefault() 6 | $el.addClass "hidden" 7 | 8 | 9 | -------------------------------------------------------------------------------- /app/assets/javascripts/views/utils/masthead.js.coffee: -------------------------------------------------------------------------------- 1 | #= require jquery 2 | 3 | $ -> 4 | # Offset the header tab 5 | headingTabWidth = $('.heading h1').outerWidth() 6 | $('.heading h1').css 'margin-left', ((headingTabWidth / 2) * -1) + 'px' -------------------------------------------------------------------------------- /db/migrate/20140625005906_change_name_of_link_description_column.rb: -------------------------------------------------------------------------------- 1 | class ChangeNameOfLinkDescriptionColumn < ActiveRecord::Migration 2 | def change 3 | rename_column :resemblances, :link_description, :source_description 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /app/assets/stylesheets/_common.css.sass: -------------------------------------------------------------------------------- 1 | // Disable text selection within SVG 2 | svg 3 | text, tspan 4 | cursor: default 5 | user-select: none 6 | -webkit-user-select: none 7 | -moz-user-select: none 8 | -ms-user-select: none 9 | -------------------------------------------------------------------------------- /app/views/contributions/show.html.slim: -------------------------------------------------------------------------------- 1 | h1= @thing.title 2 | 3 | = simple_format @thing.description 4 | 5 | - if @thing.image? 6 | = image_tag @thing.image.browse_thumb.url, alt: @thing.description 7 | 8 | p= link_to 'Return', contributions_path 9 | -------------------------------------------------------------------------------- /app/views/devise/mailer/confirmation_instructions.html.slim: -------------------------------------------------------------------------------- 1 | p 2 | | Welcome #{@email}! 3 | p You can confirm your account email through the link below: 4 | p= link_to 'Confirm my account', confirmation_url(@resource, :confirmation_token => @token) 5 | -------------------------------------------------------------------------------- /config/initializers/bugsnag.rb: -------------------------------------------------------------------------------- 1 | Bugsnag.configure do |config| 2 | config.api_key = ENV['BUGSNAG_API_KEY'] 3 | config.use_ssl = true 4 | config.notify_release_stages = ['production', 'staging'] 5 | config.release_stage = ENV['STAGE'] 6 | end 7 | -------------------------------------------------------------------------------- /app/policies/thing_policy.rb: -------------------------------------------------------------------------------- 1 | class ThingPolicy < ApplicationPolicy 2 | def create? 3 | !!record.game 4 | # record.resemblance.creator_id != user.id && 5 | # record.resemblance.link.game.participating?(user) 6 | true 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /config/initializers/filter_parameter_logging.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Configure sensitive parameters which will be filtered from the log file. 4 | Rails.application.config.filter_parameters += [:password] 5 | -------------------------------------------------------------------------------- /config/initializers/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 | -------------------------------------------------------------------------------- /db/migrate/20131121032603_add_seed_and_row_id_to_things.rb: -------------------------------------------------------------------------------- 1 | class AddSeedAndRowIdToThings < ActiveRecord::Migration 2 | def change 3 | add_column :things, :import_row_id, :string 4 | add_column :things, :random_seed, :string 5 | end 6 | end 7 | -------------------------------------------------------------------------------- /db/migrate/20140429051556_add_game_to_thing.rb: -------------------------------------------------------------------------------- 1 | class AddGameToThing < ActiveRecord::Migration 2 | def up 3 | add_reference :things, :game, index: true 4 | end 5 | 6 | def down 7 | remove_reference :things, :game 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /spec/factories/players.rb: -------------------------------------------------------------------------------- 1 | # Read about factories at https://github.com/thoughtbot/factory_girl 2 | 3 | FactoryGirl.define do 4 | factory :player do 5 | user { FactoryGirl.create(:user) } 6 | game { FactoryGirl.create(:game) } 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /app/views/api/moves/_link.json.jbuilder: -------------------------------------------------------------------------------- 1 | json.(link, :id, :source_id, :target_id, :round) 2 | json.viewable_resemblance do 3 | json.partial! 'api/moves/resemblance', resemblance: move.resemblance_for_link(link), include_rating: include_rating 4 | end 5 | 6 | -------------------------------------------------------------------------------- /app/views/api/search/_thing_query.json.jbuilder: -------------------------------------------------------------------------------- 1 | json.( 2 | query, 3 | :access_filter, 4 | :created_to, 5 | :exclude_mature, 6 | :exclude_sensitive, 7 | :include_user_contributed, 8 | :place_filter, 9 | :random_seed, 10 | :text 11 | ) 12 | -------------------------------------------------------------------------------- /db/migrate/20131017060345_add_game_attributes_to_board.rb: -------------------------------------------------------------------------------- 1 | class AddGameAttributesToBoard < ActiveRecord::Migration 2 | def change 3 | add_column :boards, :game_attributes, :text, null: false, default: '{"nodes": [{"round": 0}], "links": []}' 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /spec/controllers/games_controller_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe GamesController do 4 | describe "GET 'index'" do 5 | it "returns http success" do 6 | get :index 7 | response.should be_success 8 | end 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | /.bundle 3 | /.env 4 | /.ruby-version 5 | /.sass-cache 6 | /.vagrant 7 | /config/database.yml 8 | /coverage 9 | /db/*.sqlite3 10 | /log/*.log 11 | /log/*.lck 12 | /public/assets 13 | /public/uploads 14 | /tmp 15 | /*_dump.sql 16 | /solr 17 | -------------------------------------------------------------------------------- /vendor/assets/stylesheets/bourbon/css3/_inline-block.scss: -------------------------------------------------------------------------------- 1 | // Legacy support for inline-block in IE7 (maybe IE6) 2 | @mixin inline-block { 3 | display: inline-block; 4 | vertical-align: baseline; 5 | zoom: 1; 6 | *display: inline; 7 | *vertical-align: auto; 8 | } 9 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | # Add your own tasks in files placed in lib/tasks ending in .rake, 2 | # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake. 3 | 4 | require File.expand_path('../config/application', __FILE__) 5 | 6 | Sembl::Application.load_tasks 7 | -------------------------------------------------------------------------------- /app/policies/medal_awarder_policy.rb: -------------------------------------------------------------------------------- 1 | class MedalAwarderPolicy < ApplicationPolicy 2 | 3 | def awards? 4 | (!record.game.invite_only || 5 | record.game.participating?(user) || 6 | record.game.creator_id == user.try(:id)) && 7 | record.game.completed? 8 | end 9 | end -------------------------------------------------------------------------------- /app/views/api/search/index.json.jbuilder: -------------------------------------------------------------------------------- 1 | json.hits do 2 | json.array! ( 3 | json.things @things, partial: 'api/things/thing', as: :thing 4 | ) 5 | end 6 | json.total @total 7 | json.page @current_page 8 | json.per_page @per_page 9 | json.total_pages @total_pages 10 | -------------------------------------------------------------------------------- /spec/factories/things.rb: -------------------------------------------------------------------------------- 1 | FactoryGirl.define do 2 | factory :thing do 3 | title { "Little Monkey" } 4 | description { "Monkeys are clearly the coolest things on Earth." } 5 | image { File.open(File.join(Rails.root, '/spec/support/images/monkey.jpg')) } 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /app/policies/board_policy.rb: -------------------------------------------------------------------------------- 1 | class BoardPolicy < ApplicationPolicy 2 | def index? 3 | true 4 | end 5 | 6 | def create? 7 | user.admin? 8 | end 9 | 10 | def update? 11 | user.admin? 12 | end 13 | 14 | def destroy? 15 | user.admin? 16 | end 17 | end -------------------------------------------------------------------------------- /db/migrate/20140625001441_add_link_descriptions_to_resemblances.rb: -------------------------------------------------------------------------------- 1 | class AddLinkDescriptionsToResemblances < ActiveRecord::Migration 2 | def change 3 | add_column :resemblances, :link_description, :text 4 | add_column :resemblances, :target_description, :text 5 | end 6 | end 7 | -------------------------------------------------------------------------------- /app/mailers/user_mailer.rb: -------------------------------------------------------------------------------- 1 | class UserMailer < ActionMailer::Base 2 | default from: "feedback@sembl.net" 3 | 4 | # Player has just created an account: 5 | # TODO 6 | def welcome(user_id) 7 | @user = User.find(user_id) 8 | 9 | mail to: @user.email 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /app/views/api/moves/_move.json.jbuilder: -------------------------------------------------------------------------------- 1 | json.target_node do 2 | json.partial! 'api/moves/node', node: move.target_node, placement: move.placement 3 | end 4 | json.links move.links do |json, link| 5 | json.partial! 'api/moves/link', link: link, move: move, include_rating: false 6 | end 7 | -------------------------------------------------------------------------------- /app/views/api/ratings/_move.json.jbuilder: -------------------------------------------------------------------------------- 1 | json.target_node do 2 | json.partial! 'api/moves/node', node: move.target_node, placement: move.placement 3 | end 4 | json.links move.links do |json, link| 5 | json.partial! 'api/moves/link', link: link, move: move, include_rating: true 6 | end 7 | -------------------------------------------------------------------------------- /db/migrate/20131017231832_create_players.rb: -------------------------------------------------------------------------------- 1 | class CreatePlayers < ActiveRecord::Migration 2 | def change 3 | create_table :players do |t| 4 | t.references :game 5 | t.references :user 6 | t.float :score 7 | t.timestamps 8 | end 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /vendor/assets/stylesheets/bourbon/functions/_compact.scss: -------------------------------------------------------------------------------- 1 | // Remove `false` values from a list 2 | 3 | @function compact($vars...) { 4 | $list: (); 5 | @each $var in $vars { 6 | @if $var { 7 | $list: append($list, $var, comma); 8 | } 9 | } 10 | @return $list; 11 | } 12 | -------------------------------------------------------------------------------- /app/assets/javascripts/collections/links.js.coffee: -------------------------------------------------------------------------------- 1 | #= require models/link 2 | 3 | class Sembl.Links extends Backbone.Collection 4 | model: Sembl.Link 5 | 6 | comparator: (link) -> 7 | link.source().get('x') 8 | 9 | initialize: (models, options) -> 10 | @game = options?.game 11 | 12 | -------------------------------------------------------------------------------- /app/models/thing_search_null_fallback.rb: -------------------------------------------------------------------------------- 1 | class ThingSearchNullFallback 2 | def initialize(*) 3 | end 4 | 5 | def total 6 | 0 7 | end 8 | 9 | def results 10 | Results.new 11 | end 12 | 13 | class Results 14 | def total_pages 15 | 0 16 | end 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /app/views/game_mailer/game_started.text.erb: -------------------------------------------------------------------------------- 1 | The game '<%= @game.title %>' has begun! Come and make your first move: 2 | 3 | <%= game_url(@game) %> 4 | 5 | Regards, 6 | 7 | - Sembl 8 | 9 | 10 | 11 | If you have a question, comment or concern, please email feedback@sembl.net or tweet @semblnet 12 | -------------------------------------------------------------------------------- /app/views/api/players/_invited_player.json.jbuilder: -------------------------------------------------------------------------------- 1 | # we include player email address because only the admin of a game should see these. 2 | json.(player, :id, :email, :state, :move_state, :score) 3 | 4 | if player.user 5 | json.user do 6 | json.partial! 'api/users/user', user: player.user 7 | end 8 | end -------------------------------------------------------------------------------- /app/views/devise/mailer/unlock_instructions.html.slim: -------------------------------------------------------------------------------- 1 | p 2 | | Hello #{@resource.email}! 3 | p Your account has been locked due to an excessive number of unsuccessful sign in attempts. 4 | p Click the link below to unlock your account: 5 | p= link_to 'Unlock my account', unlock_url(@resource, :unlock_token => @token) 6 | -------------------------------------------------------------------------------- /vendor/assets/stylesheets/bourbon/css3/_perspective.scss: -------------------------------------------------------------------------------- 1 | @mixin perspective($depth: none) { 2 | // none | 3 | @include prefixer(perspective, $depth, webkit moz spec); 4 | } 5 | 6 | @mixin perspective-origin($value: 50% 50%) { 7 | @include prefixer(perspective-origin, $value, webkit moz spec); 8 | } 9 | -------------------------------------------------------------------------------- /vendor/assets/stylesheets/bourbon/functions/_px-to-em.scss: -------------------------------------------------------------------------------- 1 | // Convert pixels to ems 2 | // eg. for a relational value of 12px write em(12) when the parent is 16px 3 | // if the parent is another value say 24px write em(12, 24) 4 | 5 | @function em($pxval, $base: 16) { 6 | @return ($pxval / $base) * 1em; 7 | } 8 | 9 | -------------------------------------------------------------------------------- /app/assets/javascripts/collections/board_nodes.js.coffee: -------------------------------------------------------------------------------- 1 | #= require models/board_node 2 | 3 | class Sembl.BoardNodes extends Backbone.Collection 4 | model: Sembl.BoardNode 5 | 6 | initialize: (models, options) -> 7 | @board = options?.board 8 | 9 | selected: -> 10 | @findWhere(selected: true) 11 | -------------------------------------------------------------------------------- /config/boot.rb: -------------------------------------------------------------------------------- 1 | # Set up gems listed in the Gemfile. 2 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__) 3 | 4 | require 'bundler/setup' if File.exists?(ENV['BUNDLE_GEMFILE']) 5 | 6 | if File.exists?(File.expand_path('../../.env', __FILE__)) 7 | require 'dotenv' 8 | Dotenv.load 9 | end 10 | -------------------------------------------------------------------------------- /db/migrate/20131017044432_create_nodes.rb: -------------------------------------------------------------------------------- 1 | class CreateNodes < ActiveRecord::Migration 2 | def change 3 | create_table :nodes do |t| 4 | t.references :game 5 | t.integer :round 6 | t.string :state 7 | t.references :allocated_to 8 | t.timestamps 9 | end 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /app/mailers/admin/user_mailer.rb: -------------------------------------------------------------------------------- 1 | class Admin::UserMailer < ActionMailer::Base 2 | default from: "Sembl " 3 | def email_message(options) 4 | @user = User.find(options[:user_id]) 5 | @message_content = options[:content] 6 | mail(to: @user.email, subject: options[:subject]) 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /app/views/api/links/_link.json.jbuilder: -------------------------------------------------------------------------------- 1 | json.(link, :id, :source_id, :target_id, :round) 2 | json.viewable_resemblance do 3 | if link.viewable_resemblance(current_user).nil? 4 | json.nil! 5 | else 6 | json.partial! 'api/resemblances/resemblance', resemblance: link.viewable_resemblance(current_user) 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /app/views/games/show.html.slim: -------------------------------------------------------------------------------- 1 | #container Loading game... 2 | 3 | javascript: 4 | $(document).ready(function() { 5 | Sembl.game = new Sembl.Game(#{raw(render(template: "api/games/show", formats: :json, object: @game))}); 6 | Sembl.router = new Sembl.GameRouter(Sembl.game); 7 | Backbone.history.start(); 8 | }); 9 | -------------------------------------------------------------------------------- /db/migrate/20131017045458_create_ratings.rb: -------------------------------------------------------------------------------- 1 | class CreateRatings < ActiveRecord::Migration 2 | def change 3 | create_table :ratings do |t| 4 | t.float :rating 5 | t.references :resemblance, index: true 6 | t.references :creator, index: true 7 | t.timestamps 8 | end 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /app/views/game_mailer/game_completed.text.erb: -------------------------------------------------------------------------------- 1 | Game over! Congratulations on completing the game '<%= @game.title %>'. Go see the results! 2 | 3 | <%= game_url(@game) %> 4 | 5 | Regards, 6 | 7 | - Sembl 8 | 9 | 10 | 11 | If you have a question, comment or concern, please email feedback@sembl.net or tweet @semblnet 12 | -------------------------------------------------------------------------------- /db/migrate/20131017044440_create_links.rb: -------------------------------------------------------------------------------- 1 | class CreateLinks < ActiveRecord::Migration 2 | def change 3 | create_table :links do |t| 4 | t.references :source, index: true 5 | t.references :target, index: true 6 | t.references :game, index: true 7 | t.timestamps 8 | end 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /vendor/assets/stylesheets/bourbon/functions/_tint-shade.scss: -------------------------------------------------------------------------------- 1 | // Add percentage of white to a color 2 | @function tint($color, $percent){ 3 | @return mix(white, $color, $percent); 4 | } 5 | 6 | // Add percentage of black to a color 7 | @function shade($color, $percent){ 8 | @return mix(black, $color, $percent); 9 | } 10 | -------------------------------------------------------------------------------- /db/migrate/20141014031053_add_que.rb: -------------------------------------------------------------------------------- 1 | class AddQue < ActiveRecord::Migration 2 | def self.up 3 | # The current version as of this migration's creation. 4 | Que.migrate! :version => 3 5 | end 6 | 7 | def self.down 8 | # Completely removes Que's job queue. 9 | Que.migrate! :version => 0 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /db/migrate/20141125225629_add_moderated_flag_to_things.rb: -------------------------------------------------------------------------------- 1 | class AddModeratedFlagToThings < ActiveRecord::Migration 2 | def up 3 | add_column :things, :moderated, :boolean, default: false 4 | Thing.update_all(moderated: false) 5 | end 6 | 7 | def down 8 | remove_column :things, :moderated 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /app/models/profile.rb: -------------------------------------------------------------------------------- 1 | class Profile < ActiveRecord::Base 2 | belongs_to :user 3 | 4 | accepts_nested_attributes_for :user 5 | 6 | mount_uploader :avatar, AvatarUploader 7 | 8 | def display_name 9 | if self.name.present? 10 | self.name 11 | else 12 | self.user.email[0] 13 | end 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /config/database.yml: -------------------------------------------------------------------------------- 1 | development: &base 2 | adapter: postgresql 3 | database: sembl_development 4 | encoding: unicode 5 | host: localhost 6 | password: 7 | 8 | production: 9 | <<: *base 10 | 11 | test: 12 | adapter: postgresql 13 | database: sembl_test 14 | encoding: unicode 15 | host: localhost 16 | password: 17 | -------------------------------------------------------------------------------- /app/assets/javascripts/collections/players.js.coffee: -------------------------------------------------------------------------------- 1 | #= require models/player 2 | 3 | class Sembl.Players extends Backbone.Collection 4 | model: Sembl.Player 5 | 6 | initialize: (models, options) -> 7 | @game = options?.game 8 | 9 | comparator: (player) -> 10 | score = player.get('score') || 0 11 | 100 - (score*100) 12 | 13 | -------------------------------------------------------------------------------- /app/assets/javascripts/models/board.js.coffee: -------------------------------------------------------------------------------- 1 | #= require collections/board_nodes 2 | #= require collections/board_links 3 | 4 | class Sembl.Board extends Backbone.Model 5 | initialize: (options) -> 6 | @nodes = new Sembl.BoardNodes(@get("nodes_attributes"), board: this) 7 | @links = new Sembl.BoardLinks(@get("links_attributes"), board: this) 8 | -------------------------------------------------------------------------------- /prov/rails/tasks/update_locale.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: dev locale 3 | become: true 4 | become_user: root 5 | locale_gen: name=en_US.UTF-8 state=present 6 | 7 | - name: set default locale 8 | become: true 9 | become_user: root 10 | lineinfile: dest=/etc/default/locale 11 | regexp="LC_ALL" 12 | line="LC_ALL=\"en_US.UTF-8\"" 13 | -------------------------------------------------------------------------------- /prov/vagrant-guest/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: change to /vagrant directory automatically 3 | lineinfile: 4 | create: yes 5 | dest: /home/vagrant/foo 6 | line: bar 7 | 8 | - name: change to /vagrant directory automatically 9 | lineinfile: 10 | create: yes 11 | dest: /home/vagrant/.bashrc 12 | line: cd /vagrant 13 | -------------------------------------------------------------------------------- /app/policies/placement_policy.rb: -------------------------------------------------------------------------------- 1 | class PlacementPolicy < ApplicationPolicy 2 | 3 | def create? 4 | record.node.available_to?(user) 5 | end 6 | 7 | def update? 8 | user.try(:id) == record.creator_id && 9 | record.node.game.player(user).playing_turn? 10 | end 11 | 12 | def destroy? 13 | update? 14 | end 15 | 16 | end -------------------------------------------------------------------------------- /db/migrate/20140226011705_add_move_state_to_players.rb: -------------------------------------------------------------------------------- 1 | class AddMoveStateToPlayers < ActiveRecord::Migration 2 | def change 3 | add_column :players, :move_state, :string 4 | 5 | Player.reset_column_information 6 | Player.find_each do |player| 7 | player.move_state = 'open' 8 | player.save! 9 | end 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /db/migrate/20141126002824_alter_column_for_thing_moderation.rb: -------------------------------------------------------------------------------- 1 | class AlterColumnForThingModeration < ActiveRecord::Migration 2 | def up 3 | remove_column :things, :moderated 4 | add_column :things, :moderator_approved, :boolean 5 | end 6 | 7 | def down 8 | remove_column :things, :moderator_approved, :boolean 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /lib/templates/slim/scaffold/_form.html.slim: -------------------------------------------------------------------------------- 1 | = simple_form_for(@<%= singular_table_name %>) do |f| 2 | = f.error_notification 3 | 4 | .form-inputs 5 | <%- attributes.each do |attribute| -%> 6 | = f.<%= attribute.reference? ? :association : :input %> :<%= attribute.name %> 7 | <%- end -%> 8 | 9 | .form-actions 10 | = f.button :submit 11 | -------------------------------------------------------------------------------- /db/migrate/20131017044451_create_placements.rb: -------------------------------------------------------------------------------- 1 | class CreatePlacements < ActiveRecord::Migration 2 | def change 3 | create_table :placements do |t| 4 | t.string :state, null: false 5 | t.references :thing 6 | t.references :node 7 | t.references :creator, index: true 8 | t.timestamps 9 | end 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /app/assets/javascripts/collections/results.js.coffee: -------------------------------------------------------------------------------- 1 | #= require models/result 2 | 3 | class Sembl.Results extends Backbone.Collection 4 | url: -> 5 | root = "/api/games/#{@game.id}/results/#{@round}.json" 6 | 7 | model: Sembl.Result 8 | 9 | initialize: (models, options) -> 10 | @game = options?.game 11 | @round = options?.round 12 | 13 | -------------------------------------------------------------------------------- /app/assets/javascripts/views/games/move/placement_modal.js.jsx.coffee: -------------------------------------------------------------------------------- 1 | #= require views/components/thing_modal 2 | 3 | ###* @jsx React.DOM ### 4 | 5 | {ThingModal} = Sembl.Components 6 | 7 | @Sembl.Games.Move.PlacementModal = React.createClass 8 | render: () -> 9 | thing = @props.thing 10 | ` 11 | ` 12 | -------------------------------------------------------------------------------- /app/views/api/nodes/_node.json.jbuilder: -------------------------------------------------------------------------------- 1 | json.(node, :id, :round, :x, :y, :state) 2 | json.user_state node.user_state(current_user) 3 | json.viewable_placement do 4 | if node.viewable_placement(current_user).nil? 5 | json.nil! 6 | else 7 | json.partial! 'api/placements/placement', placement: node.viewable_placement(current_user) 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /app/assets/stylesheets/turn-off-animations.css.scss: -------------------------------------------------------------------------------- 1 | * { 2 | -webkit-transition: none !important; 3 | -moz-transition: none !important; 4 | -ms-transition: none !important; 5 | -o-transition: none !important; 6 | transition: none !important; 7 | animation-name: nothing !important; 8 | -webkit-animation-name: nothing !important; 9 | } 10 | -------------------------------------------------------------------------------- /app/models/board.rb: -------------------------------------------------------------------------------- 1 | class Board < ActiveRecord::Base 2 | validates :title, presence: true 3 | validates :number_of_players, numericality: {greater_than: 0} 4 | 5 | belongs_to :creator, class_name: "User" 6 | belongs_to :updator, class_name: "User" 7 | 8 | def title_with_players 9 | "#{title}: #{number_of_players } players" 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /vendor/assets/stylesheets/bourbon/addons/_font-family.scss: -------------------------------------------------------------------------------- 1 | $georgia: Georgia, Cambria, "Times New Roman", Times, serif; 2 | $helvetica: "Helvetica Neue", Helvetica, Arial, sans-serif; 3 | $lucida-grande: "Lucida Grande", Tahoma, Verdana, Arial, sans-serif; 4 | $monospace: "Bitstream Vera Sans Mono", Consolas, Courier, monospace; 5 | $verdana: Verdana, Geneva, sans-serif; 6 | -------------------------------------------------------------------------------- /app/views/api/users/_user.json.jbuilder: -------------------------------------------------------------------------------- 1 | json.(user, :id, :email, :role) 2 | json.(user.profile, :name, :bio) 3 | json.profile_id(user.profile.id) 4 | json.avatar_thumb user.profile.avatar.try(:thumb).try(:url) 5 | json.avatar_tiny_thumb user.profile.avatar.try(:tiny_thumb).try(:url) 6 | json.admin(user.admin?) 7 | json.power(user.power?) 8 | json.has_moved(user.has_moved?) 9 | -------------------------------------------------------------------------------- /db/migrate/20131015025606_create_things.rb: -------------------------------------------------------------------------------- 1 | class CreateThings < ActiveRecord::Migration 2 | def change 3 | create_table :things do |t| 4 | t.string :title, null: false 5 | t.text :description, default: "" 6 | t.references :creator, index: true 7 | t.references :updator, index: true 8 | t.timestamps 9 | end 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /vendor/assets/stylesheets/bourbon/css3/_backface-visibility.scss: -------------------------------------------------------------------------------- 1 | //************************************************************************// 2 | // Backface-visibility mixin 3 | //************************************************************************// 4 | @mixin backface-visibility($visibility) { 5 | @include prefixer(backface-visibility, $visibility, webkit spec); 6 | } 7 | -------------------------------------------------------------------------------- /db/migrate/20131015070339_create_boards.rb: -------------------------------------------------------------------------------- 1 | class CreateBoards < ActiveRecord::Migration 2 | def change 3 | create_table :boards do |t| 4 | t.string :title, null: false 5 | t.integer :number_of_players, null: false 6 | t.references :creator, index: true 7 | t.references :updator, index: true 8 | t.timestamps 9 | end 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /db/migrate/20131127020914_add_random_seed_to_games.rb: -------------------------------------------------------------------------------- 1 | class AddRandomSeedToGames < ActiveRecord::Migration 2 | def change 3 | add_column :games, :random_seed, :integer 4 | 5 | Game.reset_column_information 6 | 7 | Game.find_each do |game| 8 | game.random_seed = SecureRandom.random_number(2147483646) 9 | game.save! 10 | end 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /vendor/assets/stylesheets/bourbon/helpers/_shape-size-stripper.scss: -------------------------------------------------------------------------------- 1 | @function _shape-size-stripper($shape-size) { 2 | $shape-size-spec: null; 3 | @each $value in $shape-size { 4 | @if ($value == "cover") or ($value == "contain") { 5 | $value: null; 6 | } 7 | $shape-size-spec: "#{$shape-size-spec} #{$value}"; 8 | } 9 | @return $shape-size-spec; 10 | } 11 | -------------------------------------------------------------------------------- /app/assets/javascripts/models/board_node.js.coffee: -------------------------------------------------------------------------------- 1 | class Sembl.BoardNode extends Backbone.Model 2 | defaults: 3 | x: 200 4 | y: 200 5 | round: 0 6 | 7 | isSelected: -> 8 | !!@get("selected") 9 | 10 | select: -> 11 | @set "selected", true 12 | 13 | deselect: -> 14 | @set "selected", false 15 | 16 | toJSON: -> 17 | _(super).omit("selected") 18 | -------------------------------------------------------------------------------- /app/views/user_mailer/welcome.text.erb: -------------------------------------------------------------------------------- 1 | Welcome, novice Sembler! 2 | 3 | May you find joy and connectedness in the games as in life. 4 | 5 | Feel free to [link: ask a question or leave a comment], and we'll respond as best we can. 6 | 7 | Cheerios, 8 | 9 | - Sembl 10 | 11 | 12 | 13 | If you have a question, comment or concern, please email feedback@sembl.net or tweet @semblnet 14 | -------------------------------------------------------------------------------- /db/migrate/20131017044414_create_games.rb: -------------------------------------------------------------------------------- 1 | class CreateGames < ActiveRecord::Migration 2 | def change 3 | create_table :games do |t| 4 | t.references :board 5 | t.string :title, null: false 6 | t.text :description 7 | 8 | t.references :creator, index: true 9 | t.references :updator, index: true 10 | t.timestamps 11 | end 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /db/migrate/20131127230252_change_coordinates_on_node.rb: -------------------------------------------------------------------------------- 1 | class ChangeCoordinatesOnNode < ActiveRecord::Migration 2 | def change 3 | rename_column :nodes, :position_x, :x 4 | rename_column :nodes, :position_y, :y 5 | 6 | change_column :nodes, :x, :integer, null: false, default: 0 7 | change_column :nodes, :y, :integer, null: false, default: 0 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /lib/tasks/game_reminders.rake: -------------------------------------------------------------------------------- 1 | namespace :sembl do 2 | task send_game_reminders: [:environment] do 3 | Player.requiring_invitation_reminder.each(&:deliver_invitation_reminder) 4 | Player.requiring_turn_reminder.each(&:deliver_turn_reminder) 5 | Game.requiring_stale_and_incomplete_player_set_notification.each(&:deliver_stale_and_incomplete_player_set_notifications) 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /config/sunspot.yml: -------------------------------------------------------------------------------- 1 | production: 2 | solr: 3 | log_level: WARNING 4 | # read_timeout: 2 5 | # open_timeout: 0.5 6 | 7 | development: 8 | solr: 9 | hostname: localhost 10 | port: 8982 11 | log_level: INFO 12 | path: /solr/development 13 | 14 | test: 15 | solr: 16 | hostname: localhost 17 | port: 8981 18 | log_level: WARNING 19 | path: /solr/test 20 | -------------------------------------------------------------------------------- /app/views/api/resemblances/_resemblance.json.jbuilder: -------------------------------------------------------------------------------- 1 | json.id resemblance.try(:id) 2 | json.description resemblance.try(:description) 3 | json.score resemblance.try(:score) 4 | json.source_description resemblance.try(:source_description) 5 | json.target_description resemblance.try(:target_description) 6 | 7 | json.user do 8 | json.partial! 'api/users/user', user: resemblance.try(:creator) 9 | end 10 | -------------------------------------------------------------------------------- /db/migrate/20131017045438_create_resemblances.rb: -------------------------------------------------------------------------------- 1 | class CreateResemblances < ActiveRecord::Migration 2 | def change 3 | create_table :resemblances do |t| 4 | t.text :description, null: false 5 | t.string :state, null: false 6 | t.float :score 7 | t.references :link, index: true 8 | t.references :creator, index: true 9 | t.timestamps 10 | end 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /spec/features/creating_games_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | feature "Creating games", js: true do 4 | let!(:user1) { FactoryGirl.create(:user) } 5 | let!(:user2) { FactoryGirl.create(:user) } 6 | let!(:user3) { FactoryGirl.create(:user) } 7 | 8 | scenario "Creating a game" do 9 | create_game user1, "Animals" 10 | # debugger 11 | # page.driver.debug 12 | end 13 | 14 | end 15 | -------------------------------------------------------------------------------- /app/assets/javascripts/collections/board_links.js.coffee: -------------------------------------------------------------------------------- 1 | #= require models/board_link 2 | 3 | class Sembl.BoardLinks extends Backbone.Collection 4 | model: Sembl.BoardLink 5 | 6 | initialize: (models, options) -> 7 | @board = options?.board 8 | 9 | between: (a, b) -> 10 | @find (link) -> 11 | (link.source == a and link.target == b) or 12 | (link.source == b and link.target == a) 13 | -------------------------------------------------------------------------------- /db/migrate/20131120045222_add_attributes_to_things.rb: -------------------------------------------------------------------------------- 1 | class AddAttributesToThings < ActiveRecord::Migration 2 | def change 3 | add_column :things, :attribution, :string 4 | add_column :things, :item_url, :string 5 | add_column :things, :copyright, :string 6 | add_column :things, :attributes, :json, null: false, default: "[]" 7 | change_column :things, :title, :string, null: true 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /vendor/assets/javascripts/viewloader.js: -------------------------------------------------------------------------------- 1 | window.viewloader = { 2 | execute: function( views, $scope ) { 3 | var $els = $scope ? $scope.find( "[data-view]" ) : $( "[data-view]" ); 4 | 5 | $els.each( function( i, el ) { 6 | var $el = $( el ); 7 | var view = $el.data( "view" ); 8 | if ( view && views[ view ] ) { 9 | views[ view ]( $el, el ); 10 | } 11 | }); 12 | } 13 | }; 14 | -------------------------------------------------------------------------------- /vendor/assets/stylesheets/bourbon/css3/_image-rendering.scss: -------------------------------------------------------------------------------- 1 | @mixin image-rendering ($mode:optimizeQuality) { 2 | 3 | @if ($mode == optimize-contrast) { 4 | image-rendering: -moz-crisp-edges; 5 | image-rendering: -o-crisp-edges; 6 | image-rendering: -webkit-optimize-contrast; 7 | image-rendering: optimize-contrast; 8 | } 9 | 10 | @else { 11 | image-rendering: $mode; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /db/migrate/20140415064148_create_profiles.rb: -------------------------------------------------------------------------------- 1 | class CreateProfiles < ActiveRecord::Migration 2 | def change 3 | create_table :profiles do |t| 4 | t.references :user 5 | t.string :name 6 | t.text :bio 7 | t.string :avatar 8 | end 9 | 10 | User.find_each do |user| 11 | p = Profile.create(name: user.email.split('@')[0], user: user) 12 | p.save! 13 | end 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /db/migrate/20141012220934_add_state_changed_at_to_games.rb: -------------------------------------------------------------------------------- 1 | class AddStateChangedAtToGames < ActiveRecord::Migration 2 | def up 3 | add_column :games, :state_changed_at, :datetime, null: false, default: "NOW()" 4 | 5 | Game.find_each do |game| 6 | game.update_column :state_changed_at, game.updated_at 7 | end 8 | end 9 | 10 | def down 11 | remove_column :games, :state_changed_at 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /app/views/devise/mailer/reset_password_instructions.html.slim: -------------------------------------------------------------------------------- 1 | p 2 | | Hello #{@resource.email}! 3 | p Someone has requested a link to change your password. You can do this through the link below. 4 | p= link_to 'Change my password', edit_password_url(@resource, :reset_password_token => @token) 5 | p If you didn't request this, please ignore this email. 6 | p Your password won't change until you access the link above and create a new one. 7 | -------------------------------------------------------------------------------- /bin/ri: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # 3 | # This file was generated by Bundler. 4 | # 5 | # The application 'ri' is installed as part of a gem, and 6 | # this file is here to facilitate running it. 7 | # 8 | 9 | require 'pathname' 10 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", 11 | Pathname.new(__FILE__).realpath) 12 | 13 | require 'rubygems' 14 | require 'bundler/setup' 15 | 16 | load Gem.bin_path('rdoc', 'ri') 17 | -------------------------------------------------------------------------------- /bin/fog: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # 3 | # This file was generated by Bundler. 4 | # 5 | # The application 'fog' is installed as part of a gem, and 6 | # this file is here to facilitate running it. 7 | # 8 | 9 | require 'pathname' 10 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", 11 | Pathname.new(__FILE__).realpath) 12 | 13 | require 'rubygems' 14 | require 'bundler/setup' 15 | 16 | load Gem.bin_path('fog', 'fog') 17 | -------------------------------------------------------------------------------- /bin/pry: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # 3 | # This file was generated by Bundler. 4 | # 5 | # The application 'pry' is installed as part of a gem, and 6 | # this file is here to facilitate running it. 7 | # 8 | 9 | require 'pathname' 10 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", 11 | Pathname.new(__FILE__).realpath) 12 | 13 | require 'rubygems' 14 | require 'bundler/setup' 15 | 16 | load Gem.bin_path('pry', 'pry') 17 | -------------------------------------------------------------------------------- /bin/rake: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # 3 | # This file was generated by Bundler. 4 | # 5 | # The application 'rake' is installed as part of a gem, and 6 | # this file is here to facilitate running it. 7 | # 8 | 9 | require 'pathname' 10 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", 11 | Pathname.new(__FILE__).realpath) 12 | 13 | require 'rubygems' 14 | require 'bundler/setup' 15 | 16 | load Gem.bin_path('rake', 'rake') 17 | -------------------------------------------------------------------------------- /bin/rdoc: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # 3 | # This file was generated by Bundler. 4 | # 5 | # The application 'rdoc' is installed as part of a gem, and 6 | # this file is here to facilitate running it. 7 | # 8 | 9 | require 'pathname' 10 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", 11 | Pathname.new(__FILE__).realpath) 12 | 13 | require 'rubygems' 14 | require 'bundler/setup' 15 | 16 | load Gem.bin_path('rdoc', 'rdoc') 17 | -------------------------------------------------------------------------------- /bin/sass: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # 3 | # This file was generated by Bundler. 4 | # 5 | # The application 'sass' is installed as part of a gem, and 6 | # this file is here to facilitate running it. 7 | # 8 | 9 | require 'pathname' 10 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", 11 | Pathname.new(__FILE__).realpath) 12 | 13 | require 'rubygems' 14 | require 'bundler/setup' 15 | 16 | load Gem.bin_path('sass', 'sass') 17 | -------------------------------------------------------------------------------- /bin/scss: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # 3 | # This file was generated by Bundler. 4 | # 5 | # The application 'scss' is installed as part of a gem, and 6 | # this file is here to facilitate running it. 7 | # 8 | 9 | require 'pathname' 10 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", 11 | Pathname.new(__FILE__).realpath) 12 | 13 | require 'rubygems' 14 | require 'bundler/setup' 15 | 16 | load Gem.bin_path('sass', 'scss') 17 | -------------------------------------------------------------------------------- /bin/sdoc: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # 3 | # This file was generated by Bundler. 4 | # 5 | # The application 'sdoc' is installed as part of a gem, and 6 | # this file is here to facilitate running it. 7 | # 8 | 9 | require 'pathname' 10 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", 11 | Pathname.new(__FILE__).realpath) 12 | 13 | require 'rubygems' 14 | require 'bundler/setup' 15 | 16 | load Gem.bin_path('sdoc', 'sdoc') 17 | -------------------------------------------------------------------------------- /bin/thor: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # 3 | # This file was generated by Bundler. 4 | # 5 | # The application 'thor' is installed as part of a gem, and 6 | # this file is here to facilitate running it. 7 | # 8 | 9 | require 'pathname' 10 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", 11 | Pathname.new(__FILE__).realpath) 12 | 13 | require 'rubygems' 14 | require 'bundler/setup' 15 | 16 | load Gem.bin_path('thor', 'thor') 17 | -------------------------------------------------------------------------------- /bin/tilt: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # 3 | # This file was generated by Bundler. 4 | # 5 | # The application 'tilt' is installed as part of a gem, and 6 | # this file is here to facilitate running it. 7 | # 8 | 9 | require 'pathname' 10 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", 11 | Pathname.new(__FILE__).realpath) 12 | 13 | require 'rubygems' 14 | require 'bundler/setup' 15 | 16 | load Gem.bin_path('tilt', 'tilt') 17 | -------------------------------------------------------------------------------- /bin/tt: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # 3 | # This file was generated by Bundler. 4 | # 5 | # The application 'tt' is installed as part of a gem, and 6 | # this file is here to facilitate running it. 7 | # 8 | 9 | require 'pathname' 10 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", 11 | Pathname.new(__FILE__).realpath) 12 | 13 | require 'rubygems' 14 | require 'bundler/setup' 15 | 16 | load Gem.bin_path('treetop', 'tt') 17 | -------------------------------------------------------------------------------- /db/migrate/20131127020944_change_random_seed_on_things.rb: -------------------------------------------------------------------------------- 1 | class ChangeRandomSeedOnThings < ActiveRecord::Migration 2 | def change 3 | remove_column :things, :random_seed 4 | add_column :things, :random_seed, :integer 5 | 6 | Thing.reset_column_information 7 | 8 | Thing.find_each do |thing| 9 | thing.random_seed = SecureRandom.random_number(2147483646) 10 | thing.save! 11 | end 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /spec/support/devise_acceptance_helper.rb: -------------------------------------------------------------------------------- 1 | module DeviseAcceptanceHelper 2 | def login user 3 | visit new_user_session_path 4 | fill_in "Email", with: user.email 5 | fill_in "Password", with: user.password 6 | click_button "Sign in" 7 | end 8 | 9 | def logout 10 | click "Sign out" 11 | end 12 | end 13 | 14 | RSpec.configure do |config| 15 | config.include DeviseAcceptanceHelper, type: :feature 16 | end 17 | -------------------------------------------------------------------------------- /app/views/devise/unlocks/new.html.slim: -------------------------------------------------------------------------------- 1 | h2 Resend unlock instructions 2 | = simple_form_for(resource, :as => resource_name, :url => unlock_path(resource_name), :html => { :method => :post }) do |f| 3 | = f.error_notification 4 | = f.full_error :unlock_token 5 | .form-inputs 6 | = f.input :email, :required => true, :autofocus => true 7 | .form-actions 8 | = f.button :submit, "Resend unlock instructions" 9 | = render "links" 10 | -------------------------------------------------------------------------------- /bin/guard: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # 3 | # This file was generated by Bundler. 4 | # 5 | # The application 'guard' is installed as part of a gem, and 6 | # this file is here to facilitate running it. 7 | # 8 | 9 | require 'pathname' 10 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", 11 | Pathname.new(__FILE__).realpath) 12 | 13 | require 'rubygems' 14 | require 'bundler/setup' 15 | 16 | load Gem.bin_path('guard', 'guard') 17 | -------------------------------------------------------------------------------- /app/assets/stylesheets/components/animations.css.scss: -------------------------------------------------------------------------------- 1 | // Set up for animations in the default layout 2 | 3 | .animation-wrapper {} 4 | 5 | // .body-leave { 6 | // position: absolute; 7 | // top: 25px; 8 | // top: 2.5rem; 9 | // left: 20px; 10 | // left: 2rem; 11 | // right: 20px; 12 | // right: 2rem; 13 | // } 14 | 15 | .header-leave { 16 | position: absolute; 17 | top: 0; 18 | left: 0; 19 | right: 0; 20 | } 21 | 22 | -------------------------------------------------------------------------------- /bin/byebug: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # 3 | # This file was generated by Bundler. 4 | # 5 | # The application 'byebug' is installed as part of a gem, and 6 | # this file is here to facilitate running it. 7 | # 8 | 9 | require 'pathname' 10 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", 11 | Pathname.new(__FILE__).realpath) 12 | 13 | require 'rubygems' 14 | require 'bundler/setup' 15 | 16 | load Gem.bin_path('byebug', 'byebug') 17 | -------------------------------------------------------------------------------- /bin/dotenv: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # 3 | # This file was generated by Bundler. 4 | # 5 | # The application 'dotenv' is installed as part of a gem, and 6 | # this file is here to facilitate running it. 7 | # 8 | 9 | require 'pathname' 10 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", 11 | Pathname.new(__FILE__).realpath) 12 | 13 | require 'rubygems' 14 | require 'bundler/setup' 15 | 16 | load Gem.bin_path('dotenv', 'dotenv') 17 | -------------------------------------------------------------------------------- /bin/erubis: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # 3 | # This file was generated by Bundler. 4 | # 5 | # The application 'erubis' is installed as part of a gem, and 6 | # this file is here to facilitate running it. 7 | # 8 | 9 | require 'pathname' 10 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", 11 | Pathname.new(__FILE__).realpath) 12 | 13 | require 'rubygems' 14 | require 'bundler/setup' 15 | 16 | load Gem.bin_path('erubis', 'erubis') 17 | -------------------------------------------------------------------------------- /bin/ldiff: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # 3 | # This file was generated by Bundler. 4 | # 5 | # The application 'ldiff' is installed as part of a gem, and 6 | # this file is here to facilitate running it. 7 | # 8 | 9 | require 'pathname' 10 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", 11 | Pathname.new(__FILE__).realpath) 12 | 13 | require 'rubygems' 14 | require 'bundler/setup' 15 | 16 | load Gem.bin_path('diff-lcs', 'ldiff') 17 | -------------------------------------------------------------------------------- /bin/listen: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # 3 | # This file was generated by Bundler. 4 | # 5 | # The application 'listen' is installed as part of a gem, and 6 | # this file is here to facilitate running it. 7 | # 8 | 9 | require 'pathname' 10 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", 11 | Pathname.new(__FILE__).realpath) 12 | 13 | require 'rubygems' 14 | require 'bundler/setup' 15 | 16 | load Gem.bin_path('listen', 'listen') 17 | -------------------------------------------------------------------------------- /bin/rackup: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # 3 | # This file was generated by Bundler. 4 | # 5 | # The application 'rackup' is installed as part of a gem, and 6 | # this file is here to facilitate running it. 7 | # 8 | 9 | require 'pathname' 10 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", 11 | Pathname.new(__FILE__).realpath) 12 | 13 | require 'rubygems' 14 | require 'bundler/setup' 15 | 16 | load Gem.bin_path('rack', 'rackup') 17 | -------------------------------------------------------------------------------- /bin/rails: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # 3 | # This file was generated by Bundler. 4 | # 5 | # The application 'rails' is installed as part of a gem, and 6 | # this file is here to facilitate running it. 7 | # 8 | 9 | require 'pathname' 10 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", 11 | Pathname.new(__FILE__).realpath) 12 | 13 | require 'rubygems' 14 | require 'bundler/setup' 15 | 16 | load Gem.bin_path('railties', 'rails') 17 | -------------------------------------------------------------------------------- /bin/rspec: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # 3 | # This file was generated by Bundler. 4 | # 5 | # The application 'rspec' is installed as part of a gem, and 6 | # this file is here to facilitate running it. 7 | # 8 | 9 | require 'pathname' 10 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", 11 | Pathname.new(__FILE__).realpath) 12 | 13 | require 'rubygems' 14 | require 'bundler/setup' 15 | 16 | load Gem.bin_path('rspec-core', 'rspec') 17 | -------------------------------------------------------------------------------- /bin/slimrb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # 3 | # This file was generated by Bundler. 4 | # 5 | # The application 'slimrb' is installed as part of a gem, and 6 | # this file is here to facilitate running it. 7 | # 8 | 9 | require 'pathname' 10 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", 11 | Pathname.new(__FILE__).realpath) 12 | 13 | require 'rubygems' 14 | require 'bundler/setup' 15 | 16 | load Gem.bin_path('slim', 'slimrb') 17 | -------------------------------------------------------------------------------- /db/migrate/20141013000902_add_state_changed_at_to_players.rb: -------------------------------------------------------------------------------- 1 | class AddStateChangedAtToPlayers < ActiveRecord::Migration 2 | def up 3 | add_column :players, :state_changed_at, :datetime, null: false, default: "NOW()" 4 | 5 | Player.find_each do |player| 6 | player.update_column :state_changed_at, player.updated_at 7 | end 8 | end 9 | 10 | def down 11 | remove_column :players, :state_changed_at 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /bin/bundler: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # 3 | # This file was generated by Bundler. 4 | # 5 | # The application 'bundler' is installed as part of a gem, and 6 | # this file is here to facilitate running it. 7 | # 8 | 9 | require 'pathname' 10 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", 11 | Pathname.new(__FILE__).realpath) 12 | 13 | require 'rubygems' 14 | require 'bundler/setup' 15 | 16 | load Gem.bin_path('bundler', 'bundler') 17 | -------------------------------------------------------------------------------- /bin/coderay: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # 3 | # This file was generated by Bundler. 4 | # 5 | # The application 'coderay' is installed as part of a gem, and 6 | # this file is here to facilitate running it. 7 | # 8 | 9 | require 'pathname' 10 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", 11 | Pathname.new(__FILE__).realpath) 12 | 13 | require 'rubygems' 14 | require 'bundler/setup' 15 | 16 | load Gem.bin_path('coderay', 'coderay') 17 | -------------------------------------------------------------------------------- /bin/launchy: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # 3 | # This file was generated by Bundler. 4 | # 5 | # The application 'launchy' is installed as part of a gem, and 6 | # this file is here to facilitate running it. 7 | # 8 | 9 | require 'pathname' 10 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", 11 | Pathname.new(__FILE__).realpath) 12 | 13 | require 'rubygems' 14 | require 'bundler/setup' 15 | 16 | load Gem.bin_path('launchy', 'launchy') 17 | -------------------------------------------------------------------------------- /bin/unicorn: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # 3 | # This file was generated by Bundler. 4 | # 5 | # The application 'unicorn' is installed as part of a gem, and 6 | # this file is here to facilitate running it. 7 | # 8 | 9 | require 'pathname' 10 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", 11 | Pathname.new(__FILE__).realpath) 12 | 13 | require 'rubygems' 14 | require 'bundler/setup' 15 | 16 | load Gem.bin_path('unicorn', 'unicorn') 17 | -------------------------------------------------------------------------------- /db/migrate/20131018043025_add_config_options_to_games.rb: -------------------------------------------------------------------------------- 1 | class AddConfigOptionsToGames < ActiveRecord::Migration 2 | def change 3 | add_column :games, :invite_only, :boolean, default: false 4 | add_column :games, :uploads_allowed, :boolean, default: false 5 | add_column :games, :theme, :string 6 | add_column :games, :filter_content_by, :text 7 | add_column :games, :allow_keyword_search, :boolean, default: false 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /db/migrate/20140224031647_add_source_and_target_to_resemblance.rb: -------------------------------------------------------------------------------- 1 | class AddSourceAndTargetToResemblance < ActiveRecord::Migration 2 | def up 3 | add_reference :resemblances, :source, index: true, class_name: "Placement" 4 | add_reference :resemblances, :target, index: true, class_name: "Placement" 5 | end 6 | 7 | def down 8 | remove_reference :resemblances, :source 9 | remove_reference :resemblances, :target 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /prov/rails/defaults/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | ruby_install_major_version: 0 3 | ruby_install_minor_version: 5 4 | ruby_install_patch_version: 0 5 | 6 | ruby_install_version: "{{ ruby_install_major_version }}.{{ ruby_install_minor_version }}.{{ ruby_install_patch_version }}" 7 | 8 | ruby_major_version: 2 9 | ruby_minor_version: 0 10 | ruby_patch_version: 0 11 | 12 | ruby_version: "{{ ruby_major_version }}.{{ ruby_minor_version }}.{{ ruby_patch_version }}" 13 | -------------------------------------------------------------------------------- /app/views/api/things/_thing.json.jbuilder: -------------------------------------------------------------------------------- 1 | json.(@thing || thing, 2 | :id, 3 | :title, 4 | :description, 5 | :copyright, 6 | :attribution, 7 | :access_via, 8 | :item_url, 9 | :dates, 10 | :keywords, 11 | :places, 12 | :node_type 13 | ) 14 | 15 | json.image_admin_url (@thing || thing).image.admin_thumb.url 16 | json.image_large_url (@thing || thing).image.large.url 17 | json.image_browse_url (@thing || thing).image.browse_thumb.url 18 | -------------------------------------------------------------------------------- /bin/autospec: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # 3 | # This file was generated by Bundler. 4 | # 5 | # The application 'autospec' is installed as part of a gem, and 6 | # this file is here to facilitate running it. 7 | # 8 | 9 | require 'pathname' 10 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", 11 | Pathname.new(__FILE__).realpath) 12 | 13 | require 'rubygems' 14 | require 'bundler/setup' 15 | 16 | load Gem.bin_path('rspec-core', 'autospec') 17 | -------------------------------------------------------------------------------- /bin/htmldiff: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # 3 | # This file was generated by Bundler. 4 | # 5 | # The application 'htmldiff' is installed as part of a gem, and 6 | # this file is here to facilitate running it. 7 | # 8 | 9 | require 'pathname' 10 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", 11 | Pathname.new(__FILE__).realpath) 12 | 13 | require 'rubygems' 14 | require 'bundler/setup' 15 | 16 | load Gem.bin_path('diff-lcs', 'htmldiff') 17 | -------------------------------------------------------------------------------- /bin/newrelic: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # 3 | # This file was generated by Bundler. 4 | # 5 | # The application 'newrelic' is installed as part of a gem, and 6 | # this file is here to facilitate running it. 7 | # 8 | 9 | require 'pathname' 10 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", 11 | Pathname.new(__FILE__).realpath) 12 | 13 | require 'rubygems' 14 | require 'bundler/setup' 15 | 16 | load Gem.bin_path('newrelic_rpm', 'newrelic') 17 | -------------------------------------------------------------------------------- /bin/nokogiri: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # 3 | # This file was generated by Bundler. 4 | # 5 | # The application 'nokogiri' is installed as part of a gem, and 6 | # this file is here to facilitate running it. 7 | # 8 | 9 | require 'pathname' 10 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", 11 | Pathname.new(__FILE__).realpath) 12 | 13 | require 'rubygems' 14 | require 'bundler/setup' 15 | 16 | load Gem.bin_path('nokogiri', 'nokogiri') 17 | -------------------------------------------------------------------------------- /bin/nrdebug: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # 3 | # This file was generated by Bundler. 4 | # 5 | # The application 'nrdebug' is installed as part of a gem, and 6 | # this file is here to facilitate running it. 7 | # 8 | 9 | require 'pathname' 10 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", 11 | Pathname.new(__FILE__).realpath) 12 | 13 | require 'rubygems' 14 | require 'bundler/setup' 15 | 16 | load Gem.bin_path('newrelic_rpm', 'nrdebug') 17 | -------------------------------------------------------------------------------- /bin/premailer: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # 3 | # This file was generated by Bundler. 4 | # 5 | # The application 'premailer' is installed as part of a gem, and 6 | # this file is here to facilitate running it. 7 | # 8 | 9 | require 'pathname' 10 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", 11 | Pathname.new(__FILE__).realpath) 12 | 13 | require 'rubygems' 14 | require 'bundler/setup' 15 | 16 | load Gem.bin_path('premailer', 'premailer') 17 | -------------------------------------------------------------------------------- /bin/sdoc-merge: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # 3 | # This file was generated by Bundler. 4 | # 5 | # The application 'sdoc-merge' is installed as part of a gem, and 6 | # this file is here to facilitate running it. 7 | # 8 | 9 | require 'pathname' 10 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", 11 | Pathname.new(__FILE__).realpath) 12 | 13 | require 'rubygems' 14 | require 'bundler/setup' 15 | 16 | load Gem.bin_path('sdoc', 'sdoc-merge') 17 | -------------------------------------------------------------------------------- /bin/sprockets: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # 3 | # This file was generated by Bundler. 4 | # 5 | # The application 'sprockets' is installed as part of a gem, and 6 | # this file is here to facilitate running it. 7 | # 8 | 9 | require 'pathname' 10 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", 11 | Pathname.new(__FILE__).realpath) 12 | 13 | require 'rubygems' 14 | require 'bundler/setup' 15 | 16 | load Gem.bin_path('sprockets', 'sprockets') 17 | -------------------------------------------------------------------------------- /config/database.example.yml: -------------------------------------------------------------------------------- 1 | development: &base 2 | adapter: postgresql 3 | database: sembl_development 4 | encoding: unicode 5 | port: <%= ENV["BOXEN_POSTGRESQL_PORT"] || 5432 %> 6 | host: localhost 7 | password: 8 | 9 | production: 10 | <<: *base 11 | 12 | test: 13 | adapter: postgresql 14 | database: sembl_test 15 | encoding: unicode 16 | port: <%= ENV["BOXEN_POSTGRESQL_PORT"] || 5432 %> 17 | host: localhost 18 | password: 19 | -------------------------------------------------------------------------------- /vendor/assets/stylesheets/bourbon/functions/_linear-gradient.scss: -------------------------------------------------------------------------------- 1 | @function linear-gradient($pos, $gradients...) { 2 | $type: linear; 3 | $pos-type: type-of(nth($pos, 1)); 4 | 5 | // if $pos doesn't exist, fix $gradient 6 | @if ($pos-type == color) or (nth($pos, 1) == "transparent") { 7 | $gradients: zip($pos $gradients); 8 | $pos: false; 9 | } 10 | 11 | $type-gradient: $type, $pos, $gradients; 12 | @return $type-gradient; 13 | } 14 | -------------------------------------------------------------------------------- /bin/restclient: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # 3 | # This file was generated by Bundler. 4 | # 5 | # The application 'restclient' is installed as part of a gem, and 6 | # this file is here to facilitate running it. 7 | # 8 | 9 | require 'pathname' 10 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", 11 | Pathname.new(__FILE__).realpath) 12 | 13 | require 'rubygems' 14 | require 'bundler/setup' 15 | 16 | load Gem.bin_path('rest-client', 'restclient') 17 | -------------------------------------------------------------------------------- /bin/sass-convert: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # 3 | # This file was generated by Bundler. 4 | # 5 | # The application 'sass-convert' is installed as part of a gem, and 6 | # this file is here to facilitate running it. 7 | # 8 | 9 | require 'pathname' 10 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", 11 | Pathname.new(__FILE__).realpath) 12 | 13 | require 'rubygems' 14 | require 'bundler/setup' 15 | 16 | load Gem.bin_path('sass', 'sass-convert') 17 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /bin/mongrel_rpm: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # 3 | # This file was generated by Bundler. 4 | # 5 | # The application 'mongrel_rpm' is installed as part of a gem, and 6 | # this file is here to facilitate running it. 7 | # 8 | 9 | require 'pathname' 10 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", 11 | Pathname.new(__FILE__).realpath) 12 | 13 | require 'rubygems' 14 | require 'bundler/setup' 15 | 16 | load Gem.bin_path('newrelic_rpm', 'mongrel_rpm') 17 | -------------------------------------------------------------------------------- /bin/unicorn_rails: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # 3 | # This file was generated by Bundler. 4 | # 5 | # The application 'unicorn_rails' is installed as part of a gem, and 6 | # this file is here to facilitate running it. 7 | # 8 | 9 | require 'pathname' 10 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", 11 | Pathname.new(__FILE__).realpath) 12 | 13 | require 'rubygems' 14 | require 'bundler/setup' 15 | 16 | load Gem.bin_path('unicorn', 'unicorn_rails') 17 | -------------------------------------------------------------------------------- /app/assets/javascripts/views/games/gameboard/resemblance_factory.js.jsx.coffee: -------------------------------------------------------------------------------- 1 | ###* @jsx React.DOM ### 2 | 3 | Sembl.Games.Gameboard.ResemblanceFactory = class ResemblanceFactory 4 | constructor: (linkModels, @resemblanceClass) -> 5 | @lookup = {} 6 | for model in linkModels 7 | @lookup[model.id] = model 8 | 9 | createComponent: (dataWithId, props = {}) -> 10 | link = @lookup[dataWithId.id] 11 | @resemblanceClass(_.extend {link: link}, props) 12 | -------------------------------------------------------------------------------- /app/views/devise/confirmations/new.html.slim: -------------------------------------------------------------------------------- 1 | h2 Resend confirmation instructions 2 | = simple_form_for(resource, :as => resource_name, :url => confirmation_path(resource_name), :html => { :method => :post }) do |f| 3 | = f.error_notification 4 | = f.full_error :confirmation_token 5 | .form-inputs 6 | = f.input :email, :required => true, :autofocus => true 7 | .form-actions 8 | = f.button :submit, "Resend confirmation instructions" 9 | = render "links" 10 | -------------------------------------------------------------------------------- /bin/newrelic_cmd: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # 3 | # This file was generated by Bundler. 4 | # 5 | # The application 'newrelic_cmd' is installed as part of a gem, and 6 | # this file is here to facilitate running it. 7 | # 8 | 9 | require 'pathname' 10 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", 11 | Pathname.new(__FILE__).realpath) 12 | 13 | require 'rubygems' 14 | require 'bundler/setup' 15 | 16 | load Gem.bin_path('newrelic_rpm', 'newrelic_cmd') 17 | -------------------------------------------------------------------------------- /app/policies/rating_policy.rb: -------------------------------------------------------------------------------- 1 | class RatingPolicy < ApplicationPolicy 2 | 3 | # The record here is the game. 4 | # This should probably use some sort of scope policy but I can't work out how ATM 5 | def index? 6 | record.participating?(user) 7 | end 8 | 9 | def create? 10 | # TODO: enable fix this! 11 | # record.resemblance.creator_id != user.id && 12 | # record.resemblance.link.game.participating?(user) 13 | true 14 | end 15 | 16 | end 17 | -------------------------------------------------------------------------------- /spec/support/pundit_matcher.rb: -------------------------------------------------------------------------------- 1 | RSpec::Matchers.define :permit do |action| 2 | match do |policy| 3 | policy.public_send("#{action}?") 4 | end 5 | 6 | failure_message_for_should do |policy| 7 | "#{policy.class} does not permit #{action} on #{policy.record} for #{policy.user.inspect}." 8 | end 9 | 10 | failure_message_for_should_not do |policy| 11 | "#{policy.class} does not forbid #{action} on #{policy.record} for #{policy.user.inspect}." 12 | end 13 | end -------------------------------------------------------------------------------- /app/assets/javascripts/views/games/index.js.jsx.coffee: -------------------------------------------------------------------------------- 1 | ###* @jsx React.DOM ### 2 | 3 | @Sembl.views.gameIndex = ($el, el) -> 4 | html = $el.html() 5 | header = $el.data().header 6 | 7 | @layout = React.renderComponent( 8 | Sembl.Layouts.Default() 9 | document.getElementsByTagName('body')[0] 10 | ) 11 | @layout.setProps 12 | body: `
`, 13 | header: Sembl.Games.HeaderView(model: Sembl.game, title: header) 14 | 15 | -------------------------------------------------------------------------------- /app/views/api/results/_award.json.jbuilder: -------------------------------------------------------------------------------- 1 | json.(award, :name, :icon, :result_name, :result) 2 | 3 | json.player do 4 | json.partial! 'api/players/player', player: award[:player] 5 | end 6 | 7 | # json.result do 8 | # if false #award[:result].class == Resemblance 9 | # # TODO: new resemblance partial to show target and source nodes? 10 | # json.partial! 'api/resemblances/resemblance', resemblance: award[:result] 11 | # else 12 | # award[:result] 13 | # end 14 | # end 15 | -------------------------------------------------------------------------------- /app/views/devise/passwords/new.html.slim: -------------------------------------------------------------------------------- 1 | .header 2 | .heading 3 | h1 Forgot your password? 4 | = simple_form_for(resource, :as => resource_name, :url => password_path(resource_name), :html => { :method => :post }) do |f| 5 | .sign-in-form 6 | = f.error_notification 7 | .form-inputs 8 | = f.input :email, :required => true, :autofocus => true 9 | .form-actions 10 | = f.button :submit, "Send reset password email", class: "sign-in-button" 11 | = render "links" 12 | -------------------------------------------------------------------------------- /vendor/assets/stylesheets/image_area_select.css.scss: -------------------------------------------------------------------------------- 1 | .imgareaselect-border1, .imgareaselect-border2, 2 | .imgareaselect-border3, .imgareaselect-border4 { 3 | filter: alpha(opacity=50); 4 | opacity: 0.5; 5 | } 6 | 7 | .imgareaselect-handle { 8 | background-color: #fff; 9 | border: solid 1px #000; 10 | filter: alpha(opacity=50); 11 | opacity: 0.5; 12 | } 13 | 14 | .imgareaselect-outer { 15 | background-color: #000; 16 | filter: alpha(opacity=50); 17 | opacity: 0.5; 18 | } 19 | -------------------------------------------------------------------------------- /app/policies/resemblance_policy.rb: -------------------------------------------------------------------------------- 1 | class ResemblancePolicy < ApplicationPolicy 2 | 3 | def create? 4 | record.link.available_to?(user) 5 | end 6 | 7 | def update? 8 | user.id == record.creator_id && 9 | record.link.game.player(user).playing_turn? 10 | end 11 | 12 | def destroy? 13 | update? 14 | end 15 | 16 | def rate? 17 | record.creator_id != user.id && 18 | record.game.rating? && 19 | record.game.participating?(user) 20 | end 21 | 22 | end 23 | -------------------------------------------------------------------------------- /config/transloadit.yml: -------------------------------------------------------------------------------- 1 | development: &CONFIG 2 | auth: 3 | key: "<%= ENV['TRANSLOADIT_AUTH_KEY'] %>" 4 | secret: "<%= ENV['TRANSLOADIT_AUTH_SECRET'] %>" 5 | duration: 1800 # 30 minute validity period for signed upload forms 6 | 7 | templates: 8 | things_store_original: "<%= ENV['TRANSLOADIT_THINGS_STORE_ORIGINAL_TEMPLATE_ID'] %>" 9 | things_crop: "<%= ENV['TRANSLOADIT_THINGS_CROP_TEMPLATE_ID'] %>" 10 | 11 | test: 12 | <<: *CONFIG 13 | 14 | production: 15 | <<: *CONFIG 16 | -------------------------------------------------------------------------------- /app/assets/stylesheets/patterns/_smooth-font-loading.scss: -------------------------------------------------------------------------------- 1 | // Smooth font loading 2 | // 3 | // Used in tandem with Modernizr.load function to hide common 4 | // text elements until Typekit has loaded. 5 | // 6 | @mixin smooth-font-loading { 7 | h1, h2, h3, h4, h5, h6, ol, p, ul, a, dl, blockquote, li, iframe, .aside { 8 | @include transition(opacity 100ms linear); 9 | opacity: auto; 10 | .js.wf-loading & { 11 | opacity: 0; 12 | *visibility: hidden !important; 13 | } 14 | } 15 | } -------------------------------------------------------------------------------- /app/models/concerns/random_fixed_orderable.rb: -------------------------------------------------------------------------------- 1 | module RandomFixedOrderable 2 | extend ActiveSupport::Concern 3 | 4 | included do 5 | before_create :generate_random_seed 6 | end 7 | 8 | # XOR operator is # in postgres 9 | module ClassMethods 10 | def random_fixed_order(seed) 11 | order("(things.random_seed # #{seed})") 12 | end 13 | end 14 | 15 | private 16 | 17 | def generate_random_seed 18 | self.random_seed = SecureRandom.random_number(2147483646) 19 | end 20 | end 21 | -------------------------------------------------------------------------------- /db/migrate/20141014013558_add_reminder_count_for_state_to_games.rb: -------------------------------------------------------------------------------- 1 | class AddReminderCountForStateToGames < ActiveRecord::Migration 2 | def up 3 | add_column :games, :reminder_count_for_state, :integer, null: false, default: 0 4 | 5 | # Set this to a high number to start with, so that none of the existing records trigger notification emails 6 | Game.update_all(reminder_count_for_state: 10) 7 | end 8 | 9 | def down 10 | remove_column :games, :reminder_count_for_state 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /spec/support/controller_helpers.rb: -------------------------------------------------------------------------------- 1 | module ControllerHelpers 2 | def sign_in_user(user = double('user')) 3 | if user.nil? 4 | request.env['warden'].stub(:authenticate!).and_throw(:warden, { scope: :user }) 5 | controller.stub current_user: nil 6 | else 7 | request.env['warden'].stub authenticate!: user 8 | controller.stub current_user: user 9 | end 10 | end 11 | end 12 | 13 | RSpec.configure do |config| 14 | config.include ControllerHelpers, type: :controller 15 | end 16 | -------------------------------------------------------------------------------- /app/policies/player_policy.rb: -------------------------------------------------------------------------------- 1 | class PlayerPolicy < ApplicationPolicy 2 | 3 | def create? 4 | !!user && (user.id == record.game.creator_id || user.admin?) && (record.game.needs_more_players?) 5 | end 6 | 7 | def destroy? 8 | puts 'destroy' 9 | puts 'user', user.inspect 10 | puts 'game', record.game.inspect 11 | puts 'admin', user.admin? 12 | puts 'draft', record.game.draft? 13 | !!user && (user.id == record.game.creator_id || user.admin?) && !record.has_moved? 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /db/migrate/20141013004024_add_reminder_count_for_state_to_players.rb: -------------------------------------------------------------------------------- 1 | class AddReminderCountForStateToPlayers < ActiveRecord::Migration 2 | def up 3 | add_column :players, :reminder_count_for_state, :integer, null: false, default: 0 4 | 5 | # Set this to a high number to start with, so that none of the existing records trigger notification emails 6 | Player.update_all(reminder_count_for_state: 10) 7 | end 8 | 9 | def down 10 | remove_column :players, :reminder_count_for_state 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /app/views/devise/sessions/new.html.slim: -------------------------------------------------------------------------------- 1 | .header 2 | .heading 3 | h1 Sign in 4 | = simple_form_for(resource, :as => resource_name, :url => session_path(resource_name)) do |f| 5 | .sign-in-form 6 | .form-inputs 7 | = f.input :email, :required => false, :autofocus => true 8 | = f.input :password, :required => false 9 | = f.input :remember_me, :as => :boolean if devise_mapping.rememberable? 10 | .form-actions 11 | = f.button :submit, "Sign in", class: "sign-in-button" 12 | = render "links" 13 | -------------------------------------------------------------------------------- /vendor/assets/stylesheets/bourbon/functions/_grid-width.scss: -------------------------------------------------------------------------------- 1 | @function grid-width($n) { 2 | @return $n * $gw-column + ($n - 1) * $gw-gutter; 3 | } 4 | 5 | // The $gw-column and $gw-gutter variables must be defined in your base stylesheet to properly use the grid-width function. 6 | // 7 | // $gw-column: 100px; // Column Width 8 | // $gw-gutter: 40px; // Gutter Width 9 | // 10 | // div { 11 | // width: grid-width(4); // returns 520px; 12 | // margin-left: $gw-gutter; // returns 40px; 13 | // } 14 | -------------------------------------------------------------------------------- /app/admin/player.rb: -------------------------------------------------------------------------------- 1 | ActiveAdmin.register Player do 2 | config.sort_order = "updated_at_desc" 3 | 4 | filter :id 5 | 6 | index do 7 | id_column 8 | actions 9 | end 10 | 11 | show do 12 | attributes_table do 13 | row :game do 14 | link_to player.game.title, admin_game_path(player.game) 15 | end 16 | if player.user.present? 17 | row :user do 18 | link_to player.user.email, admin_user_path(player.user) 19 | end 20 | end 21 | end 22 | end 23 | end 24 | -------------------------------------------------------------------------------- /db/migrate/20140430080056_add_mature_and_sensitive_to_things.rb: -------------------------------------------------------------------------------- 1 | class AddMatureAndSensitiveToThings < ActiveRecord::Migration 2 | def up 3 | add_column :things, :sensitive, :boolean, default: false 4 | add_column :things, :mature, :boolean, default: false 5 | 6 | Thing.all.each do |thing| 7 | thing.mature = false 8 | thing.sensitive = false 9 | thing.save! 10 | end 11 | end 12 | 13 | def down 14 | remove_column :things, :sensitive 15 | remove_column :things, :mature 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /spec/factories/users.rb: -------------------------------------------------------------------------------- 1 | FactoryGirl.define do 2 | factory :user do 3 | email { Forgery(:email).address } 4 | password { Forgery(:basic).password(at_least: 8) } 5 | password_confirmation { password } 6 | after(:create) do |user| 7 | user.profile.name = Forgery(:lorem_ipsum).words(2) 8 | user.profile.save! 9 | end 10 | 11 | trait :admin do 12 | role_event { 'make_admin' } 13 | end 14 | 15 | trait :power_user do 16 | role_event { 'make_power_user' } 17 | end 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /vendor/assets/stylesheets/bourbon/css3/_hidpi-media-query.scss: -------------------------------------------------------------------------------- 1 | // HiDPI mixin. Default value set to 1.3 to target Google Nexus 7 (http://bjango.com/articles/min-device-pixel-ratio/) 2 | @mixin hidpi($ratio: 1.3) { 3 | @media only screen and (-webkit-min-device-pixel-ratio: $ratio), 4 | only screen and (min--moz-device-pixel-ratio: $ratio), 5 | only screen and (-o-min-device-pixel-ratio: #{$ratio}/1), 6 | only screen and (min-resolution: #{round($ratio*96)}dpi), 7 | only screen and (min-resolution: #{$ratio}dppx) { 8 | @content; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /spec/features/home_page_spec.rb: -------------------------------------------------------------------------------- 1 | require "spec_helper" 2 | 3 | describe "Home page", js: true do 4 | let!(:game) { FactoryGirl.create(:game_with_nodes, title: "My game, yo", state: "open") } 5 | 6 | before do 7 | visit "/" 8 | end 9 | 10 | context "User is not signed in" do 11 | it "show sign in and sign up links" do 12 | expect(page).to have_content "SIGN IN" 13 | expect(page).to have_content "SIGN UP" 14 | end 15 | it "shows open games" do 16 | expect(page).to have_content "My game, yo" 17 | end 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /app/models/thing_search_fallback.rb: -------------------------------------------------------------------------------- 1 | class ThingSearchFallback < ThingSearch 2 | def initialize(*) 3 | super 4 | 5 | @text = negate_fulltext(text) if text.present? 6 | @place_filter = negate_fulltext(place_filter) if place_filter.present? 7 | @access_filter = negate_fulltext(access_filter) if access_filter.present? 8 | end 9 | 10 | def requires_fallback? 11 | false 12 | end 13 | 14 | private 15 | 16 | def negate_fulltext(text) 17 | text.gsub(/[^A-Za-z]/, "").split.map { |word| "-#{word}" }.join(" ") 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /app/assets/javascripts/views/games/gameboard/game_header_view.js.jsx.coffee: -------------------------------------------------------------------------------- 1 | #= require views/games/header_view 2 | 3 | ###* @jsx React.DOM ### 4 | 5 | HeaderView = Sembl.Games.HeaderView 6 | Sembl.Games.Gameboard.GameHeaderView = React.createBackboneClass 7 | render: -> 8 | round = `
9 | Round 10 | 11 | {this.model().get('current_round')} 12 | 13 |
` 14 | 15 | 16 | @transferPropsTo `` 17 | -------------------------------------------------------------------------------- /app/assets/stylesheets/components/_pagination.css.scss: -------------------------------------------------------------------------------- 1 | // Pagination 2 | 3 | .pagination { 4 | @extend %clearfix-overflow; 5 | @include inset(vert, normal); 6 | clear: both; 7 | border: 1px solid lighten($border-color, 5%); 8 | border-radius: $border-radius; 9 | > span { 10 | border-right: 1px solid lighten($border-color, 5%); 11 | float: left; 12 | } 13 | > span.current, 14 | a { 15 | @include pad(horz, normal); 16 | @include pad(vert, smaller); 17 | display: block; 18 | } 19 | span.current { 20 | background-color: #fff; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /app/views/api/placements/_placement.json.jbuilder: -------------------------------------------------------------------------------- 1 | json.score placement.score 2 | json.(placement, :created_at) 3 | json.thing_id placement.try(:thing).try(:id) 4 | json.image_url placement.try(:thing).try(:image).try(:url) 5 | json.image_thumb_url placement.try(:thing).try(:image).try(:browse_thumb).try(:url) 6 | json.title placement.try(:thing).try(:title) 7 | json.thing do 8 | json.partial! 'api/things/thing', thing: placement.thing 9 | end 10 | if placement.creator.present? 11 | json.creator do 12 | json.partial! 'api/users/user', user: placement.creator 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /app/assets/javascripts/views/utils/utils.js.coffee: -------------------------------------------------------------------------------- 1 | @Sembl.Utils.genUUID = -> 2 | time = new Date().getTime() 3 | 4 | uuid = 'xxxxxxxxxxxx4xxxyxxxxxxxxxxxxxxx'.replace /[xy]/g, (char) -> 5 | random = (time + Math.random() * 16) % 16 | 0 6 | time = Math.floor(time / 16) 7 | (if char is 'x' then random else (random & 0x7 | 0x8)).toString(16) 8 | 9 | uuid 10 | 11 | @Sembl.Utils.PROTOCOL = if document.location.protocol is 'https:' then 'https' else 'http' 12 | 13 | String.prototype.camelToUnderscore = -> 14 | @replace /([a-z][A-Z])/g, (g) -> g[0] + '_' + g[1].toLowerCase() 15 | 16 | -------------------------------------------------------------------------------- /.env.example: -------------------------------------------------------------------------------- 1 | APP_NAME="Sembl" 2 | AWS_ACCESS_KEY_ID="" 3 | AWS_SECRET_ACCESS_KEY="" 4 | BUGSNAG_API_KEY="" 5 | CLOUDFRONT_DOMAIN="sembl-development.s3-ap-southeast-2.amazonaws.com" 6 | DEVISE_SECRET_TOKEN="run rake secret" 7 | DOMAIN="sembl.dev" 8 | EMAIL_SENDER_ADDRESS="hello@icelab.com.au" 9 | FOG_DIRECTORY="sembl-development" 10 | FOG_PROVIDER="AWS" 11 | FOG_REGION="ap-southeast-2" 12 | TRANSLOADIT_AUTH_KEY="" 13 | TRANSLOADIT_AUTH_SECRET="" 14 | TRANSLOADIT_THINGS_STORE_ORIGINAL_TEMPLATE_ID="" 15 | TRANSLOADIT_THINGS_CROP_TEMPLATE_ID="" 16 | HOSTLESS_UNJOINED_STALE_TIME="" 17 | SECRET_KEY_BASE="" 18 | -------------------------------------------------------------------------------- /app/assets/javascripts/views/components/tooltip.js.jsx.coffee: -------------------------------------------------------------------------------- 1 | ###* @jsx React.DOM ### 2 | 3 | @Sembl.Components.Tooltip = React.createClass 4 | 5 | getInitialState: -> 6 | hidden: false 7 | 8 | handleHide: (event) -> 9 | event.preventDefault() 10 | @setState hidden: true 11 | 12 | render: -> 13 | hidden = if @state.hidden then "hidden" else "" 14 | 15 | ` 19 |
{this.props.children}
20 |
` 21 | -------------------------------------------------------------------------------- /app/controllers/registrations_controller.rb: -------------------------------------------------------------------------------- 1 | class RegistrationsController < Devise::RegistrationsController 2 | protected 3 | 4 | # This is called by Devise's registrations contolonly after a successful 5 | # sign up. We override it here so we can send a welcome email. 6 | def sign_up(resource_name, resource) 7 | super 8 | 9 | UserMailer.welcome(resource).deliver 10 | DeliverEmailJob.enqueue("UserMailer", "welcome", resource.id) 11 | end 12 | 13 | def after_sign_up_path_for(resource) 14 | edit_profile_path(new_user: true, for_game: params[:for_game]) 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /app/models/link.rb: -------------------------------------------------------------------------------- 1 | class Link < ActiveRecord::Base 2 | belongs_to :game 3 | belongs_to :source, class_name: Node 4 | belongs_to :target, class_name: Node 5 | has_many :resemblances, dependent: :destroy 6 | 7 | def round 8 | target.round 9 | end 10 | 11 | def player_resemblance(user) 12 | resemblances.with_state(:proposed).where(creator: user).take unless !user 13 | end 14 | 15 | def final_resemblance 16 | resemblances.with_state(:final).take 17 | end 18 | 19 | def viewable_resemblance(user) 20 | final_resemblance || player_resemblance(user) 21 | end 22 | end 23 | -------------------------------------------------------------------------------- /vendor/assets/stylesheets/bourbon/helpers/_gradient-positions-parser.scss: -------------------------------------------------------------------------------- 1 | @function _gradient-positions-parser($gradient-type, $gradient-positions) { 2 | @if $gradient-positions 3 | and ($gradient-type == linear) 4 | and (type-of($gradient-positions) != color) { 5 | $gradient-positions: _linear-positions-parser($gradient-positions); 6 | } 7 | @else if $gradient-positions 8 | and ($gradient-type == radial) 9 | and (type-of($gradient-positions) != color) { 10 | $gradient-positions: _radial-positions-parser($gradient-positions); 11 | } 12 | @return $gradient-positions; 13 | } 14 | -------------------------------------------------------------------------------- /config/initializers/wrap_parameters.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # This file contains settings for ActionController::ParamsWrapper which 4 | # is enabled by default. 5 | 6 | # Enable parameter wrapping for JSON. You can disable this by setting :format to an empty array. 7 | ActiveSupport.on_load(:action_controller) do 8 | wrap_parameters format: [:json] if respond_to?(:wrap_parameters) 9 | end 10 | 11 | # To enable root element in JSON for ActiveRecord objects. 12 | # ActiveSupport.on_load(:active_record) do 13 | # self.include_root_in_json = true 14 | # end 15 | -------------------------------------------------------------------------------- /vendor/assets/stylesheets/bourbon/css3/_transform.scss: -------------------------------------------------------------------------------- 1 | @mixin transform($property: none) { 2 | // none | 3 | @include prefixer(transform, $property, webkit moz ms o spec); 4 | } 5 | 6 | @mixin transform-origin($axes: 50%) { 7 | // x-axis - left | center | right | length | % 8 | // y-axis - top | center | bottom | length | % 9 | // z-axis - length 10 | @include prefixer(transform-origin, $axes, webkit moz ms o spec); 11 | } 12 | 13 | @mixin transform-style ($style: flat) { 14 | @include prefixer(transform-style, $style, webkit moz ms o spec); 15 | } 16 | -------------------------------------------------------------------------------- /prov/rails/tasks/packages.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: install aptitude 3 | apt: 4 | name: aptitude 5 | become: true 6 | become_user: root 7 | 8 | # - name: bring system up to date 9 | # apt: update_cache=yes upgrade=yes 10 | # sudo: yes 11 | 12 | - name: install packages 13 | apt: 14 | pkg: "{{ item }}" 15 | with_items: 16 | - git 17 | - language-pack-en 18 | - libsqlite3-dev 19 | - postgresql 20 | - postgresql-contrib 21 | - libpq-dev 22 | - python-psycopg2 23 | - nodejs 24 | - imagemagick 25 | - solr-common 26 | become: true 27 | become_user: root 28 | -------------------------------------------------------------------------------- /app/assets/javascripts/views/games/gameboard/placement_factory.js.jsx.coffee: -------------------------------------------------------------------------------- 1 | ###* @jsx React.DOM ### 2 | 3 | Sembl.Games.Gameboard.PlacementFactory = class PlacementFactory 4 | constructor: (nodeModels, @nodeClass) -> 5 | @lookup = {} 6 | for model in nodeModels 7 | @lookup[model.id] = model 8 | 9 | createComponent: (dataWithId) -> 10 | node = @lookup[dataWithId.id] 11 | nodeClass = @nodeClass 12 | delay = parseInt(Math.random()*10) 13 | className = "game__placement-wrapper delay-#{delay}" 14 | `
15 | 16 |
` 17 | -------------------------------------------------------------------------------- /config/initializers/secret_token.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Your secret key is used for verifying the integrity of signed cookies. 4 | # If you change this key, all old signed cookies will become invalid! 5 | 6 | # Make sure the secret is at least 30 characters and all random, 7 | # no regular words or you'll be exposed to dictionary attacks. 8 | # You can use `rake secret` to generate a secure secret key. 9 | 10 | # Make sure your secret_key_base is kept private 11 | # if you're sharing your code publicly. 12 | Sembl::Application.config.secret_key_base = ENV["SECRET_KEY_BASE"] 13 | -------------------------------------------------------------------------------- /vendor/assets/stylesheets/bourbon/helpers/_radial-positions-parser.scss: -------------------------------------------------------------------------------- 1 | @function _radial-positions-parser($gradient-pos) { 2 | $shape-size: nth($gradient-pos, 1); 3 | $pos: nth($gradient-pos, 2); 4 | $shape-size-spec: _shape-size-stripper($shape-size); 5 | 6 | $pre-spec: unquote(if($pos, "#{$pos}, ", null)) 7 | unquote(if($shape-size, "#{$shape-size},", null)); 8 | $pos-spec: if($pos, "at #{$pos}", null); 9 | 10 | $spec: "#{$shape-size-spec} #{$pos-spec}"; 11 | 12 | // Add comma 13 | @if ($spec != ' ') { 14 | $spec: "#{$spec}," 15 | } 16 | 17 | @return $pre-spec $spec; 18 | } 19 | -------------------------------------------------------------------------------- /bin/setup: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Set up Rails app. Run this script immediately after cloning the codebase. 4 | 5 | # Set up Ruby dependencies 6 | bundle install -j4 7 | 8 | # Set up staging and production git remotes 9 | git remote add production git@heroku.com:sembl.git 10 | 11 | # Copy config files into place 12 | cp .env.example .env 13 | 14 | sed -i '/^SECRET_KEY_BASE=/d' .env 15 | bin/rake secret | awk '{print "SECRET_KEY_BASE=" $0}' >> .env 16 | 17 | sed -i '/^PORT=/d' .env 18 | 'PORT="3000"' >> .env 19 | 20 | cp config/database.example.yml config/database.yml 21 | 22 | # Set up database 23 | bundle exec rake db:setup 24 | -------------------------------------------------------------------------------- /app/assets/javascripts/views/board/board_link_view.js.coffee: -------------------------------------------------------------------------------- 1 | class Sembl.BoardLinkView extends Backbone.RaphaelView 2 | el: -> 3 | @paper.path().toBack() 4 | .attr 5 | "stroke": "#999" 6 | "stroke-width": "4px" 7 | 8 | initialize: (options) -> 9 | @listenTo @model, "change", @render 10 | @listenTo @model.source, "change", @render 11 | @listenTo @model.target, "change", @render 12 | @listenTo @model, "remove", @remove 13 | @render() 14 | 15 | render: -> 16 | @el.attr path: "M#{@model.source.get("x")},#{@model.source.get("y")}L#{@model.target.get("x")},#{@model.target.get("y")}" 17 | -------------------------------------------------------------------------------- /app/controllers/sessions_controller.rb: -------------------------------------------------------------------------------- 1 | class SessionsController < Devise::SessionsController 2 | # POST /resource/sign_in 3 | def create 4 | self.resource = warden.authenticate!(auth_options) 5 | 6 | if resource.banned? 7 | flash[:notice] = "You have been banned from this site. Please contact the site administrator." 8 | sign_out(resource) 9 | redirect_to root_path 10 | else 11 | set_flash_message(:notice, :signed_in) if is_navigational_format? 12 | sign_in(resource_name, resource) 13 | respond_with resource, :location => after_sign_in_path_for(resource) 14 | end 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /db/migrate/20131029040046_split_board_game_attributes_into_nodes_and_links.rb: -------------------------------------------------------------------------------- 1 | require "pp" 2 | 3 | class SplitBoardGameAttributesIntoNodesAndLinks < ActiveRecord::Migration 4 | def up 5 | add_column :boards, :nodes_attributes, :json, null: false, default: "[{\"round\": 0}]" 6 | add_column :boards, :links_attributes, :json, null: false, default: "[]" 7 | 8 | Board.find_each do |board| 9 | json = JSON.parse(board.game_attributes) 10 | board.nodes_attributes = json["nodes"] 11 | board.links_attributes = json["links"] 12 | board.save! 13 | end 14 | 15 | remove_column :boards, :game_attributes 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /app/assets/javascripts/views/components/graph/nodes.js.jsx.coffee: -------------------------------------------------------------------------------- 1 | ###* @jsx React.DOM ### 2 | 3 | Node = React.createClass 4 | render: -> 5 | {node, nodeFactory} = @props 6 | style = 7 | left: Math.round node.x 8 | top: Math.round node.y 9 | 10 | `
11 | {nodeFactory.createComponent(node)} 12 |
` 13 | 14 | Sembl.Components.Graph.Nodes = React.createClass 15 | render: -> 16 | nodes = for node in @props.nodes 17 | `` 18 | `
19 | {nodes} 20 |
` 21 | -------------------------------------------------------------------------------- /app/models/rating.rb: -------------------------------------------------------------------------------- 1 | class Rating < ActiveRecord::Base 2 | belongs_to :resemblance 3 | belongs_to :creator, class_name: "User" 4 | 5 | validate :cannot_belong_to_creator 6 | after_create :update_resemblance_score 7 | after_save :update_resemblance_score 8 | 9 | def cannot_belong_to_creator 10 | if creator == resemblance.creator 11 | errors.add(:base, "You cannot rate your own sembl.") 12 | end 13 | end 14 | 15 | def update_resemblance_score 16 | resemblance.calculate_score 17 | resemblance.save! 18 | end 19 | 20 | def self.for_game(game) 21 | joins(:resemblance => :link).where("links.game_id = ?", game.id) 22 | end 23 | end 24 | -------------------------------------------------------------------------------- /spec/factories/nodes.rb: -------------------------------------------------------------------------------- 1 | # Read about factories at https://github.com/thoughtbot/factory_girl 2 | 3 | FactoryGirl.define do 4 | factory :node do 5 | factory :node_with_final_placements do 6 | state {'filled'} 7 | after(:create) do |node| 8 | FactoryGirl.create(:placement, node: node, state: 'final', thing: FactoryGirl.create(:thing)) 9 | end 10 | end 11 | 12 | factory :node_with_proposed_placements do 13 | state {'in_play'} 14 | after(:create) do |node| 15 | FactoryGirl.create(:placement, node: node, state: 'proposed', thing: FactoryGirl.create(:thing)) 16 | end 17 | end 18 | end 19 | 20 | 21 | end 22 | -------------------------------------------------------------------------------- /app/assets/javascripts/views/games/move/gallery_thing_modal.js.jsx.coffee: -------------------------------------------------------------------------------- 1 | #= require views/components/thing_modal 2 | 3 | ###* @jsx React.DOM ### 4 | 5 | {ThingModal} = Sembl.Components 6 | 7 | @Sembl.Games.Move.GalleryThingModal = React.createClass 8 | handlePlaceThing: -> 9 | $(window).trigger('move.gallery.selectTargetThing', @props.thing) 10 | $(window).trigger('modal.close') 11 | 12 | render: () -> 13 | thing = @props.thing 14 | ` 15 | 18 | ` 19 | -------------------------------------------------------------------------------- /app/assets/stylesheets/active_admin.css.scss: -------------------------------------------------------------------------------- 1 | // SASS variable overrides must be declared before loading up Active Admin's styles. 2 | // 3 | // To view the variables that Active Admin provides, take a look at 4 | // `app/assets/stylesheets/active_admin/mixins/_variables.css.scss` in the 5 | // Active Admin source. 6 | // 7 | // For example, to change the sidebar width: 8 | // $sidebar-width: 242px; 9 | 10 | // Active Admin's got SASS! 11 | @import "active_admin/mixins"; 12 | @import "active_admin/base"; 13 | 14 | // Overriding any non-variable SASS must be done after the fact. 15 | // For example, to change the default status-tag color: 16 | // 17 | // .status_tag { background: #6090DB; } 18 | -------------------------------------------------------------------------------- /app/views/devise/passwords/edit.html.slim: -------------------------------------------------------------------------------- 1 | .header 2 | .heading 3 | h1 Change your password 4 | = simple_form_for(resource, :as => resource_name, :url => password_path(resource_name), :html => { :method => :put }) do |f| 5 | .sign-in-form 6 | = f.error_notification 7 | = f.input :reset_password_token, :as => :hidden 8 | = f.full_error :reset_password_token 9 | .form-inputs 10 | = f.input :password, :label => "New password", :required => true, :autofocus => true 11 | = f.input :password_confirmation, :label => "Confirm your new password", :required => true 12 | .form-actions 13 | = f.button :submit, "Change my password", class: "sign-in-button" 14 | = render "links" 15 | -------------------------------------------------------------------------------- /app/assets/javascripts/views/games/setup/steps/step_seed_thing_modal.js.jsx.coffee: -------------------------------------------------------------------------------- 1 | #= require views/components/thing_modal 2 | 3 | ###* @jsx React.DOM ### 4 | 5 | {ThingModal} = Sembl.Components 6 | @Sembl.Games.Setup.StepSeedThingModal = React.createClass 7 | handleSelectSeed: -> 8 | $(window).trigger(@props.selectEvent, @props.thing) 9 | $(window).trigger("modal.close") 10 | event.preventDefault() 11 | 12 | render: -> 13 | thing = @props.thing 14 | ` 15 | 16 | ` 17 | -------------------------------------------------------------------------------- /spec/support/database_cleaner.rb: -------------------------------------------------------------------------------- 1 | # Good read on using database_cleaner (in lieu of a shared connection): 2 | # - http://devblog.avdi.org/2012/08/31/configuring-database_cleaner-with-rails-rspec-capybara-and-selenium/ 3 | 4 | RSpec.configure do |config| 5 | config.before(:suite) do 6 | DatabaseCleaner.clean_with(:truncation) 7 | end 8 | 9 | config.before(:each) do 10 | DatabaseCleaner.strategy = :transaction 11 | end 12 | 13 | config.before(:each, js: true) do 14 | DatabaseCleaner.strategy = :truncation 15 | end 16 | 17 | config.before(:each) do 18 | DatabaseCleaner.start 19 | end 20 | 21 | config.after(:each) do 22 | DatabaseCleaner.clean 23 | end 24 | end 25 | -------------------------------------------------------------------------------- /app/assets/javascripts/models/board_link.js.coffee: -------------------------------------------------------------------------------- 1 | class Sembl.BoardLink extends Backbone.Model 2 | initialize: (options) -> 3 | @board = @collection.board 4 | 5 | if @has("source") 6 | @source = @get("source") 7 | if _.isNumber(@source) 8 | @source = @board.nodes.at(@source) 9 | @listenTo @source, "destroy", -> 10 | @destroy() 11 | 12 | if @has("target") 13 | @target = @get("target") 14 | if _.isNumber(@target) 15 | @target = @board.nodes.at(@target) 16 | @listenTo @target, "destroy", -> 17 | @destroy() 18 | 19 | toJSON: -> 20 | source: @board.nodes.indexOf(@source) 21 | target: @board.nodes.indexOf(@target) 22 | -------------------------------------------------------------------------------- /vendor/assets/stylesheets/bourbon/addons/_clearfix.scss: -------------------------------------------------------------------------------- 1 | // Micro clearfix provides an easy way to contain floats without adding additional markup 2 | // 3 | // Example usage: 4 | // 5 | // // Contain all floats within .wrapper 6 | // .wrapper { 7 | // @include clearfix; 8 | // .content, 9 | // .sidebar { 10 | // float : left; 11 | // } 12 | // } 13 | 14 | @mixin clearfix { 15 | *zoom: 1; 16 | 17 | &:before, 18 | &:after { 19 | content: " "; 20 | display: table; 21 | } 22 | 23 | &:after { 24 | clear: both; 25 | } 26 | } 27 | 28 | // Acknowledgements 29 | // Micro clearfix: [Nicolas Gallagher](http://nicolasgallagher.com/micro-clearfix-hack/) 30 | -------------------------------------------------------------------------------- /db/migrate/20141210235416_create_active_admin_comments.rb: -------------------------------------------------------------------------------- 1 | class CreateActiveAdminComments < ActiveRecord::Migration 2 | def self.up 3 | create_table :active_admin_comments do |t| 4 | t.string :namespace 5 | t.text :body 6 | t.string :resource_id, null: false 7 | t.string :resource_type, null: false 8 | t.references :author, polymorphic: true 9 | t.timestamps 10 | end 11 | add_index :active_admin_comments, [:namespace] 12 | add_index :active_admin_comments, [:author_type, :author_id] 13 | add_index :active_admin_comments, [:resource_type, :resource_id] 14 | end 15 | 16 | def self.down 17 | drop_table :active_admin_comments 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /vendor/assets/stylesheets/bourbon/_bourbon-deprecated-upcoming.scss: -------------------------------------------------------------------------------- 1 | //************************************************************************// 2 | // These mixins/functions are deprecated 3 | // They will be removed in the next MAJOR version release 4 | //************************************************************************// 5 | @mixin box-shadow ($shadows...) { 6 | @include prefixer(box-shadow, $shadows, spec); 7 | @warn "box-shadow is deprecated and will be removed in the next major version release"; 8 | } 9 | 10 | @mixin background-size ($lengths...) { 11 | @include prefixer(background-size, $lengths, spec); 12 | @warn "background-size is deprecated and will be removed in the next major version release"; 13 | } 14 | -------------------------------------------------------------------------------- /app/views/admin/users/_email_form.html.slim: -------------------------------------------------------------------------------- 1 | = form_tag message_admin_user_path do 2 | fieldset 3 | ol 4 | li 5 | = label_tag "subject" 6 | = text_field_tag "subject", "Sembl" 7 | ol 8 | li 9 | = label_tag "Message" 10 | - if params[:game_id] 11 | - @game = Game.find(params[:game_id]) 12 | - email_content = "Dear #{@user.name},\n\nThe game '#{link_to(@game.title,game_path(id: @game.id)).html_safe}' that you are playing\n\nKind regards,\nSembl team" 13 | - else 14 | - email_content = "Dear #{@user.name},\n\n\n\nKind regards,\nSembl team" 15 | = text_area_tag "content", email_content, rows: 10, cols: 25 16 | p= submit_tag "Send email to user" 17 | -------------------------------------------------------------------------------- /app/views/api/results/_result.json.jbuilder: -------------------------------------------------------------------------------- 1 | json.user { json.partial! 'api/users/user', user: move.user } if move.user.present? 2 | json.score move.placement.score 3 | json.target do 4 | json.node(move.target_node, :id, :round) 5 | json.thing { json.partial! 'api/things/thing', thing: move.placement.thing} 6 | end 7 | json.resemblances do 8 | json.array! move.resemblances do |resemblance| 9 | json.(resemblance, :id, :score, :description, :source_description, :target_description) 10 | json.target_state move.placement.state 11 | json.source do 12 | json.node(resemblance.source.node, :id, :round) 13 | json.thing { json.partial! 'api/things/thing', thing: resemblance.source.thing} 14 | end 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /app/views/games/_seed_node.html.slim: -------------------------------------------------------------------------------- 1 | = form.input :seed_thing_id, label: "Seed node" 2 | .seed-image 3 | = image_tag @game.seed_thing.try(:image).try(:admin_thumb).try(:url) 4 | = hidden_field_tag('game[seed_thing_id]', @game.seed_thing.try(:id)) 5 | 6 | = form.input :change_seed_image, label: "Change seed image" 7 | = link_to_function "Suggested seed images", "$('.suggested-seeds').show()" 8 | = link_to_function "Select random image", "Sembl.gameForm.selectRandomSeed()" 9 | = link_to_function "Browse all images", "" 10 | 11 | .suggested-seeds style="display: none" 12 | label Suggested images 13 | - Thing.where(suggested_seed: true).each do |thing| 14 | - if thing.image? 15 | = render_seed_thing(thing) 16 | 17 | -------------------------------------------------------------------------------- /config/initializers/inflections.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Add new inflection rules using the following format. Inflections 4 | # are locale specific, and you may define rules for as many different 5 | # locales as you wish. All of these examples are active by default: 6 | # ActiveSupport::Inflector.inflections(:en) do |inflect| 7 | # inflect.plural /^(ox)$/i, '\1en' 8 | # inflect.singular /^(ox)en/i, '\1' 9 | # inflect.irregular 'person', 'people' 10 | # inflect.uncountable %w( fish sheep ) 11 | # end 12 | 13 | # These inflection rules are supported but not enabled by default: 14 | # ActiveSupport::Inflector.inflections(:en) do |inflect| 15 | # inflect.acronym 'RESTful' 16 | # end 17 | -------------------------------------------------------------------------------- /spec/features/admin/authentication_spec.rb: -------------------------------------------------------------------------------- 1 | require "spec_helper" 2 | 3 | describe "Admin area" do 4 | context "not logged in" do 5 | specify "asks to login" do 6 | visit "/admin" 7 | current_path.should == new_user_session_path 8 | end 9 | end 10 | 11 | context "as a normal user" do 12 | before { login(create(:user)) } 13 | 14 | specify "is not found" do 15 | # in test errors are raised, not rendered. 16 | expect { visit "/admin" }.to raise_error ActionController::RoutingError 17 | end 18 | end 19 | 20 | context "as an admin user" do 21 | before { login(create(:user, :admin)) } 22 | 23 | specify "is accessible" do 24 | visit "/admin" 25 | end 26 | end 27 | end 28 | -------------------------------------------------------------------------------- /vendor/assets/stylesheets/bourbon/css3/_placeholder.scss: -------------------------------------------------------------------------------- 1 | $placeholders: '-webkit-input-placeholder', 2 | '-moz-placeholder', 3 | '-ms-input-placeholder'; 4 | 5 | @mixin placeholder { 6 | @each $placeholder in $placeholders { 7 | @if $placeholder == "-webkit-input-placeholder" { 8 | &::#{$placeholder} { 9 | @content; 10 | } 11 | } 12 | @else if $placeholder == "-moz-placeholder" { 13 | // FF 18- 14 | &:#{$placeholder} { 15 | @content; 16 | } 17 | 18 | // FF 19+ 19 | &::#{$placeholder} { 20 | @content; 21 | } 22 | } 23 | @else { 24 | &:#{$placeholder} { 25 | @content; 26 | } 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /app/controllers/transloadit_signatures_controller.rb: -------------------------------------------------------------------------------- 1 | class TransloaditSignaturesController < ApplicationController 2 | respond_to :json 3 | 4 | before_filter :authenticate_user! 5 | 6 | def template 7 | attrs = {} 8 | 9 | if Transloadit::Rails::Engine.configuration['templates'].keys.include?(params[:template_id]) 10 | transloadit_params = Transloadit::Rails::Engine.template(params[:template_id]) 11 | 12 | transloadit_params = transloadit_params.to_hash.merge(params[:params]) if request.post? 13 | 14 | signature = Transloadit::Rails::Engine.sign(transloadit_params.to_json) 15 | 16 | attrs[:params] = transloadit_params 17 | attrs[:signature] = signature 18 | end 19 | 20 | respond_with attrs, location: nil 21 | end 22 | end 23 | -------------------------------------------------------------------------------- /app/assets/javascripts/views/games/setup/edit_view.js.jsx.coffee: -------------------------------------------------------------------------------- 1 | #= require views/games/setup/form 2 | 3 | ###* @jsx React.DOM ### 4 | 5 | {Form} = Sembl.Games.Setup 6 | @Sembl.Games.Setup.Edit = React.createClass 7 | render: -> 8 | game = @props.game 9 | 10 | `
` 13 | 14 | @Sembl.views.setupEdit = ($el, el) -> 15 | Sembl.game = new Sembl.Game($el.data().game); 16 | 17 | @layout = React.renderComponent( 18 | Sembl.Layouts.Default() 19 | document.getElementsByTagName('body')[0] 20 | ) 21 | @layout.setProps 22 | body: Sembl.Games.Setup.Edit(game: Sembl.game, user: Sembl.user), 23 | header: Sembl.Games.HeaderView(model: Sembl.game, title: "Edit Game") 24 | 25 | -------------------------------------------------------------------------------- /app/assets/javascripts/views/games/setup/new_view.js.jsx.coffee: -------------------------------------------------------------------------------- 1 | #= require views/games/setup/form 2 | 3 | ###* @jsx React.DOM ### 4 | 5 | {Form} = Sembl.Games.Setup 6 | @Sembl.Games.Setup.New = React.createClass 7 | render: -> 8 | `` 12 | 13 | @Sembl.views.setupNew = ($el, el) -> 14 | Sembl.game = new Sembl.Game($el.data().game); 15 | 16 | @layout = React.renderComponent( 17 | Sembl.Layouts.Default() 18 | document.getElementsByTagName('body')[0] 19 | ) 20 | @layout.setProps 21 | body: Sembl.Games.Setup.New(game: Sembl.game, user: Sembl.user), 22 | header: Sembl.Games.HeaderView(model: Sembl.game, title: "New Game") 23 | 24 | -------------------------------------------------------------------------------- /spec/policies/player_policy_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe PlayerPolicy do 4 | subject { PlayerPolicy.new(user, game)} 5 | 6 | let(:game) { FactoryGirl.create(:game) } 7 | let(:game_creator) { FactoryGirl.create(:user) } 8 | let(:player) { FactoryGirl.create(:player, user: user, game: game)} 9 | 10 | context "for a guest" do 11 | let(:user) { nil } 12 | 13 | pending { should_not permit(:end_turn) } 14 | end 15 | 16 | context "for a user" do 17 | let(:user) { FactoryGirl.create(:user) } 18 | 19 | pending { should_not permit(:end_turn) } 20 | 21 | context "for a game that is hosted by user" do 22 | let(:game) { FactoryGirl.create(:game, creator: user) } 23 | pending { should_not permit(:end_turn) } 24 | end 25 | end 26 | end 27 | -------------------------------------------------------------------------------- /app/views/profiles/show.html.slim: -------------------------------------------------------------------------------- 1 | .container.profile-show__container 2 | .header 3 | .heading 4 | h1 Profile 5 | .profile-show 6 | .profile-show__avatar 7 | - if @profile.avatar.present? 8 | img src=@profile.avatar.try(:thumb).try(:url) 9 | - else 10 | .profile-show__avatar-none 11 | = @profile.display_name[0].upcase 12 | - if @profile.name.present? 13 | h1.profile-show__header= @profile.name 14 | .profile-show__bio.copy 15 | p=@profile.bio 16 | 17 | - if @games.present? 18 | - if @profile.name.present? 19 | h2.profile-show__games-header 20 | = @profile.name 21 | '’s games 22 | .profile-show__games 23 | - @games.each do |game| 24 | = render partial: "games/game", locals: {game: game} 25 | -------------------------------------------------------------------------------- /app/assets/javascripts/views/components/graph/links.js.jsx.coffee: -------------------------------------------------------------------------------- 1 | #= require d3 2 | #= require raphael.js 3 | 4 | ###* @jsx React.DOM ### 5 | 6 | Sembl.Components.Graph.Links = React.createClass 7 | componentDidMount: -> 8 | @drawLinks() 9 | 10 | componentDidUpdate: -> 11 | @drawLinks() 12 | 13 | drawLinks: () -> 14 | lineFunction = d3.svg.diagonal() 15 | if @paper 16 | @paper.remove() 17 | @paper = Raphael(@getDOMNode(), @props.width, @props.height) 18 | paper = @paper 19 | 20 | for link in @props.links 21 | path = paper.path(lineFunction(link)) 22 | if @props.pathClassName 23 | path.node.setAttribute("class", @props.pathClassName) 24 | 25 | render: -> 26 | `
` 27 | 28 | -------------------------------------------------------------------------------- /spec/features/viewing_and_joining_games_spec.rb: -------------------------------------------------------------------------------- 1 | require "spec_helper" 2 | 3 | feature "Viewing, joining and playing games", js: true do 4 | let!(:user1) { FactoryGirl.create(:user) } 5 | let!(:user2) { FactoryGirl.create(:user) } 6 | let!(:board) { FactoryGirl.create(:board) } 7 | let!(:thing) { FactoryGirl.create(:thing) } 8 | 9 | scenario "a signed in user attempts to join a game and play a turn" do 10 | create_hostless_game board, "Animals", thing 11 | 12 | visit "/" 13 | sign_in user2 14 | click_on "Open to join" 15 | click_on "Animals" 16 | click_on "Join this game" 17 | play_turn 18 | 19 | expect(page).to have_content "your turn is complete" 20 | sign_out_current_user 21 | end 22 | 23 | pending "should show games that the user is participating in" 24 | end 25 | -------------------------------------------------------------------------------- /app/assets/javascripts/views/components/graph/game_midpoint.js.jsx.coffee: -------------------------------------------------------------------------------- 1 | #= require d3 2 | #= require raphael 3 | 4 | ###* @jsx React.DOM ### 5 | 6 | Sembl.Components.Graph.Resemblance = React.createClass 7 | lineFunction: d3.svg.diagonal() 8 | 9 | render: -> 10 | viewableResemblance = @props.viewableResemblance 11 | filled = !!viewableResemblance 12 | 13 | defaultChild = if filled 14 | `
15 | {filled ? viewableResemblance.description : 'filled'} 16 |
` 17 | else 18 | `
19 | unfilled 20 |
` 21 | 22 | child = this.props.children || defaultChild 23 | `
24 | {child} 25 |
` 26 | -------------------------------------------------------------------------------- /app/policies/application_policy.rb: -------------------------------------------------------------------------------- 1 | class ApplicationPolicy 2 | attr_reader :user, :record 3 | 4 | def initialize(user, record) 5 | @user = user 6 | @record = record 7 | end 8 | 9 | 10 | def index? 11 | false 12 | end 13 | 14 | def show? 15 | scope.where(:id => record.id).exists? 16 | end 17 | 18 | def create? 19 | false 20 | end 21 | 22 | def new? 23 | create? 24 | end 25 | 26 | # As a default users can update what they have created 27 | def update? 28 | user.id == record.creator_id 29 | end 30 | 31 | def edit? 32 | update? 33 | end 34 | 35 | # As a default users can destroy what they have created 36 | def destroy? 37 | user.id == record.creator_id 38 | end 39 | 40 | def scope 41 | Pundit.policy_scope!(user, record.class) 42 | end 43 | end 44 | 45 | -------------------------------------------------------------------------------- /vendor/assets/stylesheets/bourbon/functions/_transition-property-name.scss: -------------------------------------------------------------------------------- 1 | // Return vendor-prefixed property names if appropriate 2 | // Example: transition-property-names((transform, color, background), moz) -> -moz-transform, color, background 3 | //************************************************************************// 4 | @function transition-property-names($props, $vendor: false) { 5 | $new-props: (); 6 | 7 | @each $prop in $props { 8 | $new-props: append($new-props, transition-property-name($prop, $vendor), comma); 9 | } 10 | 11 | @return $new-props; 12 | } 13 | 14 | @function transition-property-name($prop, $vendor: false) { 15 | // put other properties that need to be prefixed here aswell 16 | @if $vendor and $prop == transform { 17 | @return unquote('-'+$vendor+'-'+$prop); 18 | } 19 | @else { 20 | @return $prop; 21 | } 22 | } -------------------------------------------------------------------------------- /config/locales/simple_form.en.yml: -------------------------------------------------------------------------------- 1 | en: 2 | simple_form: 3 | "yes": 'Yes' 4 | "no": 'No' 5 | required: 6 | text: 'required' 7 | mark: '*' 8 | # You can uncomment the line below if you need to overwrite the whole required html. 9 | # When using html, text and mark won't be used. 10 | # html: '*' 11 | error_notification: 12 | default_message: "Please review the problems below:" 13 | # Labels and hints examples 14 | # labels: 15 | # defaults: 16 | # password: 'Password' 17 | # user: 18 | # new: 19 | # email: 'E-mail to sign in.' 20 | # edit: 21 | # email: 'E-mail.' 22 | # hints: 23 | # defaults: 24 | # username: 'User name to sign in.' 25 | # password: 'No special characters, please.' 26 | 27 | -------------------------------------------------------------------------------- /app/assets/javascripts/views/games/rate/resemblance.js.jsx.coffee: -------------------------------------------------------------------------------- 1 | ###* @jsx React.DOM ### 2 | 3 | @Sembl.Games.Rate.Resemblance = React.createClass 4 | render: -> 5 | sembl = @props.link.get('viewable_resemblance') 6 | 7 | scoreClass = @props.link.scoreClass(true) # Use the user supplied rating, not the average. 8 | child = if @props.link.active 9 | `
10 |
11 |
12 |
13 | {sembl.description} 14 |
15 |
16 |
` 17 | else 18 | `
` 19 | 20 | `
21 | {child} 22 |
` 23 | 24 | -------------------------------------------------------------------------------- /vendor/assets/stylesheets/bourbon/functions/_radial-gradient.scss: -------------------------------------------------------------------------------- 1 | // This function is required and used by the background-image mixin. 2 | @function radial-gradient($G1, $G2, 3 | $G3: false, $G4: false, 4 | $G5: false, $G6: false, 5 | $G7: false, $G8: false, 6 | $G9: false, $G10: false, 7 | $pos: null, 8 | $shape-size: null) { 9 | 10 | $data: _radial-arg-parser($G1, $G2, $pos, $shape-size); 11 | $G1: nth($data, 1); 12 | $G2: nth($data, 2); 13 | $pos: nth($data, 3); 14 | $shape-size: nth($data, 4); 15 | 16 | $type: radial; 17 | $gradient: compact($G1, $G2, $G3, $G4, $G5, $G6, $G7, $G8, $G9, $G10); 18 | 19 | $type-gradient: $type, $shape-size $pos, $gradient; 20 | @return $type-gradient; 21 | } 22 | 23 | 24 | -------------------------------------------------------------------------------- /Vagrantfile: -------------------------------------------------------------------------------- 1 | VAGRANTFILE_API_VERSION = '2' 2 | 3 | Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| 4 | config.hostmanager.enabled = true 5 | config.hostmanager.manage_host = true 6 | 7 | config.ssh.forward_agent = true 8 | 9 | config.vm.box = 'bento/ubuntu-16.04' 10 | config.vm.box_download_insecure = true 11 | 12 | config.vm.hostname = 'sembl.dev' 13 | config.vm.network 'private_network', ip: '172.17.145.2' 14 | 15 | config.vm.provision :ansible do |ansible| 16 | ansible.host_key_checking = false 17 | ansible.inventory_path = 'prov/vagrant' 18 | ansible.limit = 'all' 19 | ansible.playbook = 'prov/vagrant.yml' 20 | end 21 | 22 | config.vm.provider :virtualbox do |v| 23 | v.memory = 1024 24 | v.cpus = 2 25 | end 26 | 27 | config.vm.synced_folder '.', '/vagrant', rsync: true # FIXME ideally this should be NFS 28 | end 29 | -------------------------------------------------------------------------------- /spec/factories/boards.rb: -------------------------------------------------------------------------------- 1 | FactoryGirl.define do 2 | factory :board do 3 | title { "#{Forgery(:lorem_ipsum).word} #{number_of_players}" } 4 | number_of_players { (2..6).to_a.sample } 5 | nodes_attributes { '[{"y":600.0,"x":412.4031007751938,"fixed":1,"round":0},{"y":424.03846153846155,"x":800.0,"fixed":1,"round":1},{"y":288.46153846153845,"x":257.36434108527135,"fixed":1,"round":1},{"y":400.96153846153845,"x":0.0,"fixed":1,"round":1},{"y":0.0,"x":741.0852713178296,"fixed":1,"round":2},{"y":14.423076923076923,"x":120.93023255813954,"fixed":1,"round":2},{"y":279.8076923076923,"x":579.8449612403101,"fixed":1,"round":3}]' } 6 | links_attributes { '[{"source":0,"target":1},{"source":0,"target":2},{"source":0,"target":3},{"source":1,"target":4},{"source":2,"target":4},{"source":2,"target":5},{"source":3,"target":5},{"source":4,"target":6},{"source":5,"target":6},{"source":0,"target":6}]' } 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /app/assets/javascripts/views/games/move/upload_modal.js.jsx.coffee: -------------------------------------------------------------------------------- 1 | #= require views/games/move/gallery_thing_modal 2 | #= require views/games/setup/steps/step_upload 3 | 4 | ###* @jsx React.DOM ### 5 | 6 | # TODO: This is not hooked up to anything 7 | 8 | {GalleryThingModal} = Sembl.Games.Move 9 | {StepUpload} = Sembl.Games.Setup 10 | 11 | @Sembl.Games.Move.UploadModal = React.createClass 12 | galleryClickEvent: "move.upload.gallery.click" 13 | 14 | componentDidMount: -> 15 | $(window).on(@galleryClickEvent, @handleGalleryClick) 16 | 17 | componentWillUnmount: -> 18 | $(window).off(@galleryClickEvent, @handleGalleryClick) 19 | 20 | handleGalleryClick: (event, thing) -> 21 | $(window).trigger('modal.open', ``) 22 | 23 | render: -> 24 | stepList = ['upload'] 25 | `` 26 | -------------------------------------------------------------------------------- /app/views/game_mailer/player_invitation.text.erb: -------------------------------------------------------------------------------- 1 | <% user_game_url = (@existing_user) ? game_url(@game) : new_user_registration_url(email: @email, for_game: @game.id) -%> 2 | Hello, 3 | 4 | <% if @player.reminder_count_for_state == 0 -%> 5 | <%= @game.creator.name %> has invited you to play a game of Sembl: <%= user_game_url %> 6 | 7 | In each move, describe how two things are alike. And be interesting – other players will rate your every connections. 8 | <% else -%> 9 | <%= @game.creator.name %> has invited you to play a game of Sembl: <%= user_game_url %> 10 | 11 | In each move, describe how two things are alike. And be interesting – other players will rate your every connections. 12 | 13 | Sign up to start playing instantly. 14 | <% end -%> 15 | 16 | Hope you enjoy it :) 17 | 18 | Regards, 19 | — Sembl 20 | 21 | If you have a question, comment or concern, please email feedback@sembl.net or tweet @semblnet 22 | -------------------------------------------------------------------------------- /db/migrate/20131212030054_add_role_to_users.rb: -------------------------------------------------------------------------------- 1 | class AddRoleToUsers < ActiveRecord::Migration 2 | def up 3 | add_column :users, :role, :integer, null: false, default: 1 4 | 5 | User.reset_column_information 6 | User.find_each do |user| 7 | begin 8 | user.role = user.admin ? 10 : 1 9 | user.save! 10 | rescue 11 | puts "Error creating role for #{user.email}" 12 | end 13 | end 14 | 15 | remove_column :users, :admin 16 | end 17 | 18 | def down 19 | add_column :users, :admin, :boolean, null: false, default: false 20 | 21 | User.reset_column_information 22 | User.find_each do |user| 23 | begin 24 | user.admin = (user.role == 10) 25 | user.save! 26 | rescue 27 | puts "Error rolling back role for user: #{user.email}" 28 | end 29 | end 30 | 31 | remove_column :users, :role 32 | end 33 | end 34 | -------------------------------------------------------------------------------- /app/inputs/image_file_input.rb: -------------------------------------------------------------------------------- 1 | # TODO: Something more flexible like https://gist.github.com/sj26/2026284 2 | # Maybe with http://jasny.github.io/bootstrap/javascript.html#fileupload 3 | # Will need SimpleForm.wrapper_mappings help 4 | class ImageFileInput < SimpleForm::Inputs::FileInput 5 | def preview 6 | version = input_html_options.delete(:preview_version) 7 | use_default_url = options.delete(:use_default_url) 8 | preview_options = options.delete(:preview_html) 9 | 10 | uploader = object.send(attribute_name) 11 | uploader = uploader.send(version) if uploader && version 12 | 13 | if uploader || use_default_url 14 | template.image_tag(uploader.url, *Array(preview_options)) 15 | end 16 | end 17 | 18 | def cache 19 | @builder.hidden_field "#{attribute_name}_cache" 20 | end 21 | 22 | def input 23 | template.safe_join([preview, cache, super].compact) 24 | end 25 | end 26 | -------------------------------------------------------------------------------- /app/uploaders/avatar_uploader.rb: -------------------------------------------------------------------------------- 1 | require 'carrierwave/processing/mime_types' 2 | 3 | # TODO: user carrierwave backgrounder to move image processing into a background task. 4 | class AvatarUploader < CarrierWave::Uploader::Base 5 | include CarrierWave::MimeTypes 6 | include CarrierWave::MiniMagick 7 | 8 | process :set_content_type 9 | 10 | def extension_white_list 11 | %w(jpg jpeg gif png) 12 | end 13 | 14 | version(:thumb) do 15 | process resize_to_fill: [150, 150] 16 | end 17 | 18 | version(:tiny_thumb) do 19 | process resize_to_fit: [40, 40] 20 | end 21 | 22 | def filename 23 | @name ||= "#{secure_token}.#{file.extension.downcase}" if original_filename 24 | end 25 | 26 | 27 | private 28 | 29 | def secure_token 30 | ivar = "@#{mounted_as}_secure_token" 31 | token = model.instance_variable_get(ivar) 32 | token ||= model.instance_variable_set(ivar, SecureRandom.hex(4)) 33 | end 34 | end 35 | -------------------------------------------------------------------------------- /vendor/assets/stylesheets/bourbon/addons/_position.scss: -------------------------------------------------------------------------------- 1 | @mixin position ($position: relative, $coordinates: 0 0 0 0) { 2 | 3 | @if type-of($position) == list { 4 | $coordinates: $position; 5 | $position: relative; 6 | } 7 | 8 | $top: nth($coordinates, 1); 9 | $right: nth($coordinates, 2); 10 | $bottom: nth($coordinates, 3); 11 | $left: nth($coordinates, 4); 12 | 13 | position: $position; 14 | 15 | @if $top == auto { 16 | top: $top; 17 | } 18 | @else if not(unitless($top)) { 19 | top: $top; 20 | } 21 | 22 | @if $right == auto { 23 | right: $right; 24 | } 25 | @else if not(unitless($right)) { 26 | right: $right; 27 | } 28 | 29 | @if $bottom == auto { 30 | bottom: $bottom; 31 | } 32 | @else if not(unitless($bottom)) { 33 | bottom: $bottom; 34 | } 35 | 36 | @if $left == auto { 37 | left: $left; 38 | } 39 | @else if not(unitless($left)) { 40 | left: $left; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /app/assets/stylesheets/patterns/_type.scss: -------------------------------------------------------------------------------- 1 | @mixin antialiased { 2 | -webkit-font-smoothing: antialiased; 3 | font-smoothing: antialiased; 4 | } 5 | 6 | @mixin standard-links-no-underline { 7 | a { 8 | color: $primary; 9 | &:hover { 10 | color: $highlight; 11 | text-decoration: underline; 12 | } 13 | } 14 | } 15 | 16 | @mixin standard-links { 17 | a { 18 | color: $primary; 19 | text-decoration: underline; 20 | &:hover { 21 | color: $highlight; 22 | text-decoration: underline; 23 | } 24 | } 25 | } 26 | 27 | @mixin image-replace { 28 | background-color: transparent; 29 | border: 0; 30 | overflow: hidden; 31 | *text-indent: -99999px; // IE 6/7 fallback 32 | &:before { 33 | content: ""; 34 | display: block; 35 | width: 0; 36 | height: 150%; 37 | } 38 | } 39 | 40 | @mixin truncate { 41 | width: 100%; 42 | white-space: nowrap; 43 | overflow: hidden; 44 | text-overflow: ellipsis; 45 | } -------------------------------------------------------------------------------- /config/application.rb: -------------------------------------------------------------------------------- 1 | require File.expand_path('../boot', __FILE__) 2 | 3 | require "active_record/railtie" 4 | require "action_controller/railtie" 5 | require "action_mailer/railtie" 6 | require "sprockets/railtie" 7 | 8 | Bundler.require(:default, Rails.env) 9 | 10 | module Sembl 11 | class Application < Rails::Application 12 | config.autoload_paths << Rails.root.join("lib") 13 | config.autoload_paths << Rails.root.join("app/responders") 14 | 15 | config.time_zone = "Melbourne" 16 | 17 | config.i18n.enforce_available_locales = true 18 | 19 | config.assets.precompile += %w(admin.css admin.js) 20 | 21 | config.generators do |g| 22 | g.hidden_namespaces += [:test_unit, :erb] 23 | 24 | g.template_engine :slim 25 | g.javascript_engine :coffee 26 | g.stylesheet_engine :sass 27 | g.test_framework :rspec 28 | g.fixture_replacement :factory_girl 29 | end 30 | config.react.addons = true 31 | end 32 | end 33 | -------------------------------------------------------------------------------- /vendor/assets/stylesheets/bourbon/css3/_border-radius.scss: -------------------------------------------------------------------------------- 1 | //************************************************************************// 2 | // Shorthand Border-radius mixins 3 | //************************************************************************// 4 | @mixin border-top-radius($radii) { 5 | @include prefixer(border-top-left-radius, $radii, spec); 6 | @include prefixer(border-top-right-radius, $radii, spec); 7 | } 8 | 9 | @mixin border-bottom-radius($radii) { 10 | @include prefixer(border-bottom-left-radius, $radii, spec); 11 | @include prefixer(border-bottom-right-radius, $radii, spec); 12 | } 13 | 14 | @mixin border-left-radius($radii) { 15 | @include prefixer(border-top-left-radius, $radii, spec); 16 | @include prefixer(border-bottom-left-radius, $radii, spec); 17 | } 18 | 19 | @mixin border-right-radius($radii) { 20 | @include prefixer(border-top-right-radius, $radii, spec); 21 | @include prefixer(border-bottom-right-radius, $radii, spec); 22 | } 23 | -------------------------------------------------------------------------------- /app/assets/stylesheets/patterns/_accessibility.scss: -------------------------------------------------------------------------------- 1 | // Accessibility ---------------------- 2 | 3 | // Hide for both screenreaders and browsers 4 | // css-discuss.incutio.com/wiki/Screenreader_Visibility 5 | @mixin hide-from-all { 6 | display: none; 7 | visibility: hidden; 8 | } 9 | 10 | // Hide only visually, but have it available for screenreaders 11 | // www.webaim.org/techniques/css/invisiblecontent/ 12 | // Solution from: j.mp/visuallyhidden - Thanks Jonathan Neal! 13 | @mixin screenreaders-only { 14 | position: absolute !important; 15 | clip: rect(1px 1px 1px 1px); /* IE6, IE7 */ 16 | clip: rect(1px, 1px, 1px, 1px); 17 | } 18 | 19 | // Hide visually and from screenreaders, but maintain layout 20 | @mixin invisible { 21 | visibility: hidden; 22 | } 23 | 24 | // Remove text for image replacement 25 | @mixin hide-text { 26 | font: 0/0 a; 27 | color: transparent; 28 | text-shadow: none; 29 | background-color: transparent; 30 | border: 0; 31 | } -------------------------------------------------------------------------------- /vendor/assets/stylesheets/bourbon/addons/_retina-image.scss: -------------------------------------------------------------------------------- 1 | @mixin retina-image($filename, $background-size, $extension: png, $retina-filename: null, $asset-pipeline: false) { 2 | @if $asset-pipeline { 3 | background-image: image-url("#{$filename}.#{$extension}"); 4 | } 5 | @else { 6 | background-image: url("#{$filename}.#{$extension}"); 7 | } 8 | 9 | @include hidpi { 10 | 11 | @if $asset-pipeline { 12 | @if $retina-filename { 13 | background-image: image-url("#{$retina-filename}.#{$extension}"); 14 | } 15 | @else { 16 | background-image: image-url("#{$filename}@2x.#{$extension}"); 17 | } 18 | } 19 | 20 | @else { 21 | @if $retina-filename { 22 | background-image: url("#{$retina-filename}.#{$extension}"); 23 | } 24 | @else { 25 | background-image: url("#{$filename}@2x.#{$extension}"); 26 | } 27 | } 28 | 29 | background-size: $background-size; 30 | 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /app/assets/javascripts/collections/moves.js.coffee: -------------------------------------------------------------------------------- 1 | #= require models/move 2 | 3 | class Sembl.Moves extends Backbone.Collection 4 | url: -> 5 | root = "/api/games/#{@game.get('id')}" 6 | if @rating 7 | "#{root}/ratings" 8 | else if @for_round 9 | "#{root}/moves/round" 10 | else 11 | "#{root}/moves" 12 | 13 | model: Sembl.Move 14 | 15 | comparator: (move) -> 16 | if placement = move.get('target_node').viewable_placement 17 | placement.created_at 18 | 19 | initialize: (models, options) -> 20 | @game = options?.game 21 | 22 | @for_round = options?.for_round 23 | @rating = options?.rating 24 | 25 | deactivateLinks: -> 26 | @each (move) -> 27 | move.links.each (link) -> 28 | link.active = false 29 | 30 | # TODO: this is an ugly way to get the full list of resemblances 31 | resemblances: -> 32 | _.flatten( @map (move) -> 33 | move.links.map (link) -> link.get('viewable_resemblance') 34 | ) 35 | 36 | -------------------------------------------------------------------------------- /app/models/resemblance.rb: -------------------------------------------------------------------------------- 1 | class Resemblance < ActiveRecord::Base 2 | validates_presence_of :description 3 | belongs_to :link 4 | 5 | # A resemeblance needs two placements, because every resemblance between the same two nodes 6 | # can have a different target placement. So knowing about the link, and thus the nodes, is not enough. 7 | belongs_to :source, class_name: "Placement" 8 | belongs_to :target, class_name: "Placement" 9 | 10 | belongs_to :creator, class_name: "User" 11 | 12 | has_many :ratings 13 | 14 | # == States 15 | # proposed 16 | # final 17 | state_machine initial: :proposed do 18 | event :reify do 19 | transition :proposed => :final 20 | end 21 | end 22 | 23 | def rating_by(user) 24 | ratings.where(creator: user).take 25 | end 26 | 27 | def calculate_score 28 | self.score = ratings.average(:rating) 29 | end 30 | 31 | def self.for_game(game) 32 | joins(:link).where("links.game_id = ?", game.id) 33 | end 34 | 35 | end 36 | -------------------------------------------------------------------------------- /db/migrate/20140211225733_change_filter_content_by_on_games.rb: -------------------------------------------------------------------------------- 1 | class ChangeFilterContentByOnGames < ActiveRecord::Migration 2 | def up 3 | add_column :games, :filter_content_by_tmp, :json 4 | 5 | Game.reset_column_information 6 | Game.find_each do |game| 7 | if game.filter_content_by.present? 8 | game.filter_content_by_tmp = ['Keywords' => game.filter_content_by] 9 | game.save 10 | end 11 | end 12 | 13 | remove_column :games, :filter_content_by 14 | rename_column :games, :filter_content_by_tmp, :filter_content_by 15 | end 16 | 17 | def down 18 | add_column :games, :filter_content_by_tmp, :text, null: false, default: "" 19 | 20 | Game.reset_column_information 21 | Game.find_each do |game| 22 | game.filter_content_by_tmp = game.filter_content_by.to_s 23 | game.save 24 | end 25 | 26 | remove_column :games, :filter_content_by 27 | rename_column :games, :filter_content_by_tmp, :filter_content_by 28 | end 29 | end 30 | -------------------------------------------------------------------------------- /app/admin/board.rb: -------------------------------------------------------------------------------- 1 | ActiveAdmin.register Board do 2 | permit_params :title, :number_of_players, :nodes_attributes, :links_attributes 3 | config.sort_order = "updated_at_desc" 4 | 5 | filter :creator, collection: proc { User.includes(:profile).all } 6 | filter :updator, collection: proc { User.includes(:profile).all } 7 | attributes_to_exclude_from_filter = ["creator_id", "updator_id"] 8 | (Board.attribute_names - attributes_to_exclude_from_filter).sort.each do |attr| 9 | filter attr.to_sym 10 | end 11 | 12 | index do 13 | selectable_column 14 | column :title 15 | column "players", :number_of_players 16 | actions 17 | end 18 | 19 | form do |f| 20 | f.semantic_errors # shows errors on :base 21 | f.inputs do 22 | f.input :title 23 | f.input :number_of_players 24 | f.input :nodes_attributes, as: :text 25 | f.input :links_attributes, as: :text 26 | end 27 | f.actions # adds the 'Submit' and 'Cancel' buttons 28 | end 29 | end 30 | -------------------------------------------------------------------------------- /vendor/assets/stylesheets/bourbon/helpers/_render-gradients.scss: -------------------------------------------------------------------------------- 1 | // User for linear and radial gradients within background-image or border-image properties 2 | 3 | @function _render-gradients($gradient-positions, $gradients, $gradient-type, $vendor: false) { 4 | $pre-spec: null; 5 | $spec: null; 6 | $vendor-gradients: null; 7 | @if $gradient-type == linear { 8 | @if $gradient-positions { 9 | $pre-spec: nth($gradient-positions, 1); 10 | $spec: nth($gradient-positions, 2); 11 | } 12 | } 13 | @else if $gradient-type == radial { 14 | $pre-spec: nth($gradient-positions, 1); 15 | $spec: nth($gradient-positions, 2); 16 | } 17 | 18 | @if $vendor { 19 | $vendor-gradients: -#{$vendor}-#{$gradient-type}-gradient(#{$pre-spec} $gradients); 20 | } 21 | @else if $vendor == false { 22 | $vendor-gradients: "#{$gradient-type}-gradient(#{$spec} #{$gradients})"; 23 | $vendor-gradients: unquote($vendor-gradients); 24 | } 25 | @return $vendor-gradients; 26 | } 27 | -------------------------------------------------------------------------------- /app/controllers/api/results_controller.rb: -------------------------------------------------------------------------------- 1 | class Api::ResultsController < ApiController 2 | respond_to :json 3 | 4 | after_filter :verify_authorized 5 | before_filter :find_game 6 | 7 | # def index 8 | # authorize @game 9 | # round = @game.current_round 10 | # placements = @game.completed? ? Placement.for_round(@game, round) : Placement.for_game(game) 11 | # @moves = placements.collect{|p| Move.new(placement: p)} 12 | # respond_with :api, @moves 13 | # end 14 | 15 | def show 16 | authorize @game 17 | round = params[:id] 18 | placements = @game.completed? ? Placement.for_game(@game) : Placement.for_round(@game, round) 19 | @moves = placements.collect{|p| Move.new(placement: p)} 20 | respond_with :api, @moves 21 | end 22 | 23 | def awards 24 | @awards = MedalAwarder.new(@game) 25 | authorize @awards 26 | respond_with :api, @awards 27 | end 28 | 29 | private 30 | 31 | def find_game 32 | @game = Game.find(params[:game_id]) 33 | end 34 | end 35 | -------------------------------------------------------------------------------- /vendor/assets/stylesheets/bourbon/addons/_size.scss: -------------------------------------------------------------------------------- 1 | @mixin size($size) { 2 | @if length($size) == 1 { 3 | @if $size == auto { 4 | width: $size; 5 | height: $size; 6 | } 7 | 8 | @else if unitless($size) { 9 | width: $size + px; 10 | height: $size + px; 11 | } 12 | 13 | @else if not(unitless($size)) { 14 | width: $size; 15 | height: $size; 16 | } 17 | } 18 | 19 | // Width x Height 20 | @if length($size) == 2 { 21 | $width: nth($size, 1); 22 | $height: nth($size, 2); 23 | 24 | @if $width == auto { 25 | width: $width; 26 | } 27 | @else if not(unitless($width)) { 28 | width: $width; 29 | } 30 | @else if unitless($width) { 31 | width: $width + px; 32 | } 33 | 34 | @if $height == auto { 35 | height: $height; 36 | } 37 | @else if not(unitless($height)) { 38 | height: $height; 39 | } 40 | @else if unitless($height) { 41 | height: $height + px; 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /app/controllers/api/moves_controller.rb: -------------------------------------------------------------------------------- 1 | class Api::MovesController < ApiController 2 | respond_to :json 3 | 4 | after_filter :verify_authorized, except: [:round, :show] 5 | 6 | before_filter :authenticate_user! 7 | before_filter :find_game 8 | 9 | def create 10 | @move = Move.new(user: current_user) 11 | @move.placement = move_params[:placement] 12 | @move.resemblances = move_params[:resemblances] 13 | authorize @move 14 | if @move.valid? and @move.save 15 | @game.player(current_user).create_move 16 | end 17 | respond_with @move, :location => api_game_moves_url 18 | end 19 | 20 | private 21 | 22 | def move_params 23 | move = params.require(:move).permit( 24 | :game_id, 25 | { 26 | resemblances: [ :description, :link_id, :source_description, :target_description ] 27 | }, 28 | placement: [:node_id, :thing_id] 29 | ) 30 | move 31 | end 32 | 33 | def find_game 34 | @game = Game.find(params[:game_id]) 35 | end 36 | 37 | end 38 | -------------------------------------------------------------------------------- /config/initializers/carrierwave.rb: -------------------------------------------------------------------------------- 1 | CarrierWave.configure do |config| 2 | config.storage = :fog 3 | config.store_dir = lambda { |uploader| "#{uploader.model.class.model_name.collection}/#{uploader.model.id}/#{uploader.mounted_as}" } 4 | 5 | # S3 + CloudFront settings 6 | config.fog_credentials = { 7 | provider: "AWS", 8 | aws_access_key_id: ENV["AWS_ACCESS_KEY_ID"], 9 | aws_secret_access_key: ENV["AWS_SECRET_ACCESS_KEY"], 10 | region: ENV["FOG_REGION"] 11 | } 12 | config.fog_directory = ENV["FOG_DIRECTORY"] 13 | config.fog_public = true 14 | config.fog_attributes = { 15 | "Cache-Control" => "max-age=4838400, public", 16 | "Expires" => 10.years.from_now.httpdate 17 | } 18 | 19 | if ENV["CLOUDFRONT_DOMAIN"].present? 20 | config.asset_host = "https://#{ENV['CLOUDFRONT_DOMAIN']}" 21 | end 22 | 23 | if Rails.env.test? || Rails.env.cucumber? 24 | config.storage = :file 25 | config.enable_processing = false 26 | config.asset_host = "http://localhost:5000" 27 | end 28 | end 29 | -------------------------------------------------------------------------------- /app/assets/javascripts/models/link.js.coffee: -------------------------------------------------------------------------------- 1 | class Sembl.Link extends Backbone.Model 2 | initialize: (options) -> 3 | @game = @collection.game 4 | 5 | @listenTo @source(), "change:x change:y", => 6 | @trigger "change:source" 7 | @trigger "change" 8 | @listenTo @target(), "change:x change:y", => 9 | @trigger "change:target" 10 | @trigger "change" 11 | 12 | @active = false 13 | 14 | source: -> 15 | @game.nodes.get(@get("source_id")) 16 | 17 | target: -> 18 | @game.nodes.get(@get("target_id")) 19 | 20 | source_id: -> 21 | @source.id 22 | 23 | target_id: -> 24 | @target.id 25 | 26 | scoreClass: (current_user_rating) -> 27 | resemblance = @get('viewable_resemblance') 28 | score = if current_user_rating then resemblance?.rating else resemblance?.score 29 | if score < 0.20 30 | 'very-low' 31 | else if score < 0.40 32 | 'low' 33 | else if score < 0.60 34 | 'medium' 35 | else if score < 0.80 36 | 'high' 37 | else 38 | 'very-high' 39 | -------------------------------------------------------------------------------- /app/views/devise/registrations/edit.html.slim: -------------------------------------------------------------------------------- 1 | h2 2 | | Edit #{resource_name.to_s.humanize} 3 | = simple_form_for(resource, :as => resource_name, :url => registration_path(resource_name), :html => { :method => :put }) do |f| 4 | = f.error_notification 5 | .form-inputs 6 | = f.input :email, :required => true, :autofocus => true 7 | - if devise_mapping.confirmable? && resource.pending_reconfirmation? 8 | p 9 | | Currently waiting confirmation for: #{resource.unconfirmed_email} 10 | = f.input :password, :autocomplete => "off", :hint => "leave it blank if you don't want to change it", :required => false 11 | = f.input :password_confirmation, :required => false 12 | = f.input :current_password, :hint => "we need your current password to confirm your changes", :required => true 13 | .form-actions 14 | = f.button :submit, "Update" 15 | h3 Cancel my account 16 | p 17 | | Unhappy? #{link_to "Cancel my account", registration_path(resource_name), :data => { :confirm => "Are you sure?" }, :method => :delete} 18 | = link_to "Back", :back 19 | -------------------------------------------------------------------------------- /db/migrate/20150126221244_make_thing_meta_fields_proper_attributes.rb: -------------------------------------------------------------------------------- 1 | class MakeThingMetaFieldsProperAttributes < ActiveRecord::Migration 2 | def up 3 | add_column :things, :dates, :string 4 | add_column :things, :keywords, :string 5 | add_column :things, :places, :string 6 | add_column :things, :node_type, :string 7 | 8 | puts "Migrating data from general attributes" 9 | Thing.find_each do |thing| 10 | # Dates 11 | dates = thing.general_attributes["Date/s"] 12 | thing.dates = dates.join(", ") if dates 13 | # Keywords 14 | keywords = thing.general_attributes["Keywords"] 15 | thing.keywords = keywords.join(", ") if keywords 16 | # Places 17 | places = thing.general_attributes["Places"] 18 | thing.places = places.join(", ") if places 19 | # Node type 20 | node_types = thing.general_attributes["Node type"] 21 | thing.node_type = node_types.join(", ") if node_types 22 | thing.save! 23 | end 24 | end 25 | 26 | def down 27 | # no operation required 28 | end 29 | end 30 | -------------------------------------------------------------------------------- /prov/rails/tasks/ruby.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: install build-essential 3 | apt: 4 | name: build-essential 5 | become: true 6 | become_user: root 7 | 8 | - name: download ruby-install archive 9 | get_url: 10 | dest: /tmp/ruby-install-{{ ruby_install_version }}.tar.gz 11 | sha256sum: aa4448c2c356510cc7c2505961961a17bd3f3435842831e04c8516eb703afd19 12 | url: https://github.com/postmodern/ruby-install/archive/v{{ ruby_install_version }}.tar.gz 13 | 14 | - name: extract ruby-install 15 | unarchive: 16 | copy: no 17 | dest: /tmp 18 | src: /tmp/ruby-install-{{ ruby_install_version }}.tar.gz 19 | 20 | - name: make install ruby-install 21 | command: make install chdir=/tmp/ruby-install-{{ ruby_install_version }} 22 | become: true 23 | become_user: root 24 | 25 | - name: install ruby 26 | command: ruby-install ruby {{ ruby_version }} --no-reinstall --system 27 | become: true 28 | become_user: root 29 | 30 | - name: install bundler 31 | gem: 32 | name: bundler 33 | user_install: no 34 | become: true 35 | become_user: root 36 | -------------------------------------------------------------------------------- /app/assets/javascripts/views/games/gameboard/links_view.js.jsx.coffee: -------------------------------------------------------------------------------- 1 | #= require d3 2 | #= require raphael.js 3 | 4 | ###* @jsx React.DOM ### 5 | 6 | class RaphaelLink 7 | constructor: (link) -> 8 | @source = 9 | x: link.source().get("x") 10 | y: link.source().get("y") 11 | @target = 12 | x: link.target().get("x") 13 | y: link.target().get("y") 14 | 15 | render: (paper) -> 16 | lineFunction = d3.svg.diagonal() 17 | input = 18 | source: @source 19 | target: @target 20 | path_data = lineFunction(input) 21 | path = paper.path(path_data) 22 | 23 | # resemblance nodes will go here. 24 | midpoint = path.getPointAtLength(path.getTotalLength() / 2) 25 | paper.circle(midpoint.x, midpoint.y, 5) 26 | 27 | 28 | Sembl.Games.Gameboard.LinksView = React.createClass 29 | componentDidMount: () -> 30 | paper = Raphael(@getDOMNode(), @props.width, @props.height) 31 | @props.links.each (link) -> 32 | new RaphaelLink(link).render(paper) 33 | 34 | render: -> 35 | `
` 36 | 37 | -------------------------------------------------------------------------------- /app/helpers/application_helper.rb: -------------------------------------------------------------------------------- 1 | module ApplicationHelper 2 | def modular_application_name 3 | @application_name ||= Rails.application.class.name.sub(/::Application\Z/, "").underscore 4 | end 5 | 6 | def modular_controller_namespace 7 | @modular_controller_namespace ||= if controller.class.parent 8 | controller.class.parent.name.underscore 9 | end 10 | end 11 | 12 | def modular_controller_name 13 | @modular_controller_name ||= controller.class.name.sub(/Controller\Z/, "").underscore 14 | end 15 | 16 | def body_classes 17 | @body_classes ||= [ 18 | modular_application_name.parameterize, 19 | modular_controller_namespace.parameterize, 20 | modular_controller_name.parameterize, 21 | [modular_controller_name, action_name].join("-").parameterize, 22 | ].compact 23 | end 24 | 25 | def flashes 26 | safe_join(flash.keys.map { |key| 27 | content_tag :aside, flash[key], class: [:flash, key] 28 | }) 29 | end 30 | 31 | def url_matches?(url_string) 32 | request.fullpath.match(url_string) 33 | end 34 | end 35 | -------------------------------------------------------------------------------- /config/unicorn.rb: -------------------------------------------------------------------------------- 1 | listen_address = if ENV["RACK_ENV"] == "development" && ENV["BOXEN_SOCKET_DIR"].to_s != "" 2 | ENV["BOXEN_SOCKET_DIR"] + "/sembl" 3 | else 4 | ENV["PORT"] 5 | end 6 | 7 | listen listen_address, backlog: Integer(ENV["UNICORN_BACKLOG"] || 16) 8 | worker_processes Integer(ENV["UNICORN_WORKERS"] || 3) 9 | timeout 30 10 | preload_app true 11 | 12 | before_fork do |server, worker| 13 | Signal.trap "TERM" do 14 | puts "Unicorn master intercepting TERM and sending myself QUIT instead." 15 | Process.kill "QUIT", Process.pid 16 | end 17 | 18 | if defined?(ActiveRecord::Base) 19 | ActiveRecord::Base.connection.disconnect! 20 | end 21 | end 22 | 23 | after_fork do |server, worker| 24 | Signal.trap "TERM" do 25 | puts "Unicorn worker intercepting TERM and doing nothing. Wait for master to send QUIT." 26 | end 27 | 28 | if defined?(ActiveRecord::Base) 29 | ActiveRecord::Base.establish_connection 30 | end 31 | 32 | # Enable Que worker threads in-process (thereby avoiding a separate 33 | # dedicated worker process). 34 | Que.mode = :async 35 | end 36 | -------------------------------------------------------------------------------- /app/controllers/api/ratings_controller.rb: -------------------------------------------------------------------------------- 1 | class Api::RatingsController < ApiController 2 | respond_to :json 3 | 4 | after_filter :verify_authorized 5 | before_filter :authenticate_user! 6 | before_filter :find_game 7 | 8 | # List of moves to rate. 9 | # for_round defaults to current round 10 | def index 11 | authorize @game 12 | placements = Placement.for_round(@game).where('creator_id != ?', current_user.id) 13 | @moves = placements.collect{|p| Move.new(placement: p)}.shuffle 14 | respond_with @moves 15 | end 16 | 17 | def create 18 | sembl = Resemblance.find(rating_params[:resemblance_id]) 19 | @rating = sembl.rating_by(current_user) || Rating.new(resemblance: sembl, creator: current_user) 20 | authorize @rating 21 | 22 | @rating.assign_attributes(rating: rating_params[:rating]) 23 | @rating.save 24 | 25 | respond_with :api, @game, @rating 26 | end 27 | 28 | private 29 | 30 | def find_game 31 | @game = Game.find(params[:game_id]) 32 | end 33 | 34 | def rating_params 35 | params.require(:rating).permit(:resemblance_id, :rating) 36 | end 37 | 38 | end 39 | -------------------------------------------------------------------------------- /db/migrate/20141126215119_change_general_attributes_default_to_empty_object.rb: -------------------------------------------------------------------------------- 1 | # Use a naked class so that we don't get errors when `Thing.filter_keys` is 2 | # run inside of its `searchable` block. Before this migration is run, 3 | # `.filter_keys` will return errors, since it depends on all things having 4 | # `{}` as the defalut value for general_attributes. 5 | class BareThing < ActiveRecord::Base 6 | self.table_name = "things" 7 | end 8 | 9 | class ChangeGeneralAttributesDefaultToEmptyObject < ActiveRecord::Migration 10 | def up 11 | # Convert all the empty array attributes (the previous default) to empty objects (the new default) 12 | Sunspot.session = Sunspot::SessionProxy::SilentFailSessionProxy.new 13 | BareThing.find_each do |thing| 14 | if thing.general_attributes.blank? 15 | thing.update_attribute :general_attributes, {} 16 | end 17 | end 18 | 19 | # Set the new default 20 | change_column :things, :general_attributes, :json, default: '{}', null: false 21 | end 22 | 23 | def down 24 | change_column :things, :general_attributes, :json, default: '[]' 25 | end 26 | end 27 | -------------------------------------------------------------------------------- /app/assets/stylesheets/patterns/_animation.scss: -------------------------------------------------------------------------------- 1 | @mixin animate-background($transition-duration: 250ms, $transition-delay: 0) { 2 | @include transition(background-color $transition-duration ease-in-out $transition-delay); 3 | } 4 | 5 | @mixin animate-border($transition-duration: 250ms, $transition-delay: 0) { 6 | @include transition(border $transition-duration ease-in-out $transition-delay); 7 | } 8 | 9 | @mixin animate-color($transition-duration: 250ms, $transition-delay: 0) { 10 | @include transition(color $transition-duration ease-in-out $transition-delay); 11 | } 12 | 13 | @mixin animate-width($transition-duration: 250ms, $transition-delay: 0) { 14 | @include transition(width $transition-duration ease-in-out $transition-delay); 15 | } 16 | 17 | @mixin animate-grow($scale: 1.2, $transition-duration: 100ms, $transition-delay: 0) { 18 | @include transform(translate3d(0,0,0)); 19 | @include transform(scale($scale)); 20 | @include transition-property(transform); 21 | @include transition-duration($transition-duration); 22 | @include transition-timing-function(ease-in-out); 23 | @include transition-delay($transition-delay); 24 | } -------------------------------------------------------------------------------- /db/migrate/20140205010520_alter_json_format_of_things_attributes.rb: -------------------------------------------------------------------------------- 1 | class AlterJsonFormatOfThingsAttributes < ActiveRecord::Migration 2 | def up 3 | Thing.find_each do |thing| 4 | begin 5 | atts = thing.general_attributes.dup 6 | thing.general_attributes = {} 7 | atts.each do |att| 8 | thing.general_attributes[att.keys.first] ||= [] 9 | thing.general_attributes[att.keys.first] << att[att.keys.first] 10 | end 11 | thing.save! 12 | rescue Exception => e 13 | puts "Warning: Attribute not transformed #{e.message}" 14 | end 15 | end 16 | end 17 | 18 | def down 19 | Thing.find_each do |thing| 20 | begin 21 | atts = thing.general_attributes.dup 22 | thing.general_attributes = [] 23 | atts.each do |key, value_list| 24 | value_list.each do |val| 25 | thing.general_attributes << {key => val} 26 | end 27 | end 28 | thing.save! 29 | rescue Exception => e 30 | puts "Warning: Attribute not transformed #{e.message}" 31 | end 32 | end 33 | end 34 | end 35 | -------------------------------------------------------------------------------- /app/models/placement.rb: -------------------------------------------------------------------------------- 1 | class Placement < ActiveRecord::Base 2 | belongs_to :node 3 | belongs_to :thing 4 | belongs_to :creator, class_name: "User" 5 | 6 | HUMANIZED_ATTRIBUTES = { 7 | :thing => "Image" 8 | } 9 | 10 | validates_presence_of :thing 11 | 12 | after_create :reify_seed_node 13 | 14 | # == States 15 | # proposed 16 | # final 17 | state_machine initial: :proposed do 18 | after_transition :proposed => :final, do: :fill_node 19 | 20 | event :reify do 21 | transition :proposed => :final 22 | end 23 | end 24 | 25 | def self.human_attribute_name(attr, default: attr) 26 | HUMANIZED_ATTRIBUTES[attr.to_sym] || super 27 | end 28 | 29 | 30 | def self.for_round(game, round = nil) 31 | round = round || game.current_round 32 | joins(:node).where("nodes.game_id = ? and nodes.round = ?", game.id, round) 33 | end 34 | 35 | def self.for_game(game) 36 | joins(:node).where("nodes.game_id = ?", game) 37 | end 38 | 39 | def fill_node 40 | node.fill 41 | end 42 | 43 | def reify_seed_node 44 | if node.round == 0 45 | self.reify 46 | end 47 | end 48 | 49 | end 50 | -------------------------------------------------------------------------------- /app/assets/stylesheets/patterns/_clearing.scss: -------------------------------------------------------------------------------- 1 | /* 2 | * clearfix used project wide to clear floats and create a new formatting context 3 | * usage @extend clearfix- 4 | */ 5 | 6 | // create stub classes for each of the four clearfix methods 7 | 8 | %clearfix-overflow { 9 | overflow: hidden; 10 | *overflow: visible; 11 | zoom: 1; 12 | } 13 | 14 | %clearfix-facebook { 15 | display: table-cell; 16 | vertical-align: top; 17 | width: 10000px; 18 | } 19 | 20 | %clearfix-micro { 21 | zoom: 1; 22 | &:before, 23 | &:after { 24 | content: " "; 25 | display: table; 26 | } 27 | &:after { 28 | clear: both; 29 | } 30 | } 31 | 32 | %clearfix-stubborn { 33 | display: table-cell; 34 | &:after { 35 | clear: both; 36 | display: block; 37 | visibility: hidden; 38 | overflow: hidden; 39 | height: 0 !important; 40 | line-height: 0; 41 | font-size: xx-large; 42 | content: "x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x"; 43 | } 44 | } -------------------------------------------------------------------------------- /vendor/assets/stylesheets/bourbon/css3/_font-face.scss: -------------------------------------------------------------------------------- 1 | // Order of the includes matters, and it is: normal, bold, italic, bold+italic. 2 | 3 | @mixin font-face($font-family, $file-path, $weight: normal, $style: normal, $asset-pipeline: false ) { 4 | @font-face { 5 | font-family: $font-family; 6 | font-weight: $weight; 7 | font-style: $style; 8 | 9 | @if $asset-pipeline == true { 10 | src: font-url('#{$file-path}.eot'); 11 | src: font-url('#{$file-path}.eot?#iefix') format('embedded-opentype'), 12 | font-url('#{$file-path}.woff') format('woff'), 13 | font-url('#{$file-path}.ttf') format('truetype'), 14 | font-url('#{$file-path}.svg##{$font-family}') format('svg'); 15 | } @else { 16 | src: url('#{$file-path}.eot'); 17 | src: url('#{$file-path}.eot?#iefix') format('embedded-opentype'), 18 | url('#{$file-path}.woff') format('woff'), 19 | url('#{$file-path}.ttf') format('truetype'), 20 | url('#{$file-path}.svg##{$font-family}') format('svg'); 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /app/assets/javascripts/views/components/flash.js.jsx.coffee: -------------------------------------------------------------------------------- 1 | ###* @jsx React.DOM ### 2 | 3 | @Sembl.Components.Flash = React.createClass 4 | 5 | getInitialState: -> 6 | msg: "" 7 | className: "hidden" 8 | 9 | componentWillMount: -> 10 | $(window).on('flash.notice', @handleNotice) 11 | $(window).on('flash.error', @handleError) 12 | $(window).on('flash.hide', @handleHide) 13 | 14 | componentWillUnmount: -> 15 | $(window).off('flash.notice', @handleNotice) 16 | $(window).off('flash.error', @handleError) 17 | $(window).off('flash.hide', @handleHide) 18 | 19 | handleNotice: (event, msg) -> 20 | @setState msg: msg, className: 'notice' 21 | 22 | handleError: (event, msg) -> 23 | @setState msg: msg, className: 'error' 24 | 25 | handleHide: (event) -> 26 | event.preventDefault() 27 | @setState msg: "", className: 'hidden' 28 | 29 | render: -> 30 | className = "flash #{this.state.className}" 31 | `` 37 | -------------------------------------------------------------------------------- /app/assets/javascripts/views/games/rate/placement.js.jsx.coffee: -------------------------------------------------------------------------------- 1 | #= require views/components/thing_modal 2 | 3 | ###* @jsx React.DOM ### 4 | 5 | {ThingModal} = Sembl.Components 6 | {Node} = Sembl.Components.Graph 7 | 8 | @Sembl.Games.Rate.Placement = React.createClass 9 | handleClick: (event) -> 10 | event?.preventDefault() 11 | thing = @props.node.get('viewable_placement')?.thing 12 | if thing 13 | $(window).trigger('modal.open', ``) 14 | 15 | render: () -> 16 | userState = @props.node.get('user_state') 17 | className = "game__placement state-#{userState}" 18 | thing = @props.node.get('viewable_placement')?.thing 19 | image_url = thing?.image_admin_url 20 | 21 | # Format the sub-description 22 | subDescription = @props.node.get("sub_description") 23 | subDescriptionNode = if subDescription? 24 | `
{subDescription}
` 25 | else 26 | "" 27 | 28 | 29 | ` 30 | 31 | {subDescriptionNode} 32 | ` 33 | -------------------------------------------------------------------------------- /app/mailers/game_mailer.rb: -------------------------------------------------------------------------------- 1 | # Subjects are set in config/locales/en.yml (see en.game_mailer.*) 2 | class GameMailer < ActionMailer::Base 3 | helper :game 4 | 5 | default from: "Sembl " 6 | 7 | def player_invitation(player_id) 8 | setup player_id 9 | 10 | @existing_user = @player.user.present? 11 | @email = @player.try(:user).try(:email) || @player.email 12 | 13 | mail to: @email 14 | end 15 | 16 | def game_started(player_id) 17 | setup player_id 18 | 19 | @existing_user = @player.user.present? 20 | @email = @player.try(:user).try(:email) || @player.email 21 | 22 | mail to: @email 23 | end 24 | 25 | def player_turn_reminder(player_id) 26 | setup player_id 27 | 28 | mail to: @player.user.email 29 | end 30 | 31 | def game_completed(player_id) 32 | setup player_id 33 | 34 | mail to: @player.user.email 35 | end 36 | 37 | def game_stale_and_incomplete_player_set(player_id) 38 | setup player_id 39 | 40 | mail to: @player.user.email 41 | end 42 | 43 | private 44 | 45 | def setup(player_id) 46 | @player = Player.find(player_id) 47 | @game = @player.game 48 | end 49 | end 50 | -------------------------------------------------------------------------------- /app/assets/javascripts/views/games/setup/steps/step_description.js.jsx.coffee: -------------------------------------------------------------------------------- 1 | ###* @jsx React.DOM ### 2 | 3 | @Sembl.Games.Setup.StepDescription = React.createClass 4 | componentDidMount: -> 5 | @refs.description.getDOMNode().focus() 6 | 7 | getInitialState: -> 8 | description: @props?.description 9 | 10 | handleChange: (event) -> 11 | description = @refs.description.getDOMNode().value 12 | state = 13 | description: description 14 | @setState(state) 15 | $(window).trigger('setup.steps.change', {description: description}) 16 | 17 | isValid: -> 18 | true # description is allowed to be empty 19 | 20 | render: -> 21 | `
22 |
23 |
24 |