Browse files

Final changes on notifications with testing on rspec included

  • Loading branch information...
1 parent c7772af commit 93e624c5ff91e051e8fe9ce85ea7e42767dec359 @adriancuadros adriancuadros committed Sep 9, 2011
View
7 app/assets/javascripts/kublog/email.js.coffee
@@ -3,10 +3,13 @@ $(document).ready ->
### Special Optional fields are not shown on check, but only enabled ###
$('#kublog .email_checkbox').change ->
$optional = $(this).siblings('.optional')
+ $optional_lightbox = $(this).siblings('.optional_lightbox')
if $(this).attr('checked')?
- $optional.find('[disabled]').attr('disabled', false)
+ $optional.show().find('[disabled]').attr('disabled', false)
+ $optional_lightbox.find('[disabled]').attr('disabled', false)
else
- $optional.find('textarea, input').attr('disabled', true)
+ $optional.hide().find('textarea, input').attr('disabled', true)
+ $optional_lightbox.find('textarea, input').attr('disabled', true)
## Notification Preview
$('#kublog .submit_fancybox').fancybox
View
18 app/models/kublog/category.rb
@@ -1,3 +1,6 @@
+# Non mandatory single category for a post
+# implements friendly_id search and json defaults
+# for ajax editing
module Kublog
class Category < ActiveRecord::Base
extend FriendlyId
@@ -13,13 +16,18 @@ def to_s
self.name.titleize
end
- # Site access to the category
- def path
- Engine.routes.url_helpers.category_path(self)
+ # Includes a path to the category by default
+ # helps reference back to edited categories in
+ # json requests
+ def as_json(params={})
+ params||={}
+ super(params.merge!({:methods => [:path]}))
end
- def as_json(params={})
- super params.merge({:methods => [:path]})
+ protected
+
+ def path
+ Engine.routes.url_helpers.category_path(self)
end
end
View
14 app/models/kublog/comment.rb
@@ -15,21 +15,21 @@ def author
return self.user.to_s
end
- # Site access to the category
- def path
- Engine.routes.url_helpers.post_comment_path(self.post, self)
+ def as_json(args={})
+ args ||={}
+ super(args.merge!({:methods => [:path, :author, :ftime, :admin?]}))
end
- def as_json(options={})
- super(options.merge({:methods => [:path, :author, :ftime, :admin?]}))
+
+
+ def path
+ Engine.routes.url_helpers.post_comment_path(self.post, self)
end
def ftime
I18n.l(self.created_at, :format => :short)
end
-
private
-
def has_user_details
if self.user.nil?
errors.add(:author_name, :blank) if author_name.blank?
View
4 app/models/kublog/notification.rb
@@ -9,7 +9,7 @@ class Notification < ActiveRecord::Base
validates_presence_of :kind
after_create :deliver
- serialize :roles, Hash
+ serialize :roles, Array
delegate :title, :url, :to => :post
@@ -20,7 +20,7 @@ def default?
private
def deliver
- self.send "deliver_#{kind}"
+ self.send "deliver_#{kind}" if respond_to?("deliver_#{kind}")
end
end
View
1 app/models/kublog/post.rb
@@ -2,7 +2,6 @@
module Kublog
class Post < ActiveRecord::Base
extend FriendlyId
- #include Notifiable::Email, Notifiable::Tweet, Notifiable::FbPost
#Associations
belongs_to :user, :class_name => Kublog.author_class
View
2 app/presenters/kublog/posts_presenter.rb
@@ -18,7 +18,7 @@ def title
end
def updated
- self.posts.first.try(:updated_at)
+ self.posts.first.try(:updated_at) - 1.seconds
end
def ftime(updated)
View
17 app/views/kublog/posts/_email_form.html.erb
@@ -1,8 +1,21 @@
<div class='field'>
<%= check_box_tag :email_notify, 1, notification.default?,
:checked => false, :class => 'email_checkbox' %>
- <%= label_tag :email_notify, t('.email_notification') %>
- <div style='display:none' class='optional'>
+ <%= label_tag :email_notify, t('.email_notification') %>
+ <% unless user_kinds.empty? %>
+ <div class='optional'>
+ <ul>
+ <% user_kinds.each do |user_kind|%>
+ <li>
+ <%= check_box_tag "#{nf.object_name}[roles][]", user_kind, nil,
+ :id => "post_intended_for_#{user_kind}" %>
+ <%= label_tag "#{nf.object_name}[roles][#{user_kind}]", user_kind.titleize %>
+ </li>
+ <% end %>
+ </ul>
+ </div>
+ <% end %>
+ <div style='display:none' class='optional_lightbox'>
<%= nf.hidden_field :kind, :disabled => !notification.default? %>
<%= link_to '#', '#email-template', :class => 'submit_fancybox', :id => 'link-to-email-template' %>
<div id="email-template">
View
3 app/views/kublog/posts/index.atom.builder
@@ -3,10 +3,9 @@ atom_feed do |feed|
feed.updated @presenter.updated
@presenter.posts.each do |post|
feed.entry(post) do |entry|
- entry.url post.url
+ entry.link(:href => post.url)
entry.title post.title
entry.content post.body, :type => 'html'
- entry.updated_at @presenter.ftime(post.updated_at)
entry.author do |author|
author.name post.user.to_s
end
View
1 db/migrate/20110901205127_create_kublog_notifications.rb
@@ -8,6 +8,7 @@ def change
t.references :post
t.datetime :sent_at
t.datetime :created_at
+ t.text :roles
t.integer :times_delivered, :default => 0
end
View
10 index.html
@@ -0,0 +1,10 @@
+<!doctype html><html><head><meta http-equiv="content-type" content="text/html; charset=ISO-8859-1"><title>Google</title><script>window.google={kEI:"ZT1oTrrUHumLsgKAoujyCw",getEI:function(a){var b;while(a&&!(a.getAttribute&&(b=a.getAttribute("eid"))))a=a.parentNode;return b||google.kEI},kEXPI:"28936,29774,30542,32214,32605",kCSI:{e:"28936,29774,30542,32214,32605",ei:"ZT1oTrrUHumLsgKAoujyCw",expi:"28936,29774,30542,32214,32605"},authuser:0,ml:function(){},kHL:"es-419",time:function(){return(new Date).getTime()},log:function(a,b,c,e){var d=new Image,f=google,h=f.lc,g=f.li,i="";d.onerror=(d.onload=(d.onabort=function(){delete h[g]}));h[g]=d;if(!c&&b.search("&ei=")==-1)i="&ei="+google.getEI(e);var j=c||"/gen_204?atyp=i&ct="+a+"&cad="+b+i+"&zx="+google.time();d.src=j;f.li=g+1},lc:[],li:0,Toolbelt:{},y:{},x:function(a,b){google.y[a.id]=[a,b];return false}};
+window.google.sn="webhp";var i=window.google.timers={};window.google.startTick=function(a,b){i[a]={t:{start:(new Date).getTime()},bfr:!(!b)}};window.google.tick=function(a,b,c){if(!i[a])google.startTick(a);i[a].t[b]=c||(new Date).getTime()};google.startTick("load",true);try{}catch(v){}
+var _gjwl=location;function _gjuc(){var e=_gjwl.href.indexOf("#");if(e>=0){var a=_gjwl.href.substring(e);if(a.indexOf("&q=")>0||a.indexOf("#q=")>=0){a=a.substring(1);if(a.indexOf("#")==-1){for(var c=0;c<a.length;){var d=c;if(a.charAt(d)=="&")++d;var b=a.indexOf("&",d);if(b==-1)b=a.length;var f=a.substring(d,b);if(f.indexOf("fp=")==0){a=a.substring(0,c)+a.substring(b,a.length);b=c}else if(f=="cad=h")return 0;c=b}_gjwl.href="/search?"+a+"&cad=h";return 1}}}return 0}function _gjp(){!(window._gjwl.hash&&
+window._gjuc())&&setTimeout(_gjp,500)};
+window._gjp && _gjp()</script><style id=gstyle>body{margin:0;overflow-y:scroll}#gog{padding:3px 8px 0}td{line-height:.8em}.gac_m td{line-height:17px}form{margin-bottom:20px}body,td,a,p,.h{font-family:arial,sans-serif}.h{color:#36c;font-size:20px}.q{color:#00c}.ts td{padding:0}.ts{border-collapse:collapse}em{font-weight:bold;font-style:normal}.lst{height:25px;width:496px}.gsfi,.lst{font:18px arial,sans-serif}.gsfs{font:17px arial,sans-serif}.ds{border-bottom:solid 1px #e7e7e7;border-right:solid 1px #e7e7e7;display:-moz-inline-box;display:inline-block;margin:3px 0 4px;margin-left:4px}input{font-family:inherit}a.gb1,a.gb2,a.gb3,a.gb4{color:#11c !important}#gbar,#guser{font-size:13px;padding-top:1px !important}#gbar{height:22px}#guser{padding-bottom:7px !important;text-align:right}.gbh,.gbd{border-top:1px solid #c9d7f1;font-size:1px}.gbh{height:0;position:absolute;top:24px;width:100%}@media all{.gb1{height:22px;margin-right:.5em;vertical-align:top}#gbar{float:left}}a.gb1,a.gb4{text-decoration:underline !important}a.gb1,a.gb4{color:#00c !important}body{background:#fff;color:black}input{-moz-box-sizing:content-box}a{color:#11c;text-decoration:none}a:hover,a:active{text-decoration:underline}.fl a{color:#36c}a:visited{color:#551a8b}a.gb1,a.gb4{text-decoration:underline}a.gb3:hover{text-decoration:none}#ghead a.gb2:hover{color:#fff!important}.sblc{padding-top:5px}.sblc a{display:block;margin:2px 0;margin-left:13px;font-size:11px;}.lsbb{background:#eee;border:solid 1px;border-color:#ccc #999 #999 #ccc;height:30px;display:block}.ftl,#fll a{display:inline-block;margin:0 12px}.lsb{background:url(/images/srpr/nav_logo80.png) bottom;border:none;color:#000;cursor:pointer;height:30px;margin:0;outline:0;font:15px arial,sans-serif;vertical-align:top}.lsb:active{background:#ccc}.lst:focus{outline:none}#addlang a{padding:0 3px}.gac_v div{display:none}.gac_v .gac_v2,.gac_bt{display:block!important}</style><script></script></head><body bgcolor=#ffffff text=#000000 link=#0000cc vlink=#551a8b alink=#ff0000 onload="document.f&&document.f.q.focus();document.gbqf&&document.gbqf.q.focus();if(document.images)new Image().src='/images/srpr/nav_logo80.png'" ><textarea id=csi style=display:none></textarea><div id=mngb><div id=gbar><nobr><b class=gb1>La Web</b> <a class=gb1 href="http://www.google.com.mx/imghp?hl=es&tab=wi">Imágenes</a> <a class=gb1 href="http://video.google.com.mx/?hl=es&tab=wv">Vídeos</a> <a class=gb1 href="http://news.google.com.mx/nwshp?hl=es&tab=wn">Noticias</a> <a class=gb1 href="http://translate.google.com.mx/?hl=es&tab=wT">Traductor</a> <a class=gb1 href="http://books.google.com.mx/bkshp?hl=es&tab=wp">Libros</a> <a class=gb1 href="https://mail.google.com/mail/?hl=es&tab=wm">Gmail</a> <a class=gb1 style="text-decoration:none" href="http://www.google.com.mx/intl/es/options/"><u>Más</u> &raquo;</a></nobr></div><div id=guser width=100%><nobr><span id=gbn class=gbi></span><span id=gbf class=gbf></span><span id=gbe></span><a href="/preferences?hl=es-419" class=gb4>Configuración</a> | <a href="https://www.google.com/accounts/ServiceLogin?hl=es&continue=http://www.google.com.mx/" class=gb4>Acceder</a></nobr></div><div class=gbh style=left:0></div><div class=gbh style=right:0></div></div><center><br clear=all id=lgpd><div id=lga><div style="padding:28px 0 3px"><div align=left style="background:url(/intl/en_com/images/srpr/logo1w.png) no-repeat;height:110px;width:276px" title="Google" id=hplogo onload="window.lol&&lol()"><div nowrap style="color:#777;font-size:16px;font-weight:bold;left:214px;position:relative;top:70px">México</div></div></div><br></div><form action="/search" name=f><table cellpadding=0 cellspacing=0><tr valign=top><td width=25%>&nbsp;</td><td align=center nowrap><input name=hl type=hidden value=es-419><input name=source type=hidden value=hp><input type=hidden name=ie value="ISO-8859-1"><div class=ds style="height:32px;margin:4px 0"><input autocomplete=off maxlength=2048 name=q class="lst" title="Buscar con Google" value="" size=57 style="background:#fff;border:1px solid #ccc;border-bottom-color:#999;border-right-color:#999;color:#000;margin:0;padding:5px 8px 0 6px;vertical-align:top"></div><br style="line-height:0"><span class=ds ><span class=lsbb><input name=btnG type=submit value="Buscar con Google" class=lsb></span></span><span class=ds><span class=lsbb><input name=btnI type=submit class=lsb value="Me siento con suerte"></span></span></td><td nowrap width=25% align=left class="fl sblc"><a href="/advanced_search?hl=es-419">Búsqueda avanzada</a><a href="/language_tools?hl=es-419">Herramientas de idioma</a></td></tr></table></form><div style="font-size:83%;min-height:3.5em"><br><div id=als><font size=-1 id=addlang>Google.com.mx ofrecido en: <a href="http://www.google.com.mx/setprefs?sig=0_-GaPH3huoX3BCf-nnUfXN5Ez3MY=&amp;hl=es">español</a></font><br><br></div></div><div id=res></div><span id=footer><center id=fctr><div style="font-size:10pt"><div id=fll style="margin:19px auto;text-align:center"><a href="/intl/es-419/ads/">Programas de publicidad</a><a href="/services/">Soluciones Empresariales</a><a href="/intl/es-419/about.html">Todo acerca de Google</a><a href="http://www.google.com/ncr" class="gl nobr">Google.com in English</a></div></div><p style="color:#767676;font-size:8pt">&copy; 2011 - <a href="/intl/es-419/privacy.html">Privacidad</a></p></center></span> <div id=xjsd></div><div id=xjsi><script>if(google.y)google.y.first=[];google.dlj=function(b){window.setTimeout(function(){var a=document.createElement("script");a.src=b;document.getElementById("xjsd").appendChild(a)},0)};
+if(google.y)google.y.first=[];if(!google.xjs){google.dstr=[];google.rein=[];if(google.timers&&google.timers.load.t){google.timers.load.t.xjsls=new Date().getTime();}google.dlj('/extern_js/f/CgJlbhICdXMrMEU4ACwrMFo4ACwrMA44ACwrMBc4ACwrMDw4ACwrMFE4ACwrMJgBOAAsKzAKOABAiwEsKzAWOAAsKzAZOAAsKzAlOAAsKzBBOAAsKzBNOAAsKzBOOAAsKzBUOAAsKzBpOAAsKzCSATgALCswGDgALCswJjgALIACUJACTQ/18OygQl-cnA.js');google.xjs=1}google.neegg=1;google.mc=[];google.mc=google.mc.concat([[69,{}],[14,{}],[60,{}],[81,{}],[152,{}],[78,{}],[25,{"g":8,"k":false,"m":{"bks":true,"blg":true,"dsc":true,"evn":true,"flm":true,"frm":true,"isch":true,"klg":true,"mbl":true,"nws":true,"plcs":true,"ppl":true,"prc":true,"pts":true,"rcp":true,"shop":true,"vid":true},"t":null}],[105,{}],[22,{"m_errors":{"32":"Lo sentimos, no hay más resultados para mostrar.","default":"\u003Cfont color=red\u003EError:\u003C/font\u003E el servidor no ha podido completar tu solicitud. Vuelve a intentarlo dentro de 30 segundos."},"m_tip":"Haz clic para obtener más información"}],[77,{}],[146,{}],[84,{}],[24,{}],[38,{}]]);google.y.first.push(function(){try{var form=document.f||document.f||document.gs||document.gbqf;google.ac.i(form,form.q,'','','',{sw:1,o:1,i:1},'hp',{"dh":true,"exp":"gsis,i18n=true","host":"google.com.mx","jsonp":true,"msgs":{"lcky":"Me siento con suerte","lml":"Más información","psrc":"Se ha eliminado esta búsqueda de tu <a href=\"/history\">Historial web</a>","psrl":"Eliminar","srch":"Buscar con Google"}});}catch(e){google.ml(e,false,{'cause':'defer'});}if(google.med){google.med('init');google.initHistory();google.med('history');}google.History&&google.History.initialize('/')});if(google.j&&google.j.en&&google.j.xi){window.setTimeout(google.j.xi,0);}</script></div><script>(function(){var a,b=window.location.href.match(/\/webhp\?[^#]*tune=[^#]*/);if(a=b&&b.length>0?"http://www.google.com/logos/2011/lespaul.html#"+b[0].substr(7):null)google.nav&&google.nav.go?google.nav.go(a):window.location.href=a;})();</script><script>(function(){
+var b,d,e,f;function g(a,c){if(a.removeEventListener){a.removeEventListener("load",c,false);a.removeEventListener("error",c,false)}else{a.detachEvent("onload",c);a.detachEvent("onerror",c)}}function h(a){f=(new Date).getTime();++d;a=a||window.event;var c=a.target||a.srcElement;g(c,h)}var i=document.getElementsByTagName("img");b=i.length;d=0;for(var j=0,k;j<b;++j){k=i[j];if(k.complete||typeof k.src!="string"||!k.src)++d;else if(k.addEventListener){k.addEventListener("load",h,false);k.addEventListener("error",
+h,false)}else{k.attachEvent("onload",h);k.attachEvent("onerror",h)}}e=b-d;function l(){if(!google.timers.load.t)return;google.timers.load.t.ol=(new Date).getTime();google.timers.load.t.iml=f;google.kCSI.imc=d;google.kCSI.imn=b;google.kCSI.imp=e;google.timers.load.t.xjs&&google.report&&google.report(google.timers.load,google.kCSI)}if(window.addEventListener)window.addEventListener("load",l,false);else if(window.attachEvent)window.attachEvent("onload",l);google.timers.load.t.prt=(f=(new Date).getTime());
+})();
+</script>
View
4 lib/kublog.rb
@@ -99,10 +99,6 @@ def self.twitter
yield @@twitter_client
end
- def self.asset_path(path)
- ["/assets", self.root_path , path].join
- end
-
def self.root_path
Engine.routes.url_helpers.root_path
end
View
5 lib/kublog/author.rb
@@ -1,6 +1,5 @@
-# Module to be included in user that enables him to be
-# published in Posts
-
+# Include module in the model to be referenced as author in the post
+# Gives the author an association to every post he has published
module Kublog
module Author
View
1 lib/kublog/engine.rb
@@ -1,3 +1,4 @@
+## Sets up the engine with an isolated namespace
module Kublog
class Engine < Rails::Engine
isolate_namespace Kublog
View
22 lib/kublog/network/email.rb
@@ -1,6 +1,5 @@
-# This class includes the interface to all the different
-# Delivery methods and requires the one that the user chose
-# in the configuration File
+# Sets up email delivery method for the notification model
+# Includes validations of non blank email content
module Kublog
module Network
@@ -16,18 +15,18 @@ def self.included(base)
module InstanceMethods
+ # Calls appropriate processor to process e-mail sending to the
+ # bulk of users
def deliver_email
Processor.work(BulkEmail.new(self))
end
- def kublog_email?(role)
- roles.include?(role)
- end
-
+ # Never send e-mail notification by default
def default_email
false
end
+ # Returns true if notification acts as e-mail
def email?
self.kind == 'email'
end
@@ -42,10 +41,15 @@ def valid_email_content
module ClassMethods
+ # Renders a preview of the e-mail that will be sent to the user
+ # so that the Author can edit the content of the e-mail on a Liquid Template
def email_template(post)
ERB.new(email_erb_template.read).result(binding)
end
+ private
+
+
def email_erb_template
if File.exists?(File.join(Rails.root, TEMPLATE))
File.open(File.join(Rails.root, TEMPLATE))
@@ -63,6 +67,9 @@ def initialize(notification)
@post = notification.post
end
+ # Processes sending email to bunch of users if appropriate
+ # calls notify_post? on every user to determine whether or not
+ # to send e-mail
def perform
klass = eval(Kublog.notify_class)
klass.all.each do |user|
@@ -86,6 +93,7 @@ def initialize(notification, user)
@user = user
end
+ # Sends a single e-mail to the user
def perform
PostMailer.new_post(self, @user).deliver
end
View
9 lib/kublog/network/facebook.rb
@@ -8,15 +8,20 @@ def self.included(base)
end
module InstanceMethods
-
+
+ # Calls the appropriate processor on create callback
+ # Posts on the fan page wall a link to the post
def deliver_facebook
Processor.work(WallPost.new(self.url, self.content))
end
+ # Defaults to create a facebook wall post when creating a post
+ # off by default when editing a post
def default_facebook
post.new_record?
end
+ # Returns true when notification acts as facebook notification
def facebook?
self.kind == 'facebook'
end
@@ -36,6 +41,8 @@ def initialize(url, message)
@message = message
end
+ # Posts a link to the post with the title of the content of the notification
+ # as a default message
def perform
Kublog.facebook_client.link! :link => @url, :message => @message
end
View
9 lib/kublog/network/twitter.rb
@@ -8,20 +8,27 @@ def self.included(base)
end
module InstanceMethods
+
+ # Calls processor to work on delivering the tweet
def deliver_twitter
Processor.work(Tweet.new(self.content, self.url))
end
-
+
+ # It's activated by default when a new post is created
+ # but not when editing the post
def default_twitter
post.new_record?
end
+ # Returns true when the notification behaves like a twitter
+ # notification
def twitter?
self.kind == 'twitter'
end
private
+ # Not valid when tweet content is empty
def valid_twitter_content
errors.add(:content, :twitter) if self.content.blank?
end
View
4 lib/kublog/notifiable.rb
@@ -7,10 +7,6 @@ module Notifiable
def self.included(base)
Kublog.notify_class = base.name
- base.class_eval do
- @@kublog_notifiable = true
- cattr_accessor :kublog_notifiable
- end
base.send :include, InstanceMethods
end
View
13 lib/kublog/processor.rb
@@ -1,18 +1,27 @@
+# Processes any given task with the method specified in the configuration
+# Currently the available processing methods are
+#
+# config.notification_processing = :immediate
+# config.notification_processing = :delayed_job
module Kublog
module Processor
+ # Proxy method that calls the configuration specified processor
def self.work(task)
- self.send Kublog.notification_processing, task
+ self.send(Kublog.notification_processing, task)
end
+ private
+
+ # Immediately calls perform on the task given (No background processing)
def self.immediate(task)
task.perform
end
+ # Should create a new Job for processing with DeleyedJob
def self.delayed_job(task)
Delayed::Job.enqueue(task)
end
-
end
end
View
1 spec/dummy/db/schema.rb
@@ -67,6 +67,7 @@
t.integer "post_id"
t.datetime "sent_at"
t.datetime "created_at"
+ t.text "roles"
t.integer "times_delivered", :default => 0
end
View
BIN spec/dummy/db/test.sqlite3
Binary file not shown.
View
6,983 spec/dummy/log/test.log
6,983 additions, 0 deletions not shown because the diff is too large. Please use a local Git client to view these changes.
View
33 spec/factories.rb
@@ -9,11 +9,42 @@
end
Factory.define :notification, :class=> Kublog::Notification do |f|
- f.kind 'Twitter'
+ f.kind 'fake_kind'
f.content 'Awesome post just published'
f.association :post, :factory => :post
end
+Factory.define :twitter_notification, :class => Kublog::Notification do |f|
+ f.kind 'twitter'
+ f.content 'tweet content'
+ f.association :post, :factory => :post
+end
+
+Factory.define :facebook_notification, :class => Kublog::Notification do |f|
+ f.kind 'facebook'
+ f.content 'wall post content'
+ f.association :post, :factory => :post
+end
+
+Factory.define :email_notification, :class => Kublog::Notification do |f|
+ f.kind 'email'
+ f.content 'email content for {{user}} with a link to the post {{link}}'
+ f.association :post, :factory => :post
+end
+
+Factory.define :user_comment, :class => Kublog::Comment do |f|
+ f.body 'Great stuff on the blog'
+ f.association :user, :factory => :user
+ f.association :post, :factory => :post
+end
+
+Factory.define :anonymous_comment, :class => Kublog::Comment do |f|
+ f.body 'Great stuff on the site'
+ f.author_name 'Adrian Cuadros'
+ f.author_email 'adrian@innku.com'
+ f.association :post, :factory => :post
+end
+
Factory.define :user do |f|
f.name 'Adrian Cuadros'
f.sequence(:email) {|n| "adrian#{n}@innku.com" }
View
BIN spec/fixtures/Adrian.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
15 spec/fixtures/rendered_email.html
@@ -0,0 +1,15 @@
+<p>
+ Greetings {{user}},
+</p>
+
+<div>
+ Hello
+</div>
+
+<p>
+ Read More
+</p>
+
+<p>
+ <a href='{{url}}'>{{url}}</a>
+</p>
View
25 spec/lib/author_spec.rb
@@ -0,0 +1,25 @@
+require 'spec_helper'
+
+describe Kublog::Author do
+
+ class TestAuthor < ActiveRecord::Base
+ set_table_name 'users'
+ end
+
+ describe '.included' do
+
+ before :all do
+ TestAuthor.send :include, Kublog::Author
+ end
+
+ it 'sets the environment variable to the class that included the module' do
+ Kublog.author_class.should == TestAuthor.name
+ end
+
+ it 'should respond to posts' do
+ TestAuthor.new.should respond_to(:posts)
+ end
+
+ end
+
+end
View
87 spec/lib/network/email_spec.rb
@@ -0,0 +1,87 @@
+require 'spec_helper'
+
+module Kublog::Network
+ describe Email do
+
+ describe '#validate' do
+ before :all do
+ @notification = Factory.build(:email_notification)
+ end
+
+ it 'is valid with content and kind' do
+ @notification.should be_valid
+ end
+
+ it 'is invalid without tweet content' do
+ @notification.content = ''
+ @notification.should_not be_valid
+ end
+ end
+
+ describe '#email?' do
+ before :all do
+ @notification = Factory.build(:email_notification)
+ end
+
+ it 'is true when kind is twitter' do
+ @notification.email?.should == true
+ end
+
+ it 'is false when other than twitter' do
+ @notification.kind = 'twitter'
+ @notification.email?.should == false
+ end
+ end
+
+ describe '#default_email?' do
+ before :all do
+ @notification = Factory.build(:email_notification, :post => Kublog::Post.new)
+ end
+
+ it 'is false always' do
+ @notification.default_email.should == false
+ end
+ end
+
+ describe '#after_create' do
+ it 'sends emails to all users when notify_post? is default true' do
+ notification = Factory.build(:email_notification)
+ Kublog::Processor.should_receive(:work)
+ notification.save
+ end
+ end
+
+ describe '.email_template' do
+ before :all do
+ @post = Factory :post, :body => 'Hello'
+ end
+
+ it 'renders the body of the post as the template' do
+ Kublog::Notification.email_template(@post).should == Support.fixture('rendered_email.html')
+ end
+ end
+
+ describe Email::BulkEmail do
+ before :all do
+ User.destroy_all
+ 2.times { Factory(:user) }
+ @bulk_email = Email::BulkEmail.new(Factory(:email_notification))
+ end
+
+ describe '#perform' do
+ it 'sends e-mails to all users when notify_post? is true' do
+ notification = Factory.build(:email_notification)
+ Kublog::Processor.should_receive(:work).exactly(User.count).times
+ @bulk_email.perform
+ end
+
+ it 'sends e-mail to no users when notify_post? defaults to false' do
+ Support.dont_notify_users_by_default
+ @bulk_email.perform
+ Kublog::Processor.should_not_receive(:work)
+ end
+ end
+ end
+
+ end
+end
View
68 spec/lib/network/facebook_spec.rb
@@ -0,0 +1,68 @@
+require 'spec_helper'
+
+describe Kublog::Network::Facebook do
+
+ describe '#validate' do
+
+ before :all do
+ @notification = Factory.build(:facebook_notification)
+ end
+
+ it 'is valid with content and kind' do
+ @notification.should be_valid
+ end
+
+ it 'is invalid without tweet content' do
+ @notification.content = ''
+ @notification.should_not be_valid
+ end
+ end
+
+ describe '#facebook?' do
+
+ before :all do
+ @notification = Factory.build(:facebook_notification)
+ end
+
+ it 'is true when kind is twitter' do
+ @notification.facebook?.should == true
+ end
+
+ it 'is false when other than twitter' do
+ @notification.kind = 'email'
+ @notification.facebook?.should == false
+ end
+
+ end
+
+ describe 'default_twitter?' do
+
+ before :all do
+ @notification = Factory.build(:facebook_notification, :post => Kublog::Post.new)
+ end
+
+ it 'is true when building a new post' do
+ @notification.default_facebook.should == true
+ end
+
+ it 'is false when updating a post' do
+ @notification.post = Factory(:post)
+ @notification.default_facebook.should == false
+ end
+
+ end
+
+ describe '#after_create' do
+
+ before :all do
+ @notification = Factory.build(:facebook_notification, :content => 'test content')
+ @post = @notification.post
+ end
+
+ it 'should send the content of the notification + a link to the post to twitter' do
+ Kublog.facebook_client.should_receive(:link!).with(:link => @post.url, :message => 'test content')
+ @notification.save
+ end
+ end
+
+end
View
68 spec/lib/network/twitter_spec.rb
@@ -0,0 +1,68 @@
+require 'spec_helper'
+
+describe Kublog::Network::Twitter do
+
+ describe '#validate' do
+
+ before :all do
+ @notification =Factory.build(:twitter_notification)
+ end
+
+ it 'is valid with content and kind' do
+ @notification.should be_valid
+ end
+
+ it 'is invalid without tweet content' do
+ @notification.content = ''
+ @notification.should_not be_valid
+ end
+ end
+
+ describe '#twitter?' do
+
+ before :all do
+ @notification = Factory.build(:twitter_notification)
+ end
+
+ it 'is true when kind is twitter' do
+ @notification.twitter?.should == true
+ end
+
+ it 'is false when other than twitter' do
+ @notification.kind = 'facebook'
+ @notification.twitter?.should == false
+ end
+
+ end
+
+ describe 'default_twitter?' do
+
+ before :all do
+ @notification = Factory.build(:twitter_notification, :post => Kublog::Post.new)
+ end
+
+ it 'is true when building a new post' do
+ @notification.default_twitter.should == true
+ end
+
+ it 'is false when updating a post' do
+ @notification.post = Factory(:post)
+ @notification.default_twitter.should == false
+ end
+
+ end
+
+ describe '#after_create' do
+
+ before :all do
+ @notification = Factory.build(:twitter_notification, :content => 'test content')
+ @post = @notification.post
+ end
+
+ it 'should send the content of the notification + a link to the post to twitter' do
+ Kublog.twitter_client.should_receive(:update).with("test content #{@post.url}")
+ @notification.save
+ end
+ end
+
+end
View
23 spec/lib/notifiable_spec.rb
@@ -0,0 +1,23 @@
+require 'spec_helper'
+
+describe Kublog::Notifiable do
+
+ class TestUser; end
+
+ describe '.included' do
+
+ before :all do
+ TestUser.send :include, Kublog::Notifiable
+ end
+
+ it 'sets up a configuration variable for the user class to notify to' do
+ Kublog.notify_class.should == 'TestUser'
+ end
+
+ it 'defaults notify_post? to true' do
+ TestUser.new.notify_post?(Kublog::Post.new).should == true
+ end
+
+ end
+
+end
View
25 spec/lib/processor_spec.rb
@@ -0,0 +1,25 @@
+require 'spec_helper'
+
+describe Kublog::Processor do
+
+ class TestTask
+ def perform
+ true
+ end
+ end
+
+ describe '.work' do
+
+ it 'performs a task immediately if notification processing is immediate' do
+ Kublog.notification_processing = :immediate
+ Kublog::Processor.work(TestTask.new).should == true
+ end
+
+ it 'creates a job in delayed job for later processing' do
+ Kublog.notification_processing = :delayed_job
+ Kublog::Processor.work(TestTask.new).should be_an_instance_of(Delayed::Backend::ActiveRecord::Job)
+ end
+
+ end
+
+end
View
43 spec/models/kublog/category_spec.rb
@@ -0,0 +1,43 @@
+require 'spec_helper'
+
+describe Kublog::Category do
+
+ describe '#validate' do
+ before :each do
+ @category = Factory :category
+ end
+
+ it 'is valid with the mandatory attributes' do
+ @category.should be_valid
+ end
+
+ it 'is invalid without a name' do
+ @category.name = ''
+ @category.should_not be_valid
+ end
+
+ end
+
+ describe '#to_s' do
+ it 'is the titleized version of the name' do
+ Factory.build(:category, :name => 'some name').to_s.should == 'Some Name'
+ end
+ end
+
+ describe '#as_json' do
+ before :all do
+ @json = JSON.parse(Factory(:category).to_json)
+ end
+
+ it 'includes the name of the category' do
+ @json["name"].match('Features').should_not be_nil
+ end
+
+ it 'includes the path to the category' do
+ @json["path"].match(/features/).should_not be_nil
+ end
+
+ end
+
+end
+
View
56 spec/models/kublog/comment_spec.rb
@@ -0,0 +1,56 @@
+require 'spec_helper'
+
+describe Kublog::Comment do
+ describe '#validate' do
+ it 'is valid with an associated user' do
+ Factory.build(:user_comment).should be_valid
+ end
+ it 'is valid with a complete anonimous user' do
+ Factory.build(:anonymous_comment).should be_valid
+ end
+ it 'is not valid with an empty comment' do
+ Factory.build(:user_comment, :body => '').should_not be_valid
+ Factory.build(:anonymous_comment, :body => '').should_not be_valid
+ end
+ it 'is not valid to be anonymous without email' do
+ Factory.build(:anonymous_comment, :author_email => '').should_not be_valid
+ end
+ it 'is not valid to be anonymous with an invalid email' do
+ Factory.build(:anonymous_comment, :author_email => 'invalidstuff').should_not be_valid
+ end
+ it 'is not valid to be anonymous without a name' do
+ Factory.build(:anonymous_comment, :author_name => '').should_not be_valid
+ end
+ end
+
+ describe '#author' do
+ it 'is the user string version when its a user comment' do
+ comment = Factory.build(:user_comment)
+ comment.author.should == comment.user.to_s
+ end
+ it 'is the author name when an anonymous comments' do
+ comment = Factory.build(:anonymous_comment)
+ comment.author.should == comment.author_name
+ end
+ end
+
+ describe '#as_json' do
+ before :all do
+ @comment = Factory(:user_comment)
+ @json = JSON.parse(@comment.to_json)
+ end
+ it 'includes a path to the comment' do
+ @json['path'].match(/\/#{@comment.id}/).should_not be_nil
+ end
+ it 'includes the author of the comment' do
+ @json['author'].should == @comment.author
+ end
+ it 'includes the i18nized created_at of the comment' do
+ @json['ftime'].should_not be_nil
+ end
+ it 'includes whether or not is an admin comment' do
+ @json['admin?'].should == false
+ end
+ end
+
+end
View
37 spec/models/kublog/image_spec.rb
@@ -0,0 +1,37 @@
+require 'spec_helper'
+
+describe Kublog::Image do
+
+ describe '#validate' do
+ before :each do
+ @image = Kublog::Image.new(:file => Support.image_fixture('adrian.png'))
+ end
+
+ it 'is valid with a file' do
+ @image.should be_valid
+ end
+
+ # Saves the image to delete the file from filesystem
+ it 'is invalid without a file' do
+ @image.file.remove!
+ @image.should_not be_valid
+ end
+ end
+
+ describe '#before_validation' do
+ it 'sets a default alt with the name of the image' do
+ image = Kublog::Image.create(:file => Support.image_fixture('adrian.png'))
+ image.alt.should == 'adrian'
+ end
+ end
+
+ describe '#after_create' do
+ it 'gets the width and height of the image' do
+ image = Kublog::Image.create(:file => Support.image_fixture('adrian.png'))
+ image.file_width.should == 48
+ image.file_height.should == 48
+ end
+ end
+
+
+end
View
37 spec/models/kublog/notification_spec.rb
@@ -3,7 +3,6 @@
describe Kublog::Notification do
describe '#validate' do
-
before(:each) do
@notification = Factory.build(:notification)
end
@@ -16,12 +15,38 @@
@notification.kind = ''
@notification.should_not be_valid
end
-
- it 'should not be valid without content' do
- @notification.content = ''
- @notification.should_not be_valid
+ end
+
+ describe '#roles' do
+ it 'serializes roles into a hash or an array' do
+ notification = Factory(:notification)
+ notification.roles = [:shipper, :carrier, :logistics]
+ notification.save
+ notification.reload
+ notification.roles.should == [:shipper, :carrier, :logistics]
+ end
+ end
+
+ describe '#title' do
+ it 'delegates title to post' do
+ @notification = Factory.build :notification, :post => Factory.build(:post)
+ @notification.title.should == @notification.post.title
+ end
+ end
+
+ describe '#url' do
+ it 'delegates url to the post' do
+ @notification = Factory.build :notification, :post => Factory.create(:post)
+ @notification.url.should == @notification.post.url
+ end
+ end
+
+ describe '#after_create' do
+ it 'calls deliver_#{notification_kind} on after create' do
+ notification = Factory.build(:twitter_notification)
+ notification.should_receive(:deliver_twitter).and_return(nil)
+ notification.save
end
-
end
View
98 spec/models/kublog/post_spec.rb
@@ -1,67 +1,63 @@
require 'spec_helper'
-module Kublog
+describe Kublog::Post do
+ it 'is invalid without a title' do
+ Factory.build(:post, :title => nil).should_not be_valid
+ end
- describe Post do
-
- it 'is invalid without a title' do
- Factory.build(:post, :title => nil).should_not be_valid
- end
-
- it 'is invalid with an empty body' do
- Factory.build(:post, :body => '').should_not be_valid
+ it 'is invalid with an empty body' do
+ Factory.build(:post, :body => '').should_not be_valid
+ end
+
+ it 'is invalid with only html tags as body' do
+ Factory.build(:post, :body => '<p> </p>').should_not be_valid
+ end
+
+ it 'is not valid without a user' do
+ Factory.build(:post, :user_id => nil)
+ end
+
+ describe '#author' do
+ it 'is a proxy for the users to_s method' do
+ user = Factory.build :user
+ post = Factory.build :post, :user => user
+ post.author.should == user.to_s
end
-
- it 'is invalid with only html tags as body' do
- Factory.build(:post, :body => '<p> </p>').should_not be_valid
+ end
+
+ describe '#to_s' do
+ it 'is the posts title' do
+ post = Factory.build(:post)
+ post.to_s.should == post.title
end
-
- it 'is not valid without a user' do
- Factory.build(:post, :user_id => nil)
+ end
+
+ describe '#url' do
+ it 'is a url to the post with the engines config url' do
+ Kublog.default_url_options = {:host => 'www.myblog.com'}
+ post = Factory(:post)
+ post.url.should == "http://www.myblog.com/blog/#{post.to_param}"
end
- describe '#author' do
- it 'is a proxy for the users to_s method' do
- user = Factory.build :user
- post = Factory.build :post, :user => user
- post.author.should == user.to_s
- end
+ it 'is nil when the post is not yet created' do
+ Factory.build(:post).url.should == nil
end
- describe '#to_s' do
- it 'is the posts title' do
- post = Factory.build(:post)
- post.to_s.should == post.title
- end
- end
+ end
+
+ describe '#related_posts' do
- describe '#url' do
- it 'is a url to the post with the engines config url' do
- Kublog.default_url_options = {:host => 'www.myblog.com'}
- post = Factory(:post)
- post.url.should == "http://www.myblog.com/blog/#{post.to_param}"
- end
-
- it 'is nil when the post is not yet created' do
- Factory.build(:post).url.should == nil
- end
-
+ before(:all) do
+ @category = Factory(:category)
+ @post = Factory(:post, :category => @category)
end
- describe '#related_posts' do
-
- before(:all) do
- @category = Factory(:category)
- @post = Factory(:post, :category => @category)
- end
-
- it 'should return all the posts' do
- related_post = Factory(:post, :title => 'Related Post', :category => @category)
- unrelated_post = Factory(:post)
- @post.related_posts.should == [related_post]
- end
-
+ it 'should return all the posts' do
+ related_post = Factory(:post, :title => 'Related Post', :category => @category)
+ unrelated_post = Factory(:post)
+ @post.related_posts.should == [related_post]
end
end
+
end
View
23 spec/spec_helper.rb
@@ -2,11 +2,34 @@
require 'rubygems'
require 'bundler/setup'
require 'ruby-debug'
+
require File.expand_path("../dummy/config/environment.rb", __FILE__)
+
require 'rspec/rails'
require 'factory_girl'
require 'factories'
+require 'json'
RSpec.configure do |config|
config.use_transactional_fixtures = true
end
+
+module Support
+
+ def self.dont_notify_users_by_default
+ User.class_eval do
+ def notify_post?(post)
+ false
+ end
+ end
+ end
+
+ def self.fixture(name='')
+ File.read File.join(File.dirname(__FILE__), 'fixtures', name)
+ end
+
+ def self.image_fixture(name='')
+ File.open File.join(File.dirname(__FILE__), 'fixtures', name)
+ end
+
+end

0 comments on commit 93e624c

Please sign in to comment.