commit 102d5fe6d69913459b391be52d7ed5e0968d3e37
Author: Harry Bomrah <harry@rulingcom.com>
Date:   Tue Jul 7 19:51:56 2015 +0800

    initial commit

diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..de5d954
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,8 @@
+.bundle/
+log/*.log
+pkg/
+test/dummy/db/*.sqlite3
+test/dummy/db/*.sqlite3-journal
+test/dummy/log/*.log
+test/dummy/tmp/
+test/dummy/.sass-cache
diff --git a/Gemfile b/Gemfile
new file mode 100644
index 0000000..c3ed41a
--- /dev/null
+++ b/Gemfile
@@ -0,0 +1,14 @@
+source "https://rubygems.org"
+
+# Declare your gem's dependencies in feeds.gemspec.
+# Bundler will treat runtime dependencies like base dependencies, and
+# development dependencies will be added by default to the :development group.
+gemspec
+
+# Declare any dependencies that are still in development here instead of in
+# your gemspec. These might include edge Rails or gems from your path or
+# Git. Remember to move these dependencies to your gemspec before releasing
+# your gem to rubygems.org.
+
+# To use debugger
+# gem 'debugger'
diff --git a/MIT-LICENSE b/MIT-LICENSE
new file mode 100644
index 0000000..1e4beb8
--- /dev/null
+++ b/MIT-LICENSE
@@ -0,0 +1,20 @@
+Copyright 2015 YOURNAME
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/README.rdoc b/README.rdoc
new file mode 100644
index 0000000..9951795
--- /dev/null
+++ b/README.rdoc
@@ -0,0 +1,3 @@
+= Feeds
+
+This project rocks and uses MIT-LICENSE.
\ No newline at end of file
diff --git a/Rakefile b/Rakefile
new file mode 100644
index 0000000..2c85305
--- /dev/null
+++ b/Rakefile
@@ -0,0 +1,34 @@
+begin
+  require 'bundler/setup'
+rescue LoadError
+  puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
+end
+
+require 'rdoc/task'
+
+RDoc::Task.new(:rdoc) do |rdoc|
+  rdoc.rdoc_dir = 'rdoc'
+  rdoc.title    = 'Feeds'
+  rdoc.options << '--line-numbers'
+  rdoc.rdoc_files.include('README.rdoc')
+  rdoc.rdoc_files.include('lib/**/*.rb')
+end
+
+APP_RAKEFILE = File.expand_path("../test/dummy/Rakefile", __FILE__)
+load 'rails/tasks/engine.rake'
+
+
+
+Bundler::GemHelper.install_tasks
+
+require 'rake/testtask'
+
+Rake::TestTask.new(:test) do |t|
+  t.libs << 'lib'
+  t.libs << 'test'
+  t.pattern = 'test/**/*_test.rb'
+  t.verbose = false
+end
+
+
+task default: :test
diff --git a/app/assets/images/feeds/.keep b/app/assets/images/feeds/.keep
new file mode 100644
index 0000000..e69de29
diff --git a/app/assets/javascripts/feeds/application.js b/app/assets/javascripts/feeds/application.js
new file mode 100644
index 0000000..a1873dd
--- /dev/null
+++ b/app/assets/javascripts/feeds/application.js
@@ -0,0 +1,13 @@
+// This is a manifest file that'll be compiled into application.js, which will include all the files
+// listed below.
+//
+// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
+// or vendor/assets/javascripts of plugins, if any, can be referenced here using a relative path.
+//
+// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
+// compiled file.
+//
+// Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details
+// about supported directives.
+//
+//= require_tree .
diff --git a/app/assets/javascripts/new_channel.js b/app/assets/javascripts/new_channel.js
new file mode 100644
index 0000000..90a512f
--- /dev/null
+++ b/app/assets/javascripts/new_channel.js
@@ -0,0 +1,124 @@
+(function(){
+  var loading = null,
+      site_url = null;
+  $("document").ready(function(){
+    loading = $("#loading");
+    bindHandlers();
+  })
+  
+  var bindHandlers = function(){
+    $("#find-channels").on("click",function(){
+      site_url = $("#site-url-wrapper input[type=text]").val();
+      $("#site-url-wrapper").fadeOut();
+      getChannelList();
+    })
+  }
+
+  var getChannelList = function(){
+    displayLoading(true,"Fetching channels from " + site_url);
+    $.ajax({
+        url : "/admin/feeds/get_channel_list",
+        data : {"url" : site_url},
+        dataType : "json",
+        type : "get"
+      }).done(function(channels){
+        $.each(channels.channels,function(index,channel){
+            var ch = $("<div id='" + channel.key + "-channel' class='module cursor-pointer'><div class='lead muted'><i class='" + channel.app_icon + "'></i><br/><span style='font-size:14px;'>" + channel.title + "</span></div></div>");
+            ch.on("click",function(){
+              getFeedList(channel);
+            })
+            $("#channels").append(ch);
+        })
+        setTimeout(function(){
+          displayLoading(false);
+          setTimeout(function(){$("#channels").fadeIn();},500);
+        },1000);
+      })
+  }  
+
+  var getFeedList = function(channel){
+    $("#channels").fadeOut(function(){
+      $("#channels").html("");
+      displayLoading(true,"Fetching feed list for " + channel.title);
+      $.ajax({
+        url : "/admin/feeds/get_feed_list",
+        data : {"url" : site_url, "channel" : channel.key, "feed_list_url" : channel.url},
+        dataType : "json",
+        type : "get"
+      }).done(function(data){
+        $.each(data.feeds, function(index,feed){
+          var klass = (feed.subscribed ? "active" : "");
+          var f = $("<div class='module cursor-pointer " + klass + "'><div class='lead muted'><i class='icons-text-2'></i><br/><span style='font-size:14px;'>" + feed.title_translations[I18n.locale] + "</span></div></div>");
+          f.on("click",function(){
+            if($(this).hasClass("active")){
+              if(confirm("Are you sure, you want to unsubscribe from " + feed.title_translations[I18n.locale] + "?")){
+                unsubscribeFeed($(this),feed);
+              }
+            }else{
+              subscribeFeed($(this),feed,channel);
+            }
+          })
+          $("#channels").append(f);
+        })
+         setTimeout(function(){
+            displayLoading(false);
+            setTimeout(function(){$("#channels").fadeIn();},500);
+          },1000);
+      })
+    })
+  }
+
+  var unsubscribeFeed = function(dom,feed){
+     dom.removeClass("active");
+     $.ajax({
+        url : "/admin/feeds/unsubscribe",
+        data : {"feed_uid": feed.uid},
+        dataType : "json",
+        type : "post"
+      }).done(function(){
+        $("#selectCategoryModal").modal("hide");
+      })
+  }
+
+  var subscribeFeed = function(dom,feed,channel){
+    var subscribe_button = $("#subscribe-button"),
+        select = $("#local-category");
+    $("#selectCategoryModal").modal("show");
+    subscribe_button.attr("disabled","disabled");
+    $.ajax({
+      url : "/admin/feeds/get_category_list",
+      data : {"channel" : channel.key},
+      dataType : "json",
+      type : "get"
+    }).done(function(data){
+      select.html("");
+      $.each(data.categories,function(index,category){
+        select.append("<option value='" + category.id + "'>" + category.title + "</option>");
+      })
+      subscribe_button.removeAttr("disabled");
+    })
+    subscribe_button.unbind("click");
+    subscribe_button.on("click",function(){
+      dom.addClass("active");
+      $.ajax({
+        url : "/admin/feeds/subscribe",
+        data : {"url" : site_url, "feed" : feed, "channel" : channel.title, "channel_key" : channel.key, "category" : select.val()},
+        dataType : "json",
+        type : "post"
+      }).done(function(){
+        $("#selectCategoryModal").modal("hide");
+      })
+    })
+
+  }
+
+  var displayLoading = function(display, msg){
+    if(display){
+      loading.find(".progress_msg").text(msg);
+      loading.fadeIn();
+    }else{
+      loading.find(".progress_msg").text("");
+      loading.fadeOut();
+    }
+  }
+})();
diff --git a/app/assets/stylesheets/feeds/application.css b/app/assets/stylesheets/feeds/application.css
new file mode 100644
index 0000000..a443db3
--- /dev/null
+++ b/app/assets/stylesheets/feeds/application.css
@@ -0,0 +1,15 @@
+/*
+ * This is a manifest file that'll be compiled into application.css, which will include all the files
+ * listed below.
+ *
+ * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
+ * or vendor/assets/stylesheets of plugins, if any, can be referenced here using a relative path.
+ *
+ * You're free to add application-wide styles to this file and they'll appear at the bottom of the
+ * compiled file so the styles you add here take precedence over styles defined in any styles
+ * defined in the other CSS/SCSS files in this directory. It is generally better to create a new
+ * file per style scope.
+ *
+ *= require_tree .
+ *= require_self
+ */
diff --git a/app/assets/stylesheets/new_channel.css b/app/assets/stylesheets/new_channel.css
new file mode 100644
index 0000000..7b0f345
--- /dev/null
+++ b/app/assets/stylesheets/new_channel.css
@@ -0,0 +1,106 @@
+.import-wrapper{
+    padding: 10px;  
+  }
+  .import-wrapper .import-url{
+    width: 565px;
+  }
+  .import-wrapper .btn{
+    margin-bottom: 10px;
+  }
+  #import-container{
+    width: auto;
+    margin: 0 auto;
+  }
+  #loading{
+    margin: 20px 0;
+    text-align: center;
+  }
+  #loading img{
+    width: 50px;
+  }
+  #import-head{
+    font-size: 18px;
+    text-align: center;
+    text-shadow: 1px 1px 1px #FFF;
+    padding-bottom: 10px;
+    margin-top: 100px;
+  }
+  #import-head i{
+    font-size: 64px; 
+  }
+  #site-url-wrapper{
+    height: 100px;
+    width: 600px;
+    margin: 0 auto;
+  }
+  #import-modules{
+    margin-top: 30px;
+    text-align: center;
+  }
+  .module{
+    text-align: center;
+    width: 120px;
+    display: inline-block;
+    margin: 8px 5px;
+    padding: 15px 0px;
+  }
+  .module.cursor-pointer {
+    cursor: pointer;
+  }
+  .module .cursor-default {
+    cursor: default;
+  }
+  .module i{
+    font-size: 48px;
+    border-radius: 10px;
+    border: 1px solid #FFF;
+    background: #888;
+    padding: 15px 18px;
+    box-shadow: 0 0 10px #555 inset;
+    color: #FFF;
+  }
+  .module.active i{
+    background: #438CDB;
+    box-shadow: none;
+  }
+  .module i:hover{
+    background: #438CDB;
+    box-shadow: none;
+  }
+  #import-modules .lead{
+    margin-bottom: 0px;
+    font-size: 12px;
+  }
+  .alert{
+    width: 500px;
+    margin: 20px auto 0;
+  }
+  .module-icon{
+    font-size: 64px;
+    border-radius: 10px;
+    padding: 15px 18px;
+    color: #888;
+  }
+  #import-progress{
+    border: 0px solid #CCC;
+    text-align: center;
+    width: 400px;
+    margin: 100px auto 0 auto;
+  }
+  #import-progress .progress{
+    margin-bottom: 0px;
+  }
+  #import-progress-text{
+    font-size: 16px;
+    line-height: 25px;
+    color: #666;
+    height: 50px;
+    margin-bottom: 5px;
+  }
+
+  .import-modal-label {
+    display: inline-block;
+    margin-top: 5px;
+    margin-right: 10px; 
+    vertical-align: top;
+  }
diff --git a/app/controllers/admin/feeds_controller.rb b/app/controllers/admin/feeds_controller.rb
new file mode 100644
index 0000000..b5a6dce
--- /dev/null
+++ b/app/controllers/admin/feeds_controller.rb
@@ -0,0 +1,92 @@
+class Admin::FeedsController < OrbitAdminController
+
+	def index
+		@site_feeds = SiteFeed.all.group_by(&:remote_site_url)
+		@school_urls = @site_feeds.keys
+		redirect_to new_admin_feed_path and return if @site_feeds.count == 0
+	end
+
+	def new
+
+	end
+
+	def get_category_list
+		app_key = params[:channel]
+		ma = ModuleApp.find_by_key(app_key) rescue nil
+		categories = []
+		if !ma.nil?
+			ma.categories.each do |category|
+				cat = {}
+				cat["title"] = category.title
+				cat["id"]  = category.id.to_s
+				categories << cat
+			end
+		end
+		render :json => {"categories" => categories}.to_json
+	end
+
+	def get_channel_list
+		url = params['url'].chomp("/") + "/feeds/channel_lists"
+		uri = URI.parse(url)
+	    http = Net::HTTP.new(uri.host, uri.port)
+	    request = Net::HTTP::Get.new(uri.request_uri)
+	    response = http.request(request)
+	    data = response.body
+	    data = JSON.parse(data)
+	    render :json => data.to_json
+	end
+
+	def get_feed_list
+		url = params['url'].chomp("/") + params[:feed_list_url]
+		uri = URI.parse(url)
+		http = Net::HTTP.new(uri.host, uri.port)
+	    request = Net::HTTP::Get.new(uri.request_uri)
+	    response = http.request(request)
+	    data = response.body
+	    data = JSON.parse(data)
+	    data_to_send = {}
+	    data_to_send["feeds"] = []
+	    data["feeds"].each do |feed|
+	    	sf = SiteFeed.find_by(:feed_uid => feed["uid"]) rescue nil
+	    	if !sf.nil?
+	    		feed["subscribed"] = true
+	    	else
+	    		feed["subscribed"] = false
+	    	end
+	    	data_to_send["feeds"] << feed
+	    end
+	    render :json => data_to_send.to_json
+	end
+
+	def subscribe
+		site_feed = SiteFeed.new
+		site_feed.remote_site_url = params[:url].chomp("/")
+		site_feed.merge_with_category = params[:category]
+		site_feed.channel_name = params[:channel]
+		site_feed.channel_key = params[:channel_key]
+		site_feed.feed_uid = params[:feed][:uid]
+		site_feed.feed_name_translations = params[:feed][:title_translations]
+		site_feed.disabled = false
+		site_feed.feed_url = params[:feed][:url]
+		site_feed.save
+		render :json => {"success" => true}.to_json
+	end
+
+	def disable
+		feed = SiteFeed.find(params[:feed_id]) rescue nil
+		if !feed.nil?
+			feed.disabled = params[:disable] 
+			feed.save
+		end
+		render :json => {"success" => true}.to_json
+	end
+
+	def unsubscribe
+		sf = SiteFeed.find_by(:feed_uid => params[:feed_uid]) rescue nil
+		if !sf.nil?
+			sf.destroy
+		end
+		render :json => {"success" => true}.to_json
+	end
+end
+
diff --git a/app/helpers/feeds/application_helper.rb b/app/helpers/feeds/application_helper.rb
new file mode 100644
index 0000000..79efd0b
--- /dev/null
+++ b/app/helpers/feeds/application_helper.rb
@@ -0,0 +1,4 @@
+module Feeds
+  module ApplicationHelper
+  end
+end
diff --git a/app/models/site_feed.rb b/app/models/site_feed.rb
new file mode 100644
index 0000000..0f3e109
--- /dev/null
+++ b/app/models/site_feed.rb
@@ -0,0 +1,16 @@
+class SiteFeed
+  include Mongoid::Document
+  include Mongoid::Timestamps
+
+  field :remote_site_url
+  field :merge_with_category
+  field :channel_name
+  field :channel_key
+  field :feed_name, localize: true
+  field :disabled, type: Boolean, default: false
+  field :feed_url
+  field :feed_uid
+
+  scope :enabled, ->{where(:disabled => false)}
+  
+end
\ No newline at end of file
diff --git a/app/views/admin/feeds/index.html.erb b/app/views/admin/feeds/index.html.erb
new file mode 100644
index 0000000..013cedf
--- /dev/null
+++ b/app/views/admin/feeds/index.html.erb
@@ -0,0 +1,81 @@
+<div>
+	<h3>Channel and feeds</h3>
+</div>
+<div class="accordion" id="feedAccordion">
+	<% @school_urls.each_with_index do |url,index| %>
+	  <div class="accordion-group">
+	    <div class="accordion-heading">
+	      <a class="accordion-toggle" data-toggle="collapse" data-parent="#feedAccordion" href="#channel_<%= index.to_s %>">
+	        <%= (index + 1).to_s %>. <%= url %>
+	      </a>
+	    </div>
+	    <div id="channel_<%= index.to_s %>" class="accordion-body collapse">
+	    	<div class="accordion-inner">
+			    <% channels =  @site_feeds[url].group_by(&:channel_name) 
+			    	channel_names = channels.keys
+			    	channel_names.each do |name|
+			    %>
+			    	<ul>
+			    		<li>
+			    			<%= name %>
+			    			<% channels[name].each do |channel| %>
+			    				<ul>
+			    					<li><%= channel.feed_name %> <button class="btn <%= channel.disabled ? "btn-info" : "btn-warning" %> disable-feed-btn" data-feed-id="<%= channel.id.to_s %>"><%= channel.disabled ? "Enable" : "Disable" %></button> <button class="btn btn-danger unsubscribe-btn" data-feed-uid="<%= channel.feed_uid %>" data-feed-name="<%= channel.feed_name %>">Unsubscribe</button></li>
+			    				</ul>
+			    			<% end %>
+			    		</li>
+			    	</ul>
+	      		<% end %>
+	      </div>
+	    </div>
+	  </div>
+	<% end %>
+</div>
+
+<script type="text/javascript">
+	$(".disable-feed-btn").on("click",function(){
+		var disable = null,
+			el = $(this),
+			feed_id = $(this).data("feed-id");
+		if(el.hasClass("btn-warning")){
+			el.removeClass("btn-warning");
+			el.text("Disabling...");
+			disable = true;
+		}else{
+			el.removeClass("btn-info");
+			el.text("Enabling...");
+			disable = false;
+		}
+
+		$.ajax({
+			url : "/admin/feeds/disable",
+			data : {"feed_id" : feed_id, "disable" : disable},
+			dataType : "json",
+			type : "post"
+		}).done(function(){
+			if(disable){
+				setTimeout(function(){el.addClass("btn-info");el.text("Enable")},800);
+			}else{
+				setTimeout(function(){el.addClass("btn-warning");el.text("Disable")},800);
+			}
+		})
+	})
+
+	$(".unsubscribe-btn").on("click",function(){
+		var el = $(this);
+		if(confirm("Are you sure, you want to unsubscribe from " + el.data("feed-name"))){
+		 $.ajax({
+	        url : "/admin/feeds/unsubscribe",
+	        data : {"feed_uid": el.data("feed-uid")},
+	        dataType : "json",
+	        type : "post"
+	      }).done(function(){
+	      	el.parent().remove();
+	      })
+		}
+	})
+</script>
+
+
+
+
diff --git a/app/views/admin/feeds/new.html.erb b/app/views/admin/feeds/new.html.erb
new file mode 100644
index 0000000..4b48941
--- /dev/null
+++ b/app/views/admin/feeds/new.html.erb
@@ -0,0 +1,45 @@
+<% content_for :page_specific_css do %>
+  <%= stylesheet_link_tag "new_channel" %>
+<% end %>
+<% content_for :page_specific_javascript do %>
+  <%= javascript_include_tag "new_channel" %>
+<% end %>
+<div id="import-container">
+  <div id="import-head" class="muted">
+    <i class='icons-rss'></i><br/>
+    Subscribe to channels
+  </div>
+
+  <div id="loading" style="display:none;">
+    <%= image_tag 'preloader.gif' %><br/>
+    <span class="progress_msg"></span>
+  </div>
+
+  <div id="site-url-wrapper" class="import-wrapper">
+    <input type="text" class="import-url" name="url" value="" placeholder="http://www.rulingcom.com">
+    <button id="find-channels" class="btn btn-primary">Find Channels</button>
+  </div>
+
+  <div id="channels" style="display:none; text-align:center;">
+  </div>
+</div>
+<div id="selectCategoryModal" class="modal hide fade" tabindex="-1" role="dialog" aria-labelledby="selectCategoryModalLabel" aria-hidden="true">
+  <div class="modal-header">
+    <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
+    <h4>Select category for feed to merge.</h4>
+  </div>
+  <div class="modal-body">
+    <label class="import-modal-label muted">Category : </label>
+    <select class="import-modal-select" name="local_category" id="local-category">
+      <option>Loading categories ...</option>
+    </select>
+  </div>
+  <div class="modal-footer">
+    <button class="btn" data-dismiss="modal" aria-hidden="true">Cancel</button>
+    <button class="btn btn-primary" id="subscribe-button">Subscribe</button>
+  </div>
+</div>
+<script type="text/javascript">
+  var I18n = {};
+  I18n.locale = "<%= I18n.locale.to_s %>";
+</script>
\ No newline at end of file
diff --git a/bin/rails b/bin/rails
new file mode 100755
index 0000000..810f0f0
--- /dev/null
+++ b/bin/rails
@@ -0,0 +1,12 @@
+#!/usr/bin/env ruby
+# This command will automatically be run when you run "rails" with Rails 4 gems installed from the root of your application.
+
+ENGINE_ROOT = File.expand_path('../..', __FILE__)
+ENGINE_PATH = File.expand_path('../../lib/feeds/engine', __FILE__)
+
+# Set up gems listed in the Gemfile.
+ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__)
+require 'bundler/setup' if File.exist?(ENV['BUNDLE_GEMFILE'])
+
+require 'rails/all'
+require 'rails/engine/commands'
diff --git a/config/locales/en.yml b/config/locales/en.yml
new file mode 100644
index 0000000..e6274c3
--- /dev/null
+++ b/config/locales/en.yml
@@ -0,0 +1,5 @@
+en:
+  feed:
+    new_: "Susbscribe to channel"
+    feed: Feed
+    all_feeds: All Feeds
\ No newline at end of file
diff --git a/config/locales/zh_tw.yml b/config/locales/zh_tw.yml
new file mode 100644
index 0000000..e932842
--- /dev/null
+++ b/config/locales/zh_tw.yml
@@ -0,0 +1,5 @@
+zh_tw:
+  feed:
+    new_: "Susbscribe to channel"
+    feed: Feed
+    all_feeds: All Feeds
\ No newline at end of file
diff --git a/config/routes.rb b/config/routes.rb
new file mode 100644
index 0000000..1cbb30b
--- /dev/null
+++ b/config/routes.rb
@@ -0,0 +1,17 @@
+Rails.application.routes.draw do
+
+  locales = Site.first.in_use_locales rescue I18n.available_locales
+  
+  scope "(:locale)", locale: Regexp.new(locales.join("|")) do
+   namespace :admin do
+    get "/feeds/get_channel_list", to: 'feeds#get_channel_list'
+    get "/feeds/get_feed_list", to: 'feeds#get_feed_list'
+    get "/feeds/get_category_list", to: 'feeds#get_category_list'
+    post "/feeds/subscribe", to: 'feeds#subscribe'
+    post "/feeds/unsubscribe", to: 'feeds#unsubscribe'
+    post "/feeds/disable", to: 'feeds#disable'
+    resources :feeds
+   end
+  end
+  
+end
diff --git a/config/schedule.rb b/config/schedule.rb
new file mode 100644
index 0000000..b95df96
--- /dev/null
+++ b/config/schedule.rb
@@ -0,0 +1,3 @@
+every 5.minutes do 
+	rake "feeds_module:make_cache"
+end
\ No newline at end of file
diff --git a/feeds.gemspec b/feeds.gemspec
new file mode 100644
index 0000000..8a714aa
--- /dev/null
+++ b/feeds.gemspec
@@ -0,0 +1,20 @@
+$:.push File.expand_path("../lib", __FILE__)
+
+# Maintain your gem's version:
+require "feeds/version"
+
+# Describe your gem and declare its dependencies:
+Gem::Specification.new do |s|
+  s.name        = "feeds"
+  s.version     = Feeds::VERSION
+  s.authors     = ["Harry"]
+  s.email       = ["harry@rulingcom.com"]
+  s.homepage    = "http://www.rulingcom.com"
+  s.summary     = "RSS reader for orbit."
+  s.description = "RSS reader for orbit."
+  s.license     = "MIT"
+
+  s.files = Dir["{app,config,db,lib}/**/*", "MIT-LICENSE", "Rakefile", "README.rdoc"]
+  s.test_files = Dir["test/**/*"]
+  s.add_dependency("whenever")
+end
diff --git a/lib/feeds.rb b/lib/feeds.rb
new file mode 100644
index 0000000..ddf12bb
--- /dev/null
+++ b/lib/feeds.rb
@@ -0,0 +1,4 @@
+require "feeds/engine"
+
+module Feeds
+end
diff --git a/lib/feeds/engine.rb b/lib/feeds/engine.rb
new file mode 100644
index 0000000..798ab74
--- /dev/null
+++ b/lib/feeds/engine.rb
@@ -0,0 +1,42 @@
+module Feeds
+  class Engine < ::Rails::Engine
+     initializer "feeds" do 
+      OrbitApp.registration "Feeds", :type => "ModuleApp" do
+        module_label "feed.feed"
+        base_url File.expand_path File.dirname(__FILE__)
+        categorizable
+        authorizable
+
+        side_bar do
+          head_label_i18n 'feed.feed', icon_class: "icons-rss"
+          available_for "managers"
+          active_for_controllers (['admin/feeds'])
+          head_link_path "admin_feeds_path"
+
+          context_link 'feed.all_feeds',
+                                :link_path=>"admin_feeds_path" ,
+                                :priority=>1,
+                                :active_for_action=>{'admin/feeds'=>'index'},
+                                :available_for => 'managers'
+          context_link 'feed.new_', 
+                                :link_path=>"new_admin_feed_path" ,
+                                :priority=>2,
+                                :active_for_action=>{'admin/feeds'=>'new'},
+                                :available_for => 'managers'
+        end
+
+      end
+      spec = Gem::Specification.find_by_name("feeds") rescue nil
+      if !spec.nil?
+        gem_root = spec.gem_dir
+        gem_tmp = gem_root + "/tmp/"
+        f = File.join(gem_tmp + "install_bash")
+        if File.exists?(f)
+          File.delete(f)
+          %x(cp "#{gem_root}/config/schedule.rb" config/schedule.rb)
+          %x(whenever --update-crontab feeds --set environment="#{ENV["RAILS_ENV"]}")
+        end
+      end
+    end
+  end
+end
diff --git a/lib/feeds/version.rb b/lib/feeds/version.rb
new file mode 100644
index 0000000..e034caa
--- /dev/null
+++ b/lib/feeds/version.rb
@@ -0,0 +1,3 @@
+module Feeds
+  VERSION = "0.0.1"
+end
diff --git a/lib/tasks/feeds_tasks.rake b/lib/tasks/feeds_tasks.rake
new file mode 100644
index 0000000..8146346
--- /dev/null
+++ b/lib/tasks/feeds_tasks.rake
@@ -0,0 +1,16 @@
+namespace :feeds_module do
+  desc "Downloading feeds"
+  task :make_cache,[:url] => :environment do |task,args|
+  	main_directory = File.join("#{Rails.root}","public","site_feeds")
+  	FileUtils.mkdir_p(main_directory) if !File.exists?(main_directory)
+  	SiteFeed.enabled.each do |site_feed|
+  		feed_directory = File.join(main_directory.to_s, site_feed.id.to_s)
+  		FileUtils.mkdir_p(feed_directory) if !File.exists?(feed_directory)
+  		uri = URI(site_feed.feed_url)
+		res = Net::HTTP.get(uri)
+		file = File.open(File.join(feed_directory.to_s,site_feed.feed_uid + ".json"),"w")
+		res.force_encoding("utf-8")
+		file.write(res)
+  	end
+  end 
+end
\ No newline at end of file
diff --git a/test/dummy/README.rdoc b/test/dummy/README.rdoc
new file mode 100644
index 0000000..dd4e97e
--- /dev/null
+++ b/test/dummy/README.rdoc
@@ -0,0 +1,28 @@
+== README
+
+This README would normally document whatever steps are necessary to get the
+application up and running.
+
+Things you may want to cover:
+
+* Ruby version
+
+* System dependencies
+
+* Configuration
+
+* Database creation
+
+* Database initialization
+
+* How to run the test suite
+
+* Services (job queues, cache servers, search engines, etc.)
+
+* Deployment instructions
+
+* ...
+
+
+Please feel free to use a different markup language if you do not plan to run
+<tt>rake doc:app</tt>.
diff --git a/test/dummy/Rakefile b/test/dummy/Rakefile
new file mode 100644
index 0000000..ba6b733
--- /dev/null
+++ b/test/dummy/Rakefile
@@ -0,0 +1,6 @@
+# Add your own tasks in files placed in lib/tasks ending in .rake,
+# for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
+
+require File.expand_path('../config/application', __FILE__)
+
+Rails.application.load_tasks
diff --git a/test/dummy/app/assets/images/.keep b/test/dummy/app/assets/images/.keep
new file mode 100644
index 0000000..e69de29
diff --git a/test/dummy/app/assets/javascripts/application.js b/test/dummy/app/assets/javascripts/application.js
new file mode 100644
index 0000000..a1873dd
--- /dev/null
+++ b/test/dummy/app/assets/javascripts/application.js
@@ -0,0 +1,13 @@
+// This is a manifest file that'll be compiled into application.js, which will include all the files
+// listed below.
+//
+// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
+// or vendor/assets/javascripts of plugins, if any, can be referenced here using a relative path.
+//
+// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
+// compiled file.
+//
+// Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details
+// about supported directives.
+//
+//= require_tree .
diff --git a/test/dummy/app/assets/stylesheets/application.css b/test/dummy/app/assets/stylesheets/application.css
new file mode 100644
index 0000000..a443db3
--- /dev/null
+++ b/test/dummy/app/assets/stylesheets/application.css
@@ -0,0 +1,15 @@
+/*
+ * This is a manifest file that'll be compiled into application.css, which will include all the files
+ * listed below.
+ *
+ * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
+ * or vendor/assets/stylesheets of plugins, if any, can be referenced here using a relative path.
+ *
+ * You're free to add application-wide styles to this file and they'll appear at the bottom of the
+ * compiled file so the styles you add here take precedence over styles defined in any styles
+ * defined in the other CSS/SCSS files in this directory. It is generally better to create a new
+ * file per style scope.
+ *
+ *= require_tree .
+ *= require_self
+ */
diff --git a/test/dummy/app/controllers/application_controller.rb b/test/dummy/app/controllers/application_controller.rb
new file mode 100644
index 0000000..d83690e
--- /dev/null
+++ b/test/dummy/app/controllers/application_controller.rb
@@ -0,0 +1,5 @@
+class ApplicationController < ActionController::Base
+  # Prevent CSRF attacks by raising an exception.
+  # For APIs, you may want to use :null_session instead.
+  protect_from_forgery with: :exception
+end
diff --git a/test/dummy/app/controllers/concerns/.keep b/test/dummy/app/controllers/concerns/.keep
new file mode 100644
index 0000000..e69de29
diff --git a/test/dummy/app/helpers/application_helper.rb b/test/dummy/app/helpers/application_helper.rb
new file mode 100644
index 0000000..de6be79
--- /dev/null
+++ b/test/dummy/app/helpers/application_helper.rb
@@ -0,0 +1,2 @@
+module ApplicationHelper
+end
diff --git a/test/dummy/app/mailers/.keep b/test/dummy/app/mailers/.keep
new file mode 100644
index 0000000..e69de29
diff --git a/test/dummy/app/models/.keep b/test/dummy/app/models/.keep
new file mode 100644
index 0000000..e69de29
diff --git a/test/dummy/app/models/concerns/.keep b/test/dummy/app/models/concerns/.keep
new file mode 100644
index 0000000..e69de29
diff --git a/test/dummy/app/views/layouts/application.html.erb b/test/dummy/app/views/layouts/application.html.erb
new file mode 100644
index 0000000..593a778
--- /dev/null
+++ b/test/dummy/app/views/layouts/application.html.erb
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <title>Dummy</title>
+  <%= stylesheet_link_tag    'application', media: 'all', 'data-turbolinks-track' => true %>
+  <%= javascript_include_tag 'application', 'data-turbolinks-track' => true %>
+  <%= csrf_meta_tags %>
+</head>
+<body>
+
+<%= yield %>
+
+</body>
+</html>
diff --git a/test/dummy/bin/bundle b/test/dummy/bin/bundle
new file mode 100755
index 0000000..66e9889
--- /dev/null
+++ b/test/dummy/bin/bundle
@@ -0,0 +1,3 @@
+#!/usr/bin/env ruby
+ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__)
+load Gem.bin_path('bundler', 'bundle')
diff --git a/test/dummy/bin/rails b/test/dummy/bin/rails
new file mode 100755
index 0000000..728cd85
--- /dev/null
+++ b/test/dummy/bin/rails
@@ -0,0 +1,4 @@
+#!/usr/bin/env ruby
+APP_PATH = File.expand_path('../../config/application',  __FILE__)
+require_relative '../config/boot'
+require 'rails/commands'
diff --git a/test/dummy/bin/rake b/test/dummy/bin/rake
new file mode 100755
index 0000000..1724048
--- /dev/null
+++ b/test/dummy/bin/rake
@@ -0,0 +1,4 @@
+#!/usr/bin/env ruby
+require_relative '../config/boot'
+require 'rake'
+Rake.application.run
diff --git a/test/dummy/config.ru b/test/dummy/config.ru
new file mode 100644
index 0000000..5bc2a61
--- /dev/null
+++ b/test/dummy/config.ru
@@ -0,0 +1,4 @@
+# This file is used by Rack-based servers to start the application.
+
+require ::File.expand_path('../config/environment',  __FILE__)
+run Rails.application
diff --git a/test/dummy/config/application.rb b/test/dummy/config/application.rb
new file mode 100644
index 0000000..4af9e51
--- /dev/null
+++ b/test/dummy/config/application.rb
@@ -0,0 +1,23 @@
+require File.expand_path('../boot', __FILE__)
+
+require 'rails/all'
+
+Bundler.require(*Rails.groups)
+require "feeds"
+
+module Dummy
+  class Application < Rails::Application
+    # Settings in config/environments/* take precedence over those specified here.
+    # Application configuration should go into files in config/initializers
+    # -- all .rb files in that directory are automatically loaded.
+
+    # Set Time.zone default to the specified zone and make Active Record auto-convert to this zone.
+    # Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC.
+    # config.time_zone = 'Central Time (US & Canada)'
+
+    # The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded.
+    # config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s]
+    # config.i18n.default_locale = :de
+  end
+end
+
diff --git a/test/dummy/config/boot.rb b/test/dummy/config/boot.rb
new file mode 100644
index 0000000..6266cfc
--- /dev/null
+++ b/test/dummy/config/boot.rb
@@ -0,0 +1,5 @@
+# Set up gems listed in the Gemfile.
+ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../../../Gemfile', __FILE__)
+
+require 'bundler/setup' if File.exist?(ENV['BUNDLE_GEMFILE'])
+$LOAD_PATH.unshift File.expand_path('../../../../lib', __FILE__)
diff --git a/test/dummy/config/database.yml b/test/dummy/config/database.yml
new file mode 100644
index 0000000..1c1a37c
--- /dev/null
+++ b/test/dummy/config/database.yml
@@ -0,0 +1,25 @@
+# SQLite version 3.x
+#   gem install sqlite3
+#
+#   Ensure the SQLite 3 gem is defined in your Gemfile
+#   gem 'sqlite3'
+#
+default: &default
+  adapter: sqlite3
+  pool: 5
+  timeout: 5000
+
+development:
+  <<: *default
+  database: db/development.sqlite3
+
+# 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:
+  <<: *default
+  database: db/test.sqlite3
+
+production:
+  <<: *default
+  database: db/production.sqlite3
diff --git a/test/dummy/config/environment.rb b/test/dummy/config/environment.rb
new file mode 100644
index 0000000..ee8d90d
--- /dev/null
+++ b/test/dummy/config/environment.rb
@@ -0,0 +1,5 @@
+# Load the Rails application.
+require File.expand_path('../application', __FILE__)
+
+# Initialize the Rails application.
+Rails.application.initialize!
diff --git a/test/dummy/config/environments/development.rb b/test/dummy/config/environments/development.rb
new file mode 100644
index 0000000..ddf0e90
--- /dev/null
+++ b/test/dummy/config/environments/development.rb
@@ -0,0 +1,37 @@
+Rails.application.configure do
+  # Settings specified here will take precedence over those in config/application.rb.
+
+  # In the development environment your application's code is reloaded on
+  # every request. This slows down response time but is perfect for development
+  # since you don't have to restart the web server when you make code changes.
+  config.cache_classes = false
+
+  # Do not eager load code on boot.
+  config.eager_load = false
+
+  # Show full error reports and disable caching.
+  config.consider_all_requests_local       = true
+  config.action_controller.perform_caching = false
+
+  # Don't care if the mailer can't send.
+  config.action_mailer.raise_delivery_errors = false
+
+  # Print deprecation notices to the Rails logger.
+  config.active_support.deprecation = :log
+
+  # Raise an error on page load if there are pending migrations.
+  config.active_record.migration_error = :page_load
+
+  # Debug mode disables concatenation and preprocessing of assets.
+  # This option may cause significant delays in view rendering with a large
+  # number of complex assets.
+  config.assets.debug = true
+
+  # Adds additional error checking when serving assets at runtime.
+  # Checks for improperly declared sprockets dependencies.
+  # Raises helpful error messages.
+  config.assets.raise_runtime_errors = true
+
+  # Raises error for missing translations
+  # config.action_view.raise_on_missing_translations = true
+end
diff --git a/test/dummy/config/environments/production.rb b/test/dummy/config/environments/production.rb
new file mode 100644
index 0000000..b93a877
--- /dev/null
+++ b/test/dummy/config/environments/production.rb
@@ -0,0 +1,78 @@
+Rails.application.configure do
+  # Settings specified here will take precedence over those in config/application.rb.
+
+  # Code is not reloaded between requests.
+  config.cache_classes = true
+
+  # Eager load code on boot. This eager loads most of Rails and
+  # your application in memory, allowing both threaded web servers
+  # and those relying on copy on write to perform better.
+  # Rake tasks automatically ignore this option for performance.
+  config.eager_load = true
+
+  # Full error reports are disabled and caching is turned on.
+  config.consider_all_requests_local       = false
+  config.action_controller.perform_caching = true
+
+  # Enable Rack::Cache to put a simple HTTP cache in front of your application
+  # Add `rack-cache` to your Gemfile before enabling this.
+  # For large-scale production use, consider using a caching reverse proxy like nginx, varnish or squid.
+  # config.action_dispatch.rack_cache = true
+
+  # Disable Rails's static asset server (Apache or nginx will already do this).
+  config.serve_static_assets = false
+
+  # Compress JavaScripts and CSS.
+  config.assets.js_compressor = :uglifier
+  # config.assets.css_compressor = :sass
+
+  # Do not fallback to assets pipeline if a precompiled asset is missed.
+  config.assets.compile = false
+
+  # Generate digests for assets URLs.
+  config.assets.digest = true
+
+  # `config.assets.precompile` and `config.assets.version` have moved to config/initializers/assets.rb
+
+  # Specifies the header that your server uses for sending files.
+  # config.action_dispatch.x_sendfile_header = "X-Sendfile" # for apache
+  # config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for nginx
+
+  # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies.
+  # config.force_ssl = true
+
+  # Set to :debug to see everything in the log.
+  config.log_level = :info
+
+  # Prepend all log lines with the following tags.
+  # config.log_tags = [ :subdomain, :uuid ]
+
+  # Use a different logger for distributed setups.
+  # config.logger = ActiveSupport::TaggedLogging.new(SyslogLogger.new)
+
+  # Use a different cache store in production.
+  # config.cache_store = :mem_cache_store
+
+  # Enable serving of images, stylesheets, and JavaScripts from an asset server.
+  # config.action_controller.asset_host = "http://assets.example.com"
+
+  # Ignore bad email addresses and do not raise email delivery errors.
+  # Set this to true and configure the email server for immediate delivery to raise delivery errors.
+  # config.action_mailer.raise_delivery_errors = false
+
+  # Enable locale fallbacks for I18n (makes lookups for any locale fall back to
+  # the I18n.default_locale when a translation cannot be found).
+  config.i18n.fallbacks = true
+
+  # Send deprecation notices to registered listeners.
+  config.active_support.deprecation = :notify
+
+  # Disable automatic flushing of the log to improve performance.
+  # config.autoflush_log = false
+
+  # Use default logging formatter so that PID and timestamp are not suppressed.
+  config.log_formatter = ::Logger::Formatter.new
+
+  # Do not dump schema after migrations.
+  config.active_record.dump_schema_after_migration = false
+end
diff --git a/test/dummy/config/environments/test.rb b/test/dummy/config/environments/test.rb
new file mode 100644
index 0000000..053f5b6
--- /dev/null
+++ b/test/dummy/config/environments/test.rb
@@ -0,0 +1,39 @@
+Rails.application.configure do
+  # Settings specified here will take precedence over those in config/application.rb.
+
+  # The test environment is used exclusively to run your application's
+  # test suite. You never need to work with it otherwise. Remember that
+  # your test database is "scratch space" for the test suite and is wiped
+  # and recreated between test runs. Don't rely on the data there!
+  config.cache_classes = true
+
+  # Do not eager load code on boot. This avoids loading your whole application
+  # just for the purpose of running a single test. If you are using a tool that
+  # preloads Rails for running tests, you may have to set it to true.
+  config.eager_load = false
+
+  # Configure static asset server for tests with Cache-Control for performance.
+  config.serve_static_assets  = true
+  config.static_cache_control = 'public, max-age=3600'
+
+  # Show full error reports and disable caching.
+  config.consider_all_requests_local       = true
+  config.action_controller.perform_caching = false
+
+  # Raise exceptions instead of rendering exception templates.
+  config.action_dispatch.show_exceptions = false
+
+  # Disable request forgery protection in test environment.
+  config.action_controller.allow_forgery_protection = false
+
+  # Tell Action Mailer not to deliver emails to the real world.
+  # The :test delivery method accumulates sent emails in the
+  # ActionMailer::Base.deliveries array.
+  config.action_mailer.delivery_method = :test
+
+  # Print deprecation notices to the stderr.
+  config.active_support.deprecation = :stderr
+
+  # Raises error for missing translations
+  # config.action_view.raise_on_missing_translations = true
+end
diff --git a/test/dummy/config/initializers/assets.rb b/test/dummy/config/initializers/assets.rb
new file mode 100644
index 0000000..d2f4ec3
--- /dev/null
+++ b/test/dummy/config/initializers/assets.rb
@@ -0,0 +1,8 @@
+# Be sure to restart your server when you modify this file.
+
+# Version of your assets, change this if you want to expire all your assets.
+Rails.application.config.assets.version = '1.0'
+
+# Precompile additional assets.
+# application.js, application.css, and all non-JS/CSS in app/assets folder are already added.
+# Rails.application.config.assets.precompile += %w( search.js )
diff --git a/test/dummy/config/initializers/backtrace_silencers.rb b/test/dummy/config/initializers/backtrace_silencers.rb
new file mode 100644
index 0000000..59385cd
--- /dev/null
+++ b/test/dummy/config/initializers/backtrace_silencers.rb
@@ -0,0 +1,7 @@
+# Be sure to restart your server when you modify this file.
+
+# You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces.
+# Rails.backtrace_cleaner.add_silencer { |line| line =~ /my_noisy_library/ }
+
+# You can also remove all the silencers if you're trying to debug a problem that might stem from framework code.
+# Rails.backtrace_cleaner.remove_silencers!
diff --git a/test/dummy/config/initializers/cookies_serializer.rb b/test/dummy/config/initializers/cookies_serializer.rb
new file mode 100644
index 0000000..7a06a89
--- /dev/null
+++ b/test/dummy/config/initializers/cookies_serializer.rb
@@ -0,0 +1,3 @@
+# Be sure to restart your server when you modify this file.
+
+Rails.application.config.action_dispatch.cookies_serializer = :json
\ No newline at end of file
diff --git a/test/dummy/config/initializers/filter_parameter_logging.rb b/test/dummy/config/initializers/filter_parameter_logging.rb
new file mode 100644
index 0000000..4a994e1
--- /dev/null
+++ b/test/dummy/config/initializers/filter_parameter_logging.rb
@@ -0,0 +1,4 @@
+# Be sure to restart your server when you modify this file.
+
+# Configure sensitive parameters which will be filtered from the log file.
+Rails.application.config.filter_parameters += [:password]
diff --git a/test/dummy/config/initializers/inflections.rb b/test/dummy/config/initializers/inflections.rb
new file mode 100644
index 0000000..ac033bf
--- /dev/null
+++ b/test/dummy/config/initializers/inflections.rb
@@ -0,0 +1,16 @@
+# Be sure to restart your server when you modify this file.
+
+# Add new inflection rules using the following format. Inflections
+# are locale specific, and you may define rules for as many different
+# locales as you wish. All of these examples are active by default:
+# ActiveSupport::Inflector.inflections(:en) do |inflect|
+#   inflect.plural /^(ox)$/i, '\1en'
+#   inflect.singular /^(ox)en/i, '\1'
+#   inflect.irregular 'person', 'people'
+#   inflect.uncountable %w( fish sheep )
+# end
+
+# These inflection rules are supported but not enabled by default:
+# ActiveSupport::Inflector.inflections(:en) do |inflect|
+#   inflect.acronym 'RESTful'
+# end
diff --git a/test/dummy/config/initializers/mime_types.rb b/test/dummy/config/initializers/mime_types.rb
new file mode 100644
index 0000000..dc18996
--- /dev/null
+++ b/test/dummy/config/initializers/mime_types.rb
@@ -0,0 +1,4 @@
+# Be sure to restart your server when you modify this file.
+
+# Add new mime types for use in respond_to blocks:
+# Mime::Type.register "text/richtext", :rtf
diff --git a/test/dummy/config/initializers/session_store.rb b/test/dummy/config/initializers/session_store.rb
new file mode 100644
index 0000000..e766b67
--- /dev/null
+++ b/test/dummy/config/initializers/session_store.rb
@@ -0,0 +1,3 @@
+# Be sure to restart your server when you modify this file.
+
+Rails.application.config.session_store :cookie_store, key: '_dummy_session'
diff --git a/test/dummy/config/initializers/wrap_parameters.rb b/test/dummy/config/initializers/wrap_parameters.rb
new file mode 100644
index 0000000..33725e9
--- /dev/null
+++ b/test/dummy/config/initializers/wrap_parameters.rb
@@ -0,0 +1,14 @@
+# Be sure to restart your server when you modify this file.
+
+# This file contains settings for ActionController::ParamsWrapper which
+# is enabled by default.
+
+# Enable parameter wrapping for JSON. You can disable this by setting :format to an empty array.
+ActiveSupport.on_load(:action_controller) do
+  wrap_parameters format: [:json] if respond_to?(:wrap_parameters)
+end
+
+# To enable root element in JSON for ActiveRecord objects.
+# ActiveSupport.on_load(:active_record) do
+#  self.include_root_in_json = true
+# end
diff --git a/test/dummy/config/locales/en.yml b/test/dummy/config/locales/en.yml
new file mode 100644
index 0000000..0653957
--- /dev/null
+++ b/test/dummy/config/locales/en.yml
@@ -0,0 +1,23 @@
+# Files in the config/locales directory are used for internationalization
+# and are automatically loaded by Rails. If you want to use locales other
+# than English, add the necessary files in this directory.
+#
+# To use the locales, use `I18n.t`:
+#
+#     I18n.t 'hello'
+#
+# In views, this is aliased to just `t`:
+#
+#     <%= t('hello') %>
+#
+# To use a different locale, set it with `I18n.locale`:
+#
+#     I18n.locale = :es
+#
+# This would use the information in config/locales/es.yml.
+#
+# To learn more, please read the Rails Internationalization guide
+# available at http://guides.rubyonrails.org/i18n.html.
+
+en:
+  hello: "Hello world"
diff --git a/test/dummy/config/routes.rb b/test/dummy/config/routes.rb
new file mode 100644
index 0000000..a8c549a
--- /dev/null
+++ b/test/dummy/config/routes.rb
@@ -0,0 +1,4 @@
+Rails.application.routes.draw do
+
+  mount Feeds::Engine => "/feeds"
+end
diff --git a/test/dummy/config/secrets.yml b/test/dummy/config/secrets.yml
new file mode 100644
index 0000000..65a977d
--- /dev/null
+++ b/test/dummy/config/secrets.yml
@@ -0,0 +1,22 @@
+# Be sure to restart your server when you modify this file.
+
+# Your secret key is used for verifying the integrity of signed cookies.
+# If you change this key, all old signed cookies will become invalid!
+
+# Make sure the secret is at least 30 characters and all random,
+# no regular words or you'll be exposed to dictionary attacks.
+# You can use `rake secret` to generate a secure secret key.
+
+# Make sure the secrets in this file are kept private
+# if you're sharing your code publicly.
+
+development:
+  secret_key_base: 14de5c9504b3f0ae7827d29e10ecc00fd2b114eb22b76d93211429287b03eba069448a3c60652e3fe4d655e7bbd6f052463b29a21f5930daff334c43e971af80
+
+test:
+  secret_key_base: a55e86cffcef5a6ed97566f7fe5fb2bd1dd0ede5d85272cb8c1b78571319181588d4780caf6be7f3cc93ea3377f9ab63174d4ab4afb4b60b2b999b69e3f4282a
+
+# Do not keep production secrets in the repository,
+# instead read values from the environment.
+production:
+  secret_key_base: <%= ENV["SECRET_KEY_BASE"] %>
diff --git a/test/dummy/lib/assets/.keep b/test/dummy/lib/assets/.keep
new file mode 100644
index 0000000..e69de29
diff --git a/test/dummy/log/.keep b/test/dummy/log/.keep
new file mode 100644
index 0000000..e69de29
diff --git a/test/dummy/public/404.html b/test/dummy/public/404.html
new file mode 100644
index 0000000..b612547
--- /dev/null
+++ b/test/dummy/public/404.html
@@ -0,0 +1,67 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <title>The page you were looking for doesn't exist (404)</title>
+  <meta name="viewport" content="width=device-width,initial-scale=1">
+  <style>
+  body {
+    background-color: #EFEFEF;
+    color: #2E2F30;
+    text-align: center;
+    font-family: arial, sans-serif;
+    margin: 0;
+  }
+
+  div.dialog {
+    width: 95%;
+    max-width: 33em;
+    margin: 4em auto 0;
+  }
+
+  div.dialog > div {
+    border: 1px solid #CCC;
+    border-right-color: #999;
+    border-left-color: #999;
+    border-bottom-color: #BBB;
+    border-top: #B00100 solid 4px;
+    border-top-left-radius: 9px;
+    border-top-right-radius: 9px;
+    background-color: white;
+    padding: 7px 12% 0;
+    box-shadow: 0 3px 8px rgba(50, 50, 50, 0.17);
+  }
+
+  h1 {
+    font-size: 100%;
+    color: #730E15;
+    line-height: 1.5em;
+  }
+
+  div.dialog > p {
+    margin: 0 0 1em;
+    padding: 1em;
+    background-color: #F7F7F7;
+    border: 1px solid #CCC;
+    border-right-color: #999;
+    border-left-color: #999;
+    border-bottom-color: #999;
+    border-bottom-left-radius: 4px;
+    border-bottom-right-radius: 4px;
+    border-top-color: #DADADA;
+    color: #666;
+    box-shadow: 0 3px 8px rgba(50, 50, 50, 0.17);
+  }
+  </style>
+</head>
+
+<body>
+  <!-- This file lives in public/404.html -->
+  <div class="dialog">
+    <div>
+      <h1>The page you were looking for doesn't exist.</h1>
+      <p>You may have mistyped the address or the page may have moved.</p>
+    </div>
+    <p>If you are the application owner check the logs for more information.</p>
+  </div>
+</body>
+</html>
diff --git a/test/dummy/public/422.html b/test/dummy/public/422.html
new file mode 100644
index 0000000..a21f82b
--- /dev/null
+++ b/test/dummy/public/422.html
@@ -0,0 +1,67 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <title>The change you wanted was rejected (422)</title>
+  <meta name="viewport" content="width=device-width,initial-scale=1">
+  <style>
+  body {
+    background-color: #EFEFEF;
+    color: #2E2F30;
+    text-align: center;
+    font-family: arial, sans-serif;
+    margin: 0;
+  }
+
+  div.dialog {
+    width: 95%;
+    max-width: 33em;
+    margin: 4em auto 0;
+  }
+
+  div.dialog > div {
+    border: 1px solid #CCC;
+    border-right-color: #999;
+    border-left-color: #999;
+    border-bottom-color: #BBB;
+    border-top: #B00100 solid 4px;
+    border-top-left-radius: 9px;
+    border-top-right-radius: 9px;
+    background-color: white;
+    padding: 7px 12% 0;
+    box-shadow: 0 3px 8px rgba(50, 50, 50, 0.17);
+  }
+
+  h1 {
+    font-size: 100%;
+    color: #730E15;
+    line-height: 1.5em;
+  }
+
+  div.dialog > p {
+    margin: 0 0 1em;
+    padding: 1em;
+    background-color: #F7F7F7;
+    border: 1px solid #CCC;
+    border-right-color: #999;
+    border-left-color: #999;
+    border-bottom-color: #999;
+    border-bottom-left-radius: 4px;
+    border-bottom-right-radius: 4px;
+    border-top-color: #DADADA;
+    color: #666;
+    box-shadow: 0 3px 8px rgba(50, 50, 50, 0.17);
+  }
+  </style>
+</head>
+
+<body>
+  <!-- This file lives in public/422.html -->
+  <div class="dialog">
+    <div>
+      <h1>The change you wanted was rejected.</h1>
+      <p>Maybe you tried to change something you didn't have access to.</p>
+    </div>
+    <p>If you are the application owner check the logs for more information.</p>
+  </div>
+</body>
+</html>
diff --git a/test/dummy/public/500.html b/test/dummy/public/500.html
new file mode 100644
index 0000000..061abc5
--- /dev/null
+++ b/test/dummy/public/500.html
@@ -0,0 +1,66 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <title>We're sorry, but something went wrong (500)</title>
+  <meta name="viewport" content="width=device-width,initial-scale=1">
+  <style>
+  body {
+    background-color: #EFEFEF;
+    color: #2E2F30;
+    text-align: center;
+    font-family: arial, sans-serif;
+    margin: 0;
+  }
+
+  div.dialog {
+    width: 95%;
+    max-width: 33em;
+    margin: 4em auto 0;
+  }
+
+  div.dialog > div {
+    border: 1px solid #CCC;
+    border-right-color: #999;
+    border-left-color: #999;
+    border-bottom-color: #BBB;
+    border-top: #B00100 solid 4px;
+    border-top-left-radius: 9px;
+    border-top-right-radius: 9px;
+    background-color: white;
+    padding: 7px 12% 0;
+    box-shadow: 0 3px 8px rgba(50, 50, 50, 0.17);
+  }
+
+  h1 {
+    font-size: 100%;
+    color: #730E15;
+    line-height: 1.5em;
+  }
+
+  div.dialog > p {
+    margin: 0 0 1em;
+    padding: 1em;
+    background-color: #F7F7F7;
+    border: 1px solid #CCC;
+    border-right-color: #999;
+    border-left-color: #999;
+    border-bottom-color: #999;
+    border-bottom-left-radius: 4px;
+    border-bottom-right-radius: 4px;
+    border-top-color: #DADADA;
+    color: #666;
+    box-shadow: 0 3px 8px rgba(50, 50, 50, 0.17);
+  }
+  </style>
+</head>
+
+<body>
+  <!-- This file lives in public/500.html -->
+  <div class="dialog">
+    <div>
+      <h1>We're sorry, but something went wrong.</h1>
+    </div>
+    <p>If you are the application owner check the logs for more information.</p>
+  </div>
+</body>
+</html>
diff --git a/test/dummy/public/favicon.ico b/test/dummy/public/favicon.ico
new file mode 100644
index 0000000..e69de29
diff --git a/test/feeds_test.rb b/test/feeds_test.rb
new file mode 100644
index 0000000..e16a236
--- /dev/null
+++ b/test/feeds_test.rb
@@ -0,0 +1,7 @@
+require 'test_helper'
+
+class FeedsTest < ActiveSupport::TestCase
+  test "truth" do
+    assert_kind_of Module, Feeds
+  end
+end
diff --git a/test/integration/navigation_test.rb b/test/integration/navigation_test.rb
new file mode 100644
index 0000000..97a94c9
--- /dev/null
+++ b/test/integration/navigation_test.rb
@@ -0,0 +1,10 @@
+require 'test_helper'
+
+class NavigationTest < ActionDispatch::IntegrationTest
+  fixtures :all
+
+  # test "the truth" do
+  #   assert true
+  # end
+end
+
diff --git a/test/test_helper.rb b/test/test_helper.rb
new file mode 100644
index 0000000..a553d9a
--- /dev/null
+++ b/test/test_helper.rb
@@ -0,0 +1,19 @@
+# Configure Rails Environment
+ENV["RAILS_ENV"] = "test"
+
+require File.expand_path("../../test/dummy/config/environment.rb",  __FILE__)
+ActiveRecord::Migrator.migrations_paths = [File.expand_path("../../test/dummy/db/migrate", __FILE__)]
+ActiveRecord::Migrator.migrations_paths << File.expand_path('../../db/migrate', __FILE__)
+require "rails/test_help"
+
+# Filter out Minitest backtrace while allowing backtrace from other libraries
+# to be shown.
+Minitest.backtrace_filter = Minitest::BacktraceFilter.new
+
+# Load support files
+Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |f| require f }
+
+# Load fixtures from the engine
+if ActiveSupport::TestCase.method_defined?(:fixture_path=)
+  ActiveSupport::TestCase.fixture_path = File.expand_path("../fixtures", __FILE__)
+end