| @@ -2,11 +2,6 @@ source 'https://rubygems.org' | |||
| gem 'rails', '3.2.12' | |||
| # Bundle edge Rails instead: | |||
| # gem 'rails', :git => 'git://github.com/rails/rails.git' | |||
| # Gems used only for assets and not required | |||
| # in production environments by default. | |||
| group :assets do | |||
| @@ -36,11 +31,16 @@ gem 'jquery-rails' | |||
| # To use debugger | |||
| # gem 'debugger' | |||
| gem 'mongo_mapper' | |||
| gem 'bson_ext' | |||
| gem 'haml-rails' | |||
| gem 'mm-multi-parameter-attributes' | |||
| gem 'feedzirra' | |||
| gem 'htmlentities' | |||
| gem 'sorcery' | |||
| gem 'will_paginate', '~> 3.0' | |||
| gem 'activerecord-postgresql-adapter' | |||
| gem 'pg' | |||
| group :development do | |||
| gem 'meta_request' | |||
| gem 'better_errors' | |||
| gem 'binding_of_caller' | |||
| end | |||
| @@ -22,6 +22,8 @@ GEM | |||
| activesupport (= 3.2.12) | |||
| arel (~> 3.0.2) | |||
| tzinfo (~> 0.3.29) | |||
| activerecord-postgresql-adapter (0.0.1) | |||
| pg | |||
| activeresource (3.2.12) | |||
| activemodel (= 3.2.12) | |||
| activesupport (= 3.2.12) | |||
| @@ -30,10 +32,13 @@ GEM | |||
| multi_json (~> 1.0) | |||
| arel (3.0.2) | |||
| bcrypt-ruby (3.0.1) | |||
| bson (1.8.2) | |||
| bson_ext (1.8.2) | |||
| bson (~> 1.8.2) | |||
| better_errors (0.6.0) | |||
| coderay (>= 1.0.0) | |||
| erubis (>= 2.6.6) | |||
| binding_of_caller (0.7.1) | |||
| debug_inspector (>= 0.0.1) | |||
| builder (3.0.4) | |||
| coderay (1.0.9) | |||
| coffee-rails (3.2.2) | |||
| coffee-script (>= 2.2.0) | |||
| railties (~> 3.2.0) | |||
| @@ -42,6 +47,7 @@ GEM | |||
| execjs | |||
| coffee-script-source (1.4.0) | |||
| curb (0.7.18) | |||
| debug_inspector (0.0.2) | |||
| erubis (2.7.0) | |||
| execjs (1.4.0) | |||
| multi_json (~> 1.0) | |||
| @@ -81,16 +87,10 @@ GEM | |||
| i18n (>= 0.4.0) | |||
| mime-types (~> 1.16) | |||
| treetop (~> 1.4.8) | |||
| meta_request (0.2.1) | |||
| rack-contrib | |||
| rails | |||
| mime-types (1.21) | |||
| mm-multi-parameter-attributes (0.2.2) | |||
| mongo_mapper (>= 0.9.0) | |||
| tzinfo | |||
| mongo (1.8.2) | |||
| bson (~> 1.8.2) | |||
| mongo_mapper (0.12.0) | |||
| activemodel (~> 3.0) | |||
| activesupport (~> 3.0) | |||
| plucky (~> 0.5.2) | |||
| multi_json (1.6.1) | |||
| multipart-post (1.1.5) | |||
| nokogiri (1.4.7) | |||
| @@ -101,12 +101,13 @@ GEM | |||
| jwt (~> 0.1.4) | |||
| multi_json (~> 1.0) | |||
| rack (~> 1.2) | |||
| plucky (0.5.2) | |||
| mongo (~> 1.5) | |||
| pg (0.14.1) | |||
| polyglot (0.3.3) | |||
| rack (1.4.5) | |||
| rack-cache (1.2) | |||
| rack (>= 0.4) | |||
| rack-contrib (1.1.0) | |||
| rack (>= 0.9.1) | |||
| rack-ssl (1.3.3) | |||
| rack | |||
| rack-test (0.6.2) | |||
| @@ -160,14 +161,16 @@ PLATFORMS | |||
| ruby | |||
| DEPENDENCIES | |||
| bson_ext | |||
| activerecord-postgresql-adapter | |||
| better_errors | |||
| binding_of_caller | |||
| coffee-rails (~> 3.2.1) | |||
| feedzirra | |||
| haml-rails | |||
| htmlentities | |||
| jquery-rails | |||
| mm-multi-parameter-attributes | |||
| mongo_mapper | |||
| meta_request | |||
| pg | |||
| rails (= 3.2.12) | |||
| sass-rails (~> 3.2.3) | |||
| sorcery | |||
| @@ -0,0 +1,3 @@ | |||
| # Place all the behaviors and hooks related to the matching controller here. | |||
| # All this logic will automatically be available in application.js. | |||
| # You can use CoffeeScript in this file: http://jashkenas.github.com/coffee-script/ | |||
| @@ -0,0 +1,3 @@ | |||
| // Place all the styles related to the Layers controller here. | |||
| // They will automatically be included in application.css. | |||
| // You can use Sass (SCSS) here: http://sass-lang.com/ | |||
| @@ -17,8 +17,8 @@ class FeedsController < ApplicationController | |||
| # GET /feeds/1.json | |||
| def show | |||
| @feed = Feed.find(params[:id]) | |||
| @posts = @feed.posts.sort(:published.desc).paginate(:page => params[:page], :per_page => 20) | |||
| @posts = @feed.posts.order("published desc").paginate(:page => params[:page], :per_page => 20) | |||
| respond_to do |format| | |||
| format.html # show.html.erb | |||
| format.json { render json: @feed } | |||
| @@ -44,11 +44,27 @@ class FeedsController < ApplicationController | |||
| # POST /feeds | |||
| # POST /feeds.json | |||
| def create | |||
| @feed = Feed.new(params[:feed]) | |||
| Rails.logger.debug "Feed URL: %s" % params['feed']['feed_url'] | |||
| if Feed.where(:feed_url => params['feed']['feed_url']).size == 1 # ensure this test returns the values we expect | |||
| Rails.logger.debug "Adding existing feed to a new layer" | |||
| @feed = Feed.where(:feed_url => params['feed']['feed_url']).first | |||
| @layer = Layer.find(params['feed']['new_layer_id']) # assumes that the specified layer exists | |||
| # Attach the existing feed to the specified layer (making sure we only add each one once) | |||
| @feed.layers << @layer unless @feed.layers.include?(@layer) | |||
| else | |||
| # Create a new feed | |||
| Rails.logger.debug "Creating a new feed" | |||
| @feed = Feed.new(params[:feed]) | |||
| @layer = Layer.find(params['feed']['new_layer_id']) # assumes that the specified layer exists | |||
| @feed.layers << @layer unless @feed.layers.include?(@layer) | |||
| end | |||
| respond_to do |format| | |||
| if @feed.save | |||
| format.html { redirect_to '/', notice: 'Feed added OK' } | |||
| format.html { redirect_to @layer, notice: 'Feed added OK' } | |||
| format.json { render json: @feed, status: :created, location: @feed } | |||
| else | |||
| format.html { render action: "new" } | |||
| @@ -87,12 +103,12 @@ class FeedsController < ApplicationController | |||
| def fetch | |||
| @feed = Feed.find(params[:id]) | |||
| @feed.get | |||
| @feed.fetch | |||
| redirect_to :back, notice: 'Feed fetched OK' | |||
| end | |||
| def fetch_all | |||
| Feed.get_all | |||
| Feed.fetch_all | |||
| redirect_to :back, notice: 'All feeds fetched OK' | |||
| end | |||
| end | |||
| @@ -0,0 +1,85 @@ | |||
| class LayersController < ApplicationController | |||
| # GET /layers | |||
| # GET /layers.json | |||
| def index | |||
| @layers = Layer.all | |||
| respond_to do |format| | |||
| format.html # index.html.erb | |||
| format.json { render json: @layers } | |||
| end | |||
| end | |||
| # GET /layers/1 | |||
| # GET /layers/1.json | |||
| def show | |||
| @layer = Layer.find(params[:id]) | |||
| @feed = Feed.new | |||
| @feed.new_layer_id = @layer.id | |||
| respond_to do |format| | |||
| format.html # show.html.erb | |||
| format.json { render json: @layer } | |||
| end | |||
| end | |||
| # GET /layers/new | |||
| # GET /layers/new.json | |||
| def new | |||
| @layer = Layer.new | |||
| respond_to do |format| | |||
| format.html # new.html.erb | |||
| format.json { render json: @layer } | |||
| end | |||
| end | |||
| # GET /layers/1/edit | |||
| def edit | |||
| @layer = Layer.find(params[:id]) | |||
| end | |||
| # POST /layers | |||
| # POST /layers.json | |||
| def create | |||
| @layer = Layer.new(params[:layer]) | |||
| respond_to do |format| | |||
| if @layer.save | |||
| format.html { redirect_to @layer, notice: 'Layer was successfully created.' } | |||
| format.json { render json: @layer, status: :created, location: @layer } | |||
| else | |||
| format.html { render action: "new" } | |||
| format.json { render json: @layer.errors, status: :unprocessable_entity } | |||
| end | |||
| end | |||
| end | |||
| # PUT /layers/1 | |||
| # PUT /layers/1.json | |||
| def update | |||
| @layer = Layer.find(params[:id]) | |||
| respond_to do |format| | |||
| if @layer.update_attributes(params[:layer]) | |||
| format.html { redirect_to @layer, notice: 'Layer was successfully updated.' } | |||
| format.json { head :no_content } | |||
| else | |||
| format.html { render action: "edit" } | |||
| format.json { render json: @layer.errors, status: :unprocessable_entity } | |||
| end | |||
| end | |||
| end | |||
| # DELETE /layers/1 | |||
| # DELETE /layers/1.json | |||
| def destroy | |||
| @layer = Layer.find(params[:id]) | |||
| @layer.destroy | |||
| respond_to do |format| | |||
| format.html { redirect_to layers_url } | |||
| format.json { head :no_content } | |||
| end | |||
| end | |||
| end | |||
| @@ -2,13 +2,13 @@ class PostsController < ApplicationController | |||
| include PostsHelper | |||
| def near | |||
| @posts = Post.near(params[:lat].to_f, params[:lon].to_f, params[:radius].to_f) | |||
| @posts = Post.near(params[:lat].to_f, params[:lon].to_f, params[:radius].to_f, params[:layer_id]) | |||
| ErrorLog.create( | |||
| :ts => Time.now, | |||
| :params => params, | |||
| :pois_returned => @posts.size | |||
| ) | |||
| # ErrorLog.create( | |||
| # :ts => Time.now, | |||
| # :params => params, | |||
| # :pois_returned => @posts.size | |||
| # ) | |||
| layar_response = { | |||
| :layer => 'hyparlocal', | |||
| @@ -0,0 +1,2 @@ | |||
| module LayersHelper | |||
| end | |||
| @@ -6,15 +6,15 @@ module PostsHelper | |||
| :imageURL => "%s%s/assets/layar-icons/tal-logo-100.png" % [ request.protocol, request.env['HTTP_HOST'] ], | |||
| :anchor => { | |||
| :geolocation => { | |||
| :lat => post.loc['lat'], | |||
| :lon => post.loc['lng'], | |||
| :lat => post.lat, | |||
| :lon => post.lon, | |||
| :alt => 0 | |||
| } | |||
| }, | |||
| :text => { | |||
| :title => decode_entities(post.title), | |||
| :description => clean_description(post.summary), | |||
| :footnote => "From #{post.feed.title}" | |||
| :footnote => "From #{post.feed_title}" | |||
| }, | |||
| :actions => [ | |||
| { | |||
| @@ -1,57 +1,45 @@ | |||
| class Feed | |||
| include MongoMapper::Document | |||
| class Feed < ActiveRecord::Base | |||
| has_many :posts, :dependent => :destroy | |||
| has_and_belongs_to_many :layers | |||
| attr_accessible :title, :url, :description, :generator, :last_fetched, :feed_url | |||
| attr_accessor :new_layer_id # non model attribute used when creating new feeds from within a layer | |||
| key :title, String, :default => "[New feed - hasn't been fetched yet]" | |||
| key :feed_url, String # The URL of the RSS feed, not the website that owns it | |||
| key :url, String # The URL of website. Called "link" in RSS 2.0 | |||
| key :description, String | |||
| key :guid, String # Atom id or RSS guid | |||
| key :generator, String | |||
| key :last_fetched, Time, :default => nil | |||
| timestamps! | |||
| ensure_index :title | |||
| many :posts, :dependent => :destroy | |||
| validates :title, :presence => true | |||
| validates_format_of :feed_url, :with => URI::regexp(%w(http https)), :message => "must be a valid URL" | |||
| after_create :get | |||
| after_create :fetch | |||
| # Fetch and parse feed contents from web | |||
| def self.get_all | |||
| Feed.all.each { |f| f.get } | |||
| def self.fetch_all | |||
| Feed.all.each { |f| f.fetch } | |||
| end | |||
| def get | |||
| puts "Fetching feed: #{@url}" | |||
| # Fetch and parse feed contents from web | |||
| def fetch | |||
| puts "Fetching feed: #{self.feed_url}" | |||
| Feedzirra::Feed.add_common_feed_entry_element('georss:point', :as => :point) | |||
| Feedzirra::Feed.add_common_feed_entry_element('geo:lat', :as => :geo_lat) | |||
| Feedzirra::Feed.add_common_feed_entry_element('geo:long', :as => :geo_long) | |||
| Feedzirra::Feed.add_common_feed_element('generator', :as => :generator) | |||
| feed = Feedzirra::Feed.fetch_and_parse(@feed_url) | |||
| feed = Feedzirra::Feed.fetch_and_parse(self.feed_url) | |||
| self.set( | |||
| self.update_attributes( | |||
| :title => feed.title, | |||
| :url => feed.url, | |||
| :description => feed.description, | |||
| :generator => feed.generator, | |||
| :last_fetched => Time.now | |||
| :last_fetched => DateTime.now | |||
| ) | |||
| feed.entries.each do |e| | |||
| if e.geo_lat && e.geo_long | |||
| latlng = [e.geo_lat, e.geo_long] | |||
| latlon = [e.geo_lat, e.geo_long] | |||
| elsif e.point | |||
| latlng = e.point.split(' ') | |||
| latlon = e.point.split(' ') | |||
| else | |||
| next | |||
| end | |||
| end | |||
| attrs = { | |||
| :title => e.title, | |||
| :url => e.url, | |||
| @@ -60,20 +48,15 @@ class Feed | |||
| :content => e.content, | |||
| :published => e.published, | |||
| :guid => e.id, | |||
| :loc => { | |||
| :lng => latlng[1].to_f, | |||
| :lat => latlng[0].to_f | |||
| } | |||
| :lon => latlon[1].to_f, | |||
| :lat => latlon[0].to_f | |||
| } | |||
| if Post.where(:url => e.url).size == 0 | |||
| self.posts << Post.create(attrs) | |||
| else | |||
| Post.set({:url => e.url}, attrs) | |||
| end | |||
| # Create a new post or update an existing one | |||
| post = Post.find_or_initialize_by_url(e.url) | |||
| post.feed = self | |||
| post.assign_attributes(attrs) | |||
| post.save | |||
| end | |||
| end | |||
| end | |||
| @@ -0,0 +1,4 @@ | |||
| class Layer < ActiveRecord::Base | |||
| attr_accessible :name | |||
| has_and_belongs_to_many :feeds | |||
| end | |||
| @@ -1,26 +1,70 @@ | |||
| class Post | |||
| include MongoMapper::Document | |||
| key :title, String | |||
| key :url, String | |||
| key :author, String | |||
| key :summary, String | |||
| key :content, String | |||
| key :published, Time | |||
| key :loc, Hash # { lng, lat } | |||
| timestamps! | |||
| ensure_index [[:loc, '2d']] | |||
| class Post < ActiveRecord::Base | |||
| belongs_to :feed | |||
| EARTH_RADIUS_M = 6378000 | |||
| EARTH_RADIUS_METRES = 6378000 | |||
| def self.near(lat, lng, radius_m) | |||
| all( | |||
| :loc => { | |||
| '$nearSphere' => [ lng, lat ], | |||
| '$maxDistance' => radius_m / EARTH_RADIUS_M | |||
| }) | |||
| def self.near(lat, lon, radius_metres, layer_id) | |||
| # Santize inputs. Is this necessary? | |||
| lat = lat.to_f | |||
| lon = lon.to_f | |||
| radius_metres = radius_metres.to_i | |||
| layer_id = layer_id.to_i | |||
| # Calculate distance using the Haversine formula | |||
| self.find_by_sql(<<-ENDQUERY | |||
| SELECT | |||
| p.id, | |||
| p.title, | |||
| p.summary, | |||
| p.url, | |||
| p.lat, | |||
| p.lon, | |||
| p.published, | |||
| f.title as feed_title, | |||
| ( #{EARTH_RADIUS_METRES} | |||
| * acos( cos( radians('#{lat}') ) | |||
| * cos( radians( p.lat ) ) | |||
| * cos( radians( p.lon ) | |||
| - radians('#{lon}') ) | |||
| + sin( radians('#{lat}') ) | |||
| * sin( radians( p.lat ) ) ) ) | |||
| As distance | |||
| FROM posts p | |||
| INNER JOIN feeds f | |||
| ON p.feed_id = f.id | |||
| WHERE | |||
| p.id IN | |||
| ( -- Subquery returns a list of post_ids for posts on this layer | |||
| SELECT p.id | |||
| FROM feeds_layers fl | |||
| INNER JOIN feeds f | |||
| ON fl.feed_id = f.id | |||
| INNER JOIN posts p | |||
| ON p.feed_id = f.id | |||
| WHERE fl.layer_id = #{layer_id} | |||
| ) | |||
| AND | |||
| ( | |||
| #{EARTH_RADIUS_METRES} | |||
| * acos( cos( radians('#{lat}') ) | |||
| * cos( radians( p.lat ) ) | |||
| * cos( radians( p.lon ) | |||
| - radians('#{lon}') ) | |||
| + sin( radians('#{lat}') ) | |||
| * sin( radians( p.lat ) ) ) | |||
| ) | |||
| <= #{radius_metres} | |||
| ORDER BY distance | |||
| ENDQUERY | |||
| ) | |||
| end | |||
| end | |||
| @@ -1,11 +1,4 @@ | |||
| class User | |||
| include MongoMapper::Document | |||
| key :email, String | |||
| key :crypted_password, String | |||
| key :salt, String | |||
| timestamps! | |||
| class User < ActiveRecord::Base | |||
| authenticates_with_sorcery! | |||
| # attr_accessible :email, :password, :password_confirmation | |||
| @@ -14,5 +7,4 @@ class User | |||
| validates_uniqueness_of :email | |||
| validates_length_of :password, :minimum => 3, :message => "password must be at least 3 characters long", :if => :password | |||
| validates_confirmation_of :password, :message => "should match confirmation", :if => :password | |||
| end | |||
| @@ -15,6 +15,7 @@ | |||
| .field | |||
| = f.label "URL" | |||
| = f.text_field :feed_url, :size => 120 | |||
| = f.hidden_field :new_layer_id, :value => @feed.new_layer_id | |||
| = f.submit 'Save', :id => 'submit' | |||
| -# | |||
| .field | |||
| @@ -28,7 +28,7 @@ | |||
| - @posts.each do |p| | |||
| %tr | |||
| %td= link_to p.title, p.url | |||
| %td= link_to "Map", "https://maps.google.co.uk/maps?q=%s,%s&hl=en&z=18" % [ p.loc['lat'], p.loc['lng'] ], :target => "_blank" | |||
| %td= link_to "Map", "https://maps.google.co.uk/maps?q=%s,%s&hl=en&z=18" % [ p.lat, p.lon ], :target => "_blank" | |||
| %td | |||
| - unless p.published.nil? | |||
| = p.published.strftime("%d %b %Y %H:%M") | |||
| @@ -0,0 +1,13 @@ | |||
| = form_for @layer do |f| | |||
| - if @layer.errors.any? | |||
| #error_explanation | |||
| %h2= "#{pluralize(@layer.errors.count, "error")} prohibited this layer from being saved:" | |||
| %ul | |||
| - @layer.errors.full_messages.each do |msg| | |||
| %li= msg | |||
| .field | |||
| = f.label :name | |||
| = f.text_field :name | |||
| .actions | |||
| = f.submit 'Save' | |||
| @@ -0,0 +1,7 @@ | |||
| %h1 Editing layer | |||
| = render 'form' | |||
| = link_to 'Show', @layer | |||
| \| | |||
| = link_to 'Back', layers_path | |||
| @@ -0,0 +1,10 @@ | |||
| %h1 Layers | |||
| = link_to 'New Layer', new_layer_path, :class => 'button' | |||
| %table | |||
| - @layers.each do |layer| | |||
| %tr | |||
| %td= link_to layer.name, layer | |||
| %td= link_to 'Edit', edit_layer_path(layer) | |||
| %td= link_to 'Delete', layer, :method => :delete, :data => { :confirm => 'Are you sure?' } | |||
| @@ -0,0 +1,5 @@ | |||
| %h1 New layer | |||
| = render 'form' | |||
| = link_to 'Back', layers_path | |||
| @@ -0,0 +1,51 @@ | |||
| %h1 | |||
| Layer: | |||
| = @layer.name | |||
| %p | |||
| API URL: | |||
| = "#{request.protocol}#{request.host_with_port}/posts/near.json?layer_id=#{@layer.id}" | |||
| %h2 Feeds | |||
| #new_feed | |||
| = render 'feeds/form' | |||
| %p= link_to "Fetch all", :fetch_all, :class => "button" | |||
| %table | |||
| %tr | |||
| %th | |||
| %th Posts | |||
| %th Fetched | |||
| %th | |||
| %th | |||
| %th | |||
| - @layer.feeds.each do |f| | |||
| %tr | |||
| %td | |||
| .feed_title | |||
| = link_to f.title, f | |||
| %td.right= f.posts.count | |||
| %td | |||
| - if f.last_fetched.nil? | |||
| never | |||
| - else | |||
| = (time_ago_in_words(f.last_fetched) + " ago").gsub(/ +/, " ").html_safe | |||
| %td= link_to "Fetch", fetch_feed_url(f), :class => "button" | |||
| %td= link_to 'Edit', edit_feed_path(f), :class => "button" | |||
| %td= link_to 'Delete', f, :confirm => "Delete #{f.title} and all its posts?", :method => :delete, :class => "button" | |||
| %tr | |||
| %td | |||
| %td.right [number of posts in this layer] | |||
| %td | |||
| %td | |||
| %td | |||
| %td | |||
| = link_to 'Edit', edit_layer_path(@layer) | |||
| \| | |||
| = link_to 'Back', layers_path | |||
| @@ -1,11 +1,20 @@ | |||
| %h1 Posts#near | |||
| %table | |||
| %thead | |||
| %tr | |||
| %th | |||
| %th Latitude | |||
| %th Longitude | |||
| %th Distance (metres) | |||
| %th Published | |||
| %tbody | |||
| - @posts.each do |p| | |||
| %tr | |||
| %td= link_to p.title, p.url | |||
| %td= p.loc['lat'] | |||
| %td= p.loc['lng'] | |||
| %td= p.lat | |||
| %td= p.lon | |||
| %td= p.distance.to_i | |||
| %td | |||
| - unless p.published.nil? | |||
| = p.published.strftime("%d %b %Y %H:%M") | |||
| @@ -1,12 +1,13 @@ | |||
| require File.expand_path('../boot', __FILE__) | |||
| # Pick the frameworks you want: | |||
| require 'rails/all' | |||
| # require "active_record/railtie" | |||
| require "action_controller/railtie" | |||
| require "action_mailer/railtie" | |||
| require "active_resource/railtie" | |||
| require "sprockets/railtie" | |||
| require "rails/test_unit/railtie" | |||
| # require "action_controller/railtie" | |||
| # require "action_mailer/railtie" | |||
| # require "active_resource/railtie" | |||
| # require "sprockets/railtie" | |||
| # require "rails/test_unit/railtie" | |||
| if defined?(Bundler) | |||
| # If you precompile assets before deploying to production, use this line | |||
| @@ -15,7 +16,6 @@ if defined?(Bundler) | |||
| # Bundler.require(:default, :assets, Rails.env) | |||
| end | |||
| module Apollo | |||
| class Application < Rails::Application | |||
| config.action_mailer.default_url_options = { :host => ENV['APOLLO_HOSTNAME'] } | |||
| @@ -72,10 +72,7 @@ module Apollo | |||
| # http://mongomapper.com/documentation/getting-started/rails.html | |||
| config.generators do |g| | |||
| g.template_engine :haml | |||
| g.orm :mongo_mapper | |||
| end | |||
| MongoMapper::Document.plugin(MongoMapper::Plugins::MultiParameterAttributes) | |||
| # Time.zone = 'London' | |||
| end | |||
| end | |||
| @@ -0,0 +1,26 @@ | |||
| development: | |||
| adapter: postgresql | |||
| encoding: unicode | |||
| database: apollo_development | |||
| pool: 5 | |||
| username: postgres | |||
| password: | |||
| port: 5433 | |||
| # Warning: The database defined as "test" will be erased and | |||
| # re-generated from your development database when you run "rake". | |||
| # Do not set this db to the same as development or production. | |||
| test: | |||
| adapter: postgresql | |||
| encoding: unicode | |||
| database: apollo_test | |||
| pool: 5 | |||
| username: postgres | |||
| password: | |||
| port: 5433 | |||
| production: | |||
| adapter: sqlite3 | |||
| database: db/production.sqlite3 | |||
| pool: 5 | |||
| timeout: 5000 | |||
| @@ -1,15 +0,0 @@ | |||
| defaults: &defaults | |||
| host: 127.0.0.1 | |||
| port: 27017 | |||
| development: | |||
| <<: *defaults | |||
| database: apollo_development | |||
| test: | |||
| <<: *defaults | |||
| database: apollo_test | |||
| # set these environment variables on your prod server | |||
| production: | |||
| uri: <%= ENV['MONGOLAB_URI'] %> | |||
| @@ -2,6 +2,7 @@ Apollo::Application.routes.draw do | |||
| get "logout" => "sessions#destroy", :as => "logout" | |||
| get "login" => "sessions#new", :as => "login" | |||
| resources :layers | |||
| resources :users | |||
| resources :sessions | |||
| resources :password_resets | |||
| @@ -65,7 +66,7 @@ Apollo::Application.routes.draw do | |||
| # You can have the root of your site routed with "root" | |||
| # just remember to delete public/index.html. | |||
| root :to => 'feeds#index' | |||
| root :to => 'layers#index' | |||
| # See how all your routes lay out with "rake routes" | |||
| @@ -0,0 +1,16 @@ | |||
| class SorceryCore < ActiveRecord::Migration | |||
| def self.up | |||
| create_table :users do |t| | |||
| t.string :username, :null => false # if you use another field as a username, for example email, you can safely remove this field. | |||
| t.string :email, :default => nil # if you use this field as a username, you might want to make it :null => false. | |||
| t.string :crypted_password, :default => nil | |||
| t.string :salt, :default => nil | |||
| t.timestamps | |||
| end | |||
| end | |||
| def self.down | |||
| drop_table :users | |||
| end | |||
| end | |||
| @@ -0,0 +1,9 @@ | |||
| class RemoveUserUsername < ActiveRecord::Migration | |||
| def up | |||
| remove_column :users, :username | |||
| end | |||
| def down | |||
| add_column :users, :username, :string, :null => false | |||
| end | |||
| end | |||
| @@ -0,0 +1,6 @@ | |||
| class AddGuidToPostsRemoveGuidFromFeeds < ActiveRecord::Migration | |||
| def change | |||
| remove_column :feeds, :guid | |||
| add_column :posts, :guid, :string | |||
| end | |||
| end | |||
| @@ -0,0 +1,11 @@ | |||
| class FeedsChangeLastFetchedToDatetime < ActiveRecord::Migration | |||
| def up | |||
| remove_column :feeds, :last_fetched | |||
| add_column :feeds, :last_fetched, :datetime | |||
| end | |||
| def down | |||
| remove_column :feeds, :last_fetched | |||
| add_column :feeds, :last_fetched, :time | |||
| end | |||
| end | |||
| @@ -0,0 +1,11 @@ | |||
| class PostPublishedChangeToDatetime < ActiveRecord::Migration | |||
| def up | |||
| remove_column :posts, :published | |||
| add_column :posts, :published, :datetime | |||
| end | |||
| def down | |||
| remove_column :posts, :published | |||
| add_column :posts, :published, :time | |||
| end | |||
| end | |||
| @@ -0,0 +1,15 @@ | |||
| class CreateLayers < ActiveRecord::Migration | |||
| def change | |||
| create_table :layers do |t| | |||
| t.string :name | |||
| t.timestamps | |||
| end | |||
| create_table :feeds_layers, :id => false do |t| | |||
| t.integer :feed_id | |||
| t.integer :layer_id | |||
| end | |||
| add_index :feeds_layers, [ :feed_id, :layer_id ] | |||
| end | |||
| end | |||
| @@ -0,0 +1,63 @@ | |||
| # encoding: UTF-8 | |||
| # This file is auto-generated from the current state of the database. Instead | |||
| # of editing this file, please use the migrations feature of Active Record to | |||
| # incrementally modify your database, and then regenerate this schema definition. | |||
| # | |||
| # Note that this schema.rb definition is the authoritative source for your | |||
| # database schema. If you need to create the application database on another | |||
| # system, you should be using db:schema:load, not running all the migrations | |||
| # from scratch. The latter is a flawed and unsustainable approach (the more migrations | |||
| # you'll amass, the slower it'll run and the greater likelihood for issues). | |||
| # | |||
| # It's strongly recommended to check this file into your version control system. | |||
| ActiveRecord::Schema.define(:version => 20130228150425) do | |||
| create_table "feeds", :force => true do |t| | |||
| t.string "title" | |||
| t.string "feed_url" | |||
| t.string "url" | |||
| t.string "description" | |||
| t.string "generator" | |||
| t.datetime "created_at", :null => false | |||
| t.datetime "updated_at", :null => false | |||
| t.datetime "last_fetched" | |||
| end | |||
| create_table "feeds_layers", :id => false, :force => true do |t| | |||
| t.integer "feed_id" | |||
| t.integer "layer_id" | |||
| end | |||
| add_index "feeds_layers", ["feed_id", "layer_id"], :name => "index_feeds_layers_on_feed_id_and_layer_id" | |||
| create_table "layers", :force => true do |t| | |||
| t.string "name" | |||
| t.datetime "created_at", :null => false | |||
| t.datetime "updated_at", :null => false | |||
| end | |||
| create_table "posts", :force => true do |t| | |||
| t.string "title" | |||
| t.string "url" | |||
| t.string "author" | |||
| t.text "summary" | |||
| t.text "content" | |||
| t.decimal "lat" | |||
| t.decimal "lon" | |||
| t.integer "feed_id" | |||
| t.datetime "created_at", :null => false | |||
| t.datetime "updated_at", :null => false | |||
| t.string "guid" | |||
| t.datetime "published" | |||
| end | |||
| create_table "users", :force => true do |t| | |||
| t.string "email" | |||
| t.string "crypted_password" | |||
| t.string "salt" | |||
| t.datetime "created_at", :null => false | |||
| t.datetime "updated_at", :null => false | |||
| end | |||
| end | |||
| @@ -0,0 +1,7 @@ | |||
| # Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/Fixtures.html | |||
| one: | |||
| name: MyString | |||
| two: | |||
| name: MyString | |||
| @@ -0,0 +1,49 @@ | |||
| require 'test_helper' | |||
| class LayersControllerTest < ActionController::TestCase | |||
| setup do | |||
| @layer = layers(:one) | |||
| end | |||
| test "should get index" do | |||
| get :index | |||
| assert_response :success | |||
| assert_not_nil assigns(:layers) | |||
| end | |||
| test "should get new" do | |||
| get :new | |||
| assert_response :success | |||
| end | |||
| test "should create layer" do | |||
| assert_difference('Layer.count') do | |||
| post :create, layer: { name: @layer.name } | |||
| end | |||
| assert_redirected_to layer_path(assigns(:layer)) | |||
| end | |||
| test "should show layer" do | |||
| get :show, id: @layer | |||
| assert_response :success | |||
| end | |||
| test "should get edit" do | |||
| get :edit, id: @layer | |||
| assert_response :success | |||
| end | |||
| test "should update layer" do | |||
| put :update, id: @layer, layer: { name: @layer.name } | |||
| assert_redirected_to layer_path(assigns(:layer)) | |||
| end | |||
| test "should destroy layer" do | |||
| assert_difference('Layer.count', -1) do | |||
| delete :destroy, id: @layer | |||
| end | |||
| assert_redirected_to layers_path | |||
| end | |||
| end | |||
| @@ -0,0 +1,4 @@ | |||
| require 'test_helper' | |||
| class LayersHelperTest < ActionView::TestCase | |||
| end | |||
| @@ -0,0 +1,7 @@ | |||
| require 'test_helper' | |||
| class LayerTest < ActiveSupport::TestCase | |||
| # test "the truth" do | |||
| # assert true | |||
| # end | |||
| end | |||