├── log └── .gitkeep ├── lib ├── tasks │ ├── .gitkeep │ └── scraping.rake └── assets │ └── .gitkeep ├── app ├── mailers │ └── .gitkeep ├── models │ ├── .gitkeep │ ├── code.rb │ ├── media_threadx.rb │ ├── threadx_collaborator.rb │ ├── taxonomy.rb │ ├── threadx_taxonomy.rb │ ├── taxonomy_option.rb │ ├── coded_page.rb │ ├── taxonomy_classification.rb │ ├── area.rb │ ├── highlighted_area.rb │ ├── media.rb │ ├── user.rb │ └── image.rb ├── helpers │ ├── home_helper.rb │ ├── users_helper.rb │ ├── coding_helper.rb │ ├── images_helper.rb │ ├── media_helper.rb │ ├── application_helper.rb │ └── thread_helper.rb ├── assets │ ├── images │ │ ├── 404.jpg │ │ ├── rails.png │ │ ├── favicon.ico │ │ ├── icon-close.png │ │ ├── icon-edit.png │ │ ├── header-blog.png │ │ ├── transparent.png │ │ ├── twitter-icon.png │ │ ├── youtube-icon.png │ │ ├── header-blog-2.png │ │ ├── wordpress-icon.png │ │ ├── imago-pageonex-1.png │ │ ├── imago-pageonex-2.png │ │ ├── imago-pageonex-3.png │ │ ├── imago-pageonex-4.png │ │ └── detail-front-pages.png │ ├── javascripts │ │ ├── images │ │ │ ├── colors.png │ │ │ └── trigger.png │ │ ├── bootstrap.js.coffee │ │ ├── home.js.coffee │ │ ├── threads.js.coffee │ │ ├── utils.js │ │ ├── topic_form.js │ │ ├── collaborators.js │ │ ├── application.js │ │ ├── spin.min.js │ │ └── jquery.hotkeys.js │ └── stylesheets │ │ ├── jquery.minicolors.png │ │ ├── imgareaselect-css │ │ ├── border-h.gif │ │ ├── border-v.gif │ │ ├── border-anim-h.gif │ │ ├── border-anim-v.gif │ │ ├── imgareaselect-deprecated.css │ │ ├── imgareaselect-default.css │ │ └── imgareaselect-animated.css │ │ ├── home.css.scss │ │ ├── threads.css.scss │ │ ├── bootstrap_and_overrides.css.less │ │ ├── coding.css.scss │ │ └── application.css ├── views │ ├── media │ │ ├── new.html.erb │ │ ├── edit.html.erb │ │ ├── show.html.erb │ │ ├── index.html.erb │ │ └── _form.html.erb │ ├── images │ │ ├── new.html.erb │ │ ├── edit.html.erb │ │ ├── _form.html.erb │ │ ├── show.html.erb │ │ └── index.html.erb │ ├── users │ │ ├── edit.html.erb │ │ ├── new.html.erb │ │ ├── _form.html.erb │ │ ├── show.html.erb │ │ └── index.html.erb │ ├── devise │ │ ├── mailer │ │ │ ├── confirmation_instructions.html.erb │ │ │ ├── unlock_instructions.html.erb │ │ │ └── reset_password_instructions.html.erb │ │ ├── unlocks │ │ │ └── new.html.erb │ │ ├── passwords │ │ │ ├── new.html.erb │ │ │ └── edit.html.erb │ │ ├── confirmations │ │ │ └── new.html.erb │ │ ├── sessions │ │ │ └── new.html.erb │ │ ├── registrations │ │ │ ├── new.html.erb │ │ │ └── edit.html.erb │ │ └── _links.erb │ ├── coding │ │ ├── _coding_footer.html.erb │ │ └── embed.html.erb │ ├── home │ │ ├── help.html.erb │ │ ├── about.html.erb │ │ └── index.html.erb │ ├── taxonomies │ │ ├── new.html.erb │ │ ├── index.html.erb │ │ └── edit.html.erb │ ├── taxonomy_options │ │ ├── _form.html.erb │ │ ├── edit.html.erb │ │ └── index.html.erb │ ├── threads │ │ ├── _topic_form.html.erb │ │ └── index.html.erb │ └── layouts │ │ └── embed.html.erb └── controllers │ ├── home_controller.rb │ ├── application_controller.rb │ ├── taxonomies_controller.rb │ ├── taxonomy_options_controller.rb │ ├── users_controller.rb │ ├── media_controller.rb │ └── images_controller.rb ├── vendor ├── plugins │ └── .gitkeep └── assets │ ├── javascripts │ └── .gitkeep │ └── stylesheets │ └── .gitkeep ├── .ruby-gemset ├── .ruby-version ├── .env ├── docker-ruby ├── v1.9.3 │ ├── REVISION │ ├── Makefile │ └── Dockerfile ├── Makefile.main └── README.md ├── docker-compose-files ├── pageonex.cnf ├── pageonex-build.cnf └── wrap-start-app.sh ├── favicon.ico ├── public ├── favicon.ico ├── nothing-to-code.png ├── robots.txt ├── 500.html ├── 422.html └── 404.html ├── .dockerignore ├── release-tasks.sh ├── config ├── local_env.yml ├── initializers │ ├── abstract_mysql2_adapter.rb │ ├── mime_types.rb │ ├── application.rb │ ├── backtrace_silencers.rb │ ├── session_store.rb │ ├── secret_token.rb │ ├── wrap_parameters.rb │ └── inflections.rb ├── boot.rb ├── locales │ ├── en.yml │ ├── en.bootstrap.yml │ └── devise.en.yml ├── environment.rb ├── piwik.yml ├── database.yml ├── environments │ ├── test.rb │ ├── development.rb │ └── production.rb ├── puma.rb ├── routes.rb └── application.rb ├── spec ├── controllers │ ├── coding_controller_spec.rb │ ├── threads_controller_spec.rb │ └── home_controller_spec.rb ├── models │ ├── area_spec.rb │ ├── code_spec.rb │ ├── image_spec.rb │ ├── media_spec.rb │ ├── user_spec.rb │ ├── threadx_spec.rb │ ├── coded_page_spec.rb │ ├── image_code_spec.rb │ ├── media_threadx_spec.rb │ ├── threadx_image_spec.rb │ ├── highlighted_area_spec.rb │ └── threadx_collaborator_spec.rb ├── factories │ ├── users.rb │ ├── codes.rb │ ├── image_codes.rb │ ├── media_threadxes.rb │ ├── threadx_collaborators.rb │ ├── coded_pages.rb │ ├── threadx_images.rb │ ├── areas.rb │ ├── highlighted_areas.rb │ ├── images.rb │ ├── media.rb │ └── threadxes.rb ├── views │ ├── home │ │ └── index.html.erb_spec.rb │ ├── users │ │ ├── show.html.erb_spec.rb │ │ ├── index.html.erb_spec.rb │ │ ├── new.html.erb_spec.rb │ │ └── edit.html.erb_spec.rb │ ├── images │ │ ├── show.html.erb_spec.rb │ │ ├── index.html.erb_spec.rb │ │ ├── new.html.erb_spec.rb │ │ └── edit.html.erb_spec.rb │ └── media │ │ ├── show.html.erb_spec.rb │ │ ├── new.html.erb_spec.rb │ │ ├── edit.html.erb_spec.rb │ │ └── index.html.erb_spec.rb ├── requests │ ├── images_spec.rb │ ├── media_spec.rb │ └── users_spec.rb ├── helpers │ ├── home_helper_spec.rb │ ├── media_helper_spec.rb │ ├── users_helper_spec.rb │ ├── coding_helper_spec.rb │ ├── images_helper_spec.rb │ ├── thread_helper_spec.rb │ └── threads_helper_spec.rb └── routing │ ├── media_routing_spec.rb │ ├── users_routing_spec.rb │ └── images_routing_spec.rb ├── db ├── migrate │ ├── 20140516094821_add_bio_to_users.rb │ ├── 20130429213553_add_admin_to_users.rb │ ├── 20120704184911_add_color_to_code.rb │ ├── 20120706030854_add_width_to_area.rb │ ├── 20120706030926_add_height_to_area.rb │ ├── 20130327162055_add_missing_to_image.rb │ ├── 20130709193435_remove_image_local_path.rb │ ├── 20120717230420_change_size_type_in_image.rb │ ├── 20130309271421_fix_column_media_name.rb │ ├── 20130322201029_add_source_url_to_image.rb │ ├── 20120706131048_add_image_name_to_image.rb │ ├── 20180703105721_add_parent_id_to_threads.rb │ ├── 20120628160725_add_display_name_to_media.rb │ ├── 20130328193053_add_working_to_media.rb │ ├── 20120704183326_add_code_description_to_code.rb │ ├── 20120713215917_add_name_to_highlighted_area.rb │ ├── 20120716010022_add_threadx_id_to_highlighted_area.rb │ ├── 20180705090755_create_taxonomies.rb │ ├── 20120627142557_create_codes.rb │ ├── 20120707072202_rename_threadx_image_id_to_code_id_from_highlighted_area.rb │ ├── 20120707072849_create_image_codes.rb │ ├── 20120627163234_create_media_threadxes.rb │ ├── 20180705090834_create_taxonomy_options.rb │ ├── 20180706092346_create_threadx_taxonomies.rb │ ├── 20120627142119_create_media.rb │ ├── 20120627151823_create_threadx_collaborators.rb │ ├── 20130306175244_create_coded_pages.rb │ ├── 20120627151947_create_threadx_images.rb │ ├── 20130225233225_remove_threadx_id_from_highlighted_area.rb │ ├── 20120627143712_create_images.rb │ ├── 20120627142446_create_highlighted_areas.rb │ ├── 20120627142253_create_areas.rb │ ├── 20180706092525_create_taxonomy_classifications.rb │ ├── 20130225162431_drop_image_codes.rb │ ├── 20130220214404_drop_threadx_images.rb │ ├── 20120627141933_create_threadxes.rb │ └── 20120627130452_devise_create_users.rb └── seeds.rb ├── app.json ├── config.ru ├── Rakefile ├── script └── rails ├── Dockerfile ├── .project ├── .travis.yml ├── .gitignore ├── Makefile ├── docker-compose-build.yml ├── docker-compose.yml ├── Gemfile └── doc ├── docker ├── running-pageonex-in-your-environment.md ├── running-pageonex-locally-with-docker-compose.md └── development-with-docker-compose.md └── local-install.md /log/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lib/tasks/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/mailers/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/models/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lib/assets/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /vendor/plugins/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.ruby-gemset: -------------------------------------------------------------------------------- 1 | pageonex 2 | -------------------------------------------------------------------------------- /.ruby-version: -------------------------------------------------------------------------------- 1 | ruby-1.9.3 2 | -------------------------------------------------------------------------------- /.env: -------------------------------------------------------------------------------- 1 | RACK_ENV=development 2 | -------------------------------------------------------------------------------- /docker-ruby/v1.9.3/REVISION: -------------------------------------------------------------------------------- 1 | 2 2 | -------------------------------------------------------------------------------- /vendor/assets/javascripts/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /vendor/assets/stylesheets/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/helpers/home_helper.rb: -------------------------------------------------------------------------------- 1 | module HomeHelper 2 | end 3 | -------------------------------------------------------------------------------- /app/helpers/users_helper.rb: -------------------------------------------------------------------------------- 1 | module UsersHelper 2 | end 3 | -------------------------------------------------------------------------------- /docker-ruby/v1.9.3/Makefile: -------------------------------------------------------------------------------- 1 | -include ../Makefile.main 2 | -------------------------------------------------------------------------------- /app/helpers/coding_helper.rb: -------------------------------------------------------------------------------- 1 | module CodingHelper 2 | end 3 | -------------------------------------------------------------------------------- /app/helpers/images_helper.rb: -------------------------------------------------------------------------------- 1 | module ImagesHelper 2 | end 3 | -------------------------------------------------------------------------------- /docker-compose-files/pageonex.cnf: -------------------------------------------------------------------------------- 1 | [mysqld] 2 | port=13306 3 | -------------------------------------------------------------------------------- /docker-compose-files/pageonex-build.cnf: -------------------------------------------------------------------------------- 1 | [mysqld] 2 | port=23306 3 | -------------------------------------------------------------------------------- /favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/montera34/pageonex/HEAD/favicon.ico -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/montera34/pageonex/HEAD/public/favicon.ico -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | .git 2 | docker-compose.yml 3 | doc 4 | *.md 5 | docker-ruby 6 | docker-compose-files 7 | -------------------------------------------------------------------------------- /app/assets/images/404.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/montera34/pageonex/HEAD/app/assets/images/404.jpg -------------------------------------------------------------------------------- /app/assets/images/rails.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/montera34/pageonex/HEAD/app/assets/images/rails.png -------------------------------------------------------------------------------- /public/nothing-to-code.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/montera34/pageonex/HEAD/public/nothing-to-code.png -------------------------------------------------------------------------------- /app/assets/images/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/montera34/pageonex/HEAD/app/assets/images/favicon.ico -------------------------------------------------------------------------------- /release-tasks.sh: -------------------------------------------------------------------------------- 1 | rake db:migrate 2 | rake scraping:update_media 3 | rake bundle exec rake assets:precompile 4 | -------------------------------------------------------------------------------- /app/assets/images/icon-close.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/montera34/pageonex/HEAD/app/assets/images/icon-close.png -------------------------------------------------------------------------------- /app/assets/images/icon-edit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/montera34/pageonex/HEAD/app/assets/images/icon-edit.png -------------------------------------------------------------------------------- /app/assets/images/header-blog.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/montera34/pageonex/HEAD/app/assets/images/header-blog.png -------------------------------------------------------------------------------- /app/assets/images/transparent.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/montera34/pageonex/HEAD/app/assets/images/transparent.png -------------------------------------------------------------------------------- /app/assets/images/twitter-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/montera34/pageonex/HEAD/app/assets/images/twitter-icon.png -------------------------------------------------------------------------------- /app/assets/images/youtube-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/montera34/pageonex/HEAD/app/assets/images/youtube-icon.png -------------------------------------------------------------------------------- /app/helpers/media_helper.rb: -------------------------------------------------------------------------------- 1 | module MediaHelper 2 | 3 | def media_index_path arg 4 | '/media' 5 | end 6 | 7 | end 8 | -------------------------------------------------------------------------------- /app/models/code.rb: -------------------------------------------------------------------------------- 1 | class Code < ActiveRecord::Base 2 | belongs_to :threadx 3 | has_many :highlighted_areas 4 | end 5 | -------------------------------------------------------------------------------- /config/local_env.yml: -------------------------------------------------------------------------------- 1 | # ImageMagick settings 2 | 3 | # yield the cpu in chunks of this many ms 4 | MAGICK_THROTTLE: '1' 5 | -------------------------------------------------------------------------------- /spec/controllers/coding_controller_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe CodingController do 4 | 5 | end 6 | -------------------------------------------------------------------------------- /spec/controllers/threads_controller_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe ThreadsController do 4 | 5 | end 6 | -------------------------------------------------------------------------------- /app/assets/images/header-blog-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/montera34/pageonex/HEAD/app/assets/images/header-blog-2.png -------------------------------------------------------------------------------- /app/assets/images/wordpress-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/montera34/pageonex/HEAD/app/assets/images/wordpress-icon.png -------------------------------------------------------------------------------- /app/models/media_threadx.rb: -------------------------------------------------------------------------------- 1 | class MediaThreadx < ActiveRecord::Base 2 | belongs_to :threadx 3 | belongs_to :media 4 | end 5 | -------------------------------------------------------------------------------- /app/assets/images/imago-pageonex-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/montera34/pageonex/HEAD/app/assets/images/imago-pageonex-1.png -------------------------------------------------------------------------------- /app/assets/images/imago-pageonex-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/montera34/pageonex/HEAD/app/assets/images/imago-pageonex-2.png -------------------------------------------------------------------------------- /app/assets/images/imago-pageonex-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/montera34/pageonex/HEAD/app/assets/images/imago-pageonex-3.png -------------------------------------------------------------------------------- /app/assets/images/imago-pageonex-4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/montera34/pageonex/HEAD/app/assets/images/imago-pageonex-4.png -------------------------------------------------------------------------------- /app/assets/images/detail-front-pages.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/montera34/pageonex/HEAD/app/assets/images/detail-front-pages.png -------------------------------------------------------------------------------- /app/assets/javascripts/images/colors.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/montera34/pageonex/HEAD/app/assets/javascripts/images/colors.png -------------------------------------------------------------------------------- /app/assets/javascripts/images/trigger.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/montera34/pageonex/HEAD/app/assets/javascripts/images/trigger.png -------------------------------------------------------------------------------- /app/assets/stylesheets/jquery.minicolors.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/montera34/pageonex/HEAD/app/assets/stylesheets/jquery.minicolors.png -------------------------------------------------------------------------------- /app/models/threadx_collaborator.rb: -------------------------------------------------------------------------------- 1 | class ThreadxCollaborator < ActiveRecord::Base 2 | belongs_to :threadx 3 | belongs_to :user 4 | end 5 | -------------------------------------------------------------------------------- /spec/models/area_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe Area do 4 | pending "add some examples to (or delete) #{__FILE__}" 5 | end 6 | -------------------------------------------------------------------------------- /spec/models/code_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe Code do 4 | pending "add some examples to (or delete) #{__FILE__}" 5 | end 6 | -------------------------------------------------------------------------------- /spec/models/image_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe Image do 4 | pending "add some examples to (or delete) #{__FILE__}" 5 | end 6 | -------------------------------------------------------------------------------- /spec/models/media_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe Media do 4 | pending "add some examples to (or delete) #{__FILE__}" 5 | end 6 | -------------------------------------------------------------------------------- /spec/models/user_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe User do 4 | pending "add some examples to (or delete) #{__FILE__}" 5 | end 6 | -------------------------------------------------------------------------------- /app/assets/javascripts/bootstrap.js.coffee: -------------------------------------------------------------------------------- 1 | jQuery -> 2 | $("a[rel=popover]").popover() 3 | $(".tooltip").tooltip() 4 | $("a[rel=tooltip]").tooltip() -------------------------------------------------------------------------------- /spec/models/threadx_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe Threadx do 4 | pending "add some examples to (or delete) #{__FILE__}" 5 | end 6 | -------------------------------------------------------------------------------- /spec/models/coded_page_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe CodedPage do 4 | pending "add some examples to (or delete) #{__FILE__}" 5 | end 6 | -------------------------------------------------------------------------------- /spec/models/image_code_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe ImageCode do 4 | pending "add some examples to (or delete) #{__FILE__}" 5 | end 6 | -------------------------------------------------------------------------------- /app/assets/stylesheets/imgareaselect-css/border-h.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/montera34/pageonex/HEAD/app/assets/stylesheets/imgareaselect-css/border-h.gif -------------------------------------------------------------------------------- /app/assets/stylesheets/imgareaselect-css/border-v.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/montera34/pageonex/HEAD/app/assets/stylesheets/imgareaselect-css/border-v.gif -------------------------------------------------------------------------------- /spec/models/media_threadx_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe MediaThreadx do 4 | pending "add some examples to (or delete) #{__FILE__}" 5 | end 6 | -------------------------------------------------------------------------------- /spec/models/threadx_image_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe ThreadxImage do 4 | pending "add some examples to (or delete) #{__FILE__}" 5 | end 6 | -------------------------------------------------------------------------------- /app/views/media/new.html.erb: -------------------------------------------------------------------------------- 1 | <% @title = "New Media - PageOneX" %> 2 |

New Media

3 | 4 | <%= render 'form' %> 5 | 6 | <%= link_to 'Back', media_path %> 7 | -------------------------------------------------------------------------------- /spec/factories/users.rb: -------------------------------------------------------------------------------- 1 | # Read about factories at https://github.com/thoughtbot/factory_girl 2 | 3 | FactoryGirl.define do 4 | factory :user do 5 | end 6 | end 7 | -------------------------------------------------------------------------------- /spec/models/highlighted_area_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe HighlightedArea do 4 | pending "add some examples to (or delete) #{__FILE__}" 5 | end 6 | -------------------------------------------------------------------------------- /app/assets/stylesheets/imgareaselect-css/border-anim-h.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/montera34/pageonex/HEAD/app/assets/stylesheets/imgareaselect-css/border-anim-h.gif -------------------------------------------------------------------------------- /app/assets/stylesheets/imgareaselect-css/border-anim-v.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/montera34/pageonex/HEAD/app/assets/stylesheets/imgareaselect-css/border-anim-v.gif -------------------------------------------------------------------------------- /app/helpers/application_helper.rb: -------------------------------------------------------------------------------- 1 | module ApplicationHelper 2 | 3 | def use_local_images 4 | Pageonex::Application.config.use_local_images 5 | end 6 | 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20140516094821_add_bio_to_users.rb: -------------------------------------------------------------------------------- 1 | class AddBioToUsers < ActiveRecord::Migration 2 | def change 3 | add_column :users, :bio, :text 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20130429213553_add_admin_to_users.rb: -------------------------------------------------------------------------------- 1 | class AddAdminToUsers < ActiveRecord::Migration 2 | def change 3 | add_column :users, :admin, :boolean 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /spec/models/threadx_collaborator_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe ThreadxCollaborator do 4 | pending "add some examples to (or delete) #{__FILE__}" 5 | end 6 | -------------------------------------------------------------------------------- /spec/views/home/index.html.erb_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe "home/index.html.erb" do 4 | pending "add some examples to (or delete) #{__FILE__}" 5 | end 6 | -------------------------------------------------------------------------------- /app.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "PageOneX", 3 | "description": "", 4 | "scripts": { 5 | "dokku": { 6 | "predepploy": "./release-tasks.sh" 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /config.ru: -------------------------------------------------------------------------------- 1 | # This file is used by Rack-based servers to start the application. 2 | 3 | require ::File.expand_path('../config/environment', __FILE__) 4 | run Pageonex::Application 5 | -------------------------------------------------------------------------------- /db/migrate/20120704184911_add_color_to_code.rb: -------------------------------------------------------------------------------- 1 | class AddColorToCode < ActiveRecord::Migration 2 | def change 3 | add_column :codes, :color, :string 4 | 5 | end 6 | end 7 | -------------------------------------------------------------------------------- /db/migrate/20120706030854_add_width_to_area.rb: -------------------------------------------------------------------------------- 1 | class AddWidthToArea < ActiveRecord::Migration 2 | def change 3 | add_column :areas, :width, :integer 4 | 5 | end 6 | end 7 | -------------------------------------------------------------------------------- /app/models/taxonomy.rb: -------------------------------------------------------------------------------- 1 | class Taxonomy < ActiveRecord::Base 2 | has_many :taxonomy_options, dependent: :destroy 3 | 4 | validates :name, presence: true, uniqueness: true 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20120706030926_add_height_to_area.rb: -------------------------------------------------------------------------------- 1 | class AddHeightToArea < ActiveRecord::Migration 2 | def change 3 | add_column :areas, :height, :integer 4 | 5 | end 6 | end 7 | -------------------------------------------------------------------------------- /db/migrate/20130327162055_add_missing_to_image.rb: -------------------------------------------------------------------------------- 1 | class AddMissingToImage < ActiveRecord::Migration 2 | def change 3 | add_column :images, :missing, :boolean 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20130709193435_remove_image_local_path.rb: -------------------------------------------------------------------------------- 1 | class RemoveImageLocalPath < ActiveRecord::Migration 2 | def change 3 | remove_column :images, :local_path 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /config/initializers/abstract_mysql2_adapter.rb: -------------------------------------------------------------------------------- 1 | class ActiveRecord::ConnectionAdapters::Mysql2Adapter 2 | NATIVE_DATABASE_TYPES[:primary_key] = "int(11) auto_increment PRIMARY KEY" 3 | end 4 | -------------------------------------------------------------------------------- /db/migrate/20120717230420_change_size_type_in_image.rb: -------------------------------------------------------------------------------- 1 | class ChangeSizeTypeInImage < ActiveRecord::Migration 2 | def change 3 | change_column :images, :size, :string 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20130309271421_fix_column_media_name.rb: -------------------------------------------------------------------------------- 1 | class FixColumnMediaName < ActiveRecord::Migration 2 | def change 3 | rename_column :media, :city, :country_code 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20130322201029_add_source_url_to_image.rb: -------------------------------------------------------------------------------- 1 | class AddSourceUrlToImage < ActiveRecord::Migration 2 | def change 3 | add_column :images, :source_url, :string 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20120706131048_add_image_name_to_image.rb: -------------------------------------------------------------------------------- 1 | class AddImageNameToImage < ActiveRecord::Migration 2 | def change 3 | add_column :images, :image_name, :string 4 | 5 | end 6 | end 7 | -------------------------------------------------------------------------------- /db/migrate/20180703105721_add_parent_id_to_threads.rb: -------------------------------------------------------------------------------- 1 | class AddParentIdToThreads < ActiveRecord::Migration 2 | def change 3 | add_column :threadxes, :parent_id, :integer 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20120628160725_add_display_name_to_media.rb: -------------------------------------------------------------------------------- 1 | class AddDisplayNameToMedia < ActiveRecord::Migration 2 | def change 3 | add_column :media, :display_name, :string 4 | 5 | end 6 | end 7 | -------------------------------------------------------------------------------- /db/migrate/20130328193053_add_working_to_media.rb: -------------------------------------------------------------------------------- 1 | class AddWorkingToMedia < ActiveRecord::Migration 2 | def change 3 | add_column :media, :working, :boolean, {:default=>true} 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /app/models/threadx_taxonomy.rb: -------------------------------------------------------------------------------- 1 | class ThreadxTaxonomy < ActiveRecord::Base 2 | belongs_to :threadx 3 | belongs_to :taxonomy 4 | 5 | validates :taxonomy_id, uniqueness: { scope: :threadx_id } 6 | end 7 | -------------------------------------------------------------------------------- /app/views/media/edit.html.erb: -------------------------------------------------------------------------------- 1 | <% @title = "Edit medium - PageOneX" %> 2 |

Editing medium

3 | 4 | <%= render 'form' %> 5 | 6 | <%= link_to 'Show', @media %> | 7 | <%= link_to 'Back', media_path %> 8 | -------------------------------------------------------------------------------- /db/migrate/20120704183326_add_code_description_to_code.rb: -------------------------------------------------------------------------------- 1 | class AddCodeDescriptionToCode < ActiveRecord::Migration 2 | def change 3 | add_column :codes, :code_description, :text 4 | 5 | end 6 | end 7 | -------------------------------------------------------------------------------- /db/migrate/20120713215917_add_name_to_highlighted_area.rb: -------------------------------------------------------------------------------- 1 | class AddNameToHighlightedArea < ActiveRecord::Migration 2 | def change 3 | add_column :highlighted_areas, :name, :string 4 | 5 | end 6 | end 7 | -------------------------------------------------------------------------------- /spec/factories/codes.rb: -------------------------------------------------------------------------------- 1 | # Read about factories at https://github.com/thoughtbot/factory_girl 2 | 3 | FactoryGirl.define do 4 | factory :code do 5 | code_text "MyString" 6 | threadx_id 1 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /spec/factories/image_codes.rb: -------------------------------------------------------------------------------- 1 | # Read about factories at https://github.com/thoughtbot/factory_girl 2 | 3 | FactoryGirl.define do 4 | factory :image_code do 5 | image_id 1 6 | code_id 1 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /app/assets/stylesheets/home.css.scss: -------------------------------------------------------------------------------- 1 | // Place all the styles related to the home controller here. 2 | // They will automatically be included in application.css. 3 | // You can use Sass (SCSS) here: http://sass-lang.com/ 4 | -------------------------------------------------------------------------------- /spec/factories/media_threadxes.rb: -------------------------------------------------------------------------------- 1 | # Read about factories at https://github.com/thoughtbot/factory_girl 2 | 3 | FactoryGirl.define do 4 | factory :media_threadx do 5 | threadx_id 1 6 | media_id 1 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /config/boot.rb: -------------------------------------------------------------------------------- 1 | require 'rubygems' 2 | 3 | # Set up gems listed in the Gemfile. 4 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__) 5 | 6 | require 'bundler/setup' if File.exists?(ENV['BUNDLE_GEMFILE']) 7 | -------------------------------------------------------------------------------- /db/migrate/20120716010022_add_threadx_id_to_highlighted_area.rb: -------------------------------------------------------------------------------- 1 | class AddThreadxIdToHighlightedArea < ActiveRecord::Migration 2 | def change 3 | add_column :highlighted_areas, :threadx_id, :integer 4 | 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 | -------------------------------------------------------------------------------- /spec/factories/threadx_collaborators.rb: -------------------------------------------------------------------------------- 1 | # Read about factories at https://github.com/thoughtbot/factory_girl 2 | 3 | FactoryGirl.define do 4 | factory :threadx_collaborator do 5 | threadx_id 1 6 | user_id 1 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /spec/factories/coded_pages.rb: -------------------------------------------------------------------------------- 1 | # Read about factories at https://github.com/thoughtbot/factory_girl 2 | 3 | FactoryGirl.define do 4 | factory :coded_page do 5 | threadx_id 1 6 | user_id 1 7 | image_id 1 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /db/migrate/20180705090755_create_taxonomies.rb: -------------------------------------------------------------------------------- 1 | class CreateTaxonomies < ActiveRecord::Migration 2 | def change 3 | create_table :taxonomies do |t| 4 | t.string :name 5 | 6 | t.timestamps 7 | end 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /config/locales/en.yml: -------------------------------------------------------------------------------- 1 | # Sample localization file for English. Add more files in this directory for other locales. 2 | # See https://github.com/svenfuchs/rails-i18n/tree/master/rails%2Flocale for starting points. 3 | 4 | en: 5 | hello: "Hello world" 6 | -------------------------------------------------------------------------------- /spec/factories/threadx_images.rb: -------------------------------------------------------------------------------- 1 | # Read about factories at https://github.com/thoughtbot/factory_girl 2 | 3 | FactoryGirl.define do 4 | factory :threadx_image do 5 | threadx_id 1 6 | image_id 1 7 | code_id 1 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /spec/factories/areas.rb: -------------------------------------------------------------------------------- 1 | # Read about factories at https://github.com/thoughtbot/factory_girl 2 | 3 | FactoryGirl.define do 4 | factory :area do 5 | x1 1 6 | y1 1 7 | x2 1 8 | y2 1 9 | highlighted_area_id 1 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /spec/factories/highlighted_areas.rb: -------------------------------------------------------------------------------- 1 | # Read about factories at https://github.com/thoughtbot/factory_girl 2 | 3 | FactoryGirl.define do 4 | factory :highlighted_area do 5 | image_id 1 6 | user_id 1 7 | threadx_image_id 1 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /db/migrate/20120627142557_create_codes.rb: -------------------------------------------------------------------------------- 1 | class CreateCodes < ActiveRecord::Migration 2 | def change 3 | create_table :codes do |t| 4 | t.string :code_text 5 | t.integer :threadx_id 6 | 7 | t.timestamps 8 | end 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /spec/factories/images.rb: -------------------------------------------------------------------------------- 1 | # Read about factories at https://github.com/thoughtbot/factory_girl 2 | 3 | FactoryGirl.define do 4 | factory :image do 5 | type "" 6 | publication_date "2012-06-27" 7 | size 1 8 | media_id 1 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /app/assets/javascripts/home.js.coffee: -------------------------------------------------------------------------------- 1 | # Place all the behaviors and hooks related to the matching controller here. 2 | # All this logic will automatically be available in application.js. 3 | # You can use CoffeeScript in this file: http://jashkenas.github.com/coffee-script/ 4 | -------------------------------------------------------------------------------- /config/environment.rb: -------------------------------------------------------------------------------- 1 | # Load the rails application 2 | require File.expand_path('../application', __FILE__) 3 | 4 | # Initialize the rails application 5 | Pageonex::Application.initialize! 6 | 7 | Mime::Type.register "application/x-vnd.oasis.opendocument.spreadsheet", :ods -------------------------------------------------------------------------------- /db/migrate/20120707072202_rename_threadx_image_id_to_code_id_from_highlighted_area.rb: -------------------------------------------------------------------------------- 1 | class RenameThreadxImageIdToCodeIdFromHighlightedArea < ActiveRecord::Migration 2 | def change 3 | rename_column :highlighted_areas, :threadx_image_id, :code_id 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /spec/controllers/home_controller_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe HomeController do 4 | 5 | describe "GET 'index'" do 6 | it "returns http success" do 7 | get 'index' 8 | response.should be_success 9 | end 10 | end 11 | 12 | end 13 | -------------------------------------------------------------------------------- /db/migrate/20120707072849_create_image_codes.rb: -------------------------------------------------------------------------------- 1 | class CreateImageCodes < ActiveRecord::Migration 2 | def change 3 | create_table :image_codes do |t| 4 | t.integer :image_id 5 | t.integer :code_id 6 | 7 | t.timestamps 8 | end 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /app/assets/javascripts/threads.js.coffee: -------------------------------------------------------------------------------- 1 | # Place all the behaviors and hooks related to the matching controller here. 2 | # All this logic will automatically be available in application.js. 3 | # You can use CoffeeScript in this file: http://jashkenas.github.com/coffee-script/ 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/assets/javascripts/utils.js: -------------------------------------------------------------------------------- 1 | $(document).ready(function () { 2 | 3 | $(".js-toggle-elements").click(function(){ 4 | show_id = $(this).data('show'); 5 | hide_id = $(this).data('hide'); 6 | $('#'+show_id).show(); 7 | $('#'+hide_id).hide(); 8 | }); 9 | 10 | }); 11 | -------------------------------------------------------------------------------- /app/models/taxonomy_option.rb: -------------------------------------------------------------------------------- 1 | class TaxonomyOption < ActiveRecord::Base 2 | belongs_to :taxonomy 3 | has_many :taxonomy_classifications, dependent: :destroy 4 | 5 | validates :value, presence: true, uniqueness: { scope: :taxonomy_id } 6 | validates :taxonomy_id, presence: true 7 | end 8 | -------------------------------------------------------------------------------- /spec/factories/media.rb: -------------------------------------------------------------------------------- 1 | # Read about factories at https://github.com/thoughtbot/factory_girl 2 | 3 | FactoryGirl.define do 4 | factory :medium, :class => 'Media' do 5 | name "MyString" 6 | country "MyString" 7 | city "MyString" 8 | url "MyString" 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /db/migrate/20120627163234_create_media_threadxes.rb: -------------------------------------------------------------------------------- 1 | class CreateMediaThreadxes < ActiveRecord::Migration 2 | def change 3 | create_table :media_threadxes do |t| 4 | t.integer :threadx_id 5 | t.integer :media_id 6 | 7 | t.timestamps 8 | end 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /db/migrate/20180705090834_create_taxonomy_options.rb: -------------------------------------------------------------------------------- 1 | class CreateTaxonomyOptions < ActiveRecord::Migration 2 | def change 3 | create_table :taxonomy_options do |t| 4 | t.string :value 5 | t.integer :taxonomy_id 6 | 7 | t.timestamps 8 | end 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /app/views/images/new.html.erb: -------------------------------------------------------------------------------- 1 | <% @title = "New image - PageOneX" %> 2 | <%- model_class = Image -%> 3 | 6 | <%= render :partial => 'form' %> 7 | -------------------------------------------------------------------------------- /app/views/users/edit.html.erb: -------------------------------------------------------------------------------- 1 | <% @title = "Edit user - PageOneX" %> 2 | <%- model_class = User -%> 3 | 6 | <%= render :partial => 'form' %> 7 | -------------------------------------------------------------------------------- /app/views/users/new.html.erb: -------------------------------------------------------------------------------- 1 | <% @title = "User page - PageOneX" %> 2 | <%- model_class = User -%> 3 | 6 | <%= render :partial => 'form' %> 7 | -------------------------------------------------------------------------------- /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 | Mime::Type.register "image/svg+xml", :svg 7 | -------------------------------------------------------------------------------- /db/migrate/20180706092346_create_threadx_taxonomies.rb: -------------------------------------------------------------------------------- 1 | class CreateThreadxTaxonomies < ActiveRecord::Migration 2 | def change 3 | create_table :threadx_taxonomies do |t| 4 | t.integer :threadx_id 5 | t.integer :taxonomy_id 6 | 7 | t.timestamps 8 | end 9 | end 10 | end -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env rake 2 | # Add your own tasks in files placed in lib/tasks ending in .rake, 3 | # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake. 4 | 5 | require File.expand_path('../config/application', __FILE__) 6 | 7 | Pageonex::Application.load_tasks 8 | -------------------------------------------------------------------------------- /app/views/images/edit.html.erb: -------------------------------------------------------------------------------- 1 | <% @title = "Image edit - PageOneX" %> 2 | <%- model_class = Image -%> 3 | 6 | <%= render :partial => 'form' %> 7 | -------------------------------------------------------------------------------- /db/migrate/20120627142119_create_media.rb: -------------------------------------------------------------------------------- 1 | class CreateMedia < ActiveRecord::Migration 2 | def change 3 | create_table :media do |t| 4 | t.string :name 5 | t.string :country 6 | t.string :city 7 | t.string :url 8 | 9 | t.timestamps 10 | end 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /db/migrate/20120627151823_create_threadx_collaborators.rb: -------------------------------------------------------------------------------- 1 | class CreateThreadxCollaborators < ActiveRecord::Migration 2 | def change 3 | create_table :threadx_collaborators do |t| 4 | t.integer :threadx_id 5 | t.integer :user_id 6 | 7 | t.timestamps 8 | end 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /db/migrate/20130306175244_create_coded_pages.rb: -------------------------------------------------------------------------------- 1 | class CreateCodedPages < ActiveRecord::Migration 2 | def change 3 | create_table :coded_pages do |t| 4 | t.integer :threadx_id 5 | t.integer :user_id 6 | t.integer :image_id 7 | 8 | t.timestamps 9 | end 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /db/migrate/20120627151947_create_threadx_images.rb: -------------------------------------------------------------------------------- 1 | class CreateThreadxImages < ActiveRecord::Migration 2 | def change 3 | create_table :threadx_images do |t| 4 | t.integer :threadx_id 5 | t.integer :image_id 6 | t.integer :code_id 7 | 8 | t.timestamps 9 | end 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /db/migrate/20130225233225_remove_threadx_id_from_highlighted_area.rb: -------------------------------------------------------------------------------- 1 | class RemoveThreadxIdFromHighlightedArea < ActiveRecord::Migration 2 | def up 3 | remove_column :highlighted_areas, :threadx_id 4 | end 5 | 6 | def down 7 | add_column :highlighted_areas, :threadx_id, :integer 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /script/rails: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # This command will automatically be run when you run "rails" with Rails 3 gems installed from the root of your application. 3 | 4 | APP_PATH = File.expand_path('../../config/application', __FILE__) 5 | require File.expand_path('../../config/boot', __FILE__) 6 | require 'rails/commands' 7 | -------------------------------------------------------------------------------- /db/migrate/20120627143712_create_images.rb: -------------------------------------------------------------------------------- 1 | class CreateImages < ActiveRecord::Migration 2 | def change 3 | create_table :images do |t| 4 | t.date :publication_date 5 | t.integer :size 6 | t.string :local_path 7 | t.integer :media_id 8 | 9 | t.timestamps 10 | end 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /db/migrate/20120627142446_create_highlighted_areas.rb: -------------------------------------------------------------------------------- 1 | class CreateHighlightedAreas < ActiveRecord::Migration 2 | def change 3 | create_table :highlighted_areas do |t| 4 | t.integer :image_id 5 | t.integer :user_id 6 | t.integer :threadx_image_id 7 | 8 | t.timestamps 9 | end 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /app/assets/stylesheets/threads.css.scss: -------------------------------------------------------------------------------- 1 | // Place all the styles related to the threads controller here. 2 | // They will automatically be included in application.css. 3 | // You can use Sass (SCSS) here: http://sass-lang.com/ 4 | 5 | .topic_color_box { 6 | margin-bottom: 10px; 7 | } 8 | 9 | ul#collab-list { 10 | margin-top: 1em; 11 | } -------------------------------------------------------------------------------- /db/migrate/20120627142253_create_areas.rb: -------------------------------------------------------------------------------- 1 | class CreateAreas < ActiveRecord::Migration 2 | def change 3 | create_table :areas do |t| 4 | t.integer :x1 5 | t.integer :y1 6 | t.integer :x2 7 | t.integer :y2 8 | t.integer :highlighted_area_id 9 | 10 | t.timestamps 11 | end 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /db/migrate/20180706092525_create_taxonomy_classifications.rb: -------------------------------------------------------------------------------- 1 | class CreateTaxonomyClassifications < ActiveRecord::Migration 2 | def change 3 | create_table :taxonomy_classifications do |t| 4 | t.integer :highlighted_area_id 5 | t.integer :taxonomy_option_id 6 | 7 | t.timestamps 8 | end 9 | end 10 | end 11 | 12 | -------------------------------------------------------------------------------- /app/views/devise/mailer/confirmation_instructions.html.erb: -------------------------------------------------------------------------------- 1 | <% @title = "Welcome email - PageOneX" %> 2 |

Welcome <%= @resource.email %>!

3 | 4 |

You can confirm your account email through the link below:

5 | 6 |

<%= link_to 'Confirm my account', confirmation_url(@resource, :confirmation_token => @resource.confirmation_token) %>

7 | -------------------------------------------------------------------------------- /spec/views/users/show.html.erb_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe "users/show" do 4 | before(:each) do 5 | @user = assign(:user, stub_model(User)) 6 | end 7 | 8 | it "renders attributes in

" do 9 | render 10 | # Run the generator again with the --webrat flag if you want to use webrat matchers 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /app/models/coded_page.rb: -------------------------------------------------------------------------------- 1 | class CodedPage < ActiveRecord::Base 2 | belongs_to :threadx 3 | has_one :user 4 | has_one :image 5 | 6 | def self.for_user(user) 7 | return where(1) if user.nil? 8 | where(:user_id => user.id) 9 | end 10 | 11 | def self.for_image(image) 12 | where(:image_id => image.id) 13 | end 14 | 15 | end 16 | -------------------------------------------------------------------------------- /spec/views/images/show.html.erb_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe "images/show" do 4 | before(:each) do 5 | @image = assign(:image, stub_model(Image)) 6 | end 7 | 8 | it "renders attributes in

" do 9 | render 10 | # Run the generator again with the --webrat flag if you want to use webrat matchers 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /spec/requests/images_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe "Images" do 4 | describe "GET /images" do 5 | it "works! (now write some real specs)" do 6 | # Run the generator again with the --webrat flag if you want to use webrat methods/matchers 7 | get images_path 8 | response.status.should be(200) 9 | end 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /spec/requests/media_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe "Media" do 4 | describe "GET /media" do 5 | it "works! (now write some real specs)" do 6 | # Run the generator again with the --webrat flag if you want to use webrat methods/matchers 7 | get media_path 8 | response.status.should be(200) 9 | end 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /spec/requests/users_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe "Users" do 4 | describe "GET /users" do 5 | it "works! (now write some real specs)" do 6 | # Run the generator again with the --webrat flag if you want to use webrat methods/matchers 7 | get users_path 8 | response.status.should be(200) 9 | end 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /docker-ruby/Makefile.main: -------------------------------------------------------------------------------- 1 | PROJECT = ruby-base 2 | DOCKER_REGISTRY = docker.io 3 | DOCKER_ORG = pageonex 4 | VERSION := $(shell echo `basename "$(PWD)"`.`cat REVISION`) 5 | DOCKER_IMAGE = $(DOCKER_REGISTRY)/$(DOCKER_ORG)/$(PROJECT):$(VERSION) 6 | 7 | docker-build: 8 | docker build -t $(DOCKER_IMAGE) . 9 | 10 | docker-push: docker-build 11 | docker push $(DOCKER_IMAGE) 12 | -------------------------------------------------------------------------------- /spec/factories/threadxes.rb: -------------------------------------------------------------------------------- 1 | # Read about factories at https://github.com/thoughtbot/factory_girl 2 | 3 | FactoryGirl.define do 4 | factory :threadx do 5 | thread_name "MyString" 6 | thread_display_name "MyString" 7 | start_date "2012-06-27" 8 | end_date "2012-06-27" 9 | description "MyText" 10 | category "MyString" 11 | status "MyString" 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /spec/views/users/index.html.erb_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe "users/index" do 4 | before(:each) do 5 | assign(:users, [ 6 | stub_model(User), 7 | stub_model(User) 8 | ]) 9 | end 10 | 11 | it "renders a list of users" do 12 | render 13 | # Run the generator again with the --webrat flag if you want to use webrat matchers 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /spec/views/images/index.html.erb_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe "images/index" do 4 | before(:each) do 5 | assign(:images, [ 6 | stub_model(Image), 7 | stub_model(Image) 8 | ]) 9 | end 10 | 11 | it "renders a list of images" do 12 | render 13 | # Run the generator again with the --webrat flag if you want to use webrat matchers 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /app/controllers/home_controller.rb: -------------------------------------------------------------------------------- 1 | class HomeController < ApplicationController 2 | def index 3 | @threads = Threadx.limit(16) 4 | end 5 | def about 6 | 7 | end 8 | def export_chart 9 | Tempfile.open(['chart', '.svg'], Rails.root.join('tmp')) do |f| 10 | f.print params[:svgdata] 11 | f.flush 12 | send_file f.path, :type => 'image/svg+xml' 13 | end 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /db/migrate/20130225162431_drop_image_codes.rb: -------------------------------------------------------------------------------- 1 | class DropImageCodes < ActiveRecord::Migration 2 | def up 3 | drop_table :image_codes 4 | end 5 | 6 | def down 7 | create_table(:threadx_images) do |t| 8 | t.integer "image_id" 9 | t.integer "code_id" 10 | t.datetime "created_at", :null => false 11 | t.datetime "updated_at", :null => false 12 | end 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM pageonex/ruby-base:v1.9.3.2 2 | 3 | ENV PATH $PATH:/usr/lib/x86_64-linux-gnu/ImageMagick-6.8.9/bin-Q16/ 4 | 5 | WORKDIR /tmp 6 | ADD ./Gemfile Gemfile 7 | ADD ./Gemfile.lock Gemfile.lock 8 | RUN bundle install 9 | 10 | ENV APP_ROOT /workspace 11 | RUN mkdir -p $APP_ROOT 12 | WORKDIR $APP_ROOT 13 | COPY . $APP_ROOT 14 | 15 | EXPOSE 3000 16 | CMD ["bundle", "exec", "puma", "-C", "config/puma.rb"] 17 | -------------------------------------------------------------------------------- /app/views/devise/mailer/unlock_instructions.html.erb: -------------------------------------------------------------------------------- 1 | <% @title = "Unlock password instructions - PageOneX" %> 2 |

Hello <%= @resource.email %>!

3 | 4 |

Your account has been locked due to an excessive amount of unsuccessful sign in attempts.

5 | 6 |

Click the link below to unlock your account:

7 | 8 |

<%= link_to 'Unlock my account', unlock_url(@resource, :unlock_token => @resource.unlock_token) %>

9 | -------------------------------------------------------------------------------- /app/views/devise/unlocks/new.html.erb: -------------------------------------------------------------------------------- 1 |

Resend unlock instructions

2 | 3 | <%= form_for(resource, :as => resource_name, :url => unlock_path(resource_name), :html => { :method => :post }) do |f| %> 4 | <%= devise_error_messages! %> 5 | 6 |
<%= f.label :email %>
7 | <%= f.email_field :email %>
8 | 9 |
<%= f.submit "Resend unlock instructions" %>
10 | <% end %> 11 | 12 | <%= render "links" %> -------------------------------------------------------------------------------- /spec/views/users/new.html.erb_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe "users/new" do 4 | before(:each) do 5 | assign(:user, stub_model(User).as_new_record) 6 | end 7 | 8 | it "renders new user form" do 9 | render 10 | 11 | # Run the generator again with the --webrat flag if you want to use webrat matchers 12 | assert_select "form[action=?][method=?]", users_path, "post" do 13 | end 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /spec/views/images/new.html.erb_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe "images/new" do 4 | before(:each) do 5 | assign(:image, stub_model(Image).as_new_record) 6 | end 7 | 8 | it "renders new image form" do 9 | render 10 | 11 | # Run the generator again with the --webrat flag if you want to use webrat matchers 12 | assert_select "form[action=?][method=?]", images_path, "post" do 13 | end 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /spec/views/users/edit.html.erb_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe "users/edit" do 4 | before(:each) do 5 | @user = assign(:user, stub_model(User)) 6 | end 7 | 8 | it "renders the edit user form" do 9 | render 10 | 11 | # Run the generator again with the --webrat flag if you want to use webrat matchers 12 | assert_select "form[action=?][method=?]", user_path(@user), "post" do 13 | end 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /db/migrate/20130220214404_drop_threadx_images.rb: -------------------------------------------------------------------------------- 1 | class DropThreadxImages < ActiveRecord::Migration 2 | def up 3 | drop_table :threadx_images 4 | end 5 | 6 | def down 7 | create_table(:threadx_images) do |t| 8 | t.integer "threadx_id" 9 | t.integer "image_id" 10 | t.integer "code_id" 11 | t.datetime "created_at", :null => false 12 | t.datetime "updated_at", :null => false 13 | end 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /db/migrate/20120627141933_create_threadxes.rb: -------------------------------------------------------------------------------- 1 | class CreateThreadxes < ActiveRecord::Migration 2 | def change 3 | create_table :threadxes do |t| 4 | t.string :thread_name 5 | t.string :thread_display_name 6 | t.date :start_date 7 | t.date :end_date 8 | t.text :description 9 | t.string :category 10 | t.string :status 11 | t.integer :owner_id 12 | 13 | t.timestamps 14 | end 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /spec/views/images/edit.html.erb_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe "images/edit" do 4 | before(:each) do 5 | @image = assign(:image, stub_model(Image)) 6 | end 7 | 8 | it "renders the edit image form" do 9 | render 10 | 11 | # Run the generator again with the --webrat flag if you want to use webrat matchers 12 | assert_select "form[action=?][method=?]", image_path(@image), "post" do 13 | end 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /config/initializers/application.rb: -------------------------------------------------------------------------------- 1 | 2 | # should we cache the kiosko image files locally, or just show them directly from kiosko's domain? 3 | Pageonex::Application.config.use_local_images = true 4 | 5 | # date format used by kiosko to name their newspaper frontpage image files 6 | Date::DATE_FORMATS[:kiosko_file_datestamp]="%Y/%m/%d" 7 | 8 | # date format we use to create the locally downloaded images 9 | Time::DATE_FORMATS[:file_datestamp] = "%Y-%m-%d" 10 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /app/helpers/thread_helper.rb: -------------------------------------------------------------------------------- 1 | module ThreadHelper 2 | 3 | # use this to link to a thread 4 | def thread_code_url thread, image_name=nil 5 | link = thread_url(thread) + "coding" 6 | link+= "/?i=#{image_name}" unless image_name.nil? 7 | link 8 | end 9 | 10 | def thread_url thread 11 | thread.link_url 12 | end 13 | 14 | def threads_by_user_link user 15 | link_to user.username, '/threads/by/'+user.username 16 | end 17 | 18 | end 19 | -------------------------------------------------------------------------------- /config/initializers/session_store.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | Pageonex::Application.config.session_store :cookie_store, key: '_pageonex_session' 4 | 5 | # Use the database for sessions instead of the cookie-based default, 6 | # which shouldn't be used to store highly confidential information 7 | # (create the session table with "rails generate session_migration") 8 | # Pageonex::Application.config.session_store :active_record_store 9 | -------------------------------------------------------------------------------- /spec/helpers/home_helper_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | # Specs in this file have access to a helper object that includes 4 | # the HomeHelper. For example: 5 | # 6 | # describe HomeHelper do 7 | # describe "string concat" do 8 | # it "concats two strings with spaces" do 9 | # helper.concat_strings("this","that").should == "this that" 10 | # end 11 | # end 12 | # end 13 | describe HomeHelper do 14 | pending "add some examples to (or delete) #{__FILE__}" 15 | end 16 | -------------------------------------------------------------------------------- /app/views/devise/passwords/new.html.erb: -------------------------------------------------------------------------------- 1 | <% @title = "Reset password action - PageOneX" %> 2 |

Forgot your password?

3 | 4 | <%= form_for(resource, :as => resource_name, :url => password_path(resource_name), :html => { :method => :post }) do |f| %> 5 | <%= devise_error_messages! %> 6 | 7 |
<%= f.label :email %> 8 | <%= f.email_field :email %>
9 | 10 |
<%= f.submit "Send me reset password instructions" %>
11 | <% end %> 12 | 13 | <%= render "links" %> 14 | -------------------------------------------------------------------------------- /spec/helpers/media_helper_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | # Specs in this file have access to a helper object that includes 4 | # the MediaHelper. For example: 5 | # 6 | # describe MediaHelper do 7 | # describe "string concat" do 8 | # it "concats two strings with spaces" do 9 | # helper.concat_strings("this","that").should == "this that" 10 | # end 11 | # end 12 | # end 13 | describe MediaHelper do 14 | pending "add some examples to (or delete) #{__FILE__}" 15 | end 16 | -------------------------------------------------------------------------------- /spec/helpers/users_helper_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | # Specs in this file have access to a helper object that includes 4 | # the UsersHelper. For example: 5 | # 6 | # describe UsersHelper do 7 | # describe "string concat" do 8 | # it "concats two strings with spaces" do 9 | # helper.concat_strings("this","that").should == "this that" 10 | # end 11 | # end 12 | # end 13 | describe UsersHelper do 14 | pending "add some examples to (or delete) #{__FILE__}" 15 | end 16 | -------------------------------------------------------------------------------- /spec/helpers/coding_helper_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | # Specs in this file have access to a helper object that includes 4 | # the CodingHelper. For example: 5 | # 6 | # describe CodingHelper do 7 | # describe "string concat" do 8 | # it "concats two strings with spaces" do 9 | # helper.concat_strings("this","that").should == "this that" 10 | # end 11 | # end 12 | # end 13 | describe CodingHelper do 14 | pending "add some examples to (or delete) #{__FILE__}" 15 | end 16 | -------------------------------------------------------------------------------- /spec/helpers/images_helper_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | # Specs in this file have access to a helper object that includes 4 | # the ImagesHelper. For example: 5 | # 6 | # describe ImagesHelper do 7 | # describe "string concat" do 8 | # it "concats two strings with spaces" do 9 | # helper.concat_strings("this","that").should == "this that" 10 | # end 11 | # end 12 | # end 13 | describe ImagesHelper do 14 | pending "add some examples to (or delete) #{__FILE__}" 15 | end 16 | -------------------------------------------------------------------------------- /spec/helpers/thread_helper_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | # Specs in this file have access to a helper object that includes 4 | # the ThreadHelper. For example: 5 | # 6 | # describe ThreadHelper do 7 | # describe "string concat" do 8 | # it "concats two strings with spaces" do 9 | # helper.concat_strings("this","that").should == "this that" 10 | # end 11 | # end 12 | # end 13 | describe ThreadHelper do 14 | pending "add some examples to (or delete) #{__FILE__}" 15 | end 16 | -------------------------------------------------------------------------------- /.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | pageonex 4 | 5 | 6 | 7 | 8 | 9 | com.aptana.ide.core.unifiedBuilder 10 | 11 | 12 | 13 | 14 | 15 | org.radrails.rails.core.railsnature 16 | com.aptana.ruby.core.rubynature 17 | 18 | 19 | -------------------------------------------------------------------------------- /spec/helpers/threads_helper_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | # Specs in this file have access to a helper object that includes 4 | # the ThreadsHelper. For example: 5 | # 6 | # describe ThreadsHelper do 7 | # describe "string concat" do 8 | # it "concats two strings with spaces" do 9 | # helper.concat_strings("this","that").should == "this that" 10 | # end 11 | # end 12 | # end 13 | describe ThreadsHelper do 14 | pending "add some examples to (or delete) #{__FILE__}" 15 | end 16 | -------------------------------------------------------------------------------- /app/views/devise/confirmations/new.html.erb: -------------------------------------------------------------------------------- 1 | <% @title = "Resend confirmation instructions - PageOneX" %> 2 |

Resend confirmation instructions

3 | 4 | <%= form_for(resource, :as => resource_name, :url => confirmation_path(resource_name), :html => { :method => :post }) do |f| %> 5 | <%= devise_error_messages! %> 6 | 7 |
<%= f.label :email %> 8 | <%= f.email_field :email %>
9 | 10 |
<%= f.submit "Resend confirmation instructions" %>
11 | <% end %> 12 | 13 | <%= render "links" %> 14 | -------------------------------------------------------------------------------- /docker-compose-files/wrap-start-app.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # cleanup-pid-file-and-wait-for-mysql.sh 3 | 4 | set -e 5 | 6 | host="$1" 7 | password="$2" 8 | shift; shift 9 | cmd="$@" 10 | 11 | exec 2>&1 12 | 13 | rm -f /workspace/tmp/pids/server.pid 14 | 15 | port=${DATABASE_PORT:-3306} 16 | 17 | until mysql -u root --port $port --password=$password -h $host -e "SELECT 1"; do 18 | echo "Mysql is unavailable - sleeping" 19 | sleep 1 20 | done 21 | 22 | echo "Mysql is up - executing command" 23 | exec bash -c "$cmd" 24 | -------------------------------------------------------------------------------- /config/locales/en.bootstrap.yml: -------------------------------------------------------------------------------- 1 | # Sample localization file for English. Add more files in this directory for other locales. 2 | # See https://github.com/svenfuchs/rails-i18n/tree/master/rails%2Flocale for starting points. 3 | 4 | en: 5 | helpers: 6 | actions: "Actions" 7 | links: 8 | back: "Back" 9 | cancel: "Cancel" 10 | confirm: "Are you sure?" 11 | destroy: "Delete" 12 | new: "New" 13 | titles: 14 | edit: "Edit" 15 | save: "Save" 16 | new: "New" 17 | delete: "Delete" 18 | -------------------------------------------------------------------------------- /config/initializers/secret_token.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Your secret key for verifying the integrity of signed cookies. 4 | # If you change this key, all old signed cookies will become invalid! 5 | # Make sure the secret is at least 30 characters and all random, 6 | # no regular words or you'll be exposed to dictionary attacks. 7 | Pageonex::Application.config.secret_token = '053292efff919bd0a5d02e4bfe0e0aaff33557d5101c0cdc79c4729c230d2258abf080ef4207f88fd0402db92917c0da67453237bef23776134cf349a328e465' 8 | -------------------------------------------------------------------------------- /app/models/taxonomy_classification.rb: -------------------------------------------------------------------------------- 1 | class TaxonomyClassification < ActiveRecord::Base 2 | belongs_to :highlighted_area 3 | belongs_to :taxonomy_option 4 | 5 | delegate :taxonomy, to: :taxonomy_option 6 | delegate :code, to: :highlighted_area 7 | 8 | validate :taxonomy_in_thread 9 | 10 | def taxonomy_in_thread 11 | thread = Threadx.find(code.threadx_id) 12 | unless thread.taxonomy_ids.include?(taxonomy_option.taxonomy_id) 13 | errors.add(:taxonomy_option_id, 'Taxonomy not allowed in this thread') 14 | end 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /config/initializers/wrap_parameters.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | # 3 | # This file contains settings for ActionController::ParamsWrapper which 4 | # is enabled by default. 5 | 6 | # Enable parameter wrapping for JSON. You can disable this by setting :format to an empty array. 7 | ActiveSupport.on_load(:action_controller) do 8 | wrap_parameters format: [:json] 9 | end 10 | 11 | # Disable root element in JSON by default. 12 | ActiveSupport.on_load(:active_record) do 13 | self.include_root_in_json = false 14 | end 15 | -------------------------------------------------------------------------------- /app/models/area.rb: -------------------------------------------------------------------------------- 1 | class Area < ActiveRecord::Base 2 | belongs_to :highlighted_area 3 | 4 | # return a scaled down copy of the area 5 | def scaled_copy scale 6 | return Area.new( 7 | :x1=>(self.x1.to_f * scale).round, 8 | :x2=>(self.x2.to_f * scale).round, 9 | :y1=>(self.y1.to_f * scale).round, 10 | :y2=>(self.y2.to_f * scale).round, 11 | :width=>(self.width.to_f * scale).round, 12 | :height=>(self.height.to_f * scale).round, 13 | :highlighted_area_id=>self.highlighted_area_id, 14 | ) 15 | end 16 | 17 | end 18 | -------------------------------------------------------------------------------- /app/views/devise/mailer/reset_password_instructions.html.erb: -------------------------------------------------------------------------------- 1 | <% @title = "Reset password instructions- PageOneX" %> 2 |

Hello <%= @resource.email %>!

3 | 4 |

Someone has requested a link to change your password, and you can do this through the link below.

5 | 6 |

<%= link_to 'Change my password', edit_password_url(@resource, :reset_password_token => @resource.reset_password_token) %>

7 | 8 |

If you didn't request this, please ignore this email.

9 |

Your password won't change until you access the link above and create a new one.

10 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | dist: trusty 2 | 3 | language: ruby 4 | 5 | rvm: 6 | - 1.9.3-p551 7 | 8 | bundler_args: --without heroku 9 | 10 | sudo: required 11 | 12 | services: 13 | - mysql 14 | 15 | stages: 16 | - name: release 17 | if: tag IS present 18 | 19 | before_install: 20 | - sudo apt-get update 21 | - sudo apt-get install -y libxml2-dev 22 | - gem update --system 23 | - gem install --force bundler 24 | - gem install debugger-ruby_core_source 25 | 26 | jobs: 27 | include: 28 | - name: 'Push image to Docker Hub' 29 | stage: release 30 | script: 31 | - make docker-push 32 | -------------------------------------------------------------------------------- /app/controllers/application_controller.rb: -------------------------------------------------------------------------------- 1 | class ApplicationController < ActionController::Base 2 | protect_from_forgery 3 | # the rails application does not accept big json request ,so to allow the user to submit a huge request to the server, we should configure rails to accept that, by setting the limit of the request to a huge number 4 | Rack::Utils.key_space_limit = 1000000000 5 | 6 | def use_local_images 7 | Pageonex::Application.config.use_local_images 8 | end 9 | 10 | def authenticate_admin! 11 | authenticate_user! 12 | redirect_to '/' unless current_user.admin 13 | end 14 | 15 | end 16 | -------------------------------------------------------------------------------- /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 4 | # (all these examples are active by default): 5 | # ActiveSupport::Inflector.inflections do |inflect| 6 | # inflect.plural /^(ox)$/i, '\1en' 7 | # inflect.singular /^(ox)en/i, '\1' 8 | # inflect.irregular 'person', 'people' 9 | # inflect.uncountable %w( fish sheep ) 10 | # end 11 | # 12 | # These inflection rules are supported but not enabled by default: 13 | # ActiveSupport::Inflector.inflections do |inflect| 14 | # inflect.acronym 'RESTful' 15 | # end 16 | -------------------------------------------------------------------------------- /db/seeds.rb: -------------------------------------------------------------------------------- 1 | # This file should contain all the record creation needed to seed the database with its default values. 2 | # The data can then be loaded with the rake db:seed (or created alongside the db with db:setup). 3 | # 4 | # Examples: 5 | # 6 | # cities = City.create([{ name: 'Chicago' }, { name: 'Copenhagen' }]) 7 | # Mayor.create(name: 'Emanuel', city: cities.first) 8 | Threadx.create(thread_name: 'thread_social movement',thread_display_name: 'Social movement in front pages', start_date: '2013-02-01', end_date: '2013-02-15', description: 'the best description ever', category: 'social', status: 'closed', owner_id: '1') 9 | 10 | -------------------------------------------------------------------------------- /docker-ruby/README.md: -------------------------------------------------------------------------------- 1 | # Pageonex Ruby base images 2 | 3 | Since we use old ruby versions, we need to build the images by ourselves compiling ruby from source. Once we're there, images will contain all the system dependencies that normally do not change so that main image builds only refer to the application 4 | 5 | Images will be uploaded to https://hub.docker.com/r/pageonex/ruby-base/tags/ 6 | 7 | In order to build and push the ruby 1.9.3 image with its dependencies 8 | 9 | ``` 10 | cd v1.9.3 11 | make docker-build 12 | make docker-push 13 | ``` 14 | 15 | Image will be named `pageonex/ruby-base`:`v1.9.3.x` where `x` will be the revision in the `v1.9.3/REVISION` file 16 | 17 | -------------------------------------------------------------------------------- /app/views/devise/passwords/edit.html.erb: -------------------------------------------------------------------------------- 1 | <% @title = "User Change Password - PageOneX" %> 2 |

Change your password

3 | 4 | <%= form_for(resource, :as => resource_name, :url => password_path(resource_name), :html => { :method => :put }) do |f| %> 5 | <%= devise_error_messages! %> 6 | <%= f.hidden_field :reset_password_token %> 7 | 8 |
<%= f.label :password, "New password" %> 9 | <%= f.password_field :password %>
10 | 11 |
<%= f.label :password_confirmation, "Confirm new password" %> 12 | <%= f.password_field :password_confirmation %>
13 | 14 |
<%= f.submit "Change my password" %>
15 | <% end %> 16 | 17 | <%= render "links" %> 18 | -------------------------------------------------------------------------------- /app/views/coding/_coding_footer.html.erb: -------------------------------------------------------------------------------- 1 |
2 | 3 |
  4 |
5 | 6 |
7 | Code 8 | 9 | - 10 | 11 | Display 12 | 13 |
14 | 15 |
16 | -------------------------------------------------------------------------------- /app/views/devise/sessions/new.html.erb: -------------------------------------------------------------------------------- 1 | <% @title = "User Sign in - PageOneX" %> 2 |

Sign in

3 | 4 | <%= form_for(resource, :as => resource_name, :url => session_path(resource_name)) do |f| %> 5 |
<%= f.label :email %> 6 | <%= f.email_field :email %>
7 | 8 |
<%= f.label :password %> 9 | <%= f.password_field :password %>
10 | 11 | <% if devise_mapping.rememberable? -%> 12 | <%= f.label :remember_me, :class => "checkbox" do %> 13 | <%= f.check_box :remember_me %>Remember me 14 | <% end %> 15 | <% end -%> 16 | 17 |
<%= f.submit "Sign in",:class => "btn" %>
18 | <% end %> 19 | 20 | <%= render "links" %> 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /app/views/home/help.html.erb: -------------------------------------------------------------------------------- 1 | <% @title = "Help - PageOneX" %> 2 |
3 |

Wiki

4 |

<%= link_to "Access the wiki", "https://github.com/numeroteca/pageonex/wiki" %>

5 |

How to use PageOneX

6 |

Tutorial about how to use PageOneX by Anibal Rossi (in Spanish). Thanks!

7 | 8 |
9 | 10 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See http://help.github.com/ignore-files/ for more about ignoring files. 2 | # 3 | # If you find yourself ignoring temporary files generated by your text editor 4 | # or operating system, you probably want to add a global ignore instead: 5 | # git config --global core.excludesfile ~/.gitignore_global 6 | 7 | # Ignore bundler config 8 | /.bundle 9 | 10 | # Ignore the default SQLite database. 11 | /db/*.sqlite3 12 | 13 | # Ignore all logfiles and tempfiles. 14 | /log/*.log 15 | /tmp 16 | *~ 17 | 18 | /app/assets/images/kiosko 19 | /app/assets/images/threads 20 | 21 | # Ignore OS X image cache 22 | .DS_Store 23 | 24 | # ignore some generated thumb files 25 | app/assets/images/404-thumb*.jpg 26 | -------------------------------------------------------------------------------- /app/views/devise/registrations/new.html.erb: -------------------------------------------------------------------------------- 1 | <% @title = "User sign up - PageOneX" %> 2 |

Sign up

3 | 4 | <%= form_for(resource, :as => resource_name, :url => registration_path(resource_name)) do |f| %> 5 | <%= devise_error_messages! %> 6 | 7 |
<%= f.label :username %> 8 | <%= f.text_field :username %>
9 | 10 |
<%= f.label :email %> 11 | <%= f.email_field :email %>
12 | 13 |
<%= f.label :password %> 14 | <%= f.password_field :password %>
15 | 16 |
<%= f.label :password_confirmation %> 17 | <%= f.password_field :password_confirmation %>
18 | 19 |
<%= f.submit "Sign up", :class => "btn" %>
20 | <% end %> 21 | 22 | <%= render "links" %> 23 | -------------------------------------------------------------------------------- /app/views/taxonomies/new.html.erb: -------------------------------------------------------------------------------- 1 | <% @title = "New taxonomy - PageOneX" %> 2 | 5 | <%= form_for @taxonomy do |f| %> 6 |
7 | <%= f.label :name, class: "control-label" %> 8 |
9 | <%= f.text_field :name %> 10 |
11 | 12 | <% if @taxonomy.errors.messages[:name].present? %> 13 | Error: <%= @taxonomy.errors.messages[:name].first %> 14 | <% end %> 15 | 16 |
17 | 18 |
19 | <%= f.submit "Create taxonomy", class: 'btn btn-primary' %> 20 | <%= link_to "Cancel", taxonomies_path, class: 'btn' %> 21 |
22 | <% end %> 23 | -------------------------------------------------------------------------------- /public/500.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | We're sorry, but something went wrong (500) 5 | 17 | 18 | 19 | 20 | 21 |
22 |

We're sorry, but something went wrong.

23 |
24 | 25 | 26 | -------------------------------------------------------------------------------- /app/models/highlighted_area.rb: -------------------------------------------------------------------------------- 1 | class HighlightedArea < ActiveRecord::Base 2 | has_many :areas 3 | has_many :taxonomy_classifications, dependent: :destroy 4 | has_many :taxonomy_options, through: :taxonomy_classifications 5 | belongs_to :code 6 | belongs_to :user 7 | belongs_to :image 8 | 9 | def threadx 10 | code.threadx unless code.nil? 11 | end 12 | 13 | def self.by_image(image) 14 | where(:image_id => image.id) 15 | end 16 | 17 | def self.by_threadx(threadx) 18 | where(:code_id => threadx.code_ids) 19 | end 20 | 21 | def self.by_code(code) 22 | where(:code_id => code.id) 23 | end 24 | 25 | def area 26 | areas.first.width * areas.first.height 27 | end 28 | 29 | def scaled_areas scale 30 | areas.collect { |a| a.scaled_copy scale } 31 | end 32 | 33 | end 34 | -------------------------------------------------------------------------------- /spec/views/media/show.html.erb_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe "media/show" do 4 | before(:each) do 5 | @medium = assign(:medium, stub_model(Medium, 6 | :name => "Name", 7 | :country => "Country", 8 | :country_code => "Country Code", 9 | :url => "Url", 10 | :display_name => "Display Name", 11 | :working => false 12 | )) 13 | end 14 | 15 | it "renders attributes in

" do 16 | render 17 | # Run the generator again with the --webrat flag if you want to use webrat matchers 18 | rendered.should match(/Name/) 19 | rendered.should match(/Country/) 20 | rendered.should match(/Country Code/) 21 | rendered.should match(/Url/) 22 | rendered.should match(/Display Name/) 23 | rendered.should match(/false/) 24 | end 25 | end 26 | -------------------------------------------------------------------------------- /app/views/media/show.html.erb: -------------------------------------------------------------------------------- 1 | <% @title = "Show Media - PageOneX" %> 2 |

<%= notice %>

3 | 4 |

<%=@media.display_name%>

5 | 6 |

7 | See all the images for this media source 8 |

9 | 10 |

11 | Name: 12 | <%= @media.name %> 13 |

14 | 15 |

16 | Country: 17 | <%= @media.country %> 18 |

19 | 20 |

21 | Country code: 22 | <%= @media.country_code %> 23 |

24 | 25 |

26 | Url: 27 | <%= @media.url %> 28 |

29 | 30 |

31 | Display name: 32 | <%= @media.display_name %> 33 |

34 | 35 |

36 | Working: 37 | <%= @media.working %> 38 |

39 | 40 | 41 | <%= link_to 'Edit', edit_medium_path(@media) %> | 42 | <%= link_to 'Back', medium_path %> 43 | -------------------------------------------------------------------------------- /public/422.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | The change you wanted was rejected (422) 5 | 17 | 18 | 19 | 20 | 21 |
22 |

The change you wanted was rejected.

23 |

Maybe you tried to change something you didn't have access to.

24 |
25 | 26 | 27 | -------------------------------------------------------------------------------- /config/piwik.yml: -------------------------------------------------------------------------------- 1 | # Configuration: 2 | # 3 | # disabled 4 | # false if tracking tag should be shown 5 | # use_async 6 | # Set to true if you want to use asynchronous tracking 7 | # url 8 | # The url of your piwik instance (e.g. localhost/piwik/ 9 | # id_site 10 | # The id of your website inside Piwik 11 | # 12 | production: 13 | piwik: 14 | id_site: <%= ENV['PIWIK_ID_SITE'].blank? ? '1' : ENV['PIWIK_ID_SITE'] %> 15 | url: <%= ENV['PIWIK_URL'].blank? ? 'piwik-production.example.com' : ENV['PIWIK_URL'] %> 16 | use_async: false 17 | disabled: false 18 | 19 | development: 20 | piwik: 21 | id_site: 1 22 | url: piwik-development.example.com 23 | disabled: true 24 | use_async: false 25 | 26 | test: 27 | piwik: 28 | id_site: 1 29 | url: localhost 30 | disabled: true 31 | use_async: false -------------------------------------------------------------------------------- /public/404.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | The page you were looking for doesn't exist (404) 5 | 17 | 18 | 19 | 20 | 21 |
22 |

The page you were looking for doesn't exist.

23 |

You may have mistyped the address or the page may have moved.

24 |
25 | 26 | 27 | -------------------------------------------------------------------------------- /app/assets/stylesheets/imgareaselect-css/imgareaselect-deprecated.css: -------------------------------------------------------------------------------- 1 | /* 2 | * imgAreaSelect style to be used with deprecated options 3 | */ 4 | 5 | .imgareaselect-border1, .imgareaselect-border2, 6 | .imgareaselect-border3, .imgareaselect-border4 { 7 | filter: alpha(opacity=50); 8 | opacity: 0.5; 9 | } 10 | 11 | .imgareaselect-border1 { 12 | border: solid 1px #000; 13 | } 14 | 15 | .imgareaselect-border2 { 16 | border: dashed 1px #fff; 17 | } 18 | 19 | .imgareaselect-handle { 20 | background-color: #fff; 21 | border: solid 1px #000; 22 | filter: alpha(opacity=50); 23 | opacity: 0.5; 24 | } 25 | 26 | .imgareaselect-outer { 27 | background-color: #000; 28 | filter: alpha(opacity=40); 29 | opacity: 0.4; 30 | } 31 | 32 | .imgareaselect-selection { 33 | background-color: #fff; 34 | filter: alpha(opacity=0); 35 | opacity: 0; 36 | } 37 | -------------------------------------------------------------------------------- /app/views/taxonomy_options/_form.html.erb: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/views/media/index.html.erb: -------------------------------------------------------------------------------- 1 | <% @title = "List media - PageOneX" %> 2 |

Listing media

3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | <% @media_list.each do |media| %> 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | <% end %> 30 |
NameCountryCountry codeUrlDisplay nameWorking
<%= media.name %><%= media.country %><%= media.country_code %><%= media.url %><%= media.display_name %><%= media.working %><%= link_to 'Show', media %><%= link_to 'Edit', edit_medium_path(media) %><%= link_to 'Destroy', media, method: :delete, data: { confirm: 'Are you sure?' } %>
31 | 32 |
33 | 34 | <%= link_to 'New Medium', new_medium_path %> 35 | -------------------------------------------------------------------------------- /spec/routing/media_routing_spec.rb: -------------------------------------------------------------------------------- 1 | require "spec_helper" 2 | 3 | describe MediaController do 4 | describe "routing" do 5 | 6 | it "routes to #index" do 7 | get("/media").should route_to("media#index") 8 | end 9 | 10 | it "routes to #new" do 11 | get("/media/new").should route_to("media#new") 12 | end 13 | 14 | it "routes to #show" do 15 | get("/media/1").should route_to("media#show", :id => "1") 16 | end 17 | 18 | it "routes to #edit" do 19 | get("/media/1/edit").should route_to("media#edit", :id => "1") 20 | end 21 | 22 | it "routes to #create" do 23 | post("/media").should route_to("media#create") 24 | end 25 | 26 | it "routes to #update" do 27 | put("/media/1").should route_to("media#update", :id => "1") 28 | end 29 | 30 | it "routes to #destroy" do 31 | delete("/media/1").should route_to("media#destroy", :id => "1") 32 | end 33 | 34 | end 35 | end 36 | -------------------------------------------------------------------------------- /spec/routing/users_routing_spec.rb: -------------------------------------------------------------------------------- 1 | require "spec_helper" 2 | 3 | describe UsersController do 4 | describe "routing" do 5 | 6 | it "routes to #index" do 7 | get("/users").should route_to("users#index") 8 | end 9 | 10 | it "routes to #new" do 11 | get("/users/new").should route_to("users#new") 12 | end 13 | 14 | it "routes to #show" do 15 | get("/users/1").should route_to("users#show", :id => "1") 16 | end 17 | 18 | it "routes to #edit" do 19 | get("/users/1/edit").should route_to("users#edit", :id => "1") 20 | end 21 | 22 | it "routes to #create" do 23 | post("/users").should route_to("users#create") 24 | end 25 | 26 | it "routes to #update" do 27 | put("/users/1").should route_to("users#update", :id => "1") 28 | end 29 | 30 | it "routes to #destroy" do 31 | delete("/users/1").should route_to("users#destroy", :id => "1") 32 | end 33 | 34 | end 35 | end 36 | -------------------------------------------------------------------------------- /spec/routing/images_routing_spec.rb: -------------------------------------------------------------------------------- 1 | require "spec_helper" 2 | 3 | describe ImagesController do 4 | describe "routing" do 5 | 6 | it "routes to #index" do 7 | get("/images").should route_to("images#index") 8 | end 9 | 10 | it "routes to #new" do 11 | get("/images/new").should route_to("images#new") 12 | end 13 | 14 | it "routes to #show" do 15 | get("/images/1").should route_to("images#show", :id => "1") 16 | end 17 | 18 | it "routes to #edit" do 19 | get("/images/1/edit").should route_to("images#edit", :id => "1") 20 | end 21 | 22 | it "routes to #create" do 23 | post("/images").should route_to("images#create") 24 | end 25 | 26 | it "routes to #update" do 27 | put("/images/1").should route_to("images#update", :id => "1") 28 | end 29 | 30 | it "routes to #destroy" do 31 | delete("/images/1").should route_to("images#destroy", :id => "1") 32 | end 33 | 34 | end 35 | end 36 | -------------------------------------------------------------------------------- /app/views/users/_form.html.erb: -------------------------------------------------------------------------------- 1 | <%= form_for @user, :html => { :class => 'form-horizontal' } do |f| %> 2 |
3 | <%= f.label :username, :class => 'control-label' %> 4 |
5 | <%= f.text_field :username, :class => 'text_field' %> 6 |
7 |
8 |
9 | <%= f.label :email, :class => 'control-label' %> 10 |
11 | <%= f.text_field :email, :class => 'text_field' %> 12 |
13 |
14 |
15 | <%= f.label :admin, :class => 'control-label' %> 16 |
17 | <%= f.check_box :admin, :class => 'check_box' %> 18 |
19 |
20 | 21 |
22 | <%= f.submit nil, :class => 'btn btn-primary' %> 23 | <%= link_to t('.cancel', :default => t("helpers.links.cancel")), 24 | users_path, :class => 'btn' %> 25 |
26 | <% end %> 27 | -------------------------------------------------------------------------------- /app/assets/stylesheets/imgareaselect-css/imgareaselect-default.css: -------------------------------------------------------------------------------- 1 | /* 2 | * imgAreaSelect default style 3 | */ 4 | 5 | .imgareaselect-border1 { 6 | background: url(border-v.gif) repeat-y left top; 7 | } 8 | 9 | .imgareaselect-border2 { 10 | background: url(border-h.gif) repeat-x left top; 11 | } 12 | 13 | .imgareaselect-border3 { 14 | background: url(border-v.gif) repeat-y right top; 15 | } 16 | 17 | .imgareaselect-border4 { 18 | background: url(border-h.gif) repeat-x left bottom; 19 | } 20 | 21 | .imgareaselect-border1, .imgareaselect-border2, 22 | .imgareaselect-border3, .imgareaselect-border4 { 23 | filter: alpha(opacity=50); 24 | opacity: 0.5; 25 | } 26 | 27 | .imgareaselect-handle { 28 | background-color: #fff; 29 | border: solid 1px #000; 30 | filter: alpha(opacity=50); 31 | opacity: 0.5; 32 | } 33 | 34 | .imgareaselect-outer { 35 | background-color: #000; 36 | filter: alpha(opacity=50); 37 | opacity: 0.5; 38 | } 39 | 40 | .imgareaselect-selection { 41 | } -------------------------------------------------------------------------------- /app/assets/javascripts/topic_form.js: -------------------------------------------------------------------------------- 1 | 2 | $(function () { 3 | 4 | var initDelete = function () { 5 | $('.delete_topic').unbind('click'); 6 | $('.delete_topic').click(function () { 7 | var index = $(this).attr('id').substr('delete_topic_'.length); 8 | $("#topic_deleted_" + index).val('1'); 9 | $("#topic_" + index).hide(); 10 | }); 11 | } 12 | 13 | // lets you add new topics via Ajax request 14 | $('#add_topic').click(function() { 15 | var existingTopicCount = parseInt($("#topic_count").val()); 16 | $.get('/threads/new_topic/'+existingTopicCount, function(data) { 17 | $('#topic-list').append(data); 18 | $("#topic_color_"+$("#topic_count").val()).minicolors({ defaultValue: '#FF0000' }); 19 | $("#topic_count").val(existingTopicCount+1); 20 | initDelete(); 21 | }); 22 | }); 23 | // add the first topic option dynamically if there are none 24 | if($("#topic_count").val()==0){ 25 | $("#add_topic").click(); 26 | } 27 | initDelete(); 28 | }); 29 | -------------------------------------------------------------------------------- /app/assets/stylesheets/imgareaselect-css/imgareaselect-animated.css: -------------------------------------------------------------------------------- 1 | /* 2 | * imgAreaSelect animated border style 3 | */ 4 | 5 | .imgareaselect-border1 { 6 | background: url(border-anim-v.gif) repeat-y left top; 7 | } 8 | 9 | .imgareaselect-border2 { 10 | background: url(border-anim-h.gif) repeat-x left top; 11 | } 12 | 13 | .imgareaselect-border3 { 14 | background: url(border-anim-v.gif) repeat-y right top; 15 | } 16 | 17 | .imgareaselect-border4 { 18 | background: url(border-anim-h.gif) repeat-x left bottom; 19 | } 20 | 21 | .imgareaselect-border1, .imgareaselect-border2, 22 | .imgareaselect-border3, .imgareaselect-border4 { 23 | filter: alpha(opacity=50); 24 | opacity: 0.5; 25 | } 26 | 27 | .imgareaselect-handle { 28 | background-color: #fff; 29 | border: solid 1px #000; 30 | filter: alpha(opacity=50); 31 | opacity: 0.5; 32 | } 33 | 34 | .imgareaselect-outer { 35 | background-color: #000; 36 | filter: alpha(opacity=50); 37 | opacity: 0.5; 38 | } 39 | 40 | .imgareaselect-selection { 41 | } -------------------------------------------------------------------------------- /app/assets/stylesheets/bootstrap_and_overrides.css.less: -------------------------------------------------------------------------------- 1 | @import "twitter/bootstrap/bootstrap"; 2 | body { padding-top: 60px; } 3 | 4 | @import "twitter/bootstrap/responsive"; 5 | 6 | // Set the correct sprite paths 7 | @iconSpritePath: asset-path('twitter/bootstrap/glyphicons-halflings.png'); 8 | @iconWhiteSpritePath: asset-path('twitter/bootstrap/glyphicons-halflings-white.png'); 9 | 10 | // Your custom LESS stylesheets goes here 11 | // 12 | // Since bootstrap was imported above you have access to its mixins which 13 | // you may use and inherit here 14 | // 15 | // If you'd like to override bootstrap's own variables, you can do so here as well 16 | // See http://twitter.github.com/bootstrap/less.html for their names and documentation 17 | // 18 | // Example: 19 | // @linkColor: #ff0000; 20 | 21 | .carousel-control{ 22 | border: 3px solid #CCC; 23 | // left: -53px; 24 | // right: -53px !important; 25 | webkit-border-radius: 0px; 26 | -moz-border-radius: 0px; 27 | border-radius: 0px; 28 | -webkit-border-radius: 0px; 29 | -moz-border-radius: 0px; 30 | border-radius: 0px; 31 | top:300px; 32 | } 33 | -------------------------------------------------------------------------------- /lib/tasks/scraping.rake: -------------------------------------------------------------------------------- 1 | require 'csv' 2 | require 'open-uri' 3 | require 'nokogiri' 4 | require 'kiosko_scraper' 5 | 6 | namespace :scraping do 7 | 8 | # rake scraping:scrape_media 9 | desc "Scrape Kiosko and generate a CSV of media sources" 10 | task :scrape_media => :environment do 11 | KioskoScraper::scrape_media_to_csv 12 | end 13 | 14 | # rake scraping:update_media 15 | desc "Import/update media into the database from a CSV of media sources" 16 | task :update_media => :environment do |t, args| 17 | KioskoScraper::update_media_from_csv 18 | end 19 | 20 | # rake scraping:scrape_day 21 | desc "Scrape images for the current day" 22 | task :scrape_day => :environment do 23 | day = Date.today - 1 24 | KioskoScraper::create_images(day, day, Media.all) 25 | end 26 | 27 | # rake scraping:migrate_media_folders_to_include_country_codes 28 | desc "One time-fix to migrate media folders to include country codes" 29 | task :migrate_media_folders_to_include_country_codes => :environment do 30 | KioskoScraper::migrate_media_folders_to_include_country_codes 31 | end 32 | 33 | end 34 | -------------------------------------------------------------------------------- /spec/views/media/new.html.erb_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe "media/new" do 4 | before(:each) do 5 | assign(:medium, stub_model(Medium, 6 | :name => "MyString", 7 | :country => "MyString", 8 | :country_code => "MyString", 9 | :url => "MyString", 10 | :display_name => "MyString", 11 | :working => false 12 | ).as_new_record) 13 | end 14 | 15 | it "renders new medium form" do 16 | render 17 | 18 | # Run the generator again with the --webrat flag if you want to use webrat matchers 19 | assert_select "form[action=?][method=?]", media_path, "post" do 20 | assert_select "input#medium_name[name=?]", "medium[name]" 21 | assert_select "input#medium_country[name=?]", "medium[country]" 22 | assert_select "input#medium_country_code[name=?]", "medium[country_code]" 23 | assert_select "input#medium_url[name=?]", "medium[url]" 24 | assert_select "input#medium_display_name[name=?]", "medium[display_name]" 25 | assert_select "input#medium_working[name=?]", "medium[working]" 26 | end 27 | end 28 | end 29 | -------------------------------------------------------------------------------- /spec/views/media/edit.html.erb_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe "media/edit" do 4 | before(:each) do 5 | @medium = assign(:medium, stub_model(Medium, 6 | :name => "MyString", 7 | :country => "MyString", 8 | :country_code => "MyString", 9 | :url => "MyString", 10 | :display_name => "MyString", 11 | :working => false 12 | )) 13 | end 14 | 15 | it "renders the edit medium form" do 16 | render 17 | 18 | # Run the generator again with the --webrat flag if you want to use webrat matchers 19 | assert_select "form[action=?][method=?]", medium_path(@medium), "post" do 20 | assert_select "input#medium_name[name=?]", "medium[name]" 21 | assert_select "input#medium_country[name=?]", "medium[country]" 22 | assert_select "input#medium_country_code[name=?]", "medium[country_code]" 23 | assert_select "input#medium_url[name=?]", "medium[url]" 24 | assert_select "input#medium_display_name[name=?]", "medium[display_name]" 25 | assert_select "input#medium_working[name=?]", "medium[working]" 26 | end 27 | end 28 | end 29 | -------------------------------------------------------------------------------- /app/models/media.rb: -------------------------------------------------------------------------------- 1 | class Media < ActiveRecord::Base 2 | has_many :images 3 | has_many :media_threadxes 4 | has_many :threadxes, :through => :media_threadxes 5 | 6 | default_scope where(:working=>true) 7 | 8 | scope :by_country_and_display_name, order("country, display_name") 9 | 10 | def name_with_country 11 | self.country + " - " + self.display_name 12 | end 13 | 14 | def image_directory_name 15 | self.country_code+"-"+self.name 16 | end 17 | 18 | def create_image_directory 19 | return false if not Pageonex::Application.config.use_local_images 20 | local_image_dir = File.join(KioskoScraper.local_image_dir, self.image_directory_name) 21 | FileUtils.mkdir local_image_dir unless File.directory? local_image_dir 22 | true 23 | end 24 | 25 | def self.from_csv_row row 26 | m = Media.new 27 | m.country = row[0] 28 | m.country_code = row[1] 29 | m.display_name = row[2] 30 | m.name = row[3] 31 | m.url = row[4] 32 | m 33 | end 34 | 35 | def to_csv_row 36 | [ self.country, self.country_code, self.display_name, self.name, self.url ] 37 | end 38 | 39 | end 40 | -------------------------------------------------------------------------------- /app/controllers/taxonomies_controller.rb: -------------------------------------------------------------------------------- 1 | class TaxonomiesController < ApplicationController 2 | 3 | before_filter :authenticate_admin! 4 | 5 | def index 6 | @taxonomies = Taxonomy.includes(:taxonomy_options).all 7 | end 8 | 9 | def new 10 | @taxonomy = Taxonomy.new 11 | end 12 | 13 | def edit 14 | @taxonomies = Taxonomy.includes(:taxonomy_options).all 15 | @taxonomy = Taxonomy.find(params[:id]) 16 | end 17 | 18 | def create 19 | @taxonomy = Taxonomy.new(params[:taxonomy]) 20 | 21 | if @taxonomy.save 22 | redirect_to taxonomy_taxonomy_options_url(@taxonomy.id), notice: 'Taxonomy was successfully created.' 23 | else 24 | render action: "new" 25 | end 26 | end 27 | 28 | def update 29 | @taxonomy = Taxonomy.find(params[:id]) 30 | 31 | if @taxonomy.update_attributes(params[:taxonomy]) 32 | redirect_to taxonomies_url 33 | else 34 | @taxonomies = Taxonomy.includes(:taxonomy_options).all 35 | render action: "edit" 36 | end 37 | end 38 | 39 | def destroy 40 | @taxonomy = Taxonomy.find(params[:id]) 41 | @taxonomy.destroy 42 | 43 | redirect_to taxonomies_url 44 | end 45 | end -------------------------------------------------------------------------------- /app/views/media/_form.html.erb: -------------------------------------------------------------------------------- 1 | <%= form_for(@media) do |f| %> 2 | <% if @media.errors.any? %> 3 |
4 |

<%= pluralize(@media.errors.count, "error") %> prohibited this media from being saved:

5 | 6 | 11 |
12 | <% end %> 13 | 14 |
15 | <%= f.label :name %>
16 | <%= f.text_field :name %> 17 |
18 |
19 | <%= f.label :country %>
20 | <%= f.text_field :country %> 21 |
22 |
23 | <%= f.label :country_code %>
24 | <%= f.text_field :country_code %> 25 |
26 |
27 | <%= f.label :url %>
28 | <%= f.text_field :url %> 29 |
30 |
31 | <%= f.label :display_name %>
32 | <%= f.text_field :display_name %> 33 |
34 |
35 | <%= f.label :working %>
36 | <%= f.check_box :working %> 37 |
38 |
39 | <%= f.submit %> 40 |
41 | <% end %> 42 | -------------------------------------------------------------------------------- /app/views/devise/_links.erb: -------------------------------------------------------------------------------- 1 | <%- if controller_name != 'sessions' %> 2 | <%= link_to "Sign in", new_session_path(resource_name) %>
3 | <% end -%> 4 | 5 | <%- if devise_mapping.registerable? && controller_name != 'registrations' %> 6 | <%= link_to "Sign up", new_registration_path(resource_name) %>
7 | <% end -%> 8 | 9 | <%- if devise_mapping.recoverable? && controller_name != 'passwords' %> 10 | <%= link_to "Forgot your password?", new_password_path(resource_name) %>
11 | <% end -%> 12 | 13 | <%- if devise_mapping.confirmable? && controller_name != 'confirmations' %> 14 | <%= link_to "Didn't receive confirmation instructions?", new_confirmation_path(resource_name) %>
15 | <% end -%> 16 | 17 | <%- if devise_mapping.lockable? && resource_class.unlock_strategy_enabled?(:email) && controller_name != 'unlocks' %> 18 | <%= link_to "Didn't receive unlock instructions?", new_unlock_path(resource_name) %>
19 | <% end -%> 20 | 21 | <%- if devise_mapping.omniauthable? %> 22 | <%- resource_class.omniauth_providers.each do |provider| %> 23 | <%= link_to "Sign in with #{provider.to_s.titleize}", omniauth_authorize_path(resource_name, provider) %>
24 | <% end -%> 25 | <% end -%> -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | PROJECT = pageonex 2 | DOCKER_REGISTRY ?= docker.io 3 | DOCKER_ORG ?= pageonex 4 | DOCKER_USERNAME ?= 5 | DOCKER_PASSWORD ?= 6 | VERSION ?= $(TRAVIS_TAG) 7 | 8 | docker-login: docker-validate 9 | @docker login -u "$(DOCKER_USERNAME)" -p "$(DOCKER_PASSWORD)" $(DOCKER_REGISTRY); \ 10 | 11 | docker-validate: 12 | @if [ -z "$(DOCKER_USERNAME)" ]; then \ 13 | echo "DOCKER_USERNAME variable cannot be empty."; \ 14 | exit 1; \ 15 | fi; \ 16 | if [ -z "$(DOCKER_PASSWORD)" ]; then \ 17 | echo "DOCKER_PASSWORD variable cannot be empty."; \ 18 | exit 1; \ 19 | fi 20 | 21 | docker-build: 22 | @if [ -z "$(VERSION)" ]; then \ 23 | echo "VERSION variable cannot be empty."; \ 24 | exit 1; \ 25 | fi; \ 26 | if [ -z "$(DOCKER_ORG)" ]; then \ 27 | echo "DOCKER_ORG variable cannot be empty."; \ 28 | exit 1; \ 29 | fi; \ 30 | docker build -t $(DOCKER_REGISTRY)/$(DOCKER_ORG)/$(PROJECT):$(VERSION) .; \ 31 | 32 | docker-push: docker-login docker-build 33 | docker push $(DOCKER_REGISTRY)/$(DOCKER_ORG)/$(PROJECT):$(VERSION); \ 34 | docker tag $(DOCKER_REGISTRY)/$(DOCKER_ORG)/$(PROJECT):$(VERSION) \ 35 | $(DOCKER_REGISTRY)/$(DOCKER_ORG)/$(PROJECT):latest; \ 36 | docker push $(DOCKER_REGISTRY)/$(DOCKER_ORG)/$(PROJECT):latest; 37 | -------------------------------------------------------------------------------- /spec/views/media/index.html.erb_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe "media/index" do 4 | before(:each) do 5 | assign(:media, [ 6 | stub_model(Medium, 7 | :name => "Name", 8 | :country => "Country", 9 | :country_code => "Country Code", 10 | :url => "Url", 11 | :display_name => "Display Name", 12 | :working => false 13 | ), 14 | stub_model(Medium, 15 | :name => "Name", 16 | :country => "Country", 17 | :country_code => "Country Code", 18 | :url => "Url", 19 | :display_name => "Display Name", 20 | :working => false 21 | ) 22 | ]) 23 | end 24 | 25 | it "renders a list of media" do 26 | render 27 | # Run the generator again with the --webrat flag if you want to use webrat matchers 28 | assert_select "tr>td", :text => "Name".to_s, :count => 2 29 | assert_select "tr>td", :text => "Country".to_s, :count => 2 30 | assert_select "tr>td", :text => "Country Code".to_s, :count => 2 31 | assert_select "tr>td", :text => "Url".to_s, :count => 2 32 | assert_select "tr>td", :text => "Display Name".to_s, :count => 2 33 | assert_select "tr>td", :text => false.to_s, :count => 2 34 | end 35 | end 36 | -------------------------------------------------------------------------------- /docker-compose-build.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | volumes: 3 | build_db_data: 4 | 5 | services: 6 | mysql_build: 7 | image: mysql:5.6.40 8 | restart: always 9 | ports: 10 | - "23306:23306" 11 | volumes: 12 | - build_db_data:/var/lib/mysql 13 | - ./docker-compose-files/pageonex-build.cnf:/etc/mysql/conf.d/pageonex-build.cnf 14 | environment: 15 | - MYSQL_ROOT_PASSWORD=root 16 | - MYSQL_DATABASE=dc-dev 17 | command: | 18 | bash -c "chmod 644 /etc/mysql/conf.d/pageonex-build.cnf && /entrypoint.sh mysqld" 19 | 20 | app_build: 21 | build: . 22 | environment: 23 | - RAILS_ENV=development 24 | - DATABASE_ADAPTER=mysql2 25 | - DATABASE_USERNAME=root 26 | - DATABASE_PASSWORD=root 27 | - DATABASE_HOST=mysql_build 28 | - DATABASE_PORT=23306 29 | - DATABASE_NAME=dc-dev 30 | depends_on: 31 | - "mysql_build" 32 | ports: 33 | - '3000:3000' 34 | links: 35 | - "mysql_build" 36 | volumes: 37 | - .:/workspace 38 | - ./docker-compose-files/wrap-start-app.sh:/usr/local/bin/wrap-start-app.sh 39 | working_dir: /workspace 40 | command: 41 | - wrap-start-app.sh 42 | - mysql_build 43 | - root 44 | - "bundle exec puma -C config/puma.rb" 45 | -------------------------------------------------------------------------------- /docker-ruby/v1.9.3/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM debian:jessie-slim 2 | 3 | ENV RUBY_VERSION 1.9.3-p551 4 | ENV RUBY_SHA1SUM 5cf6c9383444163a3f753b50c35e441988189258 5 | 6 | RUN BUILD_DIR="/tmp/ruby-build" \ 7 | && apt-get update \ 8 | && apt-get -y install \ 9 | wget \ 10 | build-essential \ 11 | zlib1g-dev \ 12 | libssl-dev \ 13 | libreadline6-dev \ 14 | libyaml-dev \ 15 | tzdata \ 16 | libmysqlclient-dev \ 17 | mysql-client \ 18 | libpq-dev \ 19 | libxml2-dev \ 20 | libxslt1-dev \ 21 | nodejs \ 22 | libmagickwand-dev \ 23 | libsqlite3-dev \ 24 | && mkdir -p "$BUILD_DIR" \ 25 | && cd "$BUILD_DIR" \ 26 | && wget -q "http://cache.ruby-lang.org/pub/ruby/ruby-${RUBY_VERSION}.tar.gz" \ 27 | && echo "${RUBY_SHA1SUM} ruby-${RUBY_VERSION}.tar.gz" | sha1sum -c - \ 28 | && tar xzf "ruby-${RUBY_VERSION}.tar.gz" \ 29 | && cd "ruby-${RUBY_VERSION}" \ 30 | && ./configure --enable-shared --prefix=/usr \ 31 | && make \ 32 | && make install \ 33 | && cd / \ 34 | && rm -r "$BUILD_DIR" \ 35 | && rm -rf /var/lib/apt/lists/* 36 | 37 | RUN gem update --system \ 38 | && gem install --force bundler \ 39 | && gem install debugger-ruby_core_source 40 | -------------------------------------------------------------------------------- /app/assets/javascripts/collaborators.js: -------------------------------------------------------------------------------- 1 | var Collaborators = { 2 | init: function () { 3 | if (!Collaborators.initialized) { 4 | Collaborators.list = $('#collab-list'); 5 | Collaborators.inputContainer = $('#collab-inputs'); 6 | Collaborators.userToLi = {} 7 | Collaborators.userToInput = {} 8 | } 9 | Collaborators.initialized = true; 10 | }, 11 | add: function (username, hash) { 12 | Collaborators.init(); 13 | if (typeof(Collaborators.userToLi[username]) != 'undefined') { 14 | return; 15 | } 16 | var li = $('
  • ' + username + ' (remove)
  • '); 17 | li.appendTo(this.list); 18 | Collaborators.userToLi[username] = li; 19 | var input = $(''); 20 | Collaborators.userToInput[username] = input; 21 | input.appendTo(this.inputContainer); 22 | }, 23 | remove: function (username) { 24 | Collaborators.init(); 25 | Collaborators.userToLi[username].remove(); 26 | Collaborators.userToInput[username].remove(); 27 | delete Collaborators.userToLi[username]; 28 | delete Collaborators.userToInput[username]; 29 | } 30 | }; 31 | -------------------------------------------------------------------------------- /config/database.yml: -------------------------------------------------------------------------------- 1 | default: &default 2 | adapter: <%= ENV['DATABASE_ADAPTER'].blank? ? 'sqlite3' : ENV['DATABASE_ADAPTER'] %> 3 | encoding: <%= ENV['DATABASE_ENCODING'].blank? ? 'utf8' : ENV['DATABASE_ENCODING'] %> 4 | pool: <%= ENV['DATABASE_POOL'].blank? ? 5 : ENV['DATABASE_POOL'].to_i %> 5 | timeout: <%= ENV['DATABASE_TIMEOUT'].blank? ? 5000 : ENV['DATABASE_TIMEOUT'].to_i %> 6 | username: <%= ENV['DATABASE_USERNAME'].blank? ? 'root' : ENV['DATABASE_USERNAME'] %> 7 | password: <%= ENV['DATABASE_PASSWORD'].blank? ? 'root' : ENV['DATABASE_PASSWORD'] %> 8 | host: <%= ENV['DATABASE_HOST'].blank? ? 'localhost' : ENV['DATABASE_HOST'] %> 9 | port: <%= ENV['DATABASE_PORT'].blank? ? 3306 : ENV['DATABASE_PORT'].to_i %> 10 | 11 | development: 12 | <<: *default 13 | database: <%= ENV['DATABASE_NAME'].blank? ? 'db/development.sqlite3' : ENV['DATABASE_NAME'] %> 14 | 15 | # Warning: The database defined as "test" will be erased and 16 | # re-generated from your development database when you run "rake". 17 | # Do not set this db to the same as development or production. 18 | test: 19 | <<: *default 20 | database: <%= ENV['DATABASE_NAME'].blank? ? 'db/test.sqlite3' : ENV['DATABASE_NAME'] %> 21 | 22 | production: 23 | <<: *default 24 | database: <%= ENV['DATABASE_NAME'].blank? ? 'db/production.sqlite3' : ENV['DATABASE_NAME'] %> 25 | -------------------------------------------------------------------------------- /app/views/devise/registrations/edit.html.erb: -------------------------------------------------------------------------------- 1 | <% @title = "User registration edit- PageOneX" %> 2 |

    Edit <%= resource_name.to_s.humanize %>

    3 | 4 | <%= form_for(resource, :as => resource_name, :url => registration_path(resource_name), :html => { :method => :put }) do |f| %> 5 | <%= devise_error_messages! %> 6 | 7 |
    <%= f.label :username %> 8 | <%= f.text_field :username %>
    9 | 10 |
    <%= f.label :bio %> 11 | <%= f.text_area :bio, rows: 5, :rel=>"popover", 'data-content'=>"Allowed HTML tags: ..." %>
    12 | 13 |
    <%= f.label :email %> 14 | <%= f.email_field :email %>
    15 | 16 |
    <%= f.label :password %> 17 | <%= f.password_field :password, :autocomplete => "off" %> (leave blank if you don't want to change it)
    18 | 19 |
    <%= f.label :password_confirmation %> 20 | <%= f.password_field :password_confirmation %>
    21 | 22 |
    <%= f.label :current_password %> 23 | <%= f.password_field :current_password %> (we need your current password to confirm your changes)
    24 | 25 |
    <%= f.submit "Update", :class => "btn" %>
    26 | <% end %> 27 | 28 |

    Cancel my account

    29 | 30 |

    Unhappy? <%= link_to "Cancel my account", registration_path(resource_name), :confirm => "Are you sure?", :method => :delete %>.

    31 | 32 | <%= link_to "Back", :back %> 33 | -------------------------------------------------------------------------------- /app/views/taxonomy_options/edit.html.erb: -------------------------------------------------------------------------------- 1 | <% @title = "Taxonomy: #{@taxonomy.name} - PageOneX" %> 2 | 5 | 6 | <%= form_for [@taxonomy, @taxonomy_option] do |f| %> 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | <% @taxonomy_options.each do |option| %> 17 | 18 | 19 | <% if option == @taxonomy_option %> 20 | 26 | 32 | 33 | <% end %> 34 | 35 | <% end %> 36 | 37 |
    Option IdValueActions
    <%= option.id %> 21 | <%= f.text_field :value, class: 'input-medium' %> 22 | <% if @taxonomy_option.errors.messages[:value].present? %> 23 | Error: <%= @taxonomy_option.errors.messages[:value].first %> 24 | <% end %> 25 | 27 | <%= f.submit "Change value", class: 'btn btn-primary btn-mini' %> 28 | <%= link_to "Cancel", taxonomy_taxonomy_options_path(@taxonomy), class: 'btn btn-mini' %> 29 | 30 | <% else %> 31 | <%= option.value %>
    38 | <% end %> 39 | -------------------------------------------------------------------------------- /app/views/taxonomies/index.html.erb: -------------------------------------------------------------------------------- 1 | <% @title = "Taxonomies list - PageOneX" %> 2 | 5 | 6 | <% if @taxonomies.present? %> 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | <% @taxonomies.each do |taxonomy| %> 18 | 19 | 20 | 21 | 22 | 29 | 30 | <% end %> 31 | 32 |
    IdNameOptionsActions
    <%= link_to taxonomy.id, taxonomy_taxonomy_options_path(taxonomy) %><%= link_to taxonomy.name, taxonomy_taxonomy_options_path(taxonomy) %><%= link_to taxonomy.taxonomy_options.map(&:value)*' | ', taxonomy_taxonomy_options_path(taxonomy) %> 23 | <%= link_to "Change name", edit_taxonomy_path(taxonomy), class: 'btn btn-mini' %> 24 | <%= link_to "Destroy", taxonomy_path(taxonomy), 25 | method: :delete, 26 | data: { confirm: 'Are you sure?' }, 27 | class: 'btn btn-mini btn-danger' %> 28 |
    33 | 34 | <%= link_to "New", new_taxonomy_path, class: 'btn btn-primary' %> 35 | <% else %> 36 |

    There are not taxonomies yet

    37 | <%= link_to "Create the first one", new_taxonomy_path, class: 'btn btn-primary' %> 38 | <% end %> 39 | 40 | 41 | -------------------------------------------------------------------------------- /app/models/user.rb: -------------------------------------------------------------------------------- 1 | require 'digest/md5' 2 | 3 | class User < ActiveRecord::Base 4 | # Include default devise modules. Others available are: 5 | # :token_authenticatable, :encryptable, :confirmable, :lockable, :timeoutable and :omniauthable 6 | devise :database_authenticatable, :registerable, :recoverable, :rememberable, :trackable, :validatable 7 | 8 | # Setup accessible (or protected) attributes for your model 9 | attr_accessible :username, :email, :password, :password_confirmation, :remember_me, :bio 10 | 11 | has_many :highlighted_areas 12 | 13 | has_many :owned_threads, :class_name => "Threadx",:foreign_key => :owner_id 14 | 15 | has_many :threadx_collaborators 16 | has_many :coll_threads, :through => :threadx_collaborators, :source => :threadx 17 | 18 | validates_uniqueness_of :username 19 | validate :ok_username 20 | 21 | # we want to prevent users from creating certain usernames 22 | def ok_username 23 | if ['pageonex', 'admin', 'user', 'thread', 'example', 'blog', 'timeline', 'documentation', 'wiki', 'about', 'frontpage'].include? self.username 24 | errors.add(:userame, "isn't valid") 25 | end 26 | end 27 | 28 | def email_hash 29 | return Digest::MD5.hexdigest(self.email.downcase) 30 | end 31 | 32 | def self.hashes 33 | emails = User.select("username, email").all 34 | result = {} 35 | hashes = emails.map do |u| 36 | digest = Digest::MD5.hexdigest(u['email'].downcase) 37 | result[u['username']] = digest 38 | end 39 | return result 40 | end 41 | 42 | end 43 | -------------------------------------------------------------------------------- /app/controllers/taxonomy_options_controller.rb: -------------------------------------------------------------------------------- 1 | class TaxonomyOptionsController < ApplicationController 2 | 3 | before_filter :authenticate_admin! 4 | 5 | before_filter :load_taxonomy, only: [:index, :destroy, :create, :edit, :update] 6 | before_filter :load_taxonomy_option, only: [:destroy, :edit, :update] 7 | before_filter :load_taxonomy_options, only: [:index, :edit] 8 | 9 | def index 10 | end 11 | 12 | def edit 13 | end 14 | 15 | def create 16 | @taxonomy_option = @taxonomy.taxonomy_options.new(params[:taxonomy_option]) 17 | 18 | if @taxonomy_option.save 19 | redirect_to taxonomy_taxonomy_options_url(@taxonomy) 20 | else 21 | redirect_to taxonomy_taxonomy_options_url(@taxonomy), alert: "Error: #{@taxonomy_option.errors[:value].first}" 22 | end 23 | end 24 | 25 | def update 26 | if @taxonomy_option.update_attributes(params[:taxonomy_option]) 27 | redirect_to taxonomy_taxonomy_options_url(@taxonomy) 28 | else 29 | load_taxonomy_options 30 | render action: "edit" 31 | end 32 | end 33 | 34 | def destroy 35 | @taxonomy_option.destroy 36 | 37 | redirect_to taxonomy_taxonomy_options_url(@taxonomy) 38 | end 39 | 40 | private 41 | def load_taxonomy 42 | @taxonomy = Taxonomy.find(params[:taxonomy_id]) 43 | end 44 | 45 | def load_taxonomy_option 46 | @taxonomy_option = @taxonomy.taxonomy_options.find(params[:id]) 47 | end 48 | 49 | def load_taxonomy_options 50 | @taxonomy_options = @taxonomy.taxonomy_options 51 | end 52 | end -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | volumes: 3 | db_data: 4 | app_kiosko_images: 5 | app_threads_images: 6 | app_tmp_dir: 7 | 8 | services: 9 | mysql: 10 | image: "mysql:5.6.40" 11 | restart: always 12 | ports: 13 | - "13306:13306" 14 | volumes: 15 | - db_data:/var/lib/mysql 16 | - ./docker-compose-files/pageonex.cnf:/etc/mysql/conf.d/pageonex.cnf 17 | environment: 18 | - MYSQL_ROOT_PASSWORD=root 19 | - MYSQL_DATABASE=dc-prod 20 | command: | 21 | bash -c "chmod 644 /etc/mysql/conf.d/pageonex.cnf && /entrypoint.sh mysqld" 22 | 23 | app: 24 | image: pageonex/pageonex:latest 25 | environment: 26 | - RAILS_ENV=production 27 | - DATABASE_ADAPTER=mysql2 28 | - DATABASE_USERNAME=root 29 | - DATABASE_PASSWORD=root 30 | - DATABASE_HOST=mysql 31 | - DATABASE_PORT=13306 32 | - DATABASE_NAME=dc-prod 33 | depends_on: 34 | - "mysql" 35 | ports: 36 | - '3000:3000' 37 | links: 38 | - "mysql" 39 | volumes: 40 | - app_tmp_dir:/workspace/tmp 41 | - app_kiosko_images:/workspace/app/assets/images/kiosko 42 | - app_threads_images:/workspace/app/assets/images/threads 43 | - ./docker-compose-files/wrap-start-app.sh:/usr/local/bin/wrap-start-app.sh 44 | command: 45 | - wrap-start-app.sh 46 | - mysql 47 | - root 48 | - "bundle exec rake db:migrate --trace && bundle exec rake scraping:update_media && bundle exec rake assets:precompile --trace && bundle exec puma -C config/puma.rb" 49 | -------------------------------------------------------------------------------- /app/views/taxonomies/edit.html.erb: -------------------------------------------------------------------------------- 1 | <% @title = "Taxonomies list - PageOneX" %> 2 | 5 | 6 | <%= form_for @taxonomy do |f| %> 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | <% @taxonomies.each do |taxonomy| %> 18 | <% if taxonomy == @taxonomy %> 19 | 20 | 21 | 27 | 28 | 32 | 33 | 34 | <% else %> 35 | 36 | 37 | 38 | 39 | 40 | 41 | <% end %> 42 | <% end %> 43 | 44 |
    IdNameOptionsActions
    <%= link_to taxonomy.id, taxonomy_taxonomy_options_path(taxonomy) %> 22 | <%= f.text_field :name, class: 'input-medium' %> 23 | <% if @taxonomy.errors.messages[:name].present? %> 24 | Error: <%= @taxonomy.errors.messages[:name].first %> 25 | <% end %> 26 | <%= link_to taxonomy.taxonomy_options.map(&:value)*' | ', taxonomy_taxonomy_options_path(taxonomy) %> 29 | <%= f.submit "Change name", class: 'btn btn-primary btn-mini' %> 30 | <%= link_to "Cancel", taxonomies_path, class: 'btn btn-mini' %> 31 |
    <%= taxonomy.id %><%= taxonomy.name %><%= taxonomy.taxonomy_options.map(&:value)*' | ' %>
    45 | <% end %> 46 | -------------------------------------------------------------------------------- /app/views/images/_form.html.erb: -------------------------------------------------------------------------------- 1 | <%= form_for @image, :html => { :class => 'form-horizontal' } do |f| %> 2 |
    3 | <%= f.label :publication_date, :class => 'control-label' %> 4 |
    5 | <%= f.date_select :publication_date, :class => 'date_select' %> 6 |
    7 |
    8 |
    9 | <%= f.label :size, :class => 'control-label' %> 10 |
    11 | <%= f.text_field :size, :class => 'text_field' %> 12 |
    13 |
    14 |
    15 | <%= f.label :media_id, :class => 'control-label' %> 16 |
    17 | <%= f.number_field :media_id, :class => 'number_field' %> 18 |
    19 |
    20 |
    21 | <%= f.label :image_name, :class => 'control-label' %> 22 |
    23 | <%= f.text_field :image_name, :class => 'text_field' %> 24 |
    25 |
    26 |
    27 | <%= f.label :source_url, :class => 'control-label' %> 28 |
    29 | <%= f.text_field :source_url, :class => 'text_field' %> 30 |
    31 |
    32 |
    33 | <%= f.label :missing, :class => 'control-label' %> 34 |
    35 | <%= f.check_box :missing, :class => 'check_box' %> 36 |
    37 |
    38 | 39 |
    40 | <%= f.submit nil, :class => 'btn btn-primary' %> 41 | <%= link_to t('.cancel', :default => t("helpers.links.cancel")), 42 | images_path, :class => 'btn' %> 43 |
    44 | <% end %> 45 | -------------------------------------------------------------------------------- /config/environments/test.rb: -------------------------------------------------------------------------------- 1 | Pageonex::Application.configure do 2 | # Settings specified here will take precedence over those in config/application.rb 3 | 4 | # The test environment is used exclusively to run your application's 5 | # test suite. You never need to work with it otherwise. Remember that 6 | # your test database is "scratch space" for the test suite and is wiped 7 | # and recreated between test runs. Don't rely on the data there! 8 | config.cache_classes = true 9 | 10 | # Configure static asset server for tests with Cache-Control for performance 11 | config.serve_static_assets = true 12 | config.static_cache_control = "public, max-age=3600" 13 | 14 | # Log error messages when you accidentally call methods on nil 15 | config.whiny_nils = true 16 | 17 | # Show full error reports and disable caching 18 | config.consider_all_requests_local = true 19 | config.action_controller.perform_caching = false 20 | 21 | # Raise exceptions instead of rendering exception templates 22 | config.action_dispatch.show_exceptions = false 23 | 24 | # Disable request forgery protection in test environment 25 | config.action_controller.allow_forgery_protection = false 26 | 27 | # Tell Action Mailer not to deliver emails to the real world. 28 | # The :test delivery method accumulates sent emails in the 29 | # ActionMailer::Base.deliveries array. 30 | config.action_mailer.delivery_method = :test 31 | 32 | # Raise exception on mass assignment protection for Active Record models 33 | config.active_record.mass_assignment_sanitizer = :strict 34 | 35 | # Print deprecation notices to the stderr 36 | config.active_support.deprecation = :stderr 37 | end 38 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | # specify a ruby version! (rvm respects this) 4 | ruby "1.9.3" 5 | 6 | gem 'rails', '3.2.13' 7 | 8 | # HACK: this group holds gems we need for heroku 9 | group :heroku do 10 | gem 'pg' 11 | end 12 | 13 | # Gems used only for assets and not required 14 | # in production environments by default. 15 | group :assets do 16 | gem 'sass-rails', '~> 3.2.3' 17 | gem 'coffee-rails', '~> 3.2.1' 18 | gem 'uglifier', '>= 1.0.3' 19 | end 20 | 21 | # GUI support libraries 22 | gem 'therubyracer', '~> 0.12.3' # See https://github.com/sstephenson/execjs#readme for more supported runtimes 23 | gem 'less-rails' 24 | gem "twitter-bootstrap-rails" 25 | gem "jquery-rails" 26 | gem "jquery-ui-rails" 27 | 28 | group :development, :test do 29 | gem 'sqlite3' 30 | gem 'rspec-rails' 31 | gem 'factory_girl_rails' 32 | gem 'debugger' 33 | end 34 | 35 | group :test do 36 | gem 'faker' 37 | gem 'capybara' 38 | gem 'guard-rspec' 39 | gem 'launchy' 40 | end 41 | 42 | gem 'mysql2', '~> 0.3.21' 43 | 44 | # ODF generation for exporting results 45 | gem 'rodf' 46 | 47 | # save image size while scraping kiosko.net 48 | gem "imagesize" 49 | 50 | # for thumbnails, because integrating paperclip gem at this point is too hard 51 | gem 'rmagick' 52 | 53 | # full management of user accounts 54 | gem 'devise' 55 | 56 | # smart generation of slugs for theadx objects 57 | gem 'stringex' 58 | 59 | # pagination support 60 | gem 'will_paginate', '~> 3.0' 61 | gem 'bootstrap-will_paginate' 62 | 63 | # web analytics 64 | gem 'piwik_analytics' 65 | 66 | # for downloading zipped archives 67 | gem 'rubyzip' 68 | 69 | gem 'puma', '~> 3.11.4' 70 | gem 'puma_worker_killer' 71 | -------------------------------------------------------------------------------- /doc/docker/running-pageonex-in-your-environment.md: -------------------------------------------------------------------------------- 1 | # Runining pageonex in your environment 2 | 3 | If you want to create your own deployment of pageonex, the easiest way to do it is to use one of our [docker images](https://hub.docker.com/r/pageonex/pageonex/tags) and connect it to the database. These are the main configuration areas: 4 | 5 | ## Rails environment configuration 6 | 7 | You need to set the `RAILS_ENV` to `production` 8 | 9 | ## Database access configuration 10 | 11 | Pageonex has been mainly tested with mysql, so this is our recommendation. Due to [this issue](https://github.com/montera34/pageonex/issues/212), mysql <= 5.6 is required 12 | 13 | There are a few env variables that should be set to customize your database access: 14 | 15 | * `DATABASE_ADAPTER`: This should be set to `mysql2` 16 | * `DATABASE_USERNAME`: The database user to accesss 17 | * `DATABASE_PASSWORD`: The password corresponding to above user 18 | * `DATABASE_HOST`: Database address 19 | * `DATABASE_PORT`: Database port 20 | * `DATABASE_NAME`: Database name in above host:port 21 | 22 | See [database.yml](/config/database.yml) for more settings and default values. 23 | 24 | ## Filesystem mounts 25 | 26 | There are a few mount points to be set in order to avoid writes in the container filesystem which would lead to data loss and performance degradation: 27 | 28 | * kiosko images: `/workspace/app/assets/images/kiosko` 29 | * threads images: `/workspace/app/assets/images/threads` 30 | * temp files: `/workspace/tmp` 31 | 32 | ## Rake tasks 33 | 34 | These should be run on deployment: 35 | 36 | * Database schema creation/modification: `db:migrate` 37 | * Media list: `scraping:update_media` 38 | * Assets precompilation: `bundle exec rake assets:precompile` 39 | -------------------------------------------------------------------------------- /config/environments/development.rb: -------------------------------------------------------------------------------- 1 | Pageonex::Application.configure do 2 | # Settings specified here will take precedence over those in config/application.rb 3 | 4 | # In the development environment your application's code is reloaded on 5 | # every request. This slows down response time but is perfect for development 6 | # since you don't have to restart the web server when you make code changes. 7 | config.cache_classes = false 8 | 9 | # Log error messages when you accidentally call methods on nil. 10 | config.whiny_nils = true 11 | 12 | # Show full error reports and disable caching 13 | config.consider_all_requests_local = true 14 | config.action_controller.perform_caching = false 15 | 16 | config.action_mailer.delivery_method = :sendmail 17 | config.action_mailer.perform_deliveries = true 18 | 19 | # Don't care if the mailer can't send 20 | config.action_mailer.raise_delivery_errors = true 21 | 22 | config.action_mailer.default_url_options = { :host => 'localhost:3000' } 23 | 24 | # Print deprecation notices to the Rails logger 25 | config.active_support.deprecation = :log 26 | 27 | # Only use best-standards-support built into browsers 28 | config.action_dispatch.best_standards_support = :builtin 29 | 30 | # Raise exception on mass assignment protection for Active Record models 31 | config.active_record.mass_assignment_sanitizer = :strict 32 | 33 | # Log the query plan for queries taking more than this (works 34 | # with SQLite, MySQL, and PostgreSQL) 35 | config.active_record.auto_explain_threshold_in_seconds = 0.5 36 | 37 | # Do not compress assets 38 | config.assets.compress = false 39 | 40 | # Expands the lines which load the assets 41 | config.assets.debug = true 42 | 43 | end 44 | -------------------------------------------------------------------------------- /db/migrate/20120627130452_devise_create_users.rb: -------------------------------------------------------------------------------- 1 | class DeviseCreateUsers < ActiveRecord::Migration 2 | def change 3 | create_table(:users) do |t| 4 | ## Database authenticatable 5 | t.string :username, :null => false, :default => "" 6 | t.string :email, :null => false, :default => "" 7 | t.string :encrypted_password, :null => false, :default => "" 8 | 9 | ## Recoverable 10 | t.string :reset_password_token 11 | t.datetime :reset_password_sent_at 12 | 13 | ## Rememberable 14 | t.datetime :remember_created_at 15 | 16 | ## Trackable 17 | t.integer :sign_in_count, :default => 0 18 | t.datetime :current_sign_in_at 19 | t.datetime :last_sign_in_at 20 | t.string :current_sign_in_ip 21 | t.string :last_sign_in_ip 22 | 23 | ## Encryptable 24 | # t.string :password_salt 25 | 26 | ## Confirmable 27 | # t.string :confirmation_token 28 | # t.datetime :confirmed_at 29 | # t.datetime :confirmation_sent_at 30 | # t.string :unconfirmed_email # Only if using reconfirmable 31 | 32 | ## Lockable 33 | # t.integer :failed_attempts, :default => 0 # Only if lock strategy is :failed_attempts 34 | # t.string :unlock_token # Only if unlock strategy is :email or :both 35 | # t.datetime :locked_at 36 | 37 | ## Token authenticatable 38 | # t.string :authentication_token 39 | 40 | 41 | t.timestamps 42 | end 43 | 44 | add_index :users, :email, :unique => true 45 | add_index :users, :reset_password_token, :unique => true 46 | # add_index :users, :confirmation_token, :unique => true 47 | # add_index :users, :unlock_token, :unique => true 48 | # add_index :users, :authentication_token, :unique => true 49 | end 50 | end 51 | -------------------------------------------------------------------------------- /app/views/taxonomy_options/index.html.erb: -------------------------------------------------------------------------------- 1 | <% @title = "Taxonomy: #{@taxonomy.name} - PageOneX" %> 2 | 5 | 6 | <% if @taxonomy_options.present? %> 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | <% @taxonomy_options.each do |option| %> 17 | 18 | 19 | 20 | 27 | 28 | <% end %> 29 | 30 |
    Option IdValueActions
    <%= option.id %><%= option.value %> 21 | <%= link_to "Change value", edit_taxonomy_taxonomy_option_path(@taxonomy, option), class: 'btn btn-mini' %> 22 | <%= link_to 'Destroy', taxonomy_taxonomy_option_path(@taxonomy.id, option.id), 23 | method: :delete, 24 | data: { confirm: 'Are you sure?' }, 25 | class: 'btn btn-mini btn-danger' %> 26 |
    31 | <% end %> 32 | 33 | <%= render partial: 'form' %> 34 | 35 |
    36 | <% if @taxonomy_options.present? %> 37 | <%= content_tag :span, 'Add new option', class: 'btn btn-primary js-toggle-elements', 38 | data: { show: 'taxonomy-option-create-form', hide: 'taxonomy-options-admin-add' } %> 39 | <% else %> 40 | 41 | 42 |
    There are not options for this taxonomy yet
    43 | <%= content_tag :span, 'Create the first one', class: 'btn btn-primary js-toggle-elements', 44 | data: { show: 'taxonomy-option-create-form', hide: 'taxonomy-options-admin-add' } %> 45 | <% end %> 46 | <%= link_to 'Back to taxonomies list', taxonomies_path, class: 'btn' %> 47 |
    -------------------------------------------------------------------------------- /app/views/threads/_topic_form.html.erb: -------------------------------------------------------------------------------- 1 | 2 | <% 3 | =begin 4 | Locals: 5 | index - integer index of the topic 6 | id - database id of the code 7 | name - name of the topic 8 | color - hex color for the topic 9 | description - text describing the topic 10 | =end 11 | human_topic_number = (Integer(index) + 1).to_s 12 | %> 13 | 14 |
    46 | 47 | 52 | 53 |
    54 | -------------------------------------------------------------------------------- /app/views/images/show.html.erb: -------------------------------------------------------------------------------- 1 | <% @title = "Show image - PageOneX" %> 2 | <%- model_class = Image -%> 3 | 6 | 7 |
    8 |
    <%= model_class.human_attribute_name(:publication_date) %>:
    9 |
    <%= @image.publication_date %>
    10 |
    <%= model_class.human_attribute_name(:size) %>:
    11 |
    <%= @image.size %>
    12 |
    <%= model_class.human_attribute_name(:media_id) %>:
    13 |
    <%= @image.media_id %>
    14 |
    <%= model_class.human_attribute_name(:image_name) %>:
    15 |
    <%= @image.image_name %>
    16 |
    <%= model_class.human_attribute_name(:source_url) %>:
    17 |
    <%= link_to @image.source_url, @image.source_url %>
    18 |
    <%= model_class.human_attribute_name(:missing) %>:
    19 |
    <%= @image.missing %>
    20 |
    21 | 22 |
    23 | Download 24 | <%= link_to t('.back', :default => t("helpers.links.back")), 25 | images_path, :class => 'btn' %> 26 | <%= link_to t('.edit', :default => t("helpers.links.edit")), 27 | edit_image_path(@image), :class => 'btn' %> 28 | <%= link_to t('.destroy', :default => t("helpers.links.destroy")), 29 | image_path(@image), 30 | :method => 'delete', 31 | :data => { :confirm => t('.confirm', :default => t("helpers.links.confirm", :default => 'Are you sure?')) }, 32 | :class => 'btn btn-danger' %> 33 |
    34 | 35 | <% if @image.missing %> 36 | Image is missing :-( 37 | <% else %> 38 |

    39 | Thumbnail
    40 | <%= image_tag @image.thumbnail_local_path(80,true), :alt => @image.image_name %> 41 |

    42 |

    43 | Full Size

    44 | <%= image_tag @image.local_path, :alt => @image.image_name %> 45 |

    46 | <% end %> 47 | -------------------------------------------------------------------------------- /doc/local-install.md: -------------------------------------------------------------------------------- 1 | Install PageOneX locally 2 | ========================== 3 | Download the files from https://github.com/numeroteca/pageonex 4 | 5 | ### Needs 6 | PageOnex runs in Ruby on Rails, so you'll ned to install: 7 | + [Ruby v1.9.3](http://www.ruby-lang.org/en/downloads/) - We highly recommend using [RVM](http://rvm.io/) and gemsets to manage ruby (ie. `rvm use 1.9.3@pageonex`) 8 | + [RubyGems](https://rubygems.org/) 9 | + [Rails](https://rubyonrails.org/) (you might also want to install [RVM (Ruby Version Manager)](https://rvm.io/) 10 | 11 | Process 12 | ------- 13 | You might want to clone the repository with git: 14 | ``` 15 | git clone git@github.com:numeroteca/pageonex.git 16 | ``` 17 | 18 | Or download the .zip file from https://github.com/numeroteca/pageonex/archive/master.zip 19 | 20 | Go to the directory 21 | ``` 22 | cd pageonex 23 | ``` 24 | 25 | Setup a database and then edit the `config/database.yml` file to give the app access to that database (we use MySQL). 26 | 27 | Install the gems 28 | ``` 29 | bundle install 30 | ``` 31 | 32 | Run the migration (this will create the database with its tables): 33 | ``` 34 | rake db:migrate 35 | ``` 36 | 37 | Create a PageOneX admin user like this: 38 | ``` 39 | rails console 40 | User.create(:username=>'admin-user',:email=>'admin-user@admin.admin',:password=>'hola1234',:password_confirmation=>'hola1234') 41 | me = User.first 42 | me.admin = true 43 | me.save 44 | ``` 45 | 46 | Load the list of newspapers into the data base: 47 | ``` 48 | rake scraping:update_media 49 | ``` 50 | 51 | Run the server: 52 | ``` 53 | rails server 54 | ``` 55 | 56 | You can now navigate the app at `http://localhost:3000/` or `http://0.0.0.0:3000/` 57 | 58 | ### Options 59 | If you have problems with the dependencies of the gems check this tricks. 60 | 61 | **Problems with dependencies** 62 | 63 | Run the same commands with 'bundle exec' like 64 | ``` 65 | bundle exec rake db:migrate 66 | ``` 67 | 68 | If you have problems with the pg gem, needed for the "heroku" version, you can run: 69 | ``` 70 | bundle install --without heroku 71 | ``` 72 | 73 | 74 | -------------------------------------------------------------------------------- /app/views/images/index.html.erb: -------------------------------------------------------------------------------- 1 | <% @title = "Image Index - PageOneX" %> 2 | <%- model_class = Image -%> 3 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | <% @images.each do |image| %> 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 40 | 41 | <% end %> 42 | 43 |
    <%= model_class.human_attribute_name(:id) %><%= model_class.human_attribute_name(:publication_date) %><%= model_class.human_attribute_name(:size) %><%= model_class.human_attribute_name(:media_id) %><%= model_class.human_attribute_name(:image_name) %><%= model_class.human_attribute_name(:source_url) %><%= model_class.human_attribute_name(:missing) %><%= model_class.human_attribute_name(:created_at) %><%=t '.actions', :default => t("helpers.actions") %>
    <%= link_to image.id, image_path(image) %><%= image.publication_date %><%= image.size %><%= image.media_id %><%= image.image_name %><%= link_to image.source_url, image.source_url %><%= image.missing %><%=l image.created_at %> 32 | <%= link_to t('.edit', :default => t("helpers.links.edit")), 33 | edit_image_path(image), :class => 'btn btn-mini' %> 34 | <%= link_to t('.destroy', :default => t("helpers.links.destroy")), 35 | image_path(image), 36 | :method => :delete, 37 | :data => { :confirm => t('.confirm', :default => t("helpers.links.confirm", :default => 'Are you sure?')) }, 38 | :class => 'btn btn-mini btn-danger' %> 39 |
    44 | 45 | <%= link_to t('.new', :default => t("helpers.links.new")), 46 | new_image_path, 47 | :class => 'btn btn-primary' %> 48 | -------------------------------------------------------------------------------- /app/views/layouts/embed.html.erb: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | <%= @title %> 7 | <% @title = "PageOneX" %> 8 | <%= csrf_meta_tags %> 9 | <%= javascript_include_tag "application" %> 10 | 11 | 12 | 15 | 16 | 17 | <%= stylesheet_link_tag "application", :media => "all" %> 18 | 23 | 24 | 30 | 31 | <%= favicon_link_tag %> 32 | 33 | 36 |
    37 | 38 | <%= yield %> 39 | 40 |
    41 | 42 | 43 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 59 | 60 | <%= piwik_tracking_tag %> 61 | 62 | 63 | -------------------------------------------------------------------------------- /app/controllers/users_controller.rb: -------------------------------------------------------------------------------- 1 | class UsersController < ApplicationController 2 | 3 | before_filter :authenticate_admin! 4 | 5 | # GET /users 6 | # GET /users.json 7 | def index 8 | @users = User.all 9 | 10 | respond_to do |format| 11 | format.html # index.html.erb 12 | format.json { render json: @users } 13 | end 14 | end 15 | 16 | # GET /users/1 17 | # GET /users/1.json 18 | def show 19 | @user = User.find(params[:id]) 20 | 21 | respond_to do |format| 22 | format.html # show.html.erb 23 | format.json { render json: @user } 24 | end 25 | end 26 | 27 | # GET /users/new 28 | # GET /users/new.json 29 | def new 30 | @user = User.new 31 | 32 | respond_to do |format| 33 | format.html # new.html.erb 34 | format.json { render json: @user } 35 | end 36 | end 37 | 38 | # GET /users/1/edit 39 | def edit 40 | @user = User.find(params[:id]) 41 | end 42 | 43 | # POST /users 44 | # POST /users.json 45 | def create 46 | @user = User.new(params[:user]) 47 | 48 | respond_to do |format| 49 | if @user.save 50 | format.html { redirect_to @user, notice: 'User was successfully created.' } 51 | format.json { render json: @user, status: :created, location: @user } 52 | else 53 | format.html { render action: "new" } 54 | format.json { render json: @user.errors, status: :unprocessable_entity } 55 | end 56 | end 57 | end 58 | 59 | # PUT /users/1 60 | # PUT /users/1.json 61 | def update 62 | @user = User.find(params[:id]) 63 | 64 | respond_to do |format| 65 | if @user.update_attributes(params[:user]) 66 | format.html { redirect_to @user, notice: 'User was successfully updated.' } 67 | format.json { head :no_content } 68 | else 69 | format.html { render action: "edit" } 70 | format.json { render json: @user.errors, status: :unprocessable_entity } 71 | end 72 | end 73 | end 74 | 75 | # DELETE /users/1 76 | # DELETE /users/1.json 77 | def destroy 78 | @user = User.find(params[:id]) 79 | @user.destroy 80 | 81 | respond_to do |format| 82 | format.html { redirect_to users_url } 83 | format.json { head :no_content } 84 | end 85 | end 86 | end 87 | -------------------------------------------------------------------------------- /app/controllers/media_controller.rb: -------------------------------------------------------------------------------- 1 | class MediaController < ApplicationController 2 | 3 | before_filter :authenticate_admin! 4 | 5 | # GET /media 6 | # GET /media.json 7 | def index 8 | @media_list = Media.all 9 | 10 | respond_to do |format| 11 | format.html # index.html.erb 12 | format.json { render json: @media_list } 13 | end 14 | end 15 | 16 | # GET /media/1 17 | # GET /media/1.json 18 | def show 19 | @media = Media.find(params[:id]) 20 | 21 | respond_to do |format| 22 | format.html # show.html.erb 23 | format.json { render json: @media } 24 | end 25 | end 26 | 27 | # GET /media/new 28 | # GET /media/new.json 29 | def new 30 | @media = Media.new 31 | 32 | respond_to do |format| 33 | format.html # new.html.erb 34 | format.json { render json: @media } 35 | end 36 | end 37 | 38 | # GET /media/1/edit 39 | def edit 40 | @media = Media.find(params[:id]) 41 | end 42 | 43 | # POST /media 44 | # POST /media.json 45 | def create 46 | @media = Media.new(params[:media]) 47 | 48 | respond_to do |format| 49 | if @media.save 50 | format.html { redirect_to @media, notice: 'Media was successfully created.' } 51 | format.json { render json: @media, status: :created, location: @media } 52 | else 53 | format.html { render action: "new" } 54 | format.json { render json: @media.errors, status: :unprocessable_entity } 55 | end 56 | end 57 | end 58 | 59 | # PUT /media/1 60 | # PUT /media/1.json 61 | def update 62 | @media = Media.find(params[:id]) 63 | 64 | respond_to do |format| 65 | if @media.update_attributes(params[:media]) 66 | format.html { redirect_to @media, notice: 'Media was successfully updated.' } 67 | format.json { head :no_content } 68 | else 69 | format.html { render action: "edit" } 70 | format.json { render json: @media.errors, status: :unprocessable_entity } 71 | end 72 | end 73 | end 74 | 75 | # DELETE /media/1 76 | # DELETE /media/1.json 77 | def destroy 78 | @media = Media.find(params[:id]) 79 | @media.destroy 80 | 81 | respond_to do |format| 82 | format.html { redirect_to media_url } 83 | format.json { head :no_content } 84 | end 85 | end 86 | end 87 | -------------------------------------------------------------------------------- /app/views/users/show.html.erb: -------------------------------------------------------------------------------- 1 | <% @title = "Users list - PageOneX" %> 2 | <%- model_class = User -%> 3 | 6 | 7 |
    8 |
    <%= model_class.human_attribute_name(:username) %>:
    9 |
    <%= @user.username %>
    10 |
    <%= model_class.human_attribute_name(:email) %>:
    11 |
    <%= @user.email %>
    12 |
    <%= model_class.human_attribute_name(:encrypted_password) %>:
    13 |
    <%= @user.encrypted_password %>
    14 |
    <%= model_class.human_attribute_name(:reset_password_token) %>:
    15 |
    <%= @user.reset_password_token %>
    16 |
    <%= model_class.human_attribute_name(:reset_password_sent_at) %>:
    17 |
    <%= @user.reset_password_sent_at %>
    18 |
    <%= model_class.human_attribute_name(:remember_created_at) %>:
    19 |
    <%= @user.remember_created_at %>
    20 |
    <%= model_class.human_attribute_name(:current_sign_in_at) %>:
    21 |
    <%= @user.current_sign_in_at %>
    22 |
    <%= model_class.human_attribute_name(:last_sign_in_at) %>:
    23 |
    <%= @user.last_sign_in_at %>
    24 |
    <%= model_class.human_attribute_name(:current_sign_in_ip) %>:
    25 |
    <%= @user.current_sign_in_ip %>
    26 |
    <%= model_class.human_attribute_name(:last_sign_in_ip) %>:
    27 |
    <%= @user.last_sign_in_ip %>
    28 |
    <%= model_class.human_attribute_name(:admin) %>:
    29 |
    <%= @user.admin %>
    30 |
    31 | 32 |
    33 | <%= link_to t('.back', :default => t("helpers.links.back")), 34 | users_path, :class => 'btn' %> 35 | <%= link_to t('.edit', :default => t("helpers.links.edit")), 36 | edit_user_path(@user), :class => 'btn' %> 37 | <%= link_to t('.destroy', :default => t("helpers.links.destroy")), 38 | user_path(@user), 39 | :method => 'delete', 40 | :data => { :confirm => t('.confirm', :default => t("helpers.links.confirm", :default => 'Are you sure?')) }, 41 | :class => 'btn btn-danger' %> 42 |
    43 | -------------------------------------------------------------------------------- /doc/docker/running-pageonex-locally-with-docker-compose.md: -------------------------------------------------------------------------------- 1 | # Running pageonex locally with docker compose 2 | 3 | You can test locally pageonex using [docker compose](https://docs.docker.com/compose/). 4 | 5 | From the command line go to the direcrtory where you have cloned (or downloaded) the Pageonex repository and type: 6 | 7 | ``` 8 | docker-compose up 9 | ``` 10 | 11 | It will take a few minutes to complet the install. 12 | You need Internet access because it needs to download the PageOneX docker image. 13 | 14 | Once it works you will get: 15 | 16 | * A mysql database running [the official mysql image](https://hub.docker.com/_/mysql/). 17 | * All the migration and admin tasks run. 18 | * A pageonex server running [the lastest pageonex image](https://hub.docker.com/r/pageonex/pageonex). 19 | * All data stored in separate volumes that will remain even if you delete your application's containers. 20 | 21 | Once everything is running correctly, you can access the application from your browser at http://localhost:3000 or http://0.0.0.0:3000 22 | 23 | **For Windows users** 24 | 25 | You need to enable virtualization to allow docker work. See the example for Windows 11: https://support.microsoft.com/en-us/windows/enable-virtualization-on-windows-11-pcs-c5578302-6e43-4b4b-a449-8ced115f58e1 26 | 27 | ## Tasks 28 | 29 | ### How to run in detached mode 30 | 31 | In order to run docker-compose in background and have the shell available, please use detached mode 32 | ``` 33 | docker-compose up -d 34 | ``` 35 | 36 | ### How to see logs 37 | 38 | Logs are not shown in the screen in detached mode, you can inspect them using 39 | ``` 40 | docker-compose logs 41 | ``` 42 | 43 | ### How to access the rails console 44 | 45 | To get a the rails console (See [doc/local-install.md](/doc/local-install.md#process) for instructions on creating an admin user) run 46 | ``` 47 | docker-compose exec app rails console 48 | ``` 49 | 50 | ### How to access the database 51 | 52 | In case you want to further inspect the database, you can run 53 | ``` 54 | docker-compose exec mysql mysql -u root -h localhost --password=root dc-prod 55 | ``` 56 | 57 | ### How to shut it down 58 | 59 | If you want to shut down everything, keeping volumes and images for a quick start 60 | ``` 61 | docker-compose stop 62 | ``` 63 | 64 | ### How to delete everything and start from scratch 65 | 66 | You may want to start fresh. You have to make sure that all related images, containers are both stopped and deleted and volumes are deleted 67 | ``` 68 | docker-compose stop 69 | docker-compose rm 70 | docker volume rm pageonex_app_kiosko_images pageonex_app_threads_images pageonex_db_data pageonex_app_tmp_dir 71 | ``` 72 | -------------------------------------------------------------------------------- /app/views/users/index.html.erb: -------------------------------------------------------------------------------- 1 | <% @title = "User list - PageOneX" %> 2 | <%- model_class = User -%> 3 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | <% @users.each do |user| %> 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 48 | 49 | <% end %> 50 | 51 |
    <%= model_class.human_attribute_name(:id) %><%= model_class.human_attribute_name(:username) %><%= model_class.human_attribute_name(:email) %><%= model_class.human_attribute_name(:reset_password_token) %><%= model_class.human_attribute_name(:reset_password_sent_at) %><%= model_class.human_attribute_name(:remember_created_at) %><%= model_class.human_attribute_name(:current_sign_in_at) %><%= model_class.human_attribute_name(:last_sign_in_at) %><%= model_class.human_attribute_name(:current_sign_in_ip) %><%= model_class.human_attribute_name(:last_sign_in_ip) %><%= model_class.human_attribute_name(:admin) %><%= model_class.human_attribute_name(:created_at) %><%=t '.actions', :default => t("helpers.actions") %>
    <%= link_to user.id, user_path(user) %><%= user.username %><%= user.email %><%= user.reset_password_token %><%= user.reset_password_sent_at %><%= user.remember_created_at %><%= user.current_sign_in_at %><%= user.last_sign_in_at %><%= user.current_sign_in_ip %><%= user.last_sign_in_ip %><%= user.admin %><%=l user.created_at %> 40 | <%= link_to t('.edit', :default => t("helpers.links.edit")), 41 | edit_user_path(user), :class => 'btn btn-mini' %> 42 | <%= link_to t('.destroy', :default => t("helpers.links.destroy")), 43 | user_path(user), 44 | :method => :delete, 45 | :data => { :confirm => t('.confirm', :default => t("helpers.links.confirm", :default => 'Are you sure?')) }, 46 | :class => 'btn btn-mini btn-danger' %> 47 |
    52 | 53 | <%= link_to t('.new', :default => t("helpers.links.new")), 54 | new_user_path, 55 | :class => 'btn btn-primary' %> 56 | -------------------------------------------------------------------------------- /app/assets/javascripts/application.js: -------------------------------------------------------------------------------- 1 | // This is a manifest file that'll be compiled into application.js, which will include all the files 2 | // listed below. 3 | // 4 | // Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts, 5 | // or vendor/assets/javascripts of plugins, if any, can be referenced here using a relative path. 6 | // 7 | // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the 8 | // the compiled file. 9 | // 10 | // WARNING: THE FIRST BLANK LINE MARKS THE END OF WHAT'S TO BE PROCESSED, ANY BLANK LINE SHOULD 11 | // GO AFTER THE REQUIRES BELOW. 12 | // 13 | //= require jquery 14 | //= require jquery_ujs 15 | 16 | // require jquery.ui.all 17 | 18 | //= require jquery.ui.core 19 | //= require jquery.ui.widget 20 | //= require jquery.ui.mouse 21 | //= require jquery.ui.position 22 | 23 | //= require jquery.ui.draggable 24 | // require jquery.ui.droppable 25 | //= require jquery.ui.resizable 26 | // require jquery.ui.selectable 27 | // require jquery.ui.sortable 28 | 29 | //= require jquery.ui.accordion 30 | // require jquery.ui.autocomplete 31 | // require jquery.ui.button 32 | // require jquery.ui.dialog 33 | // require jquery.ui.slider 34 | // require jquery.ui.tabs 35 | //= require jquery.ui.datepicker 36 | //= require jquery.ui.datepicker-en-AU 37 | // require jquery.ui.progressbar 38 | 39 | // require jquery.ui.effect.all 40 | //= require jquery.ui.effect 41 | // require jquery.ui.effect-blind 42 | // require jquery.ui.effect-bounce 43 | // require jquery.ui.effect-clip 44 | // require jquery.ui.effect-drop 45 | // require jquery.ui.effect-explode 46 | // require jquery.ui.effect-fade 47 | // require jquery.ui.effect-fold 48 | // require jquery.ui.effect-highlight 49 | // require jquery.ui.effect-pulsate 50 | // require jquery.ui.effect-scale 51 | // require jquery.ui.effect-shake 52 | // require jquery.ui.effect-slide 53 | // require jquery.ui.effect-transfer 54 | 55 | //= require twitter/bootstrap/bootstrap-transition 56 | //= require twitter/bootstrap/bootstrap-alert 57 | //= require twitter/bootstrap/bootstrap-modal 58 | //= require twitter/bootstrap/bootstrap-dropdown 59 | //= require twitter/bootstrap/bootstrap-scrollspy 60 | // require twitter/bootstrap/bootstrap-tab 61 | //= require twitter/bootstrap/bootstrap-tooltip 62 | //= require twitter/bootstrap/bootstrap-popover 63 | //= require twitter/bootstrap/bootstrap-button 64 | //= require twitter/bootstrap/bootstrap-collapse 65 | // require twitter/bootstrap/bootstrap-typeahead 66 | //= require bootstrap-carousel 67 | // require twitter/bootstrap 68 | 69 | //= require spin.min 70 | 71 | //= require utils 72 | // require_tree . 73 | 74 | $(function() { 75 | // initialize any and all popovers on the page 76 | $('[rel="popover"]').popover({trigger:'hover'}); 77 | }) -------------------------------------------------------------------------------- /config/environments/production.rb: -------------------------------------------------------------------------------- 1 | Pageonex::Application.configure do 2 | # Settings specified here will take precedence over those in config/application.rb 3 | 4 | # Code is not reloaded between requests 5 | config.cache_classes = true 6 | 7 | # Full error reports are disabled and caching is turned on 8 | config.consider_all_requests_local = false 9 | config.action_controller.perform_caching = true 10 | 11 | # Disable Rails's static asset server (Apache or nginx will already do this) 12 | config.serve_static_assets = false 13 | 14 | # Compress JavaScripts and CSS 15 | config.assets.compress = true 16 | 17 | # Don't fallback to assets pipeline if a precompiled asset is missed 18 | config.assets.compile = true 19 | 20 | # Generate digests for assets URLs 21 | config.assets.digest = false 22 | 23 | # config.assets.initialize_on_precompile = false 24 | 25 | # Defaults to Rails.root.join("public/assets") 26 | # config.assets.manifest = YOUR_PATH 27 | 28 | # Specifies the header that your server uses for sending files 29 | # config.action_dispatch.x_sendfile_header = "X-Sendfile" # for apache 30 | # config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for nginx 31 | 32 | # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. 33 | # config.force_ssl = true 34 | 35 | # See everything in the log (default is :info) 36 | # config.log_level = :debug 37 | 38 | # Prepend all log lines with the following tags 39 | # config.log_tags = [ :subdomain, :uuid ] 40 | 41 | # Use a different logger for distributed setups 42 | # config.logger = ActiveSupport::TaggedLogging.new(SyslogLogger.new) 43 | 44 | # Use a different cache store in production 45 | # config.cache_store = :mem_cache_store 46 | 47 | # Enable serving of images, stylesheets, and JavaScripts from an asset server 48 | # config.action_controller.asset_host = "http://assets.example.com" 49 | 50 | # Precompile additional assets (application.js, application.css, and all non-JS/CSS are already added) 51 | # config.assets.precompile += %w( search.js ) 52 | 53 | # Disable delivery errors, bad email addresses will be ignored 54 | config.action_mailer.delivery_method = :sendmail 55 | config.action_mailer.perform_deliveries = true 56 | config.action_mailer.raise_delivery_errors = false 57 | config.action_mailer.default_url_options = { :host => 'pageonex.com' } 58 | 59 | # Enable threaded mode 60 | # config.threadsafe! 61 | 62 | # Enable locale fallbacks for I18n (makes lookups for any locale fall back to 63 | # the I18n.default_locale when a translation can not be found) 64 | config.i18n.fallbacks = true 65 | 66 | # Send deprecation notices to registered listeners 67 | config.active_support.deprecation = :notify 68 | 69 | # Log the query plan for queries taking more than this (works 70 | # with SQLite, MySQL, and PostgreSQL) 71 | # config.active_record.auto_explain_threshold_in_seconds = 0.5 72 | end 73 | -------------------------------------------------------------------------------- /config/puma.rb: -------------------------------------------------------------------------------- 1 | rackup DefaultRackup 2 | 3 | # Puma can serve each request in a thread from an internal thread pool. 4 | # The `threads` method setting takes two numbers: a minimum and maximum. 5 | # Any libraries that use thread pools should be configured to match 6 | # the maximum value specified for Puma. Default is set to 5 threads for minimum 7 | # and maximum; this matches the default thread size of Active Record. 8 | # 9 | threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 } 10 | threads threads_count, threads_count 11 | 12 | # Specifies the `port` that Puma will listen on to receive requests; default is 3000. 13 | # 14 | port ENV.fetch("PORT") { 3000 } 15 | 16 | # Specifies the `environment` that Puma will run in. 17 | # 18 | environment ENV.fetch("RAILS_ENV") { "development" } 19 | 20 | # Specifies the number of `workers` to boot in clustered mode. 21 | # Workers are forked webserver processes. If using threads and workers together 22 | # the concurrency of the application would be max `threads` * `workers`. 23 | # Workers do not work on JRuby or Windows (both of which do not support 24 | # processes). 25 | # 26 | workers ENV.fetch("WEB_CONCURRENCY") { 2 } 27 | 28 | # Use the `preload_app!` method when specifying a `workers` number. 29 | # This directive tells Puma to first boot the application and load code 30 | # before forking the application. This takes advantage of Copy On Write 31 | # process behavior so workers use less memory. If you use this option 32 | # you need to make sure to reconnect any threads in the `on_worker_boot` 33 | # block. 34 | # 35 | preload_app! 36 | 37 | # If you are preloading your application and using Active Record, it's 38 | # recommended that you close any connections to the database before workers 39 | # are forked to prevent connection leakage. 40 | # 41 | # before_fork do 42 | # ActiveRecord::Base.connection_pool.disconnect! if defined?(ActiveRecord) 43 | # end 44 | 45 | before_fork do 46 | require 'puma_worker_killer' 47 | 48 | PumaWorkerKiller.enable_rolling_restart # Default is every 6 hours 49 | end 50 | 51 | # The code in the `on_worker_boot` will be called if you are using 52 | # clustered mode by specifying a number of `workers`. After each worker 53 | # process is booted, this block will be run. If you are using the `preload_app!` 54 | # option, you will want to use this block to reconnect to any threads 55 | # or connections that may have been created at application boot, as Ruby 56 | # cannot share connections between processes. 57 | 58 | on_worker_boot do 59 | # Valid on Rails up to 4.1 the initializer method of setting `pool` size 60 | ActiveSupport.on_load(:active_record) do 61 | config = ActiveRecord::Base.configurations[Rails.env] || 62 | Rails.application.config.database_configuration[Rails.env] 63 | config['pool'] = ENV['RAILS_MAX_THREADS'] || 5 64 | ActiveRecord::Base.establish_connection(config) 65 | end 66 | end 67 | 68 | # Allow puma to be restarted by `rails restart` command. 69 | plugin :tmp_restart 70 | -------------------------------------------------------------------------------- /app/assets/stylesheets/coding.css.scss: -------------------------------------------------------------------------------- 1 | // Place all the styles related to the coding controller here. 2 | // They will automatically be included in application.css. 3 | // You can use Sass (SCSS) here: http://sass-lang.com/ 4 | h1 { 5 | font-size: 30px; 6 | margin-top: 0; 7 | margin-bottom: 5px; 8 | } 9 | .legend_text { 10 | line-height: 1em; 11 | } 12 | .box_legend { 13 | width: 26px; 14 | height: 26px; 15 | display: block; 16 | margin: 0 4px 4px 0; 17 | float:left; 18 | cursor:pointer; 19 | } 20 | .inactive .box_legend { 21 | opacity:.4; 22 | } 23 | .legend_text:hover{ 24 | font-weight:bold; 25 | cursor:pointer; 26 | } 27 | #color-legend li{ 28 | vertical-align: top; 29 | } 30 | .codes_boxes{ 31 | margin-left: 30px; 32 | font-size: 15px; 33 | } 34 | 35 | #aboveImageToolbar { 36 | margin-bottom: 10px; 37 | } 38 | 39 | .above-image-alert { 40 | margin-bottom: 0px; 41 | padding-top: 4px; 42 | padding-bottom: 4px; 43 | } 44 | 45 | .above-image-alert form { 46 | margin-bottom: 0px; 47 | } 48 | 49 | #chart-export-img { 50 | box-shadow: 2px 2px 5px #888888; 51 | } 52 | 53 | .high_area { 54 | border: 1px solid #333333; 55 | } 56 | 57 | #topics { 58 | padding-left:0px; 59 | } 60 | //Carrousel pointer 61 | #myCarousel{ 62 | cursor:crosshair; 63 | } 64 | .ui-draggable{ 65 | cursor:move; 66 | } 67 | 68 | /* dataviz */ 69 | .gridline { 70 | stroke: #ddd; 71 | shape-rendering: crispEdges; 72 | stroke-width:1; 73 | } 74 | 75 | .yaxis line, .xaxis path{ 76 | shape-rendering: crispEdges; 77 | stroke-width:1; 78 | } 79 | 80 | /* composite image stuff */ 81 | ul.thread-composite-images { 82 | list-style-type: none; 83 | margin: 0px; 84 | padding: 0px; 85 | position: relative; 86 | display: block; 87 | } 88 | ul.thread-composite-images li { 89 | display: float; 90 | float: left; 91 | position: absolute; 92 | top: 0px; 93 | left: 0px; 94 | } 95 | ul.thread-coposite-labels { 96 | list-style-type: none; 97 | margin: 0px; 98 | padding: 0px; 99 | display: block; 100 | } 101 | ul.thread-coposite-labels li { 102 | display: block; 103 | vertical-align: top; 104 | text-align: right; 105 | cursor:pointer; 106 | } 107 | ul.thread-coposite-labels li.active { 108 | font-weight:bold; 109 | } 110 | ul.thread-coposite-labels li.inactive { 111 | font-weight:normal; 112 | } 113 | .avatar-icon { 114 | float:left; 115 | cursor:pointer; 116 | } 117 | .ha-user-name { 118 | margin-left: 25px; 119 | display: none; 120 | color: white; 121 | background-color: black; 122 | width: 150px; 123 | padding-left: 5px; 124 | } 125 | .user-id img:hover + span { 126 | display: block !important; 127 | } 128 | .ha-close-icon { 129 | cursor:pointer; 130 | width: 20px; 131 | position: absolute; 132 | right: 0px; 133 | top: 0px; 134 | } 135 | .ha-edit-icon { 136 | cursor:pointer; 137 | width: 20px; 138 | position: absolute; 139 | right: 23px; 140 | top: 0px; 141 | } 142 | #embedded_footer{ 143 | position: absolute; 144 | right: 0px; 145 | bottom: 0px; 146 | /*background-image: url("/images/header-proyecto.gif");*/ 147 | background-color:#ddd; 148 | padding:3px; 149 | } 150 | #color-legend li{ 151 | width:150px; 152 | padding:0; 153 | } 154 | -------------------------------------------------------------------------------- /config/routes.rb: -------------------------------------------------------------------------------- 1 | Pageonex::Application.routes.draw do 2 | devise_for :users 3 | resources :users 4 | 5 | match 'threads/mine' => 'threads#mine' 6 | match 'threads/by/:username' => 'threads#by_username' 7 | match 'threads/search' => 'threads#search' 8 | match 'threads/search_by_category' => 'threads#search_by_category' 9 | match 'threads/new_topic/:index' => 'threads#new_topic' 10 | resources :threads do 11 | member do 12 | post :fork 13 | end 14 | end 15 | 16 | match 'images/download' => 'images#download' 17 | match 'images/for_media/:media_id' => 'images#for_media' 18 | resources :images 19 | 20 | resources :media 21 | 22 | resources :taxonomies, except: [:show] do 23 | resources :taxonomy_options, except: [:show, :new] 24 | end 25 | 26 | match ':username/:thread_name/export' => 'threads#export' 27 | match ':username/:thread_name/raw' => 'threads#raw' 28 | match ':username/:thread_name/coding' => 'coding#process_images' 29 | match ':username/:thread_name/process_highlighted_areas' => 'coding#process_highlighted_areas' 30 | match ':username/:thread_name' => 'coding#display' 31 | match ':username/:thread_name/embed' => 'coding#embed' 32 | 33 | match '/about' => 'home#about' 34 | match '/help' => 'home#help' 35 | match '/terms-of-service' => 'home#terms-of-service' 36 | match '/privacy-policy' => 'home#privacy-policy' 37 | match '/export_chart' => 'home#export_chart' 38 | 39 | root :to => "home#index" 40 | 41 | 42 | 43 | # The priority is based upon order of creation: 44 | # first created -> highest priority. 45 | 46 | # Sample of regular route: 47 | # match 'products/:id' => 'catalog#view' 48 | # Keep in mind you can assign values other than :controller and :action 49 | 50 | # Sample of named route: 51 | # match 'products/:id/purchase' => 'catalog#purchase', :as => :purchase 52 | # This route can be invoked with purchase_url(:id => product.id) 53 | 54 | # Sample resource route (maps HTTP verbs to controller actions automatically): 55 | # resources :products 56 | 57 | # Sample resource route with options: 58 | # resources :products do 59 | # member do 60 | # get 'short' 61 | # post 'toggle' 62 | # end 63 | # 64 | # collection do 65 | # get 'sold' 66 | # end 67 | # end 68 | 69 | # Sample resource route with sub-resources: 70 | # resources :products do 71 | # resources :comments, :sales 72 | # resource :seller 73 | # end 74 | 75 | # Sample resource route with more complex sub-resources 76 | # resources :products do 77 | # resources :comments 78 | # resources :sales do 79 | # get 'recent', :on => :collection 80 | # end 81 | # end 82 | 83 | # Sample resource route within a namespace: 84 | # namespace :admin do 85 | # # Directs /admin/products/* to Admin::ProductsController 86 | # # (app/controllers/admin/products_controller.rb) 87 | # resources :products 88 | # end 89 | 90 | # You can have the root of your site routed with "root" 91 | # just remember to delete public/index.html. 92 | # root :to => 'welcome#index' 93 | 94 | # See how all your routes lay out with "rake routes" 95 | 96 | # This is a legacy wild controller route that's not recommended for RESTful applications. 97 | # Note: This route will make all actions in every controller accessible via GET requests. 98 | # match ':controller(/:action(/:id))(.:format)' 99 | end 100 | -------------------------------------------------------------------------------- /config/application.rb: -------------------------------------------------------------------------------- 1 | require File.expand_path('../boot', __FILE__) 2 | 3 | # Pick the frameworks you want: 4 | require "active_record/railtie" 5 | require "action_controller/railtie" 6 | require "action_mailer/railtie" 7 | require "active_resource/railtie" 8 | require "sprockets/railtie" 9 | # require "rails/test_unit/railtie" 10 | require "csv" 11 | 12 | if defined?(Bundler) 13 | # If you precompile assets before deploying to production, use this line 14 | Bundler.require(*Rails.groups(:assets => %w(development test))) 15 | # If you want your assets lazily compiled in production, use this line 16 | # Bundler.require(:default, :assets, Rails.env) 17 | end 18 | 19 | module Pageonex 20 | class Application < Rails::Application 21 | # Settings in config/environments/* take precedence over those specified here. 22 | # Application configuration should go into files in config/initializers 23 | # -- all .rb files in that directory are automatically loaded. 24 | 25 | # Custom directories with classes and modules you want to be autoloadable. 26 | # config.autoload_paths += %W(#{config.root}/extras) 27 | config.autoload_paths += Dir["#{config.root}/lib", "#{config.root}/lib/**/"] 28 | 29 | 30 | # Only load the plugins named here, in the order given (default is alphabetical). 31 | # :all can be used as a placeholder for all plugins not explicitly named. 32 | # config.plugins = [ :exception_notification, :ssl_requirement, :all ] 33 | 34 | # Activate observers that should always be running. 35 | # config.active_record.observers = :cacher, :garbage_collector, :forum_observer 36 | 37 | # Set Time.zone default to the specified zone and make Active Record auto-convert to this zone. 38 | # Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC. 39 | # config.time_zone = 'Central Time (US & Canada)' 40 | 41 | # The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded. 42 | # config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s] 43 | # config.i18n.default_locale = :de 44 | 45 | # Configure the default encoding used in templates for Ruby 1.9. 46 | config.encoding = "utf-8" 47 | 48 | # Configure sensitive parameters which will be filtered from the log file. 49 | config.filter_parameters += [:password] 50 | 51 | # Use SQL instead of Active Record's schema dumper when creating the database. 52 | # This is necessary if your schema can't be completely dumped by the schema dumper, 53 | # like if you have constraints or database-specific column types 54 | # config.active_record.schema_format = :sql 55 | 56 | # Enforce whitelist mode for mass assignment. 57 | # This will create an empty whitelist of attributes available for mass-assignment for all models 58 | # in your app. As such, your models will need to explicitly whitelist or blacklist accessible 59 | # parameters by using an attr_accessible or attr_protected declaration. 60 | # config.active_record.whitelist_attributes = true 61 | 62 | # Enable the asset pipeline 63 | config.assets.enabled = true 64 | 65 | # Version of your assets, change this if you want to expire all your assets 66 | config.assets.version = '1.0' 67 | 68 | # Load custom environment variables 69 | config.before_configuration do 70 | env_file = File.join(Rails.root, 'config', 'local_env.yml') 71 | YAML.load(File.open(env_file)).each do |key, value| 72 | ENV[key.to_s] = value 73 | end if File.exists?(env_file) 74 | end 75 | end 76 | end 77 | -------------------------------------------------------------------------------- /app/controllers/images_controller.rb: -------------------------------------------------------------------------------- 1 | class ImagesController < ApplicationController 2 | 3 | before_filter :authenticate_admin!, :except => [:download] 4 | 5 | def download 6 | image_id = params[:missing_image_id] 7 | thread_id = params[:thread_id] 8 | # try to download the image again 9 | image = Image.find(image_id) 10 | downloaded_something = image.download 11 | image.save 12 | # redirect back to the image in the thread 13 | if thread_id=='0' 14 | # TODO: this needs to flush the composite image cache on all the threads that use this 15 | if downloaded_something 16 | flash[:notice] = "Download the image" 17 | else 18 | flash[:error] = "Didn't download anything!" 19 | end 20 | redirect_to '/images/'+image_id 21 | else 22 | thread = Threadx.find(thread_id) 23 | # TODO: should this flush the composite images on ALL the threads that use this image? 24 | thread.remove_composite_images if downloaded_something # flush the generated composite images because there is a new highlighted area 25 | redirect_to thread.link_url+"coding?i="+image.id.to_s 26 | end 27 | end 28 | 29 | def for_media 30 | @images = Image.where(:media_id=>params[:media_id]) 31 | render :index 32 | end 33 | 34 | # GET /images 35 | # GET /images.json 36 | def index 37 | @images = Image.all(:limit=>100) 38 | 39 | respond_to do |format| 40 | format.html # index.html.erb 41 | format.json { render json: @images } 42 | end 43 | end 44 | 45 | # GET /images/1 46 | # GET /images/1.json 47 | def show 48 | @image = Image.find(params[:id]) 49 | 50 | respond_to do |format| 51 | format.html # show.html.erb 52 | format.json { render json: @image } 53 | end 54 | end 55 | 56 | # GET /images/new 57 | # GET /images/new.json 58 | def new 59 | @image = Image.new 60 | 61 | respond_to do |format| 62 | format.html # new.html.erb 63 | format.json { render json: @image } 64 | end 65 | end 66 | 67 | # GET /images/1/edit 68 | def edit 69 | @image = Image.find(params[:id]) 70 | end 71 | 72 | # POST /images 73 | # POST /images.json 74 | def create 75 | @image = Image.new(params[:image]) 76 | 77 | respond_to do |format| 78 | if @image.save 79 | format.html { redirect_to @image, notice: 'Image was successfully created.' } 80 | format.json { render json: @image, status: :created, location: @image } 81 | else 82 | format.html { render action: "new" } 83 | format.json { render json: @image.errors, status: :unprocessable_entity } 84 | end 85 | end 86 | end 87 | 88 | # PUT /images/1 89 | # PUT /images/1.json 90 | def update 91 | @image = Image.find(params[:id]) 92 | 93 | respond_to do |format| 94 | if @image.update_attributes(params[:image]) 95 | format.html { redirect_to @image, notice: 'Image was successfully updated.' } 96 | format.json { head :no_content } 97 | else 98 | format.html { render action: "edit" } 99 | format.json { render json: @image.errors, status: :unprocessable_entity } 100 | end 101 | end 102 | end 103 | 104 | # DELETE /images/1 105 | # DELETE /images/1.json 106 | def destroy 107 | @image = Image.find(params[:id]) 108 | @image.destroy 109 | 110 | respond_to do |format| 111 | format.html { redirect_to images_url } 112 | format.json { head :no_content } 113 | end 114 | end 115 | end 116 | -------------------------------------------------------------------------------- /app/assets/stylesheets/application.css: -------------------------------------------------------------------------------- 1 | /* 2 | * This is a manifest file that'll be compiled into application.css, which will include all the files 3 | * listed below. 4 | * 5 | * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets, 6 | * or vendor/assets/stylesheets of plugins, if any, can be referenced here using a relative path. 7 | * 8 | * You're free to add application-wide styles to this file and they'll appear at the top of the 9 | * compiled file, but it's generally better to create a new file per style scope. 10 | * 11 | *= require_self 12 | *= require_tree . 13 | */ 14 | 15 | /* 16 | *= require jquery.ui.core 17 | *= require jquery.ui.theme 18 | */ 19 | 20 | /* 21 | *= require jquery.ui.resizable 22 | *= require jquery.ui.selectable 23 | */ 24 | 25 | /* 26 | *= require jquery.ui.accordion 27 | * require jquery.ui.autocomplete 28 | * require jquery.ui.button 29 | *= require jquery.ui.dialog 30 | * require jquery.ui.slider 31 | * require jquery.ui.tabs 32 | *= require jquery.ui.datepicker 33 | * require jquery.ui.progressbar 34 | */ 35 | 36 | #login-info { 37 | margin-top: 3px; 38 | margin-left: 10px; 39 | } 40 | #login-info h5 { 41 | line-height: 16px; 42 | margin: 0px; 43 | } 44 | #datavis .images .span1{ 45 | margin-left: 0; 46 | } 47 | .thumb-img-coded { 48 | opacity: 0.3; 49 | } 50 | .thumb-img-no-coded { 51 | opacity: 0.7; 52 | } 53 | .custom-link{ 54 | color:#000; 55 | } 56 | 57 | #footer { 58 | margin-bottom: 40px; 59 | } 60 | .categories a { 61 | color:#fff !important; 62 | } 63 | 64 | .yaxis path { 65 | display:none; 66 | } 67 | 68 | /*----------------new menu----------*/ 69 | .pageonex-brand { 70 | text-shadow: 0 0px 0 !important; 71 | padding: 5px 20px 10px; 72 | } 73 | #pre-menu{ 74 | margin-top:6px; 75 | } 76 | #pre-menu li a { 77 | display: block!important; 78 | display: block; 79 | position: relative; 80 | text-decoration: none; 81 | z-index: 999; 82 | } 83 | #pre-menu li:hover, 84 | #pre-menu li a:hover, 85 | #pre-menu li:hover a { 86 | text-decoration: none; 87 | position: relative; 88 | z-index: 999; 89 | } 90 | #pre-menu li ul { 91 | display: none; 92 | position: absolute; 93 | z-index: 999; 94 | width: 150px; 95 | font-weight: bold; 96 | left: 0; 97 | padding: 2px 0 5px; 98 | margin: 0 !important; 99 | } 100 | #pre-menu li a:hover ul, 101 | #pre-menu li:hover ul { 102 | display: block !important; 103 | } 104 | #pre-menu li a:hover ul li, 105 | #pre-menu li:hover ul li { 106 | position: relative; 107 | display: block; 108 | margin: 0 !important; 109 | padding: 0 !important; 110 | z-index: 999; 111 | background-color: #fff; 112 | } 113 | #pre-menu li a:hover ul li a, 114 | #pre-menu li:hover ul li a { 115 | padding: 2px 0 8px 5 !important; 116 | } 117 | #pre-menu li ul li:hover{ 118 | /*background-color: #bbb;*/ 119 | } 120 | #pre-menu li ul li{ 121 | border:0; 122 | } 123 | #pre-menu ul.dropdown-menu li a{ 124 | color:gray; 125 | } 126 | #pre-menu ul.dropdown-menu li a:hover{ 127 | color:white !important; 128 | } 129 | .navbar .navbar-inner{ 130 | background-image:none; 131 | } 132 | #main-menu ul li { 133 | background-color:#a1a1a1; 134 | margin-right: 5px; 135 | } 136 | #main-menu li:hover { 137 | background-color:#ff9955; 138 | } 139 | 140 | #main-menu li a{ 141 | color:white; 142 | text-shadow: 0 0px 0 white; 143 | padding: 5px; 144 | } 145 | #main-menu li.current-menu-item{ 146 | background-color:white; 147 | } 148 | #main-menu li.current-menu-item a{ 149 | color:#a1a1a1; 150 | } 151 | -------------------------------------------------------------------------------- /config/locales/devise.en.yml: -------------------------------------------------------------------------------- 1 | # Additional translations at https://github.com/plataformatec/devise/wiki/I18n 2 | 3 | en: 4 | errors: 5 | messages: 6 | expired: "has expired, please request a new one" 7 | not_found: "not found" 8 | already_confirmed: "was already confirmed, please try signing in" 9 | not_locked: "was not locked" 10 | not_saved: 11 | one: "1 error prohibited this %{resource} from being saved:" 12 | other: "%{count} errors prohibited this %{resource} from being saved:" 13 | 14 | devise: 15 | failure: 16 | already_authenticated: 'You are already signed in.' 17 | unauthenticated: 'You need to sign in or sign up before continuing.' 18 | unconfirmed: 'You have to confirm your account before continuing.' 19 | locked: 'Your account is locked.' 20 | invalid: 'Invalid email or password.' 21 | invalid_token: 'Invalid authentication token.' 22 | timeout: 'Your session expired, please sign in again to continue.' 23 | inactive: 'Your account was not activated yet.' 24 | sessions: 25 | signed_in: 'Signed in successfully.' 26 | signed_out: 'Signed out successfully.' 27 | passwords: 28 | send_instructions: 'You will receive an email with instructions about how to reset your password in a few minutes.' 29 | updated: 'Your password was changed successfully. You are now signed in.' 30 | updated_not_active: 'Your password was changed successfully.' 31 | send_paranoid_instructions: "If your e-mail exists on our database, you will receive a password recovery link on your e-mail" 32 | confirmations: 33 | send_instructions: 'You will receive an email with instructions about how to confirm your account in a few minutes.' 34 | send_paranoid_instructions: 'If your e-mail exists on our database, you will receive an email with instructions about how to confirm your account in a few minutes.' 35 | confirmed: 'Your account was successfully confirmed. You are now signed in.' 36 | registrations: 37 | signed_up: 'Welcome! You have signed up successfully.' 38 | signed_up_but_unconfirmed: 'A message with a confirmation link has been sent to your email address. Please open the link to activate your account.' 39 | signed_up_but_inactive: 'You have signed up successfully. However, we could not sign you in because your account is not yet activated.' 40 | signed_up_but_locked: 'You have signed up successfully. However, we could not sign you in because your account is locked.' 41 | updated: 'You updated your account successfully.' 42 | update_needs_confirmation: "You updated your account successfully, but we need to verify your new email address. Please check your email and click on the confirm link to finalize confirming your new email address." 43 | destroyed: 'Bye! Your account was successfully cancelled. We hope to see you again soon.' 44 | unlocks: 45 | send_instructions: 'You will receive an email with instructions about how to unlock your account in a few minutes.' 46 | unlocked: 'Your account has been unlocked successfully. Please sign in to continue.' 47 | send_paranoid_instructions: 'If your account exists, you will receive an email with instructions about how to unlock it in a few minutes.' 48 | omniauth_callbacks: 49 | success: 'Successfully authorized from %{kind} account.' 50 | failure: 'Could not authorize you from %{kind} because "%{reason}".' 51 | mailer: 52 | confirmation_instructions: 53 | subject: 'Confirmation instructions' 54 | reset_password_instructions: 55 | subject: 'Reset password instructions' 56 | unlock_instructions: 57 | subject: 'Unlock Instructions' 58 | -------------------------------------------------------------------------------- /app/assets/javascripts/spin.min.js: -------------------------------------------------------------------------------- 1 | //fgnass.github.com/spin.js#v1.2.5 2 | (function(a,b,c){function g(a,c){var d=b.createElement(a||"div"),e;for(e in c)d[e]=c[e];return d}function h(a){for(var b=1,c=arguments.length;b>1):c.left+e)+"px",top:(c.top=="auto"?i.y-h.y+(a.offsetHeight>>1):c.top+e)+"px"})),d.setAttribute("aria-role","progressbar"),b.lines(d,b.opts);if(!f){var j=0,k=c.fps,m=k/c.speed,o=(1-c.opacity)/(m*c.trail/100),p=m/c.lines;!function q(){j++;for(var a=c.lines;a;a--){var e=Math.max(1-(j+a*p)%m*o,c.opacity);b.opacity(d,c.lines-a,e,c)}b.timeout=b.el&&setTimeout(q,~~(1e3/k))}()}return b},stop:function(){var a=this.el;return a&&(clearTimeout(this.timeout),a.parentNode&&a.parentNode.removeChild(a),this.el=c),this},lines:function(a,b){function e(a,d){return l(g(),{position:"absolute",width:b.length+b.width+"px",height:b.width+"px",background:a,boxShadow:d,transformOrigin:"left",transform:"rotate("+~~(360/b.lines*c+b.rotate)+"deg) translate("+b.radius+"px"+",0)",borderRadius:(b.width>>1)+"px"})}var c=0,d;for(;c',b)}var b=l(g("group"),{behavior:"url(#default#VML)"});!k(b,"transform")&&b.adj?(i.addRule(".spin-vml","behavior:url(#default#VML)"),p.prototype.lines=function(b,c){function f(){return l(a("group",{coordsize:e+" "+e,coordorigin:-d+" "+ -d}),{width:e,height:e})}function k(b,e,g){h(i,h(l(f(),{rotation:360/c.lines*b+"deg",left:~~e}),h(l(a("roundrect",{arcsize:1}),{width:d,height:c.width,left:c.radius,top:-c.width>>1,filter:g}),a("fill",{color:c.color,opacity:c.opacity}),a("stroke",{opacity:0}))))}var d=c.length+c.width,e=2*d,g=-(c.width+c.length)*2+"px",i=l(f(),{position:"absolute",top:g,left:g}),j;if(c.shadow)for(j=1;j<=c.lines;j++)k(j,-2,"progid:DXImageTransform.Microsoft.Blur(pixelradius=2,makeshadow=1,shadowopacity=.3)");for(j=1;j<=c.lines;j++)k(j);return h(b,i)},p.prototype.opacity=function(a,b,c,d){var e=a.firstChild;d=d.shadow&&d.lines||0,e&&b+d", "/": "?", "\\": "|" 32 | } 33 | }; 34 | 35 | function keyHandler( handleObj ) { 36 | // Only care when a possible input has been specified 37 | if ( typeof handleObj.data !== "string" ) { 38 | return; 39 | } 40 | 41 | var origHandler = handleObj.handler, 42 | keys = handleObj.data.toLowerCase().split(" "), 43 | textAcceptingInputTypes = ["text", "password", "number", "email", "url", "range", "date", "month", "week", "time", "datetime", "datetime-local", "search", "color"]; 44 | 45 | handleObj.handler = function( event ) { 46 | // Don't fire in text-accepting inputs that we didn't directly bind to 47 | if ( this !== event.target && (/textarea|select/i.test( event.target.nodeName ) || 48 | jQuery.inArray(event.target.type, textAcceptingInputTypes) > -1 ) ) { 49 | return; 50 | } 51 | 52 | // Keypress represents characters, not special keys 53 | var special = event.type !== "keypress" && jQuery.hotkeys.specialKeys[ event.which ], 54 | character = String.fromCharCode( event.which ).toLowerCase(), 55 | key, modif = "", possible = {}; 56 | 57 | // check combinations (alt|ctrl|shift+anything) 58 | if ( event.altKey && special !== "alt" ) { 59 | modif += "alt+"; 60 | } 61 | 62 | if ( event.ctrlKey && special !== "ctrl" ) { 63 | modif += "ctrl+"; 64 | } 65 | 66 | // TODO: Need to make sure this works consistently across platforms 67 | if ( event.metaKey && !event.ctrlKey && special !== "meta" ) { 68 | modif += "meta+"; 69 | } 70 | 71 | if ( event.shiftKey && special !== "shift" ) { 72 | modif += "shift+"; 73 | } 74 | 75 | if ( special ) { 76 | possible[ modif + special ] = true; 77 | 78 | } else { 79 | possible[ modif + character ] = true; 80 | possible[ modif + jQuery.hotkeys.shiftNums[ character ] ] = true; 81 | 82 | // "$" can be triggered as "Shift+4" or "Shift+$" or just "$" 83 | if ( modif === "shift+" ) { 84 | possible[ jQuery.hotkeys.shiftNums[ character ] ] = true; 85 | } 86 | } 87 | 88 | for ( var i = 0, l = keys.length; i < l; i++ ) { 89 | if ( possible[ keys[i] ] ) { 90 | return origHandler.apply( this, arguments ); 91 | } 92 | } 93 | }; 94 | } 95 | 96 | jQuery.each([ "keydown", "keyup", "keypress" ], function() { 97 | jQuery.event.special[ this ] = { add: keyHandler }; 98 | }); 99 | 100 | })( jQuery ); -------------------------------------------------------------------------------- /doc/docker/development-with-docker-compose.md: -------------------------------------------------------------------------------- 1 | # Developing pageonex with docker-compose 2 | 3 | If you need to do development in pageonex without the hassle of installing all the dependencies you can use our [docker-compose-build file](/docker-compose-build.yml) which builds the application from scratch. 4 | 5 | 1. In order to start the pageonex and mysql containers, run from the root of this repository: 6 | ``` 7 | docker-compose -f docker-compose-build.yml up -d --build 8 | ``` 9 | 10 | You might get this error `Couldn’t connect to Docker daemon at http+docker://localhost – is it running?`, it is possible to fix [with this solution](https://techoverflow.net/2019/03/16/how-to-fix-error-couldnt-connect-to-docker-daemon-at-httpdocker-localhost-is-it-running/): 11 | 12 | > There are two possible reasons for this error message. 13 | > The common reason is that the user you are running the command as does not have the permissions to access docker. 14 | > You can fix this either by running the command as root using sudo (since root has the permission to access docker) or adding your user to the docker group: `sudo usermod -a -G docker $USER` 15 | > and then logging out and logging back in completely (or restarting the system/server). 16 | > The other reason is that you have not started docker. On Ubuntu, you can start it using `sudo systemctl enable docker` (Auto-start on boot) and `sudo systemctl start docker` (Start right now). 17 | 18 | > You can also get this message: `Creating pageonex_mysql_build_1 ... error ERROR: for pageonex_mysql_build_1 Cannot start service mysql_build: driver failed programming external connectivity on endpoint pageonex_mysql_build_1 (34af946d85db80f663a8d71e550bef50128a3fd4f41593bdc9ef722a7c2f5b54): Bind for 0.0.0.0:23306 failed: port is already allocated` this is because you have another docker container running using that port. 19 | > Use `docker ps` to see which other containers you have and stop them by using the `CONTAINER ID`. If container id is `03be2d8e8337` use `docker stop 03be2d8e8337` 20 | 21 | 22 | 2. To create the initial database: 23 | ``` 24 | docker-compose -f docker-compose-build.yml exec app_build rake db:migrate --trace 25 | ``` 26 | 27 | 3. To load the list of newspapers into the data base run: 28 | ``` 29 | docker-compose -f docker-compose-build.yml exec app_build rake scraping:update_media --trace 30 | ``` 31 | 32 | Once everything is running correctly, you can access the application from your browser at http://localhost:3000 or http://0.0.0.0:3000 33 | 34 | ## Tasks 35 | 36 | ### How to access the rails console 37 | 38 | To get a the rails console (See [doc/local-install.md](/doc/local-install.md#process) for instructions on creating an admin user) 39 | ``` 40 | docker-compose -f docker-compose-build.yml exec app_build rails console 41 | ``` 42 | 43 | Once you have entered the rails console you can make one user admin with this command: 44 | 45 | ``` 46 | User.find_by_email('user@domain.com').update_attribute :admin, true 47 | ``` 48 | 49 | Admin users are able to use the taxonomies feature. 50 | 51 | To quit the console type `quit`. 52 | 53 | ### How to access the database 54 | 55 | If you want to log in the mysql database 56 | ``` 57 | docker-compose -f docker-compose-build.yml exec app_build mysql -u root --password=root dc-dev 58 | ``` 59 | 60 | ### How to rebuild your container 61 | 62 | If you make changes in the app and you want to rebuild your container 63 | ``` 64 | docker-compose -f docker-compose-build.yml up -d --build 65 | ``` 66 | 67 | ### How to see rails logs 68 | 69 | If you want to inspect the logs 70 | ``` 71 | docker-compose -f docker-compose-build.yml logs 72 | ``` 73 | 74 | ### How to shut down the app 75 | 76 | If you want to shut down everything 77 | ``` 78 | docker-compose -f docker-compose-build.yml stop 79 | ``` 80 | 81 | ### How to remove everythung and start from scratch 82 | 83 | If you want to remove everything and have a new and clean environment 84 | ``` 85 | docker-compose -f docker-compose-build.yml rm -s -v 86 | docker volume rm build_db_data build_app_data 87 | ``` 88 | -------------------------------------------------------------------------------- /app/models/image.rb: -------------------------------------------------------------------------------- 1 | require 'RMagick' 2 | require "open-uri" 3 | 4 | class Image < ActiveRecord::Base 5 | belongs_to :media 6 | 7 | has_many :highlighted_areas 8 | 9 | default_scope order("publication_date ASC, media_id ASC") 10 | 11 | before_save :check_if_missing 12 | 13 | def width 14 | return size[0..(size.index('x'))].to_i 15 | end 16 | 17 | def height 18 | length = size.length - size.index('x') - 1; 19 | return size[-1*length, length].to_i 20 | end 21 | 22 | def self.codeable 23 | where(:missing=>false) 24 | end 25 | 26 | def self.by_media(media_ids) 27 | where(:media_id => media_ids) 28 | end 29 | 30 | def self.by_date(dates) 31 | where(:publication_date => dates) 32 | end 33 | 34 | def self.publication_date 35 | select('publication_date').uniq.map { |elt| elt.publication_date } 36 | end 37 | 38 | def thumbnail_local_path width=80, generate=true 39 | path = self.local_path.chomp(File.extname(self.local_path))+'-thumb-'+width.to_s+'.jpg' 40 | self.thumbnail width if generate 41 | path 42 | end 43 | 44 | def image_height_at_width other_width 45 | (other_width.to_f / self.width) * self.height 46 | end 47 | 48 | # return a Magick img object that is a thumbnail (caches to disk) - nil if image missing or messed up 49 | def thumbnail width, path=nil 50 | return nil unless File.exists? self.full_local_path # bail if there is no image 51 | if path==nil 52 | thumb_file_path = File.join 'app','assets','images',self.thumbnail_local_path(width,false) 53 | else 54 | thumb_file_path = File.join 'app','assets','images', path 55 | end 56 | return Magick::Image.read(thumb_file_path).first if File.exists?(thumb_file_path) and File.size?(thumb_file_path) 57 | # if the thumb doesn't exist then generate it 58 | img_thumb = nil 59 | return img_thumb if not File.size? self.full_local_path 60 | begin 61 | img = Magick::Image.read(self.full_local_path).first 62 | scale = width.to_f / img.columns.to_f 63 | img_thumb = img.thumbnail(scale) 64 | img_thumb.write thumb_file_path 65 | rescue Magick::ImageMagickError=>e 66 | logger.error "Image Empty Error in image.thumbnail: #{e}" 67 | end 68 | return img_thumb 69 | end 70 | 71 | def local_path 72 | File.join('kiosko', self.media.image_directory_name, self.image_name + ".jpg") 73 | end 74 | 75 | def download 76 | if Pageonex::Application.config.use_local_images 77 | # make the media dir if you need to 78 | self.media.create_image_directory 79 | # try to fetch the image 80 | begin 81 | File.open(self.full_local_path, "wb") { |f| f.write(open(self.source_url).read) } 82 | if File.size? self.full_local_path 83 | # TODO we should check the file size here to see if it is zero (raise exception if it is) 84 | File.open(self.full_local_path,"rb") do |f| 85 | size_info = ImageSize.new(f.read).get_size 86 | self.size = "#{size_info[0]}x#{size_info[1]}" 87 | end 88 | self.missing = false 89 | else 90 | self.size = '750x951' 91 | logger.debug "Image Download Failed:#{id}: got a zero size image for #{source_url}" 92 | end 93 | rescue Exception => e 94 | # image doesn't exist on their server :-( 95 | logger.debug "Image Download Failed:#{id}: couldn't find image at #{source_url} (#{e.message})" 96 | self.size = '750x951' 97 | self.missing = true 98 | end 99 | else 100 | url = URI.parse(self.source_url) 101 | request = Net::HTTP.new(url.host, url.port) 102 | response = request.request_head(url.path) 103 | self.size = '750x951' #!!this value of pixels is 'hard coded' so it gives wrong values for long newspapers 104 | self.missing = (response.code != "200") 105 | end 106 | !missing 107 | end 108 | 109 | def full_local_path 110 | File.join('app','assets','images', self.local_path) 111 | end 112 | 113 | private 114 | 115 | # Backup strategy: default the "missing" column smartly if it isn't filled in 116 | # (even though the scraper should have filled it in) 117 | def check_if_missing 118 | if self.missing.nil? 119 | if Pageonex::Application.config.use_local_images 120 | self.missing = self.local_path.nil? 121 | else 122 | self.missing = self.source_url.nil? 123 | end 124 | end 125 | end 126 | 127 | end 128 | -------------------------------------------------------------------------------- /app/views/coding/embed.html.erb: -------------------------------------------------------------------------------- 1 | <% @title = "#{@thread.thread_display_name} - Embedded- PageOneX" %> 2 | 3 | 4 |
    5 |
    6 |
    7 | 8 | 9 |
    10 |
    11 |
      12 | <% @img_map_info['row_info'].each do |media_id,info| %> 13 |
    • <%=info['name']%>
    • 14 | <% end %> 15 |
    16 |
    17 |
    18 |
      19 |
    • <%= image_tag @thread.path_to_composite_cover_image %>
    • 20 | <% @thread.codes.each do |code| %> 21 |
    • <%= image_tag @thread.path_to_composite_highlighed_area_image code.id %>
    • 22 | <% end %> 23 |
    • <%=image_tag 'transparent.png', :style=>"width:#{@img_map_info['width']}px;height:#{@img_map_info['height']}px;", :name=>'front-page-images', :usemap=>'#front-page-images'%>
    • 24 |
    25 | 26 | <% @img_map_info['images'].each_pair do |image_id, image_info| %> 27 | 29 | <% end %> 30 | 31 |
    32 |
    33 | 34 | 35 |
    36 |
    37 |

    <%= @thread.thread_display_name %>

    38 |

    <%= @thread.start_date.inspect %> - <%= @thread.end_date.inspect %>

    39 |
      40 | <% @thread.codes.each do |code| %> 41 |
    • 42 |
      43 |
      <%= code.code_text %>
      44 |
    • 45 | <% end %> 46 |
    47 |
    48 |
    49 | 50 | Share in PageOneX 51 | 52 | <%= javascript_include_tag "d3.v3.min.js" %> 53 | <%= javascript_include_tag "dataviz.js" %> 54 | 55 | 78 | 79 | 90 | 91 | <%= javascript_tag do %> //activates and deactivates composite images clicking on legend 92 | <% @thread.codes.each do |code| %> 93 | d3.select('#code_<%= code.id %>').on('click',function() { 94 | if (d3.select(this).attr('class')==='active'){ 95 | d3.select("#composite_image_code_<%= code.id %>").style("display", "none"); 96 | d3.select(this).attr("class","inactive"); 97 | } else { 98 | d3.select("#composite_image_code_<%= code.id %>").style("display", "block"); 99 | d3.select(this).attr("class","active"); 100 | } 101 | }); 102 | <% end %> 103 | <% end %> 104 | -------------------------------------------------------------------------------- /app/views/threads/index.html.erb: -------------------------------------------------------------------------------- 1 | 2 | <% @title = @subtitle+" - PageOneX" %> 3 | <% if flash[:thread_name_error] %> 4 |
    5 | × 6 |

    <%= flash[:thread_name_error] %>

    7 |
    8 | <% end %> 9 |
    10 |

    <%=@subtitle%>

    11 |
    12 |
    13 |

    <%= raw @bio %>

    14 |
    15 |
    16 | <% if @threads.length > 0%> 17 |
    18 | <% @threads.each_with_index do |thread, i| %> 19 | 20 |
    21 | 43 |
    44 |

    <%= link_to thread.thread_display_name, thread_url(thread) %>

    45 |

    by <%=threads_by_user_link thread.owner %> | From <%= thread.start_date %> to <%= thread.end_date %>

    46 |

    <%= strip_tags(sanitize(thread.description.truncate(150))) %>

    47 | 48 | <% if current_user.nil? %> 49 | 50 | <% elsif thread.owner == current_user or current_user.admin %> 51 |
    52 | <%= link_to "View", thread_url(thread), :class => "btn btn-small" %> 53 | <%= link_to "Edit", "/threads/#{thread.thread_name}/edit/", :class => "btn btn-small" %> 54 | <%= link_to "Code", "/threads/#{thread.thread_name}/coding/", :class => "btn btn-small" %> 55 | <%= link_to "Delete", "/threads/#{thread.thread_name}" ,:method=>"delete" , :class => "btn btn-small btn-danger delete" %> 56 |
    57 | <% end %> 58 |
    59 | 60 | <% thread.category_list.each do |c| %> 61 | <%=link_to c,"/threads/search_by_category?q=#{c.strip}", :class => "label"%> 62 | <% end %> 63 | 64 |
    65 |
    66 |
    67 | 68 | <% if ((i+1)/4.0).to_i == ((i+1)/4.0) %> 69 |
    70 |
    71 |
    72 | <% end %> 73 | 74 | <% end %> 75 |
    76 | 77 | <% unless !@use_paging.nil? and @use_paging==false %> 78 |
    79 |
    80 | <%= will_paginate @threads %> 81 |
    82 |
    83 | <% end %> 84 | 85 | <% else %> 86 | 87 |

    There are no threads.

    88 | 89 | <% end %> 90 | 91 | 92 |
    93 | 94 | 106 | -------------------------------------------------------------------------------- /app/views/home/about.html.erb: -------------------------------------------------------------------------------- 1 | <% @title = "About - PageOneX" %> 2 |
    3 |

    About PageOneX

    4 |

    <%= image_tag("detail-front-pages.png") %>

    5 |

    PageOneX is an open source software tool designed to aid the coding, analysis, and visualization of front page newspaper coverage of major stories and media events. Newsrooms spend massive time and effort deciding which stories make it to the front page. Communication scholars have long used column-inches of print newspaper coverage as an important indicator of mass media attention.

    6 |

    In the past, this approach involved obtaining copies of newspapers, measurement by hand (with a physical ruler), and manual input of measurements into a spreadsheet or database, followed by calculation and analysis. Some of these steps can now be automated, while others can be simplified; some can be easily shared by distributed teams of investigators working with a common dataset hosted online.

    7 | 8 |

    You can find more information at pageonex.com, examples of PageOnex in use, or the timeline of the project.

    9 | 10 |

    Background

    11 |

    The project has gone through different phases.

    12 |

    Initially, this type of data visualization was made through a ‘manual’ process: images of newspaper front pages were downloaded from the web and reorganized in a vector graphics program to draw rectangles on top of them to highlight certain stories.

    13 | 14 |

    The first version of an automated tool was a script written in Processing, that downloaded newspapers front pages and generated an organized array of images ordered by date.

    15 | 16 |

    The second version is this tool written in Ruby on Rails that you are using. It is developed to be a web platform to provide a ready to use front page analysis tool for anyone with a connection to the Internet. The platform automates the process of newspaper selection, download, thread coding, and data visualization. The alpha version was developed by Pablo Rey Mazón with Ahmd Refat, thanks to Google Summer of Code program (GSOC) and the Berkman Center as host institution in Summer 2012. You can test the alpha version at PageOneX.com.

    17 | 18 |

    In Winter-Spring 2013, at the Center for Civic Media at MIT Media Lab Pablo Rey Mazón, with Edward L Platt and Rahul Bhargava worked on the beta version, the first stable version, that was released on April 2013. It has major improvements in speed and a cleaner data model. During Summer 2013 we were fixing bugs and making the tool work better and faster.

    19 | 20 |

    During 2014 we've made some improvements like making available to embed a PageOneX in your site or switching on and off topics in the data visualization. We need your feedback!.

    21 | 22 |

    In Summer 2014 PageOneX won the 2014 APSA-ITP (American Political Science Association-information technology and politics) award for Best Software.

    23 | 24 |

    Collaborators

    25 |

    The project has many collaborators. The coders have been/are: initially Ahmd Refat, and now developed at the Center for Civic Media by Edward L Platt, Rahul Bhargava and Pablo Rey Mazón; Rafael Porres has developed part of the original scraping code. Sasha Costanza-Chock is giving advice and support from the Center for Civic Media; Alfonso Sánchez Uzábal is providing tecnical support and Montera34 helped with the server and domains. Thanks to Jeff Warren for his advice and Rogelio López for testing.

    26 | 27 |

    Join the project

    28 |

    Join the mailing list for developers, for users or subscribe to the newsletter to get the last updates.

    29 | 30 |

    Code

    31 |

    The code of PageOneX is open source and available at https://github.com/numeroteca/pageonex.

    32 |
    33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /app/views/home/index.html.erb: -------------------------------------------------------------------------------- 1 | <% @title = "PageOneX" %> 2 |
    3 |
    4 | 7 |
    8 |
    9 | 10 |
    11 | 12 |
    13 | <%= image_tag "header-blog-2.png", :style => "margin-bottom:5px;" %> 14 |

    PageOneX makes it easy to track, code, and visualize major news stories based on the proportion of newspaper front pages that they take up.
    It's a useful tool for researchers, advocacy groups, and anyone interested in better understanding the media's priorities.

    15 |
    16 |
    17 | @PageOneX 18 | 19 |
    20 |
    21 |
    22 | 23 |
    24 | <% if user_signed_in? %> 25 | <%= link_to 'Create New Thread', '/threads/new', :class => "btn btn-success btn-large" %> 26 | <% else %> 27 | <%= link_to 'Sign in', new_user_session_path, :class => "btn btn-success btn-large" %> 28 | <%= link_to 'Sign up', new_user_registration_path, :class => "btn btn-info btn-large" %> 29 | 30 | <% end %> 31 |

    Most recent threads

    32 | <% if @threads != [] %> 33 | <% @threads.each do |thread| %> 34 | <% if thread.coded_image_ids.length > 4 %> 35 |

    <%= thread.thread_display_name %> 36 | by <%=threads_by_user_link thread.owner %>

    37 | <% end %> 38 | <% end %> 39 | <% else %> 40 |

    There are no threads.

    41 | <% end %> 42 | View All 43 |
    44 | 45 |
    46 | 47 |
    48 | 49 |
    50 |
    51 |

    Participate

    52 | You can learn from, contribute to, and gain recognition within the community.
    53 | Join the PageOneX mailing list 54 |

    Keep updated

    55 | Subscribe to the newsletter
    56 | Twitter: @PageOneX
    57 | Wiki
    58 | Blog
    59 | Contact: form or @numeroteca
    60 | 61 |

    For developers

    62 |

    This is an open source tool built in Ruby on Rails. You can download and test it locally, and/or help improve the code!
    63 | View, collaborate and download the code
    64 | Issue tracker
    65 | Email list for developers

    66 |
    67 |
    68 |

    Examples

    69 | PageOneX in Pinterest
    70 | Timeline of the project.
    71 | Slides: presentation at the MRAP, New approaches to front page analysis
    72 | Galleries of examples: at numeroteca and at Pinterest 73 |

    Projects using PageOneX

    74 |

    Open document to list all the references related to front page analysis and PageOneX related projects..

    75 |

    Featured Threads

    76 | Gezi parki protests in turkish newspapers (Turkey)
    77 | Violence x Protest (Brazil)
    78 | Corrupción españa. Agosto 2013 (Spain)
    79 | NSA leaks: PRISM (USA)
    80 | Análisis Paro Agrario (Colombia)
    81 | Local, national and world news in US newspapers (USA) 82 |
    83 |
    84 | 85 | 86 |
    87 |
    88 | --------------------------------------------------------------------------------