=0}},ID:function(g,h){return g.nodeType===1&&g.getAttribute("id")===h},TAG:function(g,h){return h==="*"&&g.nodeType===1||g.nodeName.toLowerCase()===h},CLASS:function(g,h){return(" "+(g.className||g.getAttribute("class"))+" ").indexOf(h)>-1},ATTR:function(g,h){var l=h[1];g=n.attrHandle[l]?n.attrHandle[l](g):g[l]!=null?g[l]:g.getAttribute(l);l=g+"";var m=h[2];h=h[4];return g==null?m==="!=":m===
+"="?l===h:m==="*="?l.indexOf(h)>=0:m==="~="?(" "+l+" ").indexOf(h)>=0:!h?l&&g!==false:m==="!="?l!==h:m==="^="?l.indexOf(h)===0:m==="$="?l.substr(l.length-h.length)===h:m==="|="?l===h||l.substr(0,h.length+1)===h+"-":false},POS:function(g,h,l,m){var q=n.setFilters[h[2]];if(q)return q(g,l,h,m)}}},r=n.match.POS;for(var u in n.match){n.match[u]=new RegExp(n.match[u].source+/(?![^\[]*\])(?![^\(]*\))/.source);n.leftMatch[u]=new RegExp(/(^(?:.|\r|\n)*?)/.source+n.match[u].source.replace(/\\(\d+)/g,function(g,
+h){return"\\"+(h-0+1)}))}var z=function(g,h){g=Array.prototype.slice.call(g,0);if(h){h.push.apply(h,g);return h}return g};try{Array.prototype.slice.call(s.documentElement.childNodes,0)}catch(C){z=function(g,h){h=h||[];if(j.call(g)==="[object Array]")Array.prototype.push.apply(h,g);else if(typeof g.length==="number")for(var l=0,m=g.length;l ";var l=s.documentElement;l.insertBefore(g,l.firstChild);if(s.getElementById(h)){n.find.ID=function(m,q,p){if(typeof q.getElementById!=="undefined"&&!p)return(q=q.getElementById(m[1]))?q.id===m[1]||typeof q.getAttributeNode!=="undefined"&&
+q.getAttributeNode("id").nodeValue===m[1]?[q]:w:[]};n.filter.ID=function(m,q){var p=typeof m.getAttributeNode!=="undefined"&&m.getAttributeNode("id");return m.nodeType===1&&p&&p.nodeValue===q}}l.removeChild(g);l=g=null})();(function(){var g=s.createElement("div");g.appendChild(s.createComment(""));if(g.getElementsByTagName("*").length>0)n.find.TAG=function(h,l){l=l.getElementsByTagName(h[1]);if(h[1]==="*"){h=[];for(var m=0;l[m];m++)l[m].nodeType===1&&h.push(l[m]);l=h}return l};g.innerHTML=" ";
+if(g.firstChild&&typeof g.firstChild.getAttribute!=="undefined"&&g.firstChild.getAttribute("href")!=="#")n.attrHandle.href=function(h){return h.getAttribute("href",2)};g=null})();s.querySelectorAll&&function(){var g=k,h=s.createElement("div");h.innerHTML="
";if(!(h.querySelectorAll&&h.querySelectorAll(".TEST").length===0)){k=function(m,q,p,v){q=q||s;if(!v&&q.nodeType===9&&!x(q))try{return z(q.querySelectorAll(m),p)}catch(t){}return g(m,q,p,v)};for(var l in g)k[l]=g[l];h=null}}();
+(function(){var g=s.createElement("div");g.innerHTML="
";if(!(!g.getElementsByClassName||g.getElementsByClassName("e").length===0)){g.lastChild.className="e";if(g.getElementsByClassName("e").length!==1){n.order.splice(1,0,"CLASS");n.find.CLASS=function(h,l,m){if(typeof l.getElementsByClassName!=="undefined"&&!m)return l.getElementsByClassName(h[1])};g=null}}})();var E=s.compareDocumentPosition?function(g,h){return!!(g.compareDocumentPosition(h)&16)}:
+function(g,h){return g!==h&&(g.contains?g.contains(h):true)},x=function(g){return(g=(g?g.ownerDocument||g:0).documentElement)?g.nodeName!=="HTML":false},ga=function(g,h){var l=[],m="",q;for(h=h.nodeType?[h]:h;q=n.match.PSEUDO.exec(g);){m+=q[0];g=g.replace(n.match.PSEUDO,"")}g=n.relative[g]?g+"*":g;q=0;for(var p=h.length;q=0===d})};c.fn.extend({find:function(a){for(var b=this.pushStack("","find",a),d=0,f=0,e=this.length;f0)for(var j=d;j0},closest:function(a,b){if(c.isArray(a)){var d=[],f=this[0],e,j=
+{},i;if(f&&a.length){e=0;for(var o=a.length;e-1:c(f).is(e)){d.push({selector:i,elem:f});delete j[i]}}f=f.parentNode}}return d}var k=c.expr.match.POS.test(a)?c(a,b||this.context):null;return this.map(function(n,r){for(;r&&r.ownerDocument&&r!==b;){if(k?k.index(r)>-1:c(r).is(a))return r;r=r.parentNode}return null})},index:function(a){if(!a||typeof a===
+"string")return c.inArray(this[0],a?c(a):this.parent().children());return c.inArray(a.jquery?a[0]:a,this)},add:function(a,b){a=typeof a==="string"?c(a,b||this.context):c.makeArray(a);b=c.merge(this.get(),a);return this.pushStack(qa(a[0])||qa(b[0])?b:c.unique(b))},andSelf:function(){return this.add(this.prevObject)}});c.each({parent:function(a){return(a=a.parentNode)&&a.nodeType!==11?a:null},parents:function(a){return c.dir(a,"parentNode")},parentsUntil:function(a,b,d){return c.dir(a,"parentNode",
+d)},next:function(a){return c.nth(a,2,"nextSibling")},prev:function(a){return c.nth(a,2,"previousSibling")},nextAll:function(a){return c.dir(a,"nextSibling")},prevAll:function(a){return c.dir(a,"previousSibling")},nextUntil:function(a,b,d){return c.dir(a,"nextSibling",d)},prevUntil:function(a,b,d){return c.dir(a,"previousSibling",d)},siblings:function(a){return c.sibling(a.parentNode.firstChild,a)},children:function(a){return c.sibling(a.firstChild)},contents:function(a){return c.nodeName(a,"iframe")?
+a.contentDocument||a.contentWindow.document:c.makeArray(a.childNodes)}},function(a,b){c.fn[a]=function(d,f){var e=c.map(this,b,d);eb.test(a)||(f=d);if(f&&typeof f==="string")e=c.filter(f,e);e=this.length>1?c.unique(e):e;if((this.length>1||gb.test(f))&&fb.test(a))e=e.reverse();return this.pushStack(e,a,R.call(arguments).join(","))}});c.extend({filter:function(a,b,d){if(d)a=":not("+a+")";return c.find.matches(a,b)},dir:function(a,b,d){var f=[];for(a=a[b];a&&a.nodeType!==9&&(d===w||a.nodeType!==1||!c(a).is(d));){a.nodeType===
+1&&f.push(a);a=a[b]}return f},nth:function(a,b,d){b=b||1;for(var f=0;a;a=a[d])if(a.nodeType===1&&++f===b)break;return a},sibling:function(a,b){for(var d=[];a;a=a.nextSibling)a.nodeType===1&&a!==b&&d.push(a);return d}});var Ja=/ jQuery\d+="(?:\d+|null)"/g,V=/^\s+/,Ka=/(<([\w:]+)[^>]*?)\/>/g,hb=/^(?:area|br|col|embed|hr|img|input|link|meta|param)$/i,La=/<([\w:]+)/,ib=/"+d+">"},F={option:[1,""," "],legend:[1,""," "],thead:[1,""],tr:[2,""],td:[3,""],col:[2,""],area:[1,""," "],_default:[0,"",""]};F.optgroup=F.option;F.tbody=F.tfoot=F.colgroup=F.caption=F.thead;F.th=F.td;if(!c.support.htmlSerialize)F._default=[1,"div","
"];c.fn.extend({text:function(a){if(c.isFunction(a))return this.each(function(b){var d=
+c(this);d.text(a.call(this,b,d.text()))});if(typeof a!=="object"&&a!==w)return this.empty().append((this[0]&&this[0].ownerDocument||s).createTextNode(a));return c.text(this)},wrapAll:function(a){if(c.isFunction(a))return this.each(function(d){c(this).wrapAll(a.call(this,d))});if(this[0]){var b=c(a,this[0].ownerDocument).eq(0).clone(true);this[0].parentNode&&b.insertBefore(this[0]);b.map(function(){for(var d=this;d.firstChild&&d.firstChild.nodeType===1;)d=d.firstChild;return d}).append(this)}return this},
+wrapInner:function(a){if(c.isFunction(a))return this.each(function(b){c(this).wrapInner(a.call(this,b))});return this.each(function(){var b=c(this),d=b.contents();d.length?d.wrapAll(a):b.append(a)})},wrap:function(a){return this.each(function(){c(this).wrapAll(a)})},unwrap:function(){return this.parent().each(function(){c.nodeName(this,"body")||c(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.appendChild(a)})},
+prepend:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,false,function(b){this.parentNode.insertBefore(b,this)});else if(arguments.length){var a=c(arguments[0]);a.push.apply(a,this.toArray());return this.pushStack(a,"before",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,false,function(b){this.parentNode.insertBefore(b,
+this.nextSibling)});else if(arguments.length){var a=this.pushStack(this,"after",arguments);a.push.apply(a,c(arguments[0]).toArray());return a}},remove:function(a,b){for(var d=0,f;(f=this[d])!=null;d++)if(!a||c.filter(a,[f]).length){if(!b&&f.nodeType===1){c.cleanData(f.getElementsByTagName("*"));c.cleanData([f])}f.parentNode&&f.parentNode.removeChild(f)}return this},empty:function(){for(var a=0,b;(b=this[a])!=null;a++)for(b.nodeType===1&&c.cleanData(b.getElementsByTagName("*"));b.firstChild;)b.removeChild(b.firstChild);
+return this},clone:function(a){var b=this.map(function(){if(!c.support.noCloneEvent&&!c.isXMLDoc(this)){var d=this.outerHTML,f=this.ownerDocument;if(!d){d=f.createElement("div");d.appendChild(this.cloneNode(true));d=d.innerHTML}return c.clean([d.replace(Ja,"").replace(/=([^="'>\s]+\/)>/g,'="$1">').replace(V,"")],f)[0]}else return this.cloneNode(true)});if(a===true){ra(this,b);ra(this.find("*"),b.find("*"))}return b},html:function(a){if(a===w)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(Ja,
+""):null;else if(typeof a==="string"&&!ta.test(a)&&(c.support.leadingWhitespace||!V.test(a))&&!F[(La.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(Ka,Ma);try{for(var b=0,d=this.length;b0||e.cacheable||this.length>1?k.cloneNode(true):k)}o.length&&c.each(o,Qa)}return this}});c.fragments={};c.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){c.fn[a]=function(d){var f=[];d=c(d);var e=this.length===1&&this[0].parentNode;if(e&&e.nodeType===11&&e.childNodes.length===1&&d.length===1){d[b](this[0]);
+return this}else{e=0;for(var j=d.length;e0?this.clone(true):this).get();c.fn[b].apply(c(d[e]),i);f=f.concat(i)}return this.pushStack(f,a,d.selector)}}});c.extend({clean:function(a,b,d,f){b=b||s;if(typeof b.createElement==="undefined")b=b.ownerDocument||b[0]&&b[0].ownerDocument||s;for(var e=[],j=0,i;(i=a[j])!=null;j++){if(typeof i==="number")i+="";if(i){if(typeof i==="string"&&!jb.test(i))i=b.createTextNode(i);else if(typeof i==="string"){i=i.replace(Ka,Ma);var o=(La.exec(i)||["",
+""])[1].toLowerCase(),k=F[o]||F._default,n=k[0],r=b.createElement("div");for(r.innerHTML=k[1]+i+k[2];n--;)r=r.lastChild;if(!c.support.tbody){n=ib.test(i);o=o==="table"&&!n?r.firstChild&&r.firstChild.childNodes:k[1]===""&&!n?r.childNodes:[];for(k=o.length-1;k>=0;--k)c.nodeName(o[k],"tbody")&&!o[k].childNodes.length&&o[k].parentNode.removeChild(o[k])}!c.support.leadingWhitespace&&V.test(i)&&r.insertBefore(b.createTextNode(V.exec(i)[0]),r.firstChild);i=r.childNodes}if(i.nodeType)e.push(i);else e=
+c.merge(e,i)}}if(d)for(j=0;e[j];j++)if(f&&c.nodeName(e[j],"script")&&(!e[j].type||e[j].type.toLowerCase()==="text/javascript"))f.push(e[j].parentNode?e[j].parentNode.removeChild(e[j]):e[j]);else{e[j].nodeType===1&&e.splice.apply(e,[j+1,0].concat(c.makeArray(e[j].getElementsByTagName("script"))));d.appendChild(e[j])}return e},cleanData:function(a){for(var b,d,f=c.cache,e=c.event.special,j=c.support.deleteExpando,i=0,o;(o=a[i])!=null;i++)if(d=o[c.expando]){b=f[d];if(b.events)for(var k in b.events)e[k]?
+c.event.remove(o,k):Ca(o,k,b.handle);if(j)delete o[c.expando];else o.removeAttribute&&o.removeAttribute(c.expando);delete f[d]}}});var kb=/z-?index|font-?weight|opacity|zoom|line-?height/i,Na=/alpha\([^)]*\)/,Oa=/opacity=([^)]*)/,ha=/float/i,ia=/-([a-z])/ig,lb=/([A-Z])/g,mb=/^-?\d+(?:px)?$/i,nb=/^-?\d/,ob={position:"absolute",visibility:"hidden",display:"block"},pb=["Left","Right"],qb=["Top","Bottom"],rb=s.defaultView&&s.defaultView.getComputedStyle,Pa=c.support.cssFloat?"cssFloat":"styleFloat",ja=
+function(a,b){return b.toUpperCase()};c.fn.css=function(a,b){return X(this,a,b,true,function(d,f,e){if(e===w)return c.curCSS(d,f);if(typeof e==="number"&&!kb.test(f))e+="px";c.style(d,f,e)})};c.extend({style:function(a,b,d){if(!a||a.nodeType===3||a.nodeType===8)return w;if((b==="width"||b==="height")&&parseFloat(d)<0)d=w;var f=a.style||a,e=d!==w;if(!c.support.opacity&&b==="opacity"){if(e){f.zoom=1;b=parseInt(d,10)+""==="NaN"?"":"alpha(opacity="+d*100+")";a=f.filter||c.curCSS(a,"filter")||"";f.filter=
+Na.test(a)?a.replace(Na,b):b}return f.filter&&f.filter.indexOf("opacity=")>=0?parseFloat(Oa.exec(f.filter)[1])/100+"":""}if(ha.test(b))b=Pa;b=b.replace(ia,ja);if(e)f[b]=d;return f[b]},css:function(a,b,d,f){if(b==="width"||b==="height"){var e,j=b==="width"?pb:qb;function i(){e=b==="width"?a.offsetWidth:a.offsetHeight;f!=="border"&&c.each(j,function(){f||(e-=parseFloat(c.curCSS(a,"padding"+this,true))||0);if(f==="margin")e+=parseFloat(c.curCSS(a,"margin"+this,true))||0;else e-=parseFloat(c.curCSS(a,
+"border"+this+"Width",true))||0})}a.offsetWidth!==0?i():c.swap(a,ob,i);return Math.max(0,Math.round(e))}return c.curCSS(a,b,d)},curCSS:function(a,b,d){var f,e=a.style;if(!c.support.opacity&&b==="opacity"&&a.currentStyle){f=Oa.test(a.currentStyle.filter||"")?parseFloat(RegExp.$1)/100+"":"";return f===""?"1":f}if(ha.test(b))b=Pa;if(!d&&e&&e[b])f=e[b];else if(rb){if(ha.test(b))b="float";b=b.replace(lb,"-$1").toLowerCase();e=a.ownerDocument.defaultView;if(!e)return null;if(a=e.getComputedStyle(a,null))f=
+a.getPropertyValue(b);if(b==="opacity"&&f==="")f="1"}else if(a.currentStyle){d=b.replace(ia,ja);f=a.currentStyle[b]||a.currentStyle[d];if(!mb.test(f)&&nb.test(f)){b=e.left;var j=a.runtimeStyle.left;a.runtimeStyle.left=a.currentStyle.left;e.left=d==="fontSize"?"1em":f||0;f=e.pixelLeft+"px";e.left=b;a.runtimeStyle.left=j}}return f},swap:function(a,b,d){var f={};for(var e in b){f[e]=a.style[e];a.style[e]=b[e]}d.call(a);for(e in b)a.style[e]=f[e]}});if(c.expr&&c.expr.filters){c.expr.filters.hidden=function(a){var b=
+a.offsetWidth,d=a.offsetHeight,f=a.nodeName.toLowerCase()==="tr";return b===0&&d===0&&!f?true:b>0&&d>0&&!f?false:c.curCSS(a,"display")==="none"};c.expr.filters.visible=function(a){return!c.expr.filters.hidden(a)}}var sb=J(),tb=/
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Generated
2011-01-14T17:58:09-05:00
+
+
+
+
+
+ All Files
+ (45.88% )
+
+
+
+ 141 files in total.
+ 3579 relevant lines.
+ 1642 lines covered and
+ 1937 lines missed
+
+
+
+
+
+
+
+ Controllers
+ (52.48% )
+
+
+
+ 37 files in total.
+ 524 relevant lines.
+ 275 lines covered and
+ 249 lines missed
+
+
+
+
+
+
+ Models
+ (50.26% )
+
+
+
+ 44 files in total.
+ 1906 relevant lines.
+ 958 lines covered and
+ 948 lines missed
+
+
+
+
+
+
+ Helpers
+ (59.26% )
+
+
+
+ 31 files in total.
+ 81 relevant lines.
+ 48 lines covered and
+ 33 lines missed
+
+
+
+
+
+
+ Libraries
+ (35.55% )
+
+
+
+ 5 files in total.
+ 301 relevant lines.
+ 107 lines covered and
+ 194 lines missed
+
+
+
+
+
+
+ Plugins
+ (35.69% )
+
+
+
+ 4 files in total.
+ 283 relevant lines.
+ 101 lines covered and
+ 182 lines missed
+
+
+
+
+
+
+ Ungrouped
+ (33.12% )
+
+
+
+ 24 files in total.
+ 767 relevant lines.
+ 254 lines covered and
+ 513 lines missed
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ./app/controllers/admin/posts_controller.rb
+ 100.0 % covered
+
+
+
+ #
+
+ Hits
+
+
+
+
+
+
+
+ 1
+
+
+ module Admin
+
+
+ 1
+
+
+
+
+
+
+ 2
+
+
+ class PostsController
+
+
+ 1
+
+
+
+
+
+
+ 3
+
+
+ def edit
+
+
+ 1
+
+
+
+
+
+
+ 4
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 5
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 6
+
+
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ./app/controllers/admin/users_controller.rb
+ 100.0 % covered
+
+
+
+ #
+
+ Hits
+
+
+
+
+
+
+
+ 1
+
+
+ class Admin::UsersController < ApplicationController
+
+
+ 1
+
+
+
+
+
+
+ 2
+
+
+ def edit
+
+
+ 1
+
+
+
+
+
+
+ 3
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 4
+
+
+
+
+
+
+
+
+
+
+
+
+ 5
+
+
+ def update
+
+
+ 1
+
+
+
+
+
+
+ 6
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 7
+
+
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ./app/controllers/advertisement_hits_controller.rb
+ 50.0 % covered
+
+
+
+ #
+
+ Hits
+
+
+
+
+
+
+
+ 1
+
+
+ class AdvertisementHitsController < ApplicationController
+
+
+ 1
+
+
+
+
+
+
+ 2
+
+
+ def create
+
+
+ 1
+
+
+
+
+
+
+ 3
+
+
+ advertisement = Advertisement.find(params[:id])
+
+
+ 0
+
+
+
+
+
+
+ 4
+
+
+ advertisement.hits.create(:ip_addr => request.remote_ip)
+
+
+ 0
+
+
+
+
+
+
+ 5
+
+
+ redirect_to advertisement.referral_url
+
+
+ 0
+
+
+
+
+
+
+ 6
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 7
+
+
+
+
+
+
+
+
+
+
+
+
+ 8
+
+
+ protected
+
+
+ 1
+
+
+
+
+
+
+ 9
+
+
+ def set_title
+
+
+ 1
+
+
+
+
+
+
+ 10
+
+
+ @page_title = Danbooru.config.app_name + "/advertisements"
+
+
+ 0
+
+
+
+
+
+
+ 11
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 12
+
+
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ./app/controllers/advertisements_controller.rb
+ 33.33 % covered
+
+
+
+ #
+
+ Hits
+
+
+
+
+
+
+
+ 1
+
+
+ class AdvertisementsController < ApplicationController
+
+
+ 1
+
+
+
+
+
+
+ 2
+
+
+ before_filter :advertiser_only
+
+
+ 1
+
+
+
+
+
+
+ 3
+
+
+
+
+
+
+
+
+
+
+
+
+ 4
+
+
+ def new
+
+
+ 1
+
+
+
+
+
+
+ 5
+
+
+ @advertisement = Advertisement.new(
+
+
+ 0
+
+
+
+
+
+
+ 6
+
+
+ :ad_type => "vertical",
+
+
+
+
+
+
+
+
+
+ 7
+
+
+ :status => "active"
+
+
+
+
+
+
+
+
+
+ 8
+
+
+ )
+
+
+
+
+
+
+
+
+
+ 9
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 10
+
+
+
+
+
+
+
+
+
+
+
+
+ 11
+
+
+ def edit
+
+
+ 1
+
+
+
+
+
+
+ 12
+
+
+ @advertisement = Advertisement.find(params[:id])
+
+
+ 0
+
+
+
+
+
+
+ 13
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 14
+
+
+
+
+
+
+
+
+
+
+
+
+ 15
+
+
+ def index
+
+
+ 1
+
+
+
+
+
+
+ 16
+
+
+ @advertisements = Advertisement.all
+
+
+ 0
+
+
+
+
+
+
+ 17
+
+
+ @start_date = 1.month.ago.to_date
+
+
+ 0
+
+
+
+
+
+
+ 18
+
+
+ @end_date = Date.today
+
+
+ 0
+
+
+
+
+
+
+ 19
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 20
+
+
+
+
+
+
+
+
+
+
+
+
+ 21
+
+
+ def show
+
+
+ 1
+
+
+
+
+
+
+ 22
+
+
+ @advertisement = Advertisement.find(params[:id])
+
+
+ 0
+
+
+
+
+
+
+ 23
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 24
+
+
+
+
+
+
+
+
+
+
+
+
+ 25
+
+
+ def create
+
+
+ 1
+
+
+
+
+
+
+ 26
+
+
+ @advertisement = Advertisement.new(params[:advertisement])
+
+
+ 0
+
+
+
+
+
+
+ 27
+
+
+ if @advertisement.save
+
+
+ 0
+
+
+
+
+
+
+ 28
+
+
+ redirect_to advertisement_path(@advertisement), :notice => "Advertisement created"
+
+
+ 0
+
+
+
+
+
+
+ 29
+
+
+ else
+
+
+
+
+
+
+
+
+
+ 30
+
+
+ flash[:notice] = "There were errors"
+
+
+ 0
+
+
+
+
+
+
+ 31
+
+
+ render :action => "new"
+
+
+ 0
+
+
+
+
+
+
+ 32
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 33
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 34
+
+
+
+
+
+
+
+
+
+
+
+
+ 35
+
+
+ def update
+
+
+ 1
+
+
+
+
+
+
+ 36
+
+
+ @advertisement = Advertisement.find(params[:id])
+
+
+ 0
+
+
+
+
+
+
+ 37
+
+
+ if @advertisement.update_attributes(params[:advertisement])
+
+
+ 0
+
+
+
+
+
+
+ 38
+
+
+ redirect_to advertisement_path(@advertisement), :notice => "Advertisement updated"
+
+
+ 0
+
+
+
+
+
+
+ 39
+
+
+ else
+
+
+
+
+
+
+
+
+
+ 40
+
+
+ flash[:notice] = "There were errors"
+
+
+ 0
+
+
+
+
+
+
+ 41
+
+
+ render :action => "edit"
+
+
+ 0
+
+
+
+
+
+
+ 42
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 43
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 44
+
+
+
+
+
+
+
+
+
+
+
+
+ 45
+
+
+ def destroy
+
+
+ 1
+
+
+
+
+
+
+ 46
+
+
+ @advertisement = Advertisement.find(params[:id])
+
+
+ 0
+
+
+
+
+
+
+ 47
+
+
+ @advertisement.destroy
+
+
+ 0
+
+
+
+
+
+
+ 48
+
+
+ redirect_to advertisements_path, :notice => "Advertisement destroyed"
+
+
+ 0
+
+
+
+
+
+
+ 49
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 50
+
+
+
+
+
+
+
+
+
+
+
+
+ 51
+
+
+ private
+
+
+ 1
+
+
+
+
+
+
+ 52
+
+
+ def advertiser_only
+
+
+ 1
+
+
+
+
+
+
+ 53
+
+
+ if !Danbooru.config.is_user_advertiser?(CurrentUser.user)
+
+
+ 0
+
+
+
+
+
+
+ 54
+
+
+ redirect_to "/static/access_denied"
+
+
+ 0
+
+
+
+
+
+
+ 55
+
+
+ return false
+
+
+ 0
+
+
+
+
+
+
+ 56
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 57
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 58
+
+
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ./app/controllers/application_controller.rb
+ 67.44 % covered
+
+
+
+ #
+
+ Hits
+
+
+
+
+
+
+
+ 1
+
+
+ class ApplicationController < ActionController::Base
+
+
+ 1
+
+
+
+
+
+
+ 2
+
+
+ protect_from_forgery
+
+
+ 1
+
+
+
+
+
+
+ 3
+
+
+ before_filter :set_current_user
+
+
+ 1
+
+
+
+
+
+
+ 4
+
+
+ after_filter :reset_current_user
+
+
+ 1
+
+
+
+
+
+
+ 5
+
+
+ before_filter :initialize_cookies
+
+
+ 1
+
+
+
+
+
+
+ 6
+
+
+ before_filter :set_title
+
+
+ 1
+
+
+
+
+
+
+ 7
+
+
+ layout "default"
+
+
+ 1
+
+
+
+
+
+
+ 8
+
+
+
+
+
+
+
+
+
+
+
+
+ 9
+
+
+ rescue_from User::PrivilegeError, :with => :access_denied
+
+
+ 1
+
+
+
+
+
+
+ 10
+
+
+
+
+
+
+
+
+
+
+
+
+ 11
+
+
+ protected
+
+
+ 1
+
+
+
+
+
+
+ 12
+
+
+ def access_denied
+
+
+ 1
+
+
+
+
+
+
+ 13
+
+
+ previous_url = params[:url] || request.request_uri
+
+
+ 0
+
+
+
+
+
+
+ 14
+
+
+
+
+
+
+
+
+
+
+
+
+ 15
+
+
+ respond_to do |fmt|
+
+
+ 0
+
+
+
+
+
+
+ 16
+
+
+ fmt.html do
+
+
+ 0
+
+
+
+
+
+
+ 17
+
+
+ if request.get?
+
+
+ 0
+
+
+
+
+
+
+ 18
+
+
+ redirect_to new_session_path(:url => previous_url), :notice => "Access denied"
+
+
+ 0
+
+
+
+
+
+
+ 19
+
+
+ else
+
+
+
+
+
+
+
+
+
+ 20
+
+
+ redirect_to new_session_path, :notice => "Access denied"
+
+
+ 0
+
+
+
+
+
+
+ 21
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 22
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 23
+
+
+ fmt.xml do
+
+
+ 0
+
+
+
+
+
+
+ 24
+
+
+ render :xml => {:success => false, :reason => "access denied"}.to_xml(:root => "response"), :status => 403
+
+
+ 0
+
+
+
+
+
+
+ 25
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 26
+
+
+ fmt.json do
+
+
+ 0
+
+
+
+
+
+
+ 27
+
+
+ render :json => {:success => false, :reason => "access denied"}.to_json, :status => 403
+
+
+ 0
+
+
+
+
+
+
+ 28
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 29
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 30
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 31
+
+
+
+
+
+
+
+
+
+
+
+
+ 32
+
+
+ def set_current_user
+
+
+ 1
+
+
+
+
+
+
+ 33
+
+
+ if session[:user_id]
+
+
+ 7
+
+
+
+
+
+
+ 34
+
+
+ CurrentUser.user = User.find_by_id(session[:user_id])
+
+
+ 2
+
+
+
+
+
+
+ 35
+
+
+ CurrentUser.ip_addr = request.remote_ip
+
+
+ 2
+
+
+
+
+
+
+ 36
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 37
+
+
+
+
+
+
+
+
+
+
+
+
+ 38
+
+
+ if CurrentUser.user
+
+
+ 7
+
+
+
+
+
+
+ 39
+
+
+ if CurrentUser.user.is_banned? && CurrentUser.user.ban && CurrentUser.user.ban.expires_at < Time.now
+
+
+ 7
+
+
+
+
+
+
+ 40
+
+
+ CurrentUser.user.unban!
+
+
+ 0
+
+
+
+
+
+
+ 41
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 42
+
+
+ else
+
+
+
+
+
+
+
+
+
+ 43
+
+
+ CurrentUser.user = AnonymousUser.new
+
+
+ 0
+
+
+
+
+
+
+ 44
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 45
+
+
+
+
+
+
+
+
+
+
+
+
+ 46
+
+
+ Time.zone = CurrentUser.user.time_zone
+
+
+ 7
+
+
+
+
+
+
+ 47
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 48
+
+
+
+
+
+
+
+
+
+
+
+
+ 49
+
+
+ def reset_current_user
+
+
+ 1
+
+
+
+
+
+
+ 50
+
+
+ CurrentUser.user = nil
+
+
+ 7
+
+
+
+
+
+
+ 51
+
+
+ CurrentUser.ip_addr = nil
+
+
+ 7
+
+
+
+
+
+
+ 52
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 53
+
+
+
+
+
+
+
+
+
+
+
+
+ 54
+
+
+ %w(member banned privileged contributor janitor moderator admin).each do |level|
+
+
+ 1
+
+
+
+
+
+
+ 55
+
+
+ define_method("#{level}_only") do
+
+
+ 7
+
+
+
+
+
+
+ 56
+
+
+ if CurrentUser.user.__send__("is_#{level}?")
+
+
+ 4
+
+
+
+
+
+
+ 57
+
+
+ true
+
+
+ 4
+
+
+
+
+
+
+ 58
+
+
+ else
+
+
+
+
+
+
+
+
+
+ 59
+
+
+ access_denied()
+
+
+ 0
+
+
+
+
+
+
+ 60
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 61
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 62
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 63
+
+
+
+
+
+
+
+
+
+
+
+
+ 64
+
+
+ def initialize_cookies
+
+
+ 1
+
+
+
+
+
+
+ 65
+
+
+ if CurrentUser.user.is_anonymous?
+
+
+ 7
+
+
+
+
+
+
+ 66
+
+
+ cookies["blacklisted_tags"] = ""
+
+
+ 0
+
+
+
+
+
+
+ 67
+
+
+ else
+
+
+
+
+
+
+
+
+
+ 68
+
+
+ cookies["blacklisted_tags"] = CurrentUser.user.blacklisted_tags
+
+
+ 7
+
+
+
+
+
+
+ 69
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 70
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 71
+
+
+
+
+
+
+
+
+
+
+
+
+ 72
+
+
+ def set_title
+
+
+ 1
+
+
+
+
+
+
+ 73
+
+
+ @page_title = Danbooru.config.app_name + "/#{params[:controller]}"
+
+
+ 7
+
+
+
+
+
+
+ 74
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 75
+
+
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ./app/controllers/artist_versions_controller.rb
+ 50.0 % covered
+
+
+
+ #
+
+ Hits
+
+
+
+
+
+
+
+ 1
+
+
+ class ArtistVersionsController < ApplicationController
+
+
+ 1
+
+
+
+
+
+
+ 2
+
+
+ respond_to :html, :xml, :json
+
+
+ 1
+
+
+
+
+
+
+ 3
+
+
+
+
+
+
+
+
+
+
+
+
+ 4
+
+
+ def index
+
+
+ 1
+
+
+
+
+
+
+ 5
+
+
+ @search = ArtistVersion.search(params[:search])
+
+
+ 0
+
+
+
+
+
+
+ 6
+
+
+ @artist_versions = @search.paginate :order => "id desc", :per_page => 25, :page => params[:page]
+
+
+ 0
+
+
+
+
+
+
+ 7
+
+
+ respond_with(@artist_versions)
+
+
+ 0
+
+
+
+
+
+
+ 8
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 9
+
+
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ./app/controllers/artists_controller.rb
+ 34.48 % covered
+
+
+
+ #
+
+ Hits
+
+
+
+
+
+
+
+ 1
+
+
+ class ArtistsController < ApplicationController
+
+
+ 1
+
+
+
+
+
+
+ 2
+
+
+ respond_to :html, :xml, :json
+
+
+ 1
+
+
+
+
+
+
+ 3
+
+
+ before_filter :member_only, :except => [:index, :show]
+
+
+ 1
+
+
+
+
+
+
+ 4
+
+
+
+
+
+
+
+
+
+
+
+
+ 5
+
+
+ def new
+
+
+ 1
+
+
+
+
+
+
+ 6
+
+
+ @artist = Artist.new_with_defaults(params)
+
+
+ 0
+
+
+
+
+
+
+ 7
+
+
+ respond_with(@artist)
+
+
+ 0
+
+
+
+
+
+
+ 8
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 9
+
+
+
+
+
+
+
+
+
+
+
+
+ 10
+
+
+ def edit
+
+
+ 1
+
+
+
+
+
+
+ 11
+
+
+ @artist = Artist.find(params[:id])
+
+
+ 0
+
+
+
+
+
+
+ 12
+
+
+ respond_with(@artist)
+
+
+ 0
+
+
+
+
+
+
+ 13
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 14
+
+
+
+
+
+
+
+
+
+
+
+
+ 15
+
+
+ def index
+
+
+ 1
+
+
+
+
+
+
+ 16
+
+
+ @artists = Artist.build_relation(params).paginate(:per_page => 25, :page => params[:page])
+
+
+ 0
+
+
+
+
+
+
+ 17
+
+
+ respond_with(@artists)
+
+
+ 0
+
+
+
+
+
+
+ 18
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 19
+
+
+
+
+
+
+
+
+
+
+
+
+ 20
+
+
+ def show
+
+
+ 1
+
+
+
+
+
+
+ 21
+
+
+ @artist = Artist.find(params[:id])
+
+
+ 0
+
+
+
+
+
+
+ 22
+
+
+
+
+
+
+
+
+
+
+
+
+ 23
+
+
+ if @artist
+
+
+ 0
+
+
+
+
+
+
+ 24
+
+
+ @posts = Danbooru.config.select_posts_visible_to_user(CurrentUser.user, Post.find_by_tags(@artist.name, :limit => 6))
+
+
+ 0
+
+
+
+
+
+
+ 25
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 26
+
+
+
+
+
+
+
+
+
+
+
+
+ 27
+
+
+ respond_with(@artist)
+
+
+ 0
+
+
+
+
+
+
+ 28
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 29
+
+
+
+
+
+
+
+
+
+
+
+
+ 30
+
+
+ def create
+
+
+ 1
+
+
+
+
+
+
+ 31
+
+
+ @artist = Artist.create(params[:artist])
+
+
+ 0
+
+
+
+
+
+
+ 32
+
+
+ respond_with(@artist)
+
+
+ 0
+
+
+
+
+
+
+ 33
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 34
+
+
+
+
+
+
+
+
+
+
+
+
+ 35
+
+
+ def update
+
+
+ 1
+
+
+
+
+
+
+ 36
+
+
+ @artist = Artist.find(params[:id])
+
+
+ 0
+
+
+
+
+
+
+ 37
+
+
+ @artist.update_attributes(params[:artist])
+
+
+ 0
+
+
+
+
+
+
+ 38
+
+
+ respond_with(@artist)
+
+
+ 0
+
+
+
+
+
+
+ 39
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 40
+
+
+
+
+
+
+
+
+
+
+
+
+ 41
+
+
+ def revert
+
+
+ 1
+
+
+
+
+
+
+ 42
+
+
+ @artist = Artist.find(params[:id])
+
+
+ 0
+
+
+
+
+
+
+ 43
+
+
+ @version = ArtistVersion.find(params[:version_id])
+
+
+ 0
+
+
+
+
+
+
+ 44
+
+
+ @artist.revert_to!(@version)
+
+
+ 0
+
+
+
+
+
+
+ 45
+
+
+ respond_with(@artist)
+
+
+ 0
+
+
+
+
+
+
+ 46
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 47
+
+
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ./app/controllers/bans_controller.rb
+ 34.62 % covered
+
+
+
+ #
+
+ Hits
+
+
+
+
+
+
+
+ 1
+
+
+ class BansController < ApplicationController
+
+
+ 1
+
+
+
+
+
+
+ 2
+
+
+ before_filter :moderator_only, :except => [:show, :index]
+
+
+ 1
+
+
+
+
+
+
+ 3
+
+
+
+
+
+
+
+
+
+
+
+
+ 4
+
+
+ def new
+
+
+ 1
+
+
+
+
+
+
+ 5
+
+
+ @ban = Ban.new
+
+
+ 0
+
+
+
+
+
+
+ 6
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 7
+
+
+
+
+
+
+
+
+
+
+
+
+ 8
+
+
+ def edit
+
+
+ 1
+
+
+
+
+
+
+ 9
+
+
+ @ban = Ban.find(params[:id])
+
+
+ 0
+
+
+
+
+
+
+ 10
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 11
+
+
+
+
+
+
+
+
+
+
+
+
+ 12
+
+
+ def index
+
+
+ 1
+
+
+
+
+
+
+ 13
+
+
+ @search = Ban.search(params[:search])
+
+
+ 0
+
+
+
+
+
+
+ 14
+
+
+ @bans = @search.paginate(:page => params[:page])
+
+
+ 0
+
+
+
+
+
+
+ 15
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 16
+
+
+
+
+
+
+
+
+
+
+
+
+ 17
+
+
+ def show
+
+
+ 1
+
+
+
+
+
+
+ 18
+
+
+ @ban = Ban.find(params[:id])
+
+
+ 0
+
+
+
+
+
+
+ 19
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 20
+
+
+
+
+
+
+
+
+
+
+
+
+ 21
+
+
+ def create
+
+
+ 1
+
+
+
+
+
+
+ 22
+
+
+ @ban = Ban.new(params[:ban])
+
+
+ 0
+
+
+
+
+
+
+ 23
+
+
+ @ban.banner_id = CurrentUser.id
+
+
+ 0
+
+
+
+
+
+
+ 24
+
+
+
+
+
+
+
+
+
+
+
+
+ 25
+
+
+ if @ban.save
+
+
+ 0
+
+
+
+
+
+
+ 26
+
+
+ redirect_to ban_path(@ban), :notice => "Ban created"
+
+
+ 0
+
+
+
+
+
+
+ 27
+
+
+ else
+
+
+
+
+
+
+
+
+
+ 28
+
+
+ render :action => "new"
+
+
+ 0
+
+
+
+
+
+
+ 29
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 30
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 31
+
+
+
+
+
+
+
+
+
+
+
+
+ 32
+
+
+ def update
+
+
+ 1
+
+
+
+
+
+
+ 33
+
+
+ @ban = Ban.find(params[:id])
+
+
+ 0
+
+
+
+
+
+
+ 34
+
+
+ if @ban.update_attributes(params[:ban])
+
+
+ 0
+
+
+
+
+
+
+ 35
+
+
+ redirect_to ban_path(@ban), :notice => "Ban updated"
+
+
+ 0
+
+
+
+
+
+
+ 36
+
+
+ else
+
+
+
+
+
+
+
+
+
+ 37
+
+
+ render :action => "edit"
+
+
+ 0
+
+
+
+
+
+
+ 38
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 39
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 40
+
+
+
+
+
+
+
+
+
+
+
+
+ 41
+
+
+ def destroy
+
+
+ 1
+
+
+
+
+
+
+ 42
+
+
+ @ban = Ban.find(params[:id])
+
+
+ 0
+
+
+
+
+
+
+ 43
+
+
+ @ban.destroy
+
+
+ 0
+
+
+
+
+
+
+ 44
+
+
+ redirect_to bans_path, :notice => "Ban destroyed"
+
+
+ 0
+
+
+
+
+
+
+ 45
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 46
+
+
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ./app/controllers/comment_votes_controller.rb
+ 40.0 % covered
+
+
+
+ #
+
+ Hits
+
+
+
+
+
+
+
+ 1
+
+
+ class CommentVotesController < ApplicationController
+
+
+ 1
+
+
+
+
+
+
+ 2
+
+
+ def create
+
+
+ 1
+
+
+
+
+
+
+ 3
+
+
+ @comment = Comment.find(params[:comment_id])
+
+
+ 0
+
+
+
+
+
+
+ 4
+
+
+ @comment.vote!(params[:score])
+
+
+ 0
+
+
+
+
+
+
+ 5
+
+
+ rescue CommentVote::Error => x
+
+
+
+
+
+
+
+
+
+ 6
+
+
+ @error = x
+
+
+ 0
+
+
+
+
+
+
+ 7
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 8
+
+
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ./app/controllers/comments_controller.rb
+ 31.03 % covered
+
+
+
+ #
+
+ Hits
+
+
+
+
+
+
+
+ 1
+
+
+ class CommentsController < ApplicationController
+
+
+ 1
+
+
+
+
+
+
+ 2
+
+
+ respond_to :html, :xml, :json
+
+
+ 1
+
+
+
+
+
+
+ 3
+
+
+ before_filter :member_only, :only => [:update, :create]
+
+
+ 1
+
+
+
+
+
+
+ 4
+
+
+
+
+
+
+
+
+
+
+
+
+ 5
+
+
+ def index
+
+
+ 1
+
+
+
+
+
+
+ 6
+
+
+ if params[:group_by] == "post"
+
+
+ 0
+
+
+
+
+
+
+ 7
+
+
+ index_by_post
+
+
+ 0
+
+
+
+
+
+
+ 8
+
+
+ else
+
+
+
+
+
+
+
+
+
+ 9
+
+
+ index_by_comment
+
+
+ 0
+
+
+
+
+
+
+ 10
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 11
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 12
+
+
+
+
+
+
+
+
+
+
+
+
+ 13
+
+
+ def update
+
+
+ 1
+
+
+
+
+
+
+ 14
+
+
+ @comment = Comment.find(params[:id])
+
+
+ 0
+
+
+
+
+
+
+ 15
+
+
+ @comment.update_attributes(params[:comment])
+
+
+ 0
+
+
+
+
+
+
+ 16
+
+
+ respond_with(@comment)
+
+
+ 0
+
+
+
+
+
+
+ 17
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 18
+
+
+
+
+
+
+
+
+
+
+
+
+ 19
+
+
+ def create
+
+
+ 1
+
+
+
+
+
+
+ 20
+
+
+ @comment = Comment.new(params[:comment])
+
+
+ 0
+
+
+
+
+
+
+ 21
+
+
+ @comment.post_id = params[:comment][:post_id]
+
+
+ 0
+
+
+
+
+
+
+ 22
+
+
+ @comment.score = 0
+
+
+ 0
+
+
+
+
+
+
+ 23
+
+
+ @comment.save
+
+
+ 0
+
+
+
+
+
+
+ 24
+
+
+ respond_with(@comment) do |format|
+
+
+ 0
+
+
+
+
+
+
+ 25
+
+
+ format.html do
+
+
+ 0
+
+
+
+
+
+
+ 26
+
+
+ redirect_to post_path(@comment.post), :notice => "Comment posted"
+
+
+ 0
+
+
+
+
+
+
+ 27
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 28
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 29
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 30
+
+
+
+
+
+
+
+
+
+
+
+
+ 31
+
+
+ private
+
+
+ 1
+
+
+
+
+
+
+ 32
+
+
+ def index_by_post
+
+
+ 1
+
+
+
+
+
+
+ 33
+
+
+ @posts = Post.find_by_tags(params[:tags]).commented_before(params[:before_date] || Time.now).limit(8)
+
+
+ 0
+
+
+
+
+
+
+ 34
+
+
+ respond_with(@posts) do |format|
+
+
+ 0
+
+
+
+
+
+
+ 35
+
+
+ format.html {render :action => "index_by_post"}
+
+
+ 0
+
+
+
+
+
+
+ 36
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 37
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 38
+
+
+
+
+
+
+
+
+
+
+
+
+ 39
+
+
+ def index_by_comment
+
+
+ 1
+
+
+
+
+
+
+ 40
+
+
+ @search = Comment.search(params[:search])
+
+
+ 0
+
+
+
+
+
+
+ 41
+
+
+ @comments = @search.paginate(:page => params[:page])
+
+
+ 0
+
+
+
+
+
+
+ 42
+
+
+ respond_with(@comments) do |format|
+
+
+ 0
+
+
+
+
+
+
+ 43
+
+
+ format.html {render :action => "index_by_comment"}
+
+
+ 0
+
+
+
+
+
+
+ 44
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 45
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 46
+
+
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ./app/controllers/dmails_controller.rb
+ 36.67 % covered
+
+
+
+ #
+
+ Hits
+
+
+
+
+
+
+
+ 1
+
+
+ class DmailsController < ApplicationController
+
+
+ 1
+
+
+
+
+
+
+ 2
+
+
+ respond_to :html, :xml, :json
+
+
+ 1
+
+
+
+
+
+
+ 3
+
+
+ before_filter :member_only
+
+
+ 1
+
+
+
+
+
+
+ 4
+
+
+ rescue_from User::PrivilegeError, :with => "static/access_denied"
+
+
+ 1
+
+
+
+
+
+
+ 5
+
+
+
+
+
+
+
+
+
+
+
+
+ 6
+
+
+ def new
+
+
+ 1
+
+
+
+
+
+
+ 7
+
+
+ if params[:respond_to_id]
+
+
+ 0
+
+
+
+
+
+
+ 8
+
+
+ @dmail = Dmail.find(params[:respond_to_id]).build_response(:forward => params[:forward])
+
+
+ 0
+
+
+
+
+
+
+ 9
+
+
+ else
+
+
+
+
+
+
+
+
+
+ 10
+
+
+ @dmail = Dmail.new(params[:dmail])
+
+
+ 0
+
+
+
+
+
+
+ 11
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 12
+
+
+
+
+
+
+
+
+
+
+
+
+ 13
+
+
+ respond_with(@dmail)
+
+
+ 0
+
+
+
+
+
+
+ 14
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 15
+
+
+
+
+
+
+
+
+
+
+
+
+ 16
+
+
+ def index
+
+
+ 1
+
+
+
+
+
+
+ 17
+
+
+ @search = Dmail.search(params[:search])
+
+
+ 0
+
+
+
+
+
+
+ 18
+
+
+ @dmails = @search.paginate(:page => params[:page])
+
+
+ 0
+
+
+
+
+
+
+ 19
+
+
+ @dmails.each {|x| check_privilege(x)}
+
+
+ 0
+
+
+
+
+
+
+ 20
+
+
+ respond_with(@dmails)
+
+
+ 0
+
+
+
+
+
+
+ 21
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 22
+
+
+
+
+
+
+
+
+
+
+
+
+ 23
+
+
+ def show
+
+
+ 1
+
+
+
+
+
+
+ 24
+
+
+ @dmail = Dmail.find(params[:id])
+
+
+ 0
+
+
+
+
+
+
+ 25
+
+
+ check_privilege(@dmail)
+
+
+ 0
+
+
+
+
+
+
+ 26
+
+
+ respond_with(@dmail)
+
+
+ 0
+
+
+
+
+
+
+ 27
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 28
+
+
+
+
+
+
+
+
+
+
+
+
+ 29
+
+
+ def create
+
+
+ 1
+
+
+
+
+
+
+ 30
+
+
+ @dmail = Dmail.create_split(params[:dmail])
+
+
+ 0
+
+
+
+
+
+
+ 31
+
+
+ respond_with(@dmail)
+
+
+ 0
+
+
+
+
+
+
+ 32
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 33
+
+
+
+
+
+
+
+
+
+
+
+
+ 34
+
+
+ def destroy
+
+
+ 1
+
+
+
+
+
+
+ 35
+
+
+ @dmail = Dmail.find(params[:id])
+
+
+ 0
+
+
+
+
+
+
+ 36
+
+
+ check_privilege(@dmail)
+
+
+ 0
+
+
+
+
+
+
+ 37
+
+
+ @dmail.destroy
+
+
+ 0
+
+
+
+
+
+
+ 38
+
+
+ redirect_to dmails_path, :notice => "Message destroyed"
+
+
+ 0
+
+
+
+
+
+
+ 39
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 40
+
+
+
+
+
+
+
+
+
+
+
+
+ 41
+
+
+ private
+
+
+ 1
+
+
+
+
+
+
+ 42
+
+
+ def check_privilege(dmail)
+
+
+ 1
+
+
+
+
+
+
+ 43
+
+
+ if !dmail.visible_to?(CurrentUser.user)
+
+
+ 0
+
+
+
+
+
+
+ 44
+
+
+ raise User::PrivilegeError
+
+
+ 0
+
+
+
+
+
+
+ 45
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 46
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 47
+
+
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ./app/controllers/dtext_controller.rb
+ 66.67 % covered
+
+
+
+ #
+
+ Hits
+
+
+
+
+
+
+
+ 1
+
+
+ class DtextController < ApplicationController
+
+
+ 1
+
+
+
+
+
+
+ 2
+
+
+ def preview
+
+
+ 1
+
+
+
+
+
+
+ 3
+
+
+ render :inline => "<h1>Preview</h1><%= format_text(params[:body]) %>"
+
+
+ 0
+
+
+
+
+
+
+ 4
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 5
+
+
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ./app/controllers/favorites_controller.rb
+ 36.36 % covered
+
+
+
+ #
+
+ Hits
+
+
+
+
+
+
+
+ 1
+
+
+ class FavoritesController < ApplicationController
+
+
+ 1
+
+
+
+
+
+
+ 2
+
+
+ def index
+
+
+ 1
+
+
+
+
+
+
+ 3
+
+
+ if params[:tags]
+
+
+ 0
+
+
+
+
+
+
+ 4
+
+
+ redirect_to(posts_path(:tags => "fav:#{CurrentUser.name} #{params[:tags]}"))
+
+
+ 0
+
+
+
+
+
+
+ 5
+
+
+ else
+
+
+
+
+
+
+
+
+
+ 6
+
+
+ @post_set = PostSets::Favorite.new(CurrentUser.user)
+
+
+ 0
+
+
+
+
+
+
+ 7
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 8
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 9
+
+
+
+
+
+
+
+
+
+
+
+
+ 10
+
+
+ def create
+
+
+ 1
+
+
+
+
+
+
+ 11
+
+
+ @favorite = Favorite.create(
+
+
+ 0
+
+
+
+
+
+
+ 12
+
+
+ :user_id => CurrentUser.id,
+
+
+
+
+
+
+
+
+
+ 13
+
+
+ :post_id => params[:id]
+
+
+
+
+
+
+
+
+
+ 14
+
+
+ )
+
+
+
+
+
+
+
+
+
+ 15
+
+
+ render :nothing => true
+
+
+ 0
+
+
+
+
+
+
+ 16
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 17
+
+
+
+
+
+
+
+
+
+
+
+
+ 18
+
+
+ def destroy
+
+
+ 1
+
+
+
+
+
+
+ 19
+
+
+ Favorite.destroy(
+
+
+ 0
+
+
+
+
+
+
+ 20
+
+
+ :user_id => CurrentUser.id,
+
+
+
+
+
+
+
+
+
+ 21
+
+
+ :post_id => params[:id]
+
+
+
+
+
+
+
+
+
+ 22
+
+
+ )
+
+
+
+
+
+
+
+
+
+ 23
+
+
+ render :nothing => true
+
+
+ 0
+
+
+
+
+
+
+ 24
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 25
+
+
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ./app/controllers/forum_posts_controller.rb
+ 37.14 % covered
+
+
+
+ #
+
+ Hits
+
+
+
+
+
+
+
+ 1
+
+
+ class ForumPostsController < ApplicationController
+
+
+ 1
+
+
+
+
+
+
+ 2
+
+
+ respond_to :html, :xml, :json
+
+
+ 1
+
+
+
+
+
+
+ 3
+
+
+ before_filter :member_only, :except => [:index, :show]
+
+
+ 1
+
+
+
+
+
+
+ 4
+
+
+ rescue_from User::PrivilegeError, :with => "static/access_denied"
+
+
+ 1
+
+
+
+
+
+
+ 5
+
+
+
+
+
+
+
+
+
+
+
+
+ 6
+
+
+ def new
+
+
+ 1
+
+
+
+
+
+
+ 7
+
+
+ @forum_post = ForumPost.new(:topic_id => params[:topic_id])
+
+
+ 0
+
+
+
+
+
+
+ 8
+
+
+ respond_with(@forum_post)
+
+
+ 0
+
+
+
+
+
+
+ 9
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 10
+
+
+
+
+
+
+
+
+
+
+
+
+ 11
+
+
+ def edit
+
+
+ 1
+
+
+
+
+
+
+ 12
+
+
+ @forum_post = ForumPost.find(params[:id])
+
+
+ 0
+
+
+
+
+
+
+ 13
+
+
+ check_privilege(@forum_post)
+
+
+ 0
+
+
+
+
+
+
+ 14
+
+
+ respond_with(@forum_post)
+
+
+ 0
+
+
+
+
+
+
+ 15
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 16
+
+
+
+
+
+
+
+
+
+
+
+
+ 17
+
+
+ def index
+
+
+ 1
+
+
+
+
+
+
+ 18
+
+
+ @search = ForumPost.search(params[:search])
+
+
+ 0
+
+
+
+
+
+
+ 19
+
+
+ @forum_posts = @search.paginate(:page => params[:page], :order => "id DESC")
+
+
+ 0
+
+
+
+
+
+
+ 20
+
+
+ respond_with(@forum_posts)
+
+
+ 0
+
+
+
+
+
+
+ 21
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 22
+
+
+
+
+
+
+
+
+
+
+
+
+ 23
+
+
+ def show
+
+
+ 1
+
+
+
+
+
+
+ 24
+
+
+ @forum_post = ForumPost.find(params[:id])
+
+
+ 0
+
+
+
+
+
+
+ 25
+
+
+ respond_with(@forum_post)
+
+
+ 0
+
+
+
+
+
+
+ 26
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 27
+
+
+
+
+
+
+
+
+
+
+
+
+ 28
+
+
+ def create
+
+
+ 1
+
+
+
+
+
+
+ 29
+
+
+ @forum_post = ForumPost.create(params[:forum_post])
+
+
+ 0
+
+
+
+
+
+
+ 30
+
+
+ respond_with(@forum_post)
+
+
+ 0
+
+
+
+
+
+
+ 31
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 32
+
+
+
+
+
+
+
+
+
+
+
+
+ 33
+
+
+ def update
+
+
+ 1
+
+
+
+
+
+
+ 34
+
+
+ @forum_post = ForumPost.find(params[:id])
+
+
+ 0
+
+
+
+
+
+
+ 35
+
+
+ check_privilege(@forum_post)
+
+
+ 0
+
+
+
+
+
+
+ 36
+
+
+ @forum_post.update_attributes(params[:forum_post])
+
+
+ 0
+
+
+
+
+
+
+ 37
+
+
+ respond_with(@forum_post)
+
+
+ 0
+
+
+
+
+
+
+ 38
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 39
+
+
+
+
+
+
+
+
+
+
+
+
+ 40
+
+
+ def destroy
+
+
+ 1
+
+
+
+
+
+
+ 41
+
+
+ @forum_post = ForumPost.find(params[:id])
+
+
+ 0
+
+
+
+
+
+
+ 42
+
+
+ check_privilege(@forum_post)
+
+
+ 0
+
+
+
+
+
+
+ 43
+
+
+ @forum_post.destroy
+
+
+ 0
+
+
+
+
+
+
+ 44
+
+
+ respond_with(@forum_post)
+
+
+ 0
+
+
+
+
+
+
+ 45
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 46
+
+
+
+
+
+
+
+
+
+
+
+
+ 47
+
+
+ private
+
+
+ 1
+
+
+
+
+
+
+ 48
+
+
+ def check_privilege(forum_post)
+
+
+ 1
+
+
+
+
+
+
+ 49
+
+
+ if !forum_post.editable_by?(CurrentUser.user)
+
+
+ 0
+
+
+
+
+
+
+ 50
+
+
+ raise User::PrivilegeError
+
+
+ 0
+
+
+
+
+
+
+ 51
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 52
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 53
+
+
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ./app/controllers/forum_topics_controller.rb
+ 37.14 % covered
+
+
+
+ #
+
+ Hits
+
+
+
+
+
+
+
+ 1
+
+
+ class ForumTopicsController < ApplicationController
+
+
+ 1
+
+
+
+
+
+
+ 2
+
+
+ respond_to :html, :xml, :json
+
+
+ 1
+
+
+
+
+
+
+ 3
+
+
+ before_filter :member_only, :except => [:index, :show]
+
+
+ 1
+
+
+
+
+
+
+ 4
+
+
+ rescue_from User::PrivilegeError, :with => "static/access_denied"
+
+
+ 1
+
+
+
+
+
+
+ 5
+
+
+
+
+
+
+
+
+
+
+
+
+ 6
+
+
+ def new
+
+
+ 1
+
+
+
+
+
+
+ 7
+
+
+ @forum_topic = ForumTopic.new
+
+
+ 0
+
+
+
+
+
+
+ 8
+
+
+ respond_with(@forum_topic)
+
+
+ 0
+
+
+
+
+
+
+ 9
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 10
+
+
+
+
+
+
+
+
+
+
+
+
+ 11
+
+
+ def edit
+
+
+ 1
+
+
+
+
+
+
+ 12
+
+
+ @forum_topic = ForumTopic.find(params[:id])
+
+
+ 0
+
+
+
+
+
+
+ 13
+
+
+ check_privilege(@forum_topic)
+
+
+ 0
+
+
+
+
+
+
+ 14
+
+
+ respond_with(@forum_topic)
+
+
+ 0
+
+
+
+
+
+
+ 15
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 16
+
+
+
+
+
+
+
+
+
+
+
+
+ 17
+
+
+ def index
+
+
+ 1
+
+
+
+
+
+
+ 18
+
+
+ @search = ForumTopic.search(params[:search])
+
+
+ 0
+
+
+
+
+
+
+ 19
+
+
+ @forum_topics = @search.paginate(:page => params[:page], :order => "updated_at DESC")
+
+
+ 0
+
+
+
+
+
+
+ 20
+
+
+ respond_with(@forum_topics)
+
+
+ 0
+
+
+
+
+
+
+ 21
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 22
+
+
+
+
+
+
+
+
+
+
+
+
+ 23
+
+
+ def show
+
+
+ 1
+
+
+
+
+
+
+ 24
+
+
+ @forum_topic = ForumTopic.find(params[:id])
+
+
+ 0
+
+
+
+
+
+
+ 25
+
+
+ respond_with(@forum_topic)
+
+
+ 0
+
+
+
+
+
+
+ 26
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 27
+
+
+
+
+
+
+
+
+
+
+
+
+ 28
+
+
+ def create
+
+
+ 1
+
+
+
+
+
+
+ 29
+
+
+ @forum_topic = ForumTopic.create(params[:forum_topic])
+
+
+ 0
+
+
+
+
+
+
+ 30
+
+
+ respond_with(@forum_topic)
+
+
+ 0
+
+
+
+
+
+
+ 31
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 32
+
+
+
+
+
+
+
+
+
+
+
+
+ 33
+
+
+ def update
+
+
+ 1
+
+
+
+
+
+
+ 34
+
+
+ @forum_topic = ForumTopic.find(params[:id])
+
+
+ 0
+
+
+
+
+
+
+ 35
+
+
+ check_privilege(@forum_topic)
+
+
+ 0
+
+
+
+
+
+
+ 36
+
+
+ @forum_topic.update_attributes(params[:forum_topic])
+
+
+ 0
+
+
+
+
+
+
+ 37
+
+
+ respond_with(@forum_topic)
+
+
+ 0
+
+
+
+
+
+
+ 38
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 39
+
+
+
+
+
+
+
+
+
+
+
+
+ 40
+
+
+ def destroy
+
+
+ 1
+
+
+
+
+
+
+ 41
+
+
+ @forum_topic = ForumTopic.find(params[:id])
+
+
+ 0
+
+
+
+
+
+
+ 42
+
+
+ check_privilege(@forum_topic)
+
+
+ 0
+
+
+
+
+
+
+ 43
+
+
+ @forum_topic.destroy
+
+
+ 0
+
+
+
+
+
+
+ 44
+
+
+ respond_with(@forum_topic)
+
+
+ 0
+
+
+
+
+
+
+ 45
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 46
+
+
+
+
+
+
+
+
+
+
+
+
+ 47
+
+
+ private
+
+
+ 1
+
+
+
+
+
+
+ 48
+
+
+ def check_privilege(forum_topic)
+
+
+ 1
+
+
+
+
+
+
+ 49
+
+
+ if !forum_topic.editable_by?(CurrentUser.user)
+
+
+ 0
+
+
+
+
+
+
+ 50
+
+
+ raise User::PrivilegeError
+
+
+ 0
+
+
+
+
+
+
+ 51
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 52
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 53
+
+
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ./app/controllers/ip_bans_controller.rb
+ 42.86 % covered
+
+
+
+ #
+
+ Hits
+
+
+
+
+
+
+
+ 1
+
+
+ class IpBansController < ApplicationController
+
+
+ 1
+
+
+
+
+
+
+ 2
+
+
+ before_filter :admin_only
+
+
+ 1
+
+
+
+
+
+
+ 3
+
+
+
+
+
+
+
+
+
+
+
+
+ 4
+
+
+ def new
+
+
+ 1
+
+
+
+
+
+
+ 5
+
+
+ @ip_ban = IpBan.new
+
+
+ 0
+
+
+
+
+
+
+ 6
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 7
+
+
+
+
+
+
+
+
+
+
+
+
+ 8
+
+
+ def create
+
+
+ 1
+
+
+
+
+
+
+ 9
+
+
+ @ip_ban = IpBan.create(params[:ip_ban])
+
+
+ 0
+
+
+
+
+
+
+ 10
+
+
+ redirect_to ip_bans_path
+
+
+ 0
+
+
+
+
+
+
+ 11
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 12
+
+
+
+
+
+
+
+
+
+
+
+
+ 13
+
+
+ def index
+
+
+ 1
+
+
+
+
+
+
+ 14
+
+
+ @search = IpBan.search(params[:search])
+
+
+ 0
+
+
+
+
+
+
+ 15
+
+
+ @ip_bans = @search.paginate(:page => params[:page])
+
+
+ 0
+
+
+
+
+
+
+ 16
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 17
+
+
+
+
+
+
+
+
+
+
+
+
+ 18
+
+
+ def destroy
+
+
+ 1
+
+
+
+
+
+
+ 19
+
+
+ @ip_ban = IpBan.find(params[:id])
+
+
+ 0
+
+
+
+
+
+
+ 20
+
+
+ @ip_ban.destroy
+
+
+ 0
+
+
+
+
+
+
+ 21
+
+
+ redirect_to ip_bans_path
+
+
+ 0
+
+
+
+
+
+
+ 22
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 23
+
+
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ./app/controllers/janitor_trials_controller.rb
+ 34.78 % covered
+
+
+
+ #
+
+ Hits
+
+
+
+
+
+
+
+ 1
+
+
+ class JanitorTrialsController < ApplicationController
+
+
+ 1
+
+
+
+
+
+
+ 2
+
+
+ respond_to :html, :xml, :json
+
+
+ 1
+
+
+
+
+
+
+ 3
+
+
+
+
+
+
+
+
+
+
+
+
+ 4
+
+
+ def new
+
+
+ 1
+
+
+
+
+
+
+ 5
+
+
+ @janitor_trial = JanitorTrial.new
+
+
+ 0
+
+
+
+
+
+
+ 6
+
+
+ respond_with(@janitor_trial)
+
+
+ 0
+
+
+
+
+
+
+ 7
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 8
+
+
+
+
+
+
+
+
+
+
+
+
+ 9
+
+
+ def edit
+
+
+ 1
+
+
+
+
+
+
+ 10
+
+
+ @janitor_trial = JanitorTrial.find(params[:id])
+
+
+ 0
+
+
+
+
+
+
+ 11
+
+
+ respond_with(@janitor_trial)
+
+
+ 0
+
+
+
+
+
+
+ 12
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 13
+
+
+
+
+
+
+
+
+
+
+
+
+ 14
+
+
+ def index
+
+
+ 1
+
+
+
+
+
+
+ 15
+
+
+ @search = JanitorTrial.search(params[:search])
+
+
+ 0
+
+
+
+
+
+
+ 16
+
+
+ @janitor_trials = @search.paginate(:page => params[:page])
+
+
+ 0
+
+
+
+
+
+
+ 17
+
+
+ respond_with(@janitor_trials)
+
+
+ 0
+
+
+
+
+
+
+ 18
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 19
+
+
+
+
+
+
+
+
+
+
+
+
+ 20
+
+
+ def create
+
+
+ 1
+
+
+
+
+
+
+ 21
+
+
+ @janitor_trial = JanitorTrial.create(params[:janitor_trial])
+
+
+ 0
+
+
+
+
+
+
+ 22
+
+
+ respond_with(@janitor_trial)
+
+
+ 0
+
+
+
+
+
+
+ 23
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 24
+
+
+
+
+
+
+
+
+
+
+
+
+ 25
+
+
+ def promote
+
+
+ 1
+
+
+
+
+
+
+ 26
+
+
+ @janitor_trial = JanitorTrial.find(params[:id])
+
+
+ 0
+
+
+
+
+
+
+ 27
+
+
+ @janitor_trial.promote!
+
+
+ 0
+
+
+
+
+
+
+ 28
+
+
+ respond_with(@janitor_trial)
+
+
+ 0
+
+
+
+
+
+
+ 29
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 30
+
+
+
+
+
+
+
+
+
+
+
+
+ 31
+
+
+ def demote
+
+
+ 1
+
+
+
+
+
+
+ 32
+
+
+ @janitor_trial = JanitorTrial.find(params[:id])
+
+
+ 0
+
+
+
+
+
+
+ 33
+
+
+ @janitor_trial.demote!
+
+
+ 0
+
+
+
+
+
+
+ 34
+
+
+ respond_with(@janitor_trial)
+
+
+ 0
+
+
+
+
+
+
+ 35
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 36
+
+
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ./app/controllers/notes_controller.rb
+ 100.0 % covered
+
+
+
+ #
+
+ Hits
+
+
+
+
+
+
+
+ 1
+
+
+ class NotesController < ApplicationController
+
+
+ 1
+
+
+
+
+
+
+ 2
+
+
+ respond_to :html, :xml, :json
+
+
+ 1
+
+
+
+
+
+
+ 3
+
+
+ before_filter :member_only, :except => [:index, :show]
+
+
+ 1
+
+
+
+
+
+
+ 4
+
+
+
+
+
+
+
+
+
+
+
+
+ 5
+
+
+ def index
+
+
+ 1
+
+
+
+
+
+
+ 6
+
+
+ @search = Note.search(params[:search])
+
+
+ 2
+
+
+
+
+
+
+ 7
+
+
+ @notes = @search.paginate(:page => params[:page])
+
+
+ 2
+
+
+
+
+
+
+ 8
+
+
+ respond_with(@notes)
+
+
+ 2
+
+
+
+
+
+
+ 9
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 10
+
+
+
+
+
+
+
+
+
+
+
+
+ 11
+
+
+ def show
+
+
+ 1
+
+
+
+
+
+
+ 12
+
+
+ @note = Note.find(params[:id])
+
+
+ 1
+
+
+
+
+
+
+ 13
+
+
+ respond_with(@note)
+
+
+ 1
+
+
+
+
+
+
+ 14
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 15
+
+
+
+
+
+
+
+
+
+
+
+
+ 16
+
+
+ def create
+
+
+ 1
+
+
+
+
+
+
+ 17
+
+
+ @note = Note.create(params[:note])
+
+
+ 1
+
+
+
+
+
+
+ 18
+
+
+ respond_with(@note)
+
+
+ 1
+
+
+
+
+
+
+ 19
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 20
+
+
+
+
+
+
+
+
+
+
+
+
+ 21
+
+
+ def update
+
+
+ 1
+
+
+
+
+
+
+ 22
+
+
+ @note = Note.find(params[:id])
+
+
+ 1
+
+
+
+
+
+
+ 23
+
+
+ @note.update_attributes(params[:note])
+
+
+ 1
+
+
+
+
+
+
+ 24
+
+
+ respond_with(@note)
+
+
+ 1
+
+
+
+
+
+
+ 25
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 26
+
+
+
+
+
+
+
+
+
+
+
+
+ 27
+
+
+ def destroy
+
+
+ 1
+
+
+
+
+
+
+ 28
+
+
+ @note = Note.find(params[:id])
+
+
+ 1
+
+
+
+
+
+
+ 29
+
+
+ @note.destroy
+
+
+ 1
+
+
+
+
+
+
+ 30
+
+
+ respond_with(@note)
+
+
+ 1
+
+
+
+
+
+
+ 31
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 32
+
+
+
+
+
+
+
+
+
+
+
+
+ 33
+
+
+ def revert
+
+
+ 1
+
+
+
+
+
+
+ 34
+
+
+ @note = Note.find(params[:id])
+
+
+ 1
+
+
+
+
+
+
+ 35
+
+
+ @version = NoteVersion.find(params[:version_id])
+
+
+ 1
+
+
+
+
+
+
+ 36
+
+
+ @note.revert_to(@version)
+
+
+ 1
+
+
+
+
+
+
+ 37
+
+
+ respond_with(@note)
+
+
+ 1
+
+
+
+
+
+
+ 38
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 39
+
+
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ./app/controllers/pool_versions_controller.rb
+ 100.0 % covered
+
+
+
+ #
+
+ Hits
+
+
+
+
+
+
+
+ 1
+
+
+ class PoolVersionsController < ApplicationController
+
+
+ 1
+
+
+
+
+
+
+ 2
+
+
+ def index
+
+
+ 1
+
+
+
+
+
+
+ 3
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 4
+
+
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ./app/controllers/pools_controller.rb
+ 100.0 % covered
+
+
+
+ #
+
+ Hits
+
+
+
+
+
+
+
+ 1
+
+
+ class PoolsController < ApplicationController
+
+
+ 1
+
+
+
+
+
+
+ 2
+
+
+ def new
+
+
+ 1
+
+
+
+
+
+
+ 3
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 4
+
+
+
+
+
+
+
+
+
+
+
+
+ 5
+
+
+ def edit
+
+
+ 1
+
+
+
+
+
+
+ 6
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 7
+
+
+
+
+
+
+
+
+
+
+
+
+ 8
+
+
+ def index
+
+
+ 1
+
+
+
+
+
+
+ 9
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 10
+
+
+
+
+
+
+
+
+
+
+
+
+ 11
+
+
+ def show
+
+
+ 1
+
+
+
+
+
+
+ 12
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 13
+
+
+
+
+
+
+
+
+
+
+
+
+ 14
+
+
+ def create
+
+
+ 1
+
+
+
+
+
+
+ 15
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 16
+
+
+
+
+
+
+
+
+
+
+
+
+ 17
+
+
+ def update
+
+
+ 1
+
+
+
+
+
+
+ 18
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 19
+
+
+
+
+
+
+
+
+
+
+
+
+ 20
+
+
+ def destroy
+
+
+ 1
+
+
+
+
+
+
+ 21
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 22
+
+
+
+
+
+
+
+
+
+
+
+
+ 23
+
+
+ def revert
+
+
+ 1
+
+
+
+
+
+
+ 24
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 25
+
+
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ./app/controllers/post_histories_controller.rb
+ 50.0 % covered
+
+
+
+ #
+
+ Hits
+
+
+
+
+
+
+
+ 1
+
+
+ class PostHistoriesController < ApplicationController
+
+
+ 1
+
+
+
+
+
+
+ 2
+
+
+ def index
+
+
+ 1
+
+
+
+
+
+
+ 3
+
+
+ @search = PostHistory.search(params[:search])
+
+
+ 0
+
+
+
+
+
+
+ 4
+
+
+ @histories = @search.paginate(:page => params[:page], :per_page => 20, :order => "updated_at DESC")
+
+
+ 0
+
+
+
+
+
+
+ 5
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 6
+
+
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ./app/controllers/post_moderation_details_controller.rb
+ 100.0 % covered
+
+
+
+ #
+
+ Hits
+
+
+
+
+
+
+
+ 1
+
+
+ class PostModerationDetailsController < ApplicationController
+
+
+ 1
+
+
+
+
+
+
+ 2
+
+
+ def index
+
+
+ 1
+
+
+
+
+
+
+ 3
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 4
+
+
+
+
+
+
+
+
+
+
+
+
+ 5
+
+
+ def create
+
+
+ 1
+
+
+
+
+
+
+ 6
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 7
+
+
+
+
+
+
+
+
+
+
+
+
+ 8
+
+
+ def update
+
+
+ 1
+
+
+
+
+
+
+ 9
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 10
+
+
+
+
+
+
+
+
+
+
+
+
+ 11
+
+
+ def destroy
+
+
+ 1
+
+
+
+
+
+
+ 12
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 13
+
+
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ./app/controllers/post_votes_controller.rb
+ 50.0 % covered
+
+
+
+ #
+
+ Hits
+
+
+
+
+
+
+
+ 1
+
+
+ class PostVotesController < ApplicationController
+
+
+ 1
+
+
+
+
+
+
+ 2
+
+
+ def create
+
+
+ 1
+
+
+
+
+
+
+ 3
+
+
+ @post = Post.find(params[:post_id])
+
+
+ 0
+
+
+
+
+
+
+ 4
+
+
+ @post.vote!(params[:score])
+
+
+ 0
+
+
+
+
+
+
+ 5
+
+
+ rescue PostVote::Error => x
+
+
+
+
+
+
+
+
+
+ 6
+
+
+ @error = x
+
+
+ 0
+
+
+
+
+
+
+ 7
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 8
+
+
+
+
+
+
+
+
+
+
+
+
+ 9
+
+
+ def destroy
+
+
+ 1
+
+
+
+
+
+
+ 10
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 11
+
+
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ./app/controllers/posts_controller.rb
+ 40.0 % covered
+
+
+
+ #
+
+ Hits
+
+
+
+
+
+
+
+ 1
+
+
+ class PostsController < ApplicationController
+
+
+ 1
+
+
+
+
+
+
+ 2
+
+
+ before_filter :member_only, :except => [:show, :index]
+
+
+ 1
+
+
+
+
+
+
+ 3
+
+
+ after_filter :save_recent_tags, :only => [:update]
+
+
+ 1
+
+
+
+
+
+
+ 4
+
+
+ respond_to :html, :xml, :json
+
+
+ 1
+
+
+
+
+
+
+ 5
+
+
+
+
+
+
+
+
+
+
+
+
+ 6
+
+
+ def index
+
+
+ 1
+
+
+
+
+
+
+ 7
+
+
+ @post_set = PostSets::Post.new(params[:tags], :page => params[:page], :before_id => params[:before_id])
+
+
+ 0
+
+
+
+
+
+
+ 8
+
+
+ respond_with(@post_set)
+
+
+ 0
+
+
+
+
+
+
+ 9
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 10
+
+
+
+
+
+
+
+
+
+
+
+
+ 11
+
+
+ def show
+
+
+ 1
+
+
+
+
+
+
+ 12
+
+
+ @post = Post.find(params[:id])
+
+
+ 0
+
+
+
+
+
+
+ 13
+
+
+ respond_with(@post)
+
+
+ 0
+
+
+
+
+
+
+ 14
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 15
+
+
+
+
+
+
+
+
+
+
+
+
+ 16
+
+
+ def update
+
+
+ 1
+
+
+
+
+
+
+ 17
+
+
+ @post = Post.find(params[:id])
+
+
+ 0
+
+
+
+
+
+
+ 18
+
+
+ @post.update_attributes(params[:post])
+
+
+ 0
+
+
+
+
+
+
+ 19
+
+
+ respond_with(@post)
+
+
+ 0
+
+
+
+
+
+
+ 20
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 21
+
+
+
+
+
+
+
+
+
+
+
+
+ 22
+
+
+ def revert
+
+
+ 1
+
+
+
+
+
+
+ 23
+
+
+ @post = Post.find(params[:id])
+
+
+ 0
+
+
+
+
+
+
+ 24
+
+
+ @version = PostVersion.find(params[:version_id])
+
+
+ 0
+
+
+
+
+
+
+ 25
+
+
+ @post.revert_to!(@version)
+
+
+ 0
+
+
+
+
+
+
+ 26
+
+
+ respond_width(@post)
+
+
+ 0
+
+
+
+
+
+
+ 27
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 28
+
+
+
+
+
+
+
+
+
+
+
+
+ 29
+
+
+ private
+
+
+ 1
+
+
+
+
+
+
+ 30
+
+
+ def save_recent_tags
+
+
+ 1
+
+
+
+
+
+
+ 31
+
+
+ if params[:tags] || (params[:post] && params[:post][:tags])
+
+
+ 0
+
+
+
+
+
+
+ 32
+
+
+ tags = Tag.scan_tags(params[:tags] || params[:post][:tags])
+
+
+ 0
+
+
+
+
+
+
+ 33
+
+
+ tags = TagAlias.to_aliased(tags) + Tag.scan_tags(session[:recent_tags])
+
+
+ 0
+
+
+
+
+
+
+ 34
+
+
+ session[:recent_tags] = tags.uniq.slice(0, 40).join(" ")
+
+
+ 0
+
+
+
+
+
+
+ 35
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 36
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 37
+
+
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ./app/controllers/sessions_controller.rb
+ 33.33 % covered
+
+
+
+ #
+
+ Hits
+
+
+
+
+
+
+
+ 1
+
+
+ class SessionsController < ApplicationController
+
+
+ 1
+
+
+
+
+
+
+ 2
+
+
+ def new
+
+
+ 1
+
+
+
+
+
+
+ 3
+
+
+ @user = User.new
+
+
+ 0
+
+
+
+
+
+
+ 4
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 5
+
+
+
+
+
+
+
+
+
+
+
+
+ 6
+
+
+ def create
+
+
+ 1
+
+
+
+
+
+
+ 7
+
+
+ if User.authenticate(params[:name], params[:password])
+
+
+ 0
+
+
+
+
+
+
+ 8
+
+
+ @user = User.find_by_name(params[:name])
+
+
+ 0
+
+
+
+
+
+
+ 9
+
+
+ session[:user_id] = @user.id
+
+
+ 0
+
+
+
+
+
+
+ 10
+
+
+ redirect_to(params[:url] || session[:previous_uri] || posts_path, :notice => "You are now logged in.")
+
+
+ 0
+
+
+
+
+
+
+ 11
+
+
+ else
+
+
+
+
+
+
+
+
+
+ 12
+
+
+ redirect_to(new_session_path, :notice => "Password was incorrect.")
+
+
+ 0
+
+
+
+
+
+
+ 13
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 14
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 15
+
+
+
+
+
+
+
+
+
+
+
+
+ 16
+
+
+ def destroy
+
+
+ 1
+
+
+
+
+
+
+ 17
+
+
+ session.delete(:user_id)
+
+
+ 0
+
+
+
+
+
+
+ 18
+
+
+ redirect_to(posts_path, :notice => "You are now logged out.")
+
+
+ 0
+
+
+
+
+
+
+ 19
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 20
+
+
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ./app/controllers/static_controller.rb
+ 100.0 % covered
+
+
+
+ #
+
+ Hits
+
+
+
+
+
+
+
+ 1
+
+
+ class StaticController < ApplicationController
+
+
+ 1
+
+
+
+
+
+
+ 2
+
+
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ./app/controllers/tag_aliases_controller.rb
+ 100.0 % covered
+
+
+
+ #
+
+ Hits
+
+
+
+
+
+
+
+ 1
+
+
+ class TagAliasesController < ApplicationController
+
+
+ 1
+
+
+
+
+
+
+ 2
+
+
+ def new
+
+
+ 1
+
+
+
+
+
+
+ 3
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 4
+
+
+
+
+
+
+
+
+
+
+
+
+ 5
+
+
+ def edit
+
+
+ 1
+
+
+
+
+
+
+ 6
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 7
+
+
+
+
+
+
+
+
+
+
+
+
+ 8
+
+
+ def index
+
+
+ 1
+
+
+
+
+
+
+ 9
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 10
+
+
+
+
+
+
+
+
+
+
+
+
+ 11
+
+
+ def create
+
+
+ 1
+
+
+
+
+
+
+ 12
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 13
+
+
+
+
+
+
+
+
+
+
+
+
+ 14
+
+
+ def update
+
+
+ 1
+
+
+
+
+
+
+ 15
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 16
+
+
+
+
+
+
+
+
+
+
+
+
+ 17
+
+
+ def destroy
+
+
+ 1
+
+
+
+
+
+
+ 18
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 19
+
+
+
+
+
+
+
+
+
+
+
+
+ 20
+
+
+ def destroy_cache
+
+
+ 1
+
+
+
+
+
+
+ 21
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 22
+
+
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ./app/controllers/tag_implications_controller.rb
+ 100.0 % covered
+
+
+
+ #
+
+ Hits
+
+
+
+
+
+
+
+ 1
+
+
+ class TagImplicationsController < ApplicationController
+
+
+ 1
+
+
+
+
+
+
+ 2
+
+
+ def new
+
+
+ 1
+
+
+
+
+
+
+ 3
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 4
+
+
+
+
+
+
+
+
+
+
+
+
+ 5
+
+
+ def edit
+
+
+ 1
+
+
+
+
+
+
+ 6
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 7
+
+
+
+
+
+
+
+
+
+
+
+
+ 8
+
+
+ def index
+
+
+ 1
+
+
+
+
+
+
+ 9
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 10
+
+
+
+
+
+
+
+
+
+
+
+
+ 11
+
+
+ def create
+
+
+ 1
+
+
+
+
+
+
+ 12
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 13
+
+
+
+
+
+
+
+
+
+
+
+
+ 14
+
+
+ def update
+
+
+ 1
+
+
+
+
+
+
+ 15
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 16
+
+
+
+
+
+
+
+
+
+
+
+
+ 17
+
+
+ def destroy
+
+
+ 1
+
+
+
+
+
+
+ 18
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 19
+
+
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ./app/controllers/tag_subscriptions_controller.rb
+ 100.0 % covered
+
+
+
+ #
+
+ Hits
+
+
+
+
+
+
+
+ 1
+
+
+ class TagSubscriptionsController < ApplicationController
+
+
+ 1
+
+
+
+
+
+
+ 2
+
+
+ def new
+
+
+ 1
+
+
+
+
+
+
+ 3
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 4
+
+
+
+
+
+
+
+
+
+
+
+
+ 5
+
+
+ def edit
+
+
+ 1
+
+
+
+
+
+
+ 6
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 7
+
+
+
+
+
+
+
+
+
+
+
+
+ 8
+
+
+ def index
+
+
+ 1
+
+
+
+
+
+
+ 9
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 10
+
+
+
+
+
+
+
+
+
+
+
+
+ 11
+
+
+ def show
+
+
+ 1
+
+
+
+
+
+
+ 12
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 13
+
+
+
+
+
+
+
+
+
+
+
+
+ 14
+
+
+ def create
+
+
+ 1
+
+
+
+
+
+
+ 15
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 16
+
+
+
+
+
+
+
+
+
+
+
+
+ 17
+
+
+ def update
+
+
+ 1
+
+
+
+
+
+
+ 18
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 19
+
+
+
+
+
+
+
+
+
+
+
+
+ 20
+
+
+ def destroy
+
+
+ 1
+
+
+
+
+
+
+ 21
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 22
+
+
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ./app/controllers/tags_controller.rb
+ 100.0 % covered
+
+
+
+ #
+
+ Hits
+
+
+
+
+
+
+
+ 1
+
+
+ class TagsController < ApplicationController
+
+
+ 1
+
+
+
+
+
+
+ 2
+
+
+ def edit
+
+
+ 1
+
+
+
+
+
+
+ 3
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 4
+
+
+
+
+
+
+
+
+
+
+
+
+ 5
+
+
+ def index
+
+
+ 1
+
+
+
+
+
+
+ 6
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 7
+
+
+
+
+
+
+
+
+
+
+
+
+ 8
+
+
+ def show
+
+
+ 1
+
+
+
+
+
+
+ 9
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 10
+
+
+
+
+
+
+
+
+
+
+
+
+ 11
+
+
+ def update
+
+
+ 1
+
+
+
+
+
+
+ 12
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 13
+
+
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ./app/controllers/unapprovals_controller.rb
+ 100.0 % covered
+
+
+
+ #
+
+ Hits
+
+
+
+
+
+
+
+ 1
+
+
+ class UnapprovalsController < ApplicationController
+
+
+ 1
+
+
+
+
+
+
+ 2
+
+
+ def new
+
+
+ 1
+
+
+
+
+
+
+ 3
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 4
+
+
+
+
+
+
+
+
+
+
+
+
+ 5
+
+
+ def index
+
+
+ 1
+
+
+
+
+
+
+ 6
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 7
+
+
+
+
+
+
+
+
+
+
+
+
+ 8
+
+
+ def create
+
+
+ 1
+
+
+
+
+
+
+ 9
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 10
+
+
+
+
+
+
+
+
+
+
+
+
+ 11
+
+
+ def destroy
+
+
+ 1
+
+
+
+
+
+
+ 12
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 13
+
+
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ./app/controllers/uploads_controller.rb
+ 38.1 % covered
+
+
+
+ #
+
+ Hits
+
+
+
+
+
+
+
+ 1
+
+
+ class UploadsController < ApplicationController
+
+
+ 1
+
+
+
+
+
+
+ 2
+
+
+ before_filter :member_only
+
+
+ 1
+
+
+
+
+
+
+ 3
+
+
+ respond_to :html, :xml, :json
+
+
+ 1
+
+
+
+
+
+
+ 4
+
+
+
+
+
+
+
+
+
+
+
+
+ 5
+
+
+ def new
+
+
+ 1
+
+
+
+
+
+
+ 6
+
+
+ @upload = Upload.new(:rating => "q")
+
+
+ 0
+
+
+
+
+
+
+ 7
+
+
+ if params[:url]
+
+
+ 0
+
+
+
+
+
+
+ 8
+
+
+ @post = Post.find_by_source(params[:url])
+
+
+ 0
+
+
+
+
+
+
+ 9
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 10
+
+
+ respond_with(@upload)
+
+
+ 0
+
+
+
+
+
+
+ 11
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 12
+
+
+
+
+
+
+
+
+
+
+
+
+ 13
+
+
+ def index
+
+
+ 1
+
+
+
+
+
+
+ 14
+
+
+ @uploads = Upload.where("uploader_id = ?", CurrentUser.user.id).includes(:uploader).order("uploads.id desc").limit(10)
+
+
+ 0
+
+
+
+
+
+
+ 15
+
+
+ respond_with(@uploads)
+
+
+ 0
+
+
+
+
+
+
+ 16
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 17
+
+
+
+
+
+
+
+
+
+
+
+
+ 18
+
+
+ def show
+
+
+ 1
+
+
+
+
+
+
+ 19
+
+
+ @upload = Upload.find(params[:id])
+
+
+ 0
+
+
+
+
+
+
+ 20
+
+
+ respond_with(@upload)
+
+
+ 0
+
+
+
+
+
+
+ 21
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 22
+
+
+
+
+
+
+
+
+
+
+
+
+ 23
+
+
+ def create
+
+
+ 1
+
+
+
+
+
+
+ 24
+
+
+ @upload = Upload.create(params[:upload])
+
+
+ 0
+
+
+
+
+
+
+ 25
+
+
+ respond_with(@upload)
+
+
+ 0
+
+
+
+
+
+
+ 26
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 27
+
+
+
+
+
+
+
+
+
+
+
+
+ 28
+
+
+ def update
+
+
+ 1
+
+
+
+
+
+
+ 29
+
+
+ @upload = Upload.find(params[:id])
+
+
+ 0
+
+
+
+
+
+
+ 30
+
+
+ @upload.process!
+
+
+ 0
+
+
+
+
+
+
+ 31
+
+
+ respond_with(@upload)
+
+
+ 0
+
+
+
+
+
+
+ 32
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 33
+
+
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ./app/controllers/user_feedback_controller.rb
+ 100.0 % covered
+
+
+
+ #
+
+ Hits
+
+
+
+
+
+
+
+ 1
+
+
+ class UserFeedbackController < ApplicationController
+
+
+ 1
+
+
+
+
+
+
+ 2
+
+
+ def new
+
+
+ 1
+
+
+
+
+
+
+ 3
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 4
+
+
+
+
+
+
+
+
+
+
+
+
+ 5
+
+
+ def edit
+
+
+ 1
+
+
+
+
+
+
+ 6
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 7
+
+
+
+
+
+
+
+
+
+
+
+
+ 8
+
+
+ def index
+
+
+ 1
+
+
+
+
+
+
+ 9
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 10
+
+
+
+
+
+
+
+
+
+
+
+
+ 11
+
+
+ def create
+
+
+ 1
+
+
+
+
+
+
+ 12
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 13
+
+
+
+
+
+
+
+
+
+
+
+
+ 14
+
+
+ def update
+
+
+ 1
+
+
+
+
+
+
+ 15
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 16
+
+
+
+
+
+
+
+
+
+
+
+
+ 17
+
+
+ def destroy
+
+
+ 1
+
+
+
+
+
+
+ 18
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 19
+
+
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ./app/controllers/user_maintenance_controller.rb
+ 100.0 % covered
+
+
+
+ #
+
+ Hits
+
+
+
+
+
+
+
+ 1
+
+
+ class UserMaintenanceController < ApplicationController
+
+
+ 1
+
+
+
+
+
+
+ 2
+
+
+ def delete_account
+
+
+ 1
+
+
+
+
+
+
+ 3
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 4
+
+
+
+
+
+
+
+
+
+
+
+
+ 5
+
+
+ def login_reminder
+
+
+ 1
+
+
+
+
+
+
+ 6
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 7
+
+
+
+
+
+
+
+
+
+
+
+
+ 8
+
+
+ def reset_password
+
+
+ 1
+
+
+
+
+
+
+ 9
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 10
+
+
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ./app/controllers/users_controller.rb
+ 45.45 % covered
+
+
+
+ #
+
+ Hits
+
+
+
+
+
+
+
+ 1
+
+
+ class UsersController < ApplicationController
+
+
+ 1
+
+
+
+
+
+
+ 2
+
+
+ respond_to :html, :xml, :json
+
+
+ 1
+
+
+
+
+
+
+ 3
+
+
+ before_filter :member_only, :only => [:edit, :show, :update, :destroy]
+
+
+ 1
+
+
+
+
+
+
+ 4
+
+
+
+
+
+
+
+
+
+
+
+
+ 5
+
+
+ def new
+
+
+ 1
+
+
+
+
+
+
+ 6
+
+
+ @user = User.new
+
+
+ 0
+
+
+
+
+
+
+ 7
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 8
+
+
+
+
+
+
+
+
+
+
+
+
+ 9
+
+
+ def edit
+
+
+ 1
+
+
+
+
+
+
+ 10
+
+
+ @user = User.find(params[:id])
+
+
+ 0
+
+
+
+
+
+
+ 11
+
+
+ unless CurrentUser.user.is_admin?
+
+
+ 0
+
+
+
+
+
+
+ 12
+
+
+ @user = CurrentUser.user
+
+
+ 0
+
+
+
+
+
+
+ 13
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 14
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 15
+
+
+
+
+
+
+
+
+
+
+
+
+ 16
+
+
+ def index
+
+
+ 1
+
+
+
+
+
+
+ 17
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 18
+
+
+
+
+
+
+
+
+
+
+
+
+ 19
+
+
+ def show
+
+
+ 1
+
+
+
+
+
+
+ 20
+
+
+ @user = User.find(params[:id])
+
+
+ 0
+
+
+
+
+
+
+ 21
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 22
+
+
+
+
+
+
+
+
+
+
+
+
+ 23
+
+
+ def create
+
+
+ 1
+
+
+
+
+
+
+ 24
+
+
+ @user = User.new(params[:user].merge(:ip_addr => request.remote_ip))
+
+
+ 0
+
+
+
+
+
+
+ 25
+
+
+ if @user.save
+
+
+ 0
+
+
+
+
+
+
+ 26
+
+
+ flash[:notice] = "You have succesfully created a new account"
+
+
+ 0
+
+
+
+
+
+
+ 27
+
+
+ session[:user_id] = @user.id
+
+
+ 0
+
+
+
+
+
+
+ 28
+
+
+ redirect_to user_path(@user)
+
+
+ 0
+
+
+
+
+
+
+ 29
+
+
+ else
+
+
+
+
+
+
+
+
+
+ 30
+
+
+ flash[:notice] = "There were errors"
+
+
+ 0
+
+
+
+
+
+
+ 31
+
+
+ render :action => "new"
+
+
+ 0
+
+
+
+
+
+
+ 32
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 33
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 34
+
+
+
+
+
+
+
+
+
+
+
+
+ 35
+
+
+ def update
+
+
+ 1
+
+
+
+
+
+
+ 36
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 37
+
+
+
+
+
+
+
+
+
+
+
+
+ 38
+
+
+ def destroy
+
+
+ 1
+
+
+
+
+
+
+ 39
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 40
+
+
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ./app/controllers/wiki_page_versions_controller.rb
+ 100.0 % covered
+
+
+
+ #
+
+ Hits
+
+
+
+
+
+
+
+ 1
+
+
+ class WikiPageVersionsController < ApplicationController
+
+
+ 1
+
+
+
+
+
+
+ 2
+
+
+ def index
+
+
+ 1
+
+
+
+
+
+
+ 3
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 4
+
+
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ./app/controllers/wiki_pages_controller.rb
+ 100.0 % covered
+
+
+
+ #
+
+ Hits
+
+
+
+
+
+
+
+ 1
+
+
+ class WikiPagesController < ApplicationController
+
+
+ 1
+
+
+
+
+
+
+ 2
+
+
+ def new
+
+
+ 1
+
+
+
+
+
+
+ 3
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 4
+
+
+
+
+
+
+
+
+
+
+
+
+ 5
+
+
+ def edit
+
+
+ 1
+
+
+
+
+
+
+ 6
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 7
+
+
+
+
+
+
+
+
+
+
+
+
+ 8
+
+
+ def index
+
+
+ 1
+
+
+
+
+
+
+ 9
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 10
+
+
+
+
+
+
+
+
+
+
+
+
+ 11
+
+
+ def show
+
+
+ 1
+
+
+
+
+
+
+ 12
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 13
+
+
+
+
+
+
+
+
+
+
+
+
+ 14
+
+
+ def create
+
+
+ 1
+
+
+
+
+
+
+ 15
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 16
+
+
+
+
+
+
+
+
+
+
+
+
+ 17
+
+
+ def update
+
+
+ 1
+
+
+
+
+
+
+ 18
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 19
+
+
+
+
+
+
+
+
+
+
+
+
+ 20
+
+
+ def destroy
+
+
+ 1
+
+
+
+
+
+
+ 21
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 22
+
+
+
+
+
+
+
+
+
+
+
+
+ 23
+
+
+ def revert
+
+
+ 1
+
+
+
+
+
+
+ 24
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 25
+
+
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ./app/helpers/admin/users_helper.rb
+ 100.0 % covered
+
+
+
+ #
+
+ Hits
+
+
+
+
+
+
+
+ 1
+
+
+ module Admin::UsersHelper
+
+
+ 1
+
+
+
+
+
+
+ 2
+
+
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ./app/helpers/advertisements_helper.rb
+ 33.33 % covered
+
+
+
+ #
+
+ Hits
+
+
+
+
+
+
+
+ 1
+
+
+ module AdvertisementsHelper
+
+
+ 1
+
+
+
+
+
+
+ 2
+
+
+ def render_advertisement(ad_type)
+
+
+ 1
+
+
+
+
+
+
+ 3
+
+
+ if Danbooru.config.can_user_see_ads?(CurrentUser.user)
+
+
+ 0
+
+
+
+
+
+
+ 4
+
+
+ @advertisement = Advertisement.find(:first, :conditions => ["ad_type = ? AND status = 'active'", ad_type], :order => "random()")
+
+
+ 0
+
+
+
+
+
+
+ 5
+
+
+ content_tag(
+
+
+
+
+
+
+
+
+
+ 6
+
+
+ "div",
+
+
+ 0
+
+
+
+
+
+
+ 7
+
+
+ link_to_remote(
+
+
+
+
+
+
+
+
+
+ 8
+
+
+ image_tag(
+
+
+
+
+
+
+
+
+
+ 9
+
+
+ @advertisement.image_url,
+
+
+
+
+
+
+
+
+
+ 10
+
+
+ :alt => "Advertisement",
+
+
+
+
+
+
+
+
+
+ 11
+
+
+ :width => @advertisement.width,
+
+
+
+
+
+
+
+
+
+ 12
+
+
+ :height => @advertisement.height
+
+
+
+
+
+
+
+
+
+ 13
+
+
+ ),
+
+
+
+
+
+
+
+
+
+ 14
+
+
+ advertisement_hit_path(:advertisement_id => @advertisement.id),
+
+
+
+
+
+
+
+
+
+ 15
+
+
+ :style => "margin-bottom: 1em;"
+
+
+
+
+
+
+
+
+
+ 16
+
+
+ )
+
+
+
+
+
+
+
+
+
+ 17
+
+
+ )
+
+
+
+
+
+
+
+
+
+ 18
+
+
+ else
+
+
+
+
+
+
+
+
+
+ 19
+
+
+ ""
+
+
+ 0
+
+
+
+
+
+
+ 20
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 21
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 22
+
+
+
+
+
+
+
+
+
+
+
+
+ 23
+
+
+ def render_rss_advertisement
+
+
+ 1
+
+
+
+
+
+
+ 24
+
+
+ if Danbooru.config.can_user_see_ads?(CurrentUser.user)
+
+
+ 0
+
+
+
+
+
+
+ 25
+
+
+ render :partial => "static/jlist_rss_ads"
+
+
+ 0
+
+
+
+
+
+
+ 26
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 27
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 28
+
+
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ./app/helpers/application_helper.rb
+ 50.0 % covered
+
+
+
+ #
+
+ Hits
+
+
+
+
+
+
+
+ 1
+
+
+ module ApplicationHelper
+
+
+ 1
+
+
+
+
+
+
+ 2
+
+
+ def nav_link_to(text, url, options = nil)
+
+
+ 1
+
+
+
+
+
+
+ 3
+
+
+ if nav_link_match(params[:controller], url)
+
+
+ 50
+
+
+
+
+
+
+ 4
+
+
+ klass = "current"
+
+
+ 5
+
+
+
+
+
+
+ 5
+
+
+ else
+
+
+
+
+
+
+
+
+
+ 6
+
+
+ klass = nil
+
+
+ 45
+
+
+
+
+
+
+ 7
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 8
+
+
+
+
+
+
+
+
+
+
+
+
+ 9
+
+
+ content_tag("li", link_to(text, url, options), :class => klass)
+
+
+ 50
+
+
+
+
+
+
+ 10
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 11
+
+
+
+
+
+
+
+
+
+
+
+
+ 12
+
+
+ def format_text(text, options = {})
+
+
+ 1
+
+
+
+
+
+
+ 13
+
+
+ DText.parse(text)
+
+
+ 0
+
+
+
+
+
+
+ 14
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 15
+
+
+
+
+
+
+
+
+
+
+
+
+ 16
+
+
+ def error_messages_for(instance_name)
+
+
+ 1
+
+
+
+
+
+
+ 17
+
+
+ instance = instance_variable_get("@#{instance_name}")
+
+
+ 0
+
+
+
+
+
+
+ 18
+
+
+
+
+
+
+
+
+
+
+
+
+ 19
+
+
+ if instance.errors.any?
+
+
+ 0
+
+
+
+
+
+
+ 20
+
+
+ %{<div class="error-messages"><h1>There were errors</h1><p>#{instance.__send__(:errors).full_messages.join(", ")}</div>}.html_safe
+
+
+ 0
+
+
+
+
+
+
+ 21
+
+
+ else
+
+
+
+
+
+
+
+
+
+ 22
+
+
+ ""
+
+
+ 0
+
+
+
+
+
+
+ 23
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 24
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 25
+
+
+
+
+
+
+
+
+
+
+
+
+ 26
+
+
+ def compact_time(time)
+
+
+ 1
+
+
+
+
+
+
+ 27
+
+
+ if time > Time.now.beginning_of_day
+
+
+ 0
+
+
+
+
+
+
+ 28
+
+
+ time.strftime("%H:%M")
+
+
+ 0
+
+
+
+
+
+
+ 29
+
+
+ elsif time > Time.now.beginning_of_year
+
+
+ 0
+
+
+
+
+
+
+ 30
+
+
+ time.strftime("%b %e")
+
+
+ 0
+
+
+
+
+
+
+ 31
+
+
+ else
+
+
+
+
+
+
+
+
+
+ 32
+
+
+ time.strftime("%b %e, %Y")
+
+
+ 0
+
+
+
+
+
+
+ 33
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 34
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 35
+
+
+
+
+
+
+
+
+
+
+
+
+ 36
+
+
+ protected
+
+
+ 1
+
+
+
+
+
+
+ 37
+
+
+ def nav_link_match(controller, url)
+
+
+ 1
+
+
+
+
+
+
+ 38
+
+
+ url =~ case controller
+
+
+
+
+
+
+
+
+
+ 39
+
+
+ when "tag_aliases", "tag_implications"
+
+
+
+
+
+
+
+
+
+ 40
+
+
+ /^\/tags/
+
+
+ 0
+
+
+
+
+
+
+ 41
+
+
+
+
+
+
+
+
+
+
+
+
+ 42
+
+
+ when "sessions", "user_maintenance"
+
+
+
+
+
+
+
+
+
+ 43
+
+
+ /^\/users/
+
+
+ 0
+
+
+
+
+
+
+ 44
+
+
+
+
+
+
+
+
+
+
+
+
+ 45
+
+
+ when "forum_posts"
+
+
+
+
+
+
+
+
+
+ 46
+
+
+ /^\/forum_topics/
+
+
+ 0
+
+
+
+
+
+
+ 47
+
+
+
+
+
+
+
+
+
+
+
+
+ 48
+
+
+ else
+
+
+
+
+
+
+
+
+
+ 49
+
+
+ /^\/#{controller}/
+
+
+ 50
+
+
+
+
+
+
+ 50
+
+
+ end
+
+
+ 50
+
+
+
+
+
+
+ 51
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 52
+
+
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ./app/helpers/artist_versions_helper.rb
+ 100.0 % covered
+
+
+
+ #
+
+ Hits
+
+
+
+
+
+
+
+ 1
+
+
+ module ArtistVersionsHelper
+
+
+ 1
+
+
+
+
+
+
+ 2
+
+
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ./app/helpers/artists_helper.rb
+ 33.33 % covered
+
+
+
+ #
+
+ Hits
+
+
+
+
+
+
+
+ 1
+
+
+ module ArtistsHelper
+
+
+ 1
+
+
+
+
+
+
+ 2
+
+
+ def link_to_artist(name)
+
+
+ 1
+
+
+
+
+
+
+ 3
+
+
+ artist = Artist.find_by_name(name)
+
+
+ 0
+
+
+
+
+
+
+ 4
+
+
+
+
+
+
+
+
+
+
+
+
+ 5
+
+
+ if artist
+
+
+ 0
+
+
+
+
+
+
+ 6
+
+
+ link_to(artist.name, artist_path(artist))
+
+
+ 0
+
+
+
+
+
+
+ 7
+
+
+ else
+
+
+
+
+
+
+
+
+
+ 8
+
+
+ link_to(name, new_artist_path(:name => name)) + " " + content_tag("span", "*", :class => "new-artist")
+
+
+ 0
+
+
+
+
+
+
+ 9
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 10
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 11
+
+
+
+
+
+
+
+
+
+
+
+
+ 12
+
+
+ def link_to_artists(names)
+
+
+ 1
+
+
+
+
+
+
+ 13
+
+
+ names.map do |name|
+
+
+ 0
+
+
+
+
+
+
+ 14
+
+
+ link_to_artist(name)
+
+
+ 0
+
+
+
+
+
+
+ 15
+
+
+ end.join(", ").html_safe
+
+
+
+
+
+
+
+
+
+ 16
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 17
+
+
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ./app/helpers/bans_helper.rb
+ 100.0 % covered
+
+
+
+ #
+
+ Hits
+
+
+
+
+
+
+
+ 1
+
+
+ module BansHelper
+
+
+ 1
+
+
+
+
+
+
+ 2
+
+
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ./app/helpers/comment_votes_helper.rb
+ 100.0 % covered
+
+
+
+ #
+
+ Hits
+
+
+
+
+
+
+
+ 1
+
+
+ module CommentVotesHelper
+
+
+ 1
+
+
+
+
+
+
+ 2
+
+
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ./app/helpers/comments_helper.rb
+ 100.0 % covered
+
+
+
+ #
+
+ Hits
+
+
+
+
+
+
+
+ 1
+
+
+ module CommentsHelper
+
+
+ 1
+
+
+
+
+
+
+ 2
+
+
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ./app/helpers/dmails_helper.rb
+ 100.0 % covered
+
+
+
+ #
+
+ Hits
+
+
+
+
+
+
+
+ 1
+
+
+ module DmailsHelper
+
+
+ 1
+
+
+
+
+
+
+ 2
+
+
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ./app/helpers/favorites_helper.rb
+ 100.0 % covered
+
+
+
+ #
+
+ Hits
+
+
+
+
+
+
+
+ 1
+
+
+ module FavoritesHelper
+
+
+ 1
+
+
+
+
+
+
+ 2
+
+
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ./app/helpers/forum_posts_helper.rb
+ 100.0 % covered
+
+
+
+ #
+
+ Hits
+
+
+
+
+
+
+
+ 1
+
+
+ module ForumPostsHelper
+
+
+ 1
+
+
+
+
+
+
+ 2
+
+
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ./app/helpers/forum_topics_helper.rb
+ 100.0 % covered
+
+
+
+ #
+
+ Hits
+
+
+
+
+
+
+
+ 1
+
+
+ module ForumTopicsHelper
+
+
+ 1
+
+
+
+
+
+
+ 2
+
+
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ./app/helpers/janitor_trials_helper.rb
+ 100.0 % covered
+
+
+
+ #
+
+ Hits
+
+
+
+
+
+
+
+ 1
+
+
+ module JanitorTrialsHelper
+
+
+ 1
+
+
+
+
+
+
+ 2
+
+
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ./app/helpers/notes_helper.rb
+ 100.0 % covered
+
+
+
+ #
+
+ Hits
+
+
+
+
+
+
+
+ 1
+
+
+ module NotesHelper
+
+
+ 1
+
+
+
+
+
+
+ 2
+
+
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ./app/helpers/pool_versions_helper.rb
+ 100.0 % covered
+
+
+
+ #
+
+ Hits
+
+
+
+
+
+
+
+ 1
+
+
+ module PoolVersionsHelper
+
+
+ 1
+
+
+
+
+
+
+ 2
+
+
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ./app/helpers/pools_helper.rb
+ 100.0 % covered
+
+
+
+ #
+
+ Hits
+
+
+
+
+
+
+
+ 1
+
+
+ module PoolsHelper
+
+
+ 1
+
+
+
+
+
+
+ 2
+
+
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ./app/helpers/post_moderation_details_helper.rb
+ 100.0 % covered
+
+
+
+ #
+
+ Hits
+
+
+
+
+
+
+
+ 1
+
+
+ module PostModerationDetailsHelper
+
+
+ 1
+
+
+
+
+
+
+ 2
+
+
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ./app/helpers/post_versions_helper.rb
+ 100.0 % covered
+
+
+
+ #
+
+ Hits
+
+
+
+
+
+
+
+ 1
+
+
+ module PostVersionsHelper
+
+
+ 1
+
+
+
+
+
+
+ 2
+
+
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ./app/helpers/post_votes_helper.rb
+ 100.0 % covered
+
+
+
+ #
+
+ Hits
+
+
+
+
+
+
+
+ 1
+
+
+ module PostVotesHelper
+
+
+ 1
+
+
+
+
+
+
+ 2
+
+
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ./app/helpers/posts_helper.rb
+ 20.0 % covered
+
+
+
+ #
+
+ Hits
+
+
+
+
+
+
+
+ 1
+
+
+ module PostsHelper
+
+
+ 1
+
+
+
+
+
+
+ 2
+
+
+ def resize_image_links(post, user)
+
+
+ 1
+
+
+
+
+
+
+ 3
+
+
+ links = []
+
+
+ 0
+
+
+
+
+
+
+ 4
+
+
+
+
+
+
+
+
+
+
+
+
+ 5
+
+
+ links << %{<a href="#" data-src="#{post.file_url}" data-width="#{post.image_width}" data-height="#{post.image_height}">Original</a>} if post.has_medium? || post.has_large?
+
+
+ 0
+
+
+
+
+
+
+ 6
+
+
+ links << %{<a href="#" data-src="#{post.medium_file_url}" data-width="#{post.medium_image_width}" data-height="#{post.medium_image_height}">Medium</a>} if post.has_medium?
+
+
+ 0
+
+
+
+
+
+
+ 7
+
+
+ links << %{<a href="#" data-src="#{post.large_file_url}" data-width="#{post.large_image_width}" data-height="#{post.large_image_height}">Large</a>} if post.has_large?
+
+
+ 0
+
+
+
+
+
+
+ 8
+
+
+
+
+
+
+
+
+
+
+
+
+ 9
+
+
+ if links.any?
+
+
+ 0
+
+
+
+
+
+
+ 10
+
+
+ html = %{<li id="resize-link"><a href="#">Resize</a></li><ul id="resize-links">} + links.map {|x| %{<li>#{x}</li>}}.join("") + %{</ul>}
+
+
+ 0
+
+
+
+
+
+
+ 11
+
+
+ html.html_safe
+
+
+ 0
+
+
+
+
+
+
+ 12
+
+
+ else
+
+
+
+
+
+
+
+
+
+ 13
+
+
+ ""
+
+
+ 0
+
+
+
+
+
+
+ 14
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 15
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 16
+
+
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ./app/helpers/sessions_helper.rb
+ 100.0 % covered
+
+
+
+ #
+
+ Hits
+
+
+
+
+
+
+
+ 1
+
+
+ module SessionsHelper
+
+
+ 1
+
+
+
+
+
+
+ 2
+
+
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ./app/helpers/tag_aliases_helper.rb
+ 100.0 % covered
+
+
+
+ #
+
+ Hits
+
+
+
+
+
+
+
+ 1
+
+
+ module TagAliasesHelper
+
+
+ 1
+
+
+
+
+
+
+ 2
+
+
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ./app/helpers/tag_implications_helper.rb
+ 100.0 % covered
+
+
+
+ #
+
+ Hits
+
+
+
+
+
+
+
+ 1
+
+
+ module TagImplicationsHelper
+
+
+ 1
+
+
+
+
+
+
+ 2
+
+
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ./app/helpers/tag_subscriptions_helper.rb
+ 100.0 % covered
+
+
+
+ #
+
+ Hits
+
+
+
+
+
+
+
+ 1
+
+
+ module TagSubscriptionsHelper
+
+
+ 1
+
+
+
+
+
+
+ 2
+
+
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ./app/helpers/tags_helper.rb
+ 100.0 % covered
+
+
+
+ #
+
+ Hits
+
+
+
+
+
+
+
+ 1
+
+
+ module TagsHelper
+
+
+ 1
+
+
+
+
+
+
+ 2
+
+
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ./app/helpers/unapprovals_helper.rb
+ 100.0 % covered
+
+
+
+ #
+
+ Hits
+
+
+
+
+
+
+
+ 1
+
+
+ module UnapprovalsHelper
+
+
+ 1
+
+
+
+
+
+
+ 2
+
+
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ./app/helpers/uploads_helper.rb
+ 100.0 % covered
+
+
+
+ #
+
+ Hits
+
+
+
+
+
+
+
+ 1
+
+
+ module UploadsHelper
+
+
+ 1
+
+
+
+
+
+
+ 2
+
+
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ./app/helpers/user_feedback_helper.rb
+ 100.0 % covered
+
+
+
+ #
+
+ Hits
+
+
+
+
+
+
+
+ 1
+
+
+ module UserFeedbackHelper
+
+
+ 1
+
+
+
+
+
+
+ 2
+
+
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ./app/helpers/users_helper.rb
+ 100.0 % covered
+
+
+
+ #
+
+ Hits
+
+
+
+
+
+
+
+ 1
+
+
+ module UsersHelper
+
+
+ 1
+
+
+
+
+
+
+ 2
+
+
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ./app/helpers/wiki_page_versions_helper.rb
+ 100.0 % covered
+
+
+
+ #
+
+ Hits
+
+
+
+
+
+
+
+ 1
+
+
+ module WikiPageVersionsHelper
+
+
+ 1
+
+
+
+
+
+
+ 2
+
+
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ./app/helpers/wiki_pages_helper.rb
+ 100.0 % covered
+
+
+
+ #
+
+ Hits
+
+
+
+
+
+
+
+ 1
+
+
+ module WikiPagesHelper
+
+
+ 1
+
+
+
+
+
+
+ 2
+
+
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ./app/logical/anonymous_user.rb
+ 52.54 % covered
+
+
+
+ #
+
+ Hits
+
+
+
+
+
+
+
+ 1
+
+
+ # This is a proxy class to make various nil checks unnecessary
+
+
+
+
+
+
+
+
+
+ 2
+
+
+ class AnonymousUser
+
+
+ 1
+
+
+
+
+
+
+ 3
+
+
+ def id
+
+
+ 1
+
+
+
+
+
+
+ 4
+
+
+ nil
+
+
+
+
+
+
+
+
+
+ 5
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 6
+
+
+
+
+
+
+
+
+
+
+
+
+ 7
+
+
+ def level
+
+
+ 1
+
+
+
+
+
+
+ 8
+
+
+ 0
+
+
+ 0
+
+
+
+
+
+
+ 9
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 10
+
+
+
+
+
+
+
+
+
+
+
+
+ 11
+
+
+ def comment_threshold
+
+
+ 1
+
+
+
+
+
+
+ 12
+
+
+ 0
+
+
+ 0
+
+
+
+
+
+
+ 13
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 14
+
+
+
+
+
+
+
+
+
+
+
+
+ 15
+
+
+ def created_at
+
+
+ 1
+
+
+
+
+
+
+ 16
+
+
+ Time.now
+
+
+ 0
+
+
+
+
+
+
+ 17
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 18
+
+
+
+
+
+
+
+
+
+
+
+
+ 19
+
+
+ def updated_at
+
+
+ 1
+
+
+
+
+
+
+ 20
+
+
+ Time.now
+
+
+ 0
+
+
+
+
+
+
+ 21
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 22
+
+
+
+
+
+
+
+
+
+
+
+
+ 23
+
+
+ def name
+
+
+ 1
+
+
+
+
+
+
+ 24
+
+
+ "Anonymous"
+
+
+ 0
+
+
+
+
+
+
+ 25
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 26
+
+
+
+
+
+
+
+
+
+
+
+
+ 27
+
+
+ def pretty_name
+
+
+ 1
+
+
+
+
+
+
+ 28
+
+
+ "Anonymous"
+
+
+ 0
+
+
+
+
+
+
+ 29
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 30
+
+
+
+
+
+
+
+
+
+
+
+
+ 31
+
+
+ def is_anonymous?
+
+
+ 1
+
+
+
+
+
+
+ 32
+
+
+ true
+
+
+ 0
+
+
+
+
+
+
+ 33
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 34
+
+
+
+
+
+
+
+
+
+
+
+
+ 35
+
+
+ def has_mail?
+
+
+ 1
+
+
+
+
+
+
+ 36
+
+
+ false
+
+
+ 0
+
+
+
+
+
+
+ 37
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 38
+
+
+
+
+
+
+
+
+
+
+
+
+ 39
+
+
+ def has_forum_been_updated?
+
+
+ 1
+
+
+
+
+
+
+ 40
+
+
+ false
+
+
+ 0
+
+
+
+
+
+
+ 41
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 42
+
+
+
+
+
+
+
+
+
+
+
+
+ 43
+
+
+ def has_permission?(obj, foreign_key = :user_id)
+
+
+ 1
+
+
+
+
+
+
+ 44
+
+
+ false
+
+
+ 0
+
+
+
+
+
+
+ 45
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 46
+
+
+
+
+
+
+
+
+
+
+
+
+ 47
+
+
+ def ban
+
+
+ 1
+
+
+
+
+
+
+ 48
+
+
+ false
+
+
+ 0
+
+
+
+
+
+
+ 49
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 50
+
+
+
+
+
+
+
+
+
+
+
+
+ 51
+
+
+ def always_resize_images?
+
+
+ 1
+
+
+
+
+
+
+ 52
+
+
+ false
+
+
+ 0
+
+
+
+
+
+
+ 53
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 54
+
+
+
+
+
+
+
+
+
+
+
+
+ 55
+
+
+ def show_samples?
+
+
+ 1
+
+
+
+
+
+
+ 56
+
+
+ true
+
+
+ 0
+
+
+
+
+
+
+ 57
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 58
+
+
+
+
+
+
+
+
+
+
+
+
+ 59
+
+
+ def tag_subscriptions
+
+
+ 1
+
+
+
+
+
+
+ 60
+
+
+ []
+
+
+ 0
+
+
+
+
+
+
+ 61
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 62
+
+
+
+
+
+
+
+
+
+
+
+
+ 63
+
+
+ def upload_limit
+
+
+ 1
+
+
+
+
+
+
+ 64
+
+
+ 0
+
+
+ 0
+
+
+
+
+
+
+ 65
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 66
+
+
+
+
+
+
+
+
+
+
+
+
+ 67
+
+
+ def base_upload_limit
+
+
+ 1
+
+
+
+
+
+
+ 68
+
+
+ 0
+
+
+ 0
+
+
+
+
+
+
+ 69
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 70
+
+
+
+
+
+
+
+
+
+
+
+
+ 71
+
+
+ def uploaded_tags
+
+
+ 1
+
+
+
+
+
+
+ 72
+
+
+ ""
+
+
+ 0
+
+
+
+
+
+
+ 73
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 74
+
+
+
+
+
+
+
+
+
+
+
+
+ 75
+
+
+ def uploaded_tags_with_types
+
+
+ 1
+
+
+
+
+
+
+ 76
+
+
+ []
+
+
+ 0
+
+
+
+
+
+
+ 77
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 78
+
+
+
+
+
+
+
+
+
+
+
+
+ 79
+
+
+ def recent_tags
+
+
+ 1
+
+
+
+
+
+
+ 80
+
+
+ ""
+
+
+ 0
+
+
+
+
+
+
+ 81
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 82
+
+
+
+
+
+
+
+
+
+
+
+
+ 83
+
+
+ def recent_tags_with_types
+
+
+ 1
+
+
+
+
+
+
+ 84
+
+
+ []
+
+
+ 0
+
+
+
+
+
+
+ 85
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 86
+
+
+
+
+
+
+
+
+
+
+
+
+ 87
+
+
+ def can_upload?
+
+
+ 1
+
+
+
+
+
+
+ 88
+
+
+ false
+
+
+ 0
+
+
+
+
+
+
+ 89
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 90
+
+
+
+
+
+
+
+
+
+
+
+
+ 91
+
+
+ def can_comment?
+
+
+ 1
+
+
+
+
+
+
+ 92
+
+
+ false
+
+
+ 0
+
+
+
+
+
+
+ 93
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 94
+
+
+
+
+
+
+
+
+
+
+
+
+ 95
+
+
+ def can_remove_from_pools?
+
+
+ 1
+
+
+
+
+
+
+ 96
+
+
+ false
+
+
+ 0
+
+
+
+
+
+
+ 97
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 98
+
+
+
+
+
+
+
+
+
+
+
+
+ 99
+
+
+ def blacklisted_tags
+
+
+ 1
+
+
+
+
+
+
+ 100
+
+
+ ""
+
+
+ 0
+
+
+
+
+
+
+ 101
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 102
+
+
+
+
+
+
+
+
+
+
+
+
+ 103
+
+
+ def time_zone
+
+
+ 1
+
+
+
+
+
+
+ 104
+
+
+ "Eastern Time (US & Canada)"
+
+
+ 0
+
+
+
+
+
+
+ 105
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 106
+
+
+
+
+
+
+
+
+
+
+
+
+ 107
+
+
+ def default_image_size
+
+
+ 1
+
+
+
+
+
+
+ 108
+
+
+ "medium"
+
+
+ 0
+
+
+
+
+
+
+ 109
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 110
+
+
+
+
+
+
+
+
+
+
+
+
+ 111
+
+
+ def blacklisted_tags
+
+
+ 1
+
+
+
+
+
+
+ 112
+
+
+ []
+
+
+ 0
+
+
+
+
+
+
+ 113
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 114
+
+
+
+
+
+
+
+
+
+
+
+
+ 115
+
+
+ %w(member banned privileged contributor janitor moderator admin).each do |name|
+
+
+ 1
+
+
+
+
+
+
+ 116
+
+
+ define_method("is_#{name}?") do
+
+
+ 7
+
+
+
+
+
+
+ 117
+
+
+ false
+
+
+ 0
+
+
+
+
+
+
+ 118
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 119
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 120
+
+
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ./app/logical/cache.rb
+ 67.24 % covered
+
+
+
+ #
+
+ Hits
+
+
+
+
+
+
+
+ 1
+
+
+ class Cache
+
+
+ 1
+
+
+
+
+
+
+ 2
+
+
+ def self.incr(key, expiry = 0)
+
+
+ 1
+
+
+
+
+
+
+ 3
+
+
+ val = Cache.get(key, expiry)
+
+
+ 0
+
+
+
+
+
+
+ 4
+
+
+ Cache.put(key, val.to_i + 1)
+
+
+ 0
+
+
+
+
+
+
+ 5
+
+
+ ActiveRecord::Base.logger.debug('MemCache Incr %s' % [key])
+
+
+ 0
+
+
+
+
+
+
+ 6
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 7
+
+
+
+
+
+
+
+
+
+
+
+
+ 8
+
+
+ def self.get_multi(keys, prefix, expiry = 0)
+
+
+ 1
+
+
+
+
+
+
+ 9
+
+
+ key_to_sanitized_key_hash = keys.inject({}) do |hash, x|
+
+
+ 72
+
+
+
+
+
+
+ 10
+
+
+ hash[x] = "#{prefix}:#{Cache.sanitize(x)}"
+
+
+ 36
+
+
+
+
+
+
+ 11
+
+
+ hash
+
+
+ 36
+
+
+
+
+
+
+ 12
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 13
+
+
+ start_time = Time.now
+
+
+ 72
+
+
+
+
+
+
+ 14
+
+
+ sanitized_key_to_value_hash = MEMCACHE.get_multi(key_to_sanitized_key_hash.values)
+
+
+ 72
+
+
+
+
+
+
+ 15
+
+
+ elapsed = Time.now - start_time
+
+
+ 72
+
+
+
+
+
+
+ 16
+
+
+ {}.tap do |result_hash|
+
+
+ 72
+
+
+
+
+
+
+ 17
+
+
+ key_to_sanitized_key_hash.each do |key, sanitized_key|
+
+
+ 72
+
+
+
+
+
+
+ 18
+
+
+ if sanitized_key_to_value_hash.has_key?(sanitized_key)
+
+
+ 36
+
+
+
+
+
+
+ 19
+
+
+ result_hash[key] = sanitized_key_to_value_hash[sanitized_key]
+
+
+ 36
+
+
+
+
+
+
+ 20
+
+
+ else
+
+
+
+
+
+
+
+
+
+ 21
+
+
+ result_hash[key] = yield(key)
+
+
+ 0
+
+
+
+
+
+
+ 22
+
+
+ Cache.put(sanitized_key, result_hash[key], expiry)
+
+
+ 0
+
+
+
+
+
+
+ 23
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 24
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 25
+
+
+
+
+
+
+
+
+
+
+
+
+ 26
+
+
+ ActiveRecord::Base.logger.debug('MemCache Multi-Get (%0.6f) %s' % [elapsed, keys.join(",")])
+
+
+ 72
+
+
+
+
+
+
+ 27
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 28
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 29
+
+
+
+
+
+
+
+
+
+
+
+
+ 30
+
+
+ def self.get(key, expiry = 0)
+
+
+ 1
+
+
+
+
+
+
+ 31
+
+
+ begin
+
+
+ 18
+
+
+
+
+
+
+ 32
+
+
+ start_time = Time.now
+
+
+ 18
+
+
+
+
+
+
+ 33
+
+
+ value = MEMCACHE.get key
+
+
+ 18
+
+
+
+
+
+
+ 34
+
+
+ elapsed = Time.now - start_time
+
+
+ 18
+
+
+
+
+
+
+ 35
+
+
+ ActiveRecord::Base.logger.debug('MemCache Get (%0.6f) %s' % [elapsed, key])
+
+
+ 18
+
+
+
+
+
+
+ 36
+
+
+ if value.nil? and block_given? then
+
+
+ 18
+
+
+
+
+
+
+ 37
+
+
+ value = yield
+
+
+ 0
+
+
+
+
+
+
+ 38
+
+
+ MEMCACHE.set key, value, expiry
+
+
+ 0
+
+
+
+
+
+
+ 39
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 40
+
+
+ value
+
+
+ 18
+
+
+
+
+
+
+ 41
+
+
+ rescue MemCache::MemCacheError => err
+
+
+ 0
+
+
+
+
+
+
+ 42
+
+
+ ActiveRecord::Base.logger.debug "MemCache Error: #{err.message}"
+
+
+ 0
+
+
+
+
+
+
+ 43
+
+
+ if block_given? then
+
+
+ 0
+
+
+
+
+
+
+ 44
+
+
+ value = yield
+
+
+ 0
+
+
+
+
+
+
+ 45
+
+
+ put key, value, expiry
+
+
+ 0
+
+
+
+
+
+
+ 46
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 47
+
+
+ value
+
+
+ 0
+
+
+
+
+
+
+ 48
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 49
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 50
+
+
+
+
+
+
+
+
+
+
+
+
+ 51
+
+
+ def self.put(key, value, expiry = 0)
+
+
+ 1
+
+
+
+
+
+
+ 52
+
+
+ key.gsub!(/\s/, "_")
+
+
+ 31
+
+
+
+
+
+
+ 53
+
+
+ key = key[0, 200]
+
+
+ 31
+
+
+
+
+
+
+ 54
+
+
+
+
+
+
+
+
+
+
+
+
+ 55
+
+
+ begin
+
+
+ 31
+
+
+
+
+
+
+ 56
+
+
+ start_time = Time.now
+
+
+ 31
+
+
+
+
+
+
+ 57
+
+
+ MEMCACHE.set key, value, expiry
+
+
+ 31
+
+
+
+
+
+
+ 58
+
+
+ elapsed = Time.now - start_time
+
+
+ 31
+
+
+
+
+
+
+ 59
+
+
+ ActiveRecord::Base.logger.debug('MemCache Set (%0.6f) %s' % [elapsed, key])
+
+
+ 31
+
+
+
+
+
+
+ 60
+
+
+ value
+
+
+ 31
+
+
+
+
+
+
+ 61
+
+
+ rescue MemCache::MemCacheError => err
+
+
+ 0
+
+
+
+
+
+
+ 62
+
+
+ ActiveRecord::Base.logger.debug "MemCache Error: #{err.message}"
+
+
+ 0
+
+
+
+
+
+
+ 63
+
+
+ nil
+
+
+ 0
+
+
+
+
+
+
+ 64
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 65
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 66
+
+
+
+
+
+
+
+
+
+
+
+
+ 67
+
+
+ def self.delete(key, delay = nil)
+
+
+ 1
+
+
+
+
+
+
+ 68
+
+
+ begin
+
+
+ 36
+
+
+
+
+
+
+ 69
+
+
+ start_time = Time.now
+
+
+ 36
+
+
+
+
+
+
+ 70
+
+
+ MEMCACHE.delete key, delay
+
+
+ 36
+
+
+
+
+
+
+ 71
+
+
+ elapsed = Time.now - start_time
+
+
+ 36
+
+
+
+
+
+
+ 72
+
+
+ ActiveRecord::Base.logger.debug('MemCache Delete (%0.6f) %s' % [elapsed, key])
+
+
+ 36
+
+
+
+
+
+
+ 73
+
+
+ nil
+
+
+
+
+
+
+
+
+
+ 74
+
+
+ rescue MemCache::MemCacheError => err
+
+
+ 0
+
+
+
+
+
+
+ 75
+
+
+ ActiveRecord::Base.logger.debug "MemCache Error: #{err.message}"
+
+
+ 0
+
+
+
+
+
+
+ 76
+
+
+ nil
+
+
+ 0
+
+
+
+
+
+
+ 77
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 78
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 79
+
+
+
+
+
+
+
+
+
+
+
+
+ 80
+
+
+ def self.sanitize(key)
+
+
+ 1
+
+
+
+
+
+
+ 81
+
+
+ key.gsub(/\W/) {|x| "%#{x.ord}"}.slice(0, 240)
+
+
+ 84
+
+
+
+
+
+
+ 82
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 83
+
+
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ./app/logical/current_user.rb
+ 53.85 % covered
+
+
+
+ #
+
+ Hits
+
+
+
+
+
+
+
+ 1
+
+
+ class CurrentUser
+
+
+ 1
+
+
+
+
+
+
+ 2
+
+
+ def self.scoped(user, ip_addr)
+
+
+ 1
+
+
+
+
+
+
+ 3
+
+
+ old_user = self.user
+
+
+ 0
+
+
+
+
+
+
+ 4
+
+
+ old_ip_addr = self.ip_addr
+
+
+ 0
+
+
+
+
+
+
+ 5
+
+
+
+
+
+
+
+
+
+
+
+
+ 6
+
+
+ self.user = user
+
+
+ 0
+
+
+
+
+
+
+ 7
+
+
+ self.ip_addr = ip_addr
+
+
+ 0
+
+
+
+
+
+
+ 8
+
+
+
+
+
+
+
+
+
+
+
+
+ 9
+
+
+ begin
+
+
+ 0
+
+
+
+
+
+
+ 10
+
+
+ yield
+
+
+ 0
+
+
+
+
+
+
+ 11
+
+
+ ensure
+
+
+
+
+
+
+
+
+
+ 12
+
+
+ self.user = old_user
+
+
+ 0
+
+
+
+
+
+
+ 13
+
+
+ self.ip_addr = old_ip_addr
+
+
+ 0
+
+
+
+
+
+
+ 14
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 15
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 16
+
+
+
+
+
+
+
+
+
+
+
+
+ 17
+
+
+ def self.user=(user)
+
+
+ 1
+
+
+
+
+
+
+ 18
+
+
+ Thread.current[:current_user] = user
+
+
+ 23
+
+
+
+
+
+
+ 19
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 20
+
+
+
+
+
+
+
+
+
+
+
+
+ 21
+
+
+ def self.ip_addr=(ip_addr)
+
+
+ 1
+
+
+
+
+
+
+ 22
+
+
+ Thread.current[:current_ip_addr] = ip_addr
+
+
+ 16
+
+
+
+
+
+
+ 23
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 24
+
+
+
+
+
+
+
+
+
+
+
+
+ 25
+
+
+ def self.user
+
+
+ 1
+
+
+
+
+
+
+ 26
+
+
+ Thread.current[:current_user]
+
+
+ 89
+
+
+
+
+
+
+ 27
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 28
+
+
+
+
+
+
+
+
+
+
+
+
+ 29
+
+
+ def self.ip_addr
+
+
+ 1
+
+
+
+
+
+
+ 30
+
+
+ Thread.current[:current_ip_addr]
+
+
+ 13
+
+
+
+
+
+
+ 31
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 32
+
+
+
+
+
+
+
+
+
+
+
+
+ 33
+
+
+ def self.id
+
+
+ 1
+
+
+
+
+
+
+ 34
+
+
+ user.id
+
+
+ 24
+
+
+
+
+
+
+ 35
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 36
+
+
+
+
+
+
+
+
+
+
+
+
+ 37
+
+
+ def self.name
+
+
+ 1
+
+
+
+
+
+
+ 38
+
+
+ user.name
+
+
+ 0
+
+
+
+
+
+
+ 39
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 40
+
+
+
+
+
+
+
+
+
+
+
+
+ 41
+
+
+ def self.method_missing(method, *params, &block)
+
+
+ 1
+
+
+
+
+
+
+ 42
+
+
+ if user.respond_to?(method)
+
+
+ 0
+
+
+
+
+
+
+ 43
+
+
+ user.__send__(method, *params, &block)
+
+
+ 0
+
+
+
+
+
+
+ 44
+
+
+ else
+
+
+
+
+
+
+
+
+
+ 45
+
+
+ super
+
+
+ 0
+
+
+
+
+
+
+ 46
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 47
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 48
+
+
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ./app/logical/d_text.rb
+ 10.84 % covered
+
+
+
+ #
+
+ Hits
+
+
+
+
+
+
+
+ 1
+
+
+ require 'cgi'
+
+
+ 1
+
+
+
+
+
+
+ 2
+
+
+
+
+
+
+
+
+
+
+
+
+ 3
+
+
+ class DText
+
+
+ 1
+
+
+
+
+
+
+ 4
+
+
+ def self.parse_inline(str, options = {})
+
+
+ 1
+
+
+
+
+
+
+ 5
+
+
+ str = parse_aliased_wiki_links(str)
+
+
+ 0
+
+
+
+
+
+
+ 6
+
+
+ str = parse_wiki_links(str)
+
+
+ 0
+
+
+
+
+
+
+ 7
+
+
+ str = parse_post_links(str)
+
+
+ 0
+
+
+
+
+
+
+ 8
+
+
+ str = parse_id_links(str)
+
+
+ 0
+
+
+
+
+
+
+ 9
+
+
+
+
+
+
+
+
+
+
+
+
+ 10
+
+
+ str.gsub!(/\n/m, "<br>")
+
+
+ 0
+
+
+
+
+
+
+ 11
+
+
+ str.gsub!(/\[b\](.+?)\[\/b\]/i, '<strong>\1</strong>')
+
+
+ 0
+
+
+
+
+
+
+ 12
+
+
+ str.gsub!(/\[i\](.+?)\[\/i\]/i, '<em>\1</em>')
+
+
+ 0
+
+
+
+
+
+
+ 13
+
+
+ str.gsub!(/\[spoilers?\](.+?)\[\/spoilers?\]/m, '<span class="spoiler">\1</span>')
+
+
+ 0
+
+
+
+
+
+
+ 14
+
+
+ str.gsub!(/\[url\](.+?)\[\/url\]/i) do
+
+
+ 0
+
+
+
+
+
+
+ 15
+
+
+ %{<a href="#{u($1)}">#{h($1)}</a>}
+
+
+ 0
+
+
+
+
+
+
+ 16
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 17
+
+
+ str.gsub!(/\[url=(.+?)\](.+?)\[\/url\]/m) do
+
+
+ 0
+
+
+
+
+
+
+ 18
+
+
+ %{<a href="#{u($1)}">#{h($2)}</a>}
+
+
+ 0
+
+
+
+
+
+
+ 19
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 20
+
+
+ str
+
+
+ 0
+
+
+
+
+
+
+ 21
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 22
+
+
+
+
+
+
+
+
+
+
+
+
+ 23
+
+
+ def self.parse_aliased_wiki_links(str)
+
+
+ 1
+
+
+
+
+
+
+ 24
+
+
+ str.gsub(/\[\[(.+?)\|(.+?)\]\]/m) do
+
+
+ 0
+
+
+
+
+
+
+ 25
+
+
+ text = $1
+
+
+ 0
+
+
+
+
+
+
+ 26
+
+
+ title = $2
+
+
+ 0
+
+
+
+
+
+
+ 27
+
+
+ wiki_page = WikiPage.find_title_and_id(title)
+
+
+ 0
+
+
+
+
+
+
+ 28
+
+
+
+
+
+
+
+
+
+
+
+
+ 29
+
+
+ if wiki_page
+
+
+ 0
+
+
+
+
+
+
+ 30
+
+
+ %{[url=/wiki_pages/#{wiki_page.id}]#{text}[/url]}
+
+
+ 0
+
+
+
+
+
+
+ 31
+
+
+ else
+
+
+
+
+
+
+
+
+
+ 32
+
+
+ %{[url=/wiki_pages/new?title=#{title}]#{text}[/url]}
+
+
+ 0
+
+
+
+
+
+
+ 33
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 34
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 35
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 36
+
+
+
+
+
+
+
+
+
+
+
+
+ 37
+
+
+ def self.parse_wiki_links(str)
+
+
+ 1
+
+
+
+
+
+
+ 38
+
+
+ str.gsub(/\[\[(.+?)\]\]/) do
+
+
+ 0
+
+
+
+
+
+
+ 39
+
+
+ title = $1
+
+
+ 0
+
+
+
+
+
+
+ 40
+
+
+ wiki_page = WikiPage.find_title_and_id(title)
+
+
+ 0
+
+
+
+
+
+
+ 41
+
+
+
+
+
+
+
+
+
+
+
+
+ 42
+
+
+ if wiki_page
+
+
+ 0
+
+
+
+
+
+
+ 43
+
+
+ %{[url=/wiki_pages/#{wiki_page.id}]#{title}[/url]}
+
+
+ 0
+
+
+
+
+
+
+ 44
+
+
+ else
+
+
+
+
+
+
+
+
+
+ 45
+
+
+ %{[url=/wiki_pages/new?title=#{title}]#{title}[/url]}
+
+
+ 0
+
+
+
+
+
+
+ 46
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 47
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 48
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 49
+
+
+
+
+
+
+
+
+
+
+
+
+ 50
+
+
+ def self.parse_post_links(str)
+
+
+ 1
+
+
+
+
+
+
+ 51
+
+
+ str.gsub(/\{\{(.+?)\}\}/, %{[url=/posts?tags=\1]\1[/url]})
+
+
+ 0
+
+
+
+
+
+
+ 52
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 53
+
+
+
+
+
+
+
+
+
+
+
+
+ 54
+
+
+ def self.parse_id_links(str)
+
+
+ 1
+
+
+
+
+
+
+ 55
+
+
+ str = str.gsub(/\bpost #(\d+)/i, %{[url=/posts/\1]post #\1[/url]})
+
+
+ 0
+
+
+
+
+
+
+ 56
+
+
+ str = str.gsub(/\bforum #(\d+)/i, %{[url=/forum_posts/\1]forum #\1[/url]})
+
+
+ 0
+
+
+
+
+
+
+ 57
+
+
+ str = str.gsub(/\bcomment #(\d+)/i, %{[url=/comments/\1]comment #\1[/url]})
+
+
+ 0
+
+
+
+
+
+
+ 58
+
+
+ str = str.gsub(/\bpool #(\d+)/i, %{[url=/pools/\1]pool #\1[/url]})
+
+
+ 0
+
+
+
+
+
+
+ 59
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 60
+
+
+
+
+
+
+
+
+
+
+
+
+ 61
+
+
+ def self.parse_list(str, options = {})
+
+
+ 1
+
+
+
+
+
+
+ 62
+
+
+ html = ""
+
+
+ 0
+
+
+
+
+
+
+ 63
+
+
+ layout = []
+
+
+ 0
+
+
+
+
+
+
+ 64
+
+
+ nest = 0
+
+
+ 0
+
+
+
+
+
+
+ 65
+
+
+
+
+
+
+
+
+
+
+
+
+ 66
+
+
+ str.split(/\n/).each do |line|
+
+
+ 0
+
+
+
+
+
+
+ 67
+
+
+ if line =~ /^\s*(\*+) (.+)/
+
+
+ 0
+
+
+
+
+
+
+ 68
+
+
+ nest = $1.size
+
+
+ 0
+
+
+
+
+
+
+ 69
+
+
+ content = parse_inline($2)
+
+
+ 0
+
+
+
+
+
+
+ 70
+
+
+ else
+
+
+
+
+
+
+
+
+
+ 71
+
+
+ content = parse_inline(line)
+
+
+ 0
+
+
+
+
+
+
+ 72
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 73
+
+
+
+
+
+
+
+
+
+
+
+
+ 74
+
+
+ if nest > layout.size
+
+
+ 0
+
+
+
+
+
+
+ 75
+
+
+ html += "<ul>"
+
+
+ 0
+
+
+
+
+
+
+ 76
+
+
+ layout << "ul"
+
+
+ 0
+
+
+
+
+
+
+ 77
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 78
+
+
+
+
+
+
+
+
+
+
+
+
+ 79
+
+
+ while nest < layout.size
+
+
+ 0
+
+
+
+
+
+
+ 80
+
+
+ elist = layout.pop
+
+
+ 0
+
+
+
+
+
+
+ 81
+
+
+ if elist
+
+
+ 0
+
+
+
+
+
+
+ 82
+
+
+ html += "</#{elist}>"
+
+
+ 0
+
+
+
+
+
+
+ 83
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 84
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 85
+
+
+
+
+
+
+
+
+
+
+
+
+ 86
+
+
+ html += "<li>#{content}</li>"
+
+
+ 0
+
+
+
+
+
+
+ 87
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 88
+
+
+
+
+
+
+
+
+
+
+
+
+ 89
+
+
+ while layout.any?
+
+
+ 0
+
+
+
+
+
+
+ 90
+
+
+ elist = layout.pop
+
+
+ 0
+
+
+
+
+
+
+ 91
+
+
+ html += "</#{elist}>"
+
+
+ 0
+
+
+
+
+
+
+ 92
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 93
+
+
+
+
+
+
+
+
+
+
+
+
+ 94
+
+
+ html
+
+
+ 0
+
+
+
+
+
+
+ 95
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 96
+
+
+
+
+
+
+
+
+
+
+
+
+ 97
+
+
+ def self.parse(str, options = {})
+
+
+ 1
+
+
+
+
+
+
+ 98
+
+
+ return "" if str.blank?
+
+
+ 0
+
+
+
+
+
+
+ 99
+
+
+
+
+
+
+
+
+
+
+
+
+ 100
+
+
+ # Make sure quote tags are surrounded by newlines
+
+
+
+
+
+
+
+
+
+ 101
+
+
+
+
+
+
+
+
+
+
+
+
+ 102
+
+
+ unless options[:inline]
+
+
+ 0
+
+
+
+
+
+
+ 103
+
+
+ str.gsub!(/\s*\[quote\]\s*/m, "\n\n[quote]\n\n")
+
+
+ 0
+
+
+
+
+
+
+ 104
+
+
+ str.gsub!(/\s*\[\/quote\]\s*/m, "\n\n[/quote]\n\n")
+
+
+ 0
+
+
+
+
+
+
+ 105
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 106
+
+
+
+
+
+
+
+
+
+
+
+
+ 107
+
+
+ str.gsub!(/(?:\r?\n){3,}/, "\n\n")
+
+
+ 0
+
+
+
+
+
+
+ 108
+
+
+ str.strip!
+
+
+ 0
+
+
+
+
+
+
+ 109
+
+
+ blocks = str.split(/(?:\r?\n){2}/)
+
+
+ 0
+
+
+
+
+
+
+ 110
+
+
+
+
+
+
+
+
+
+
+
+
+ 111
+
+
+ html = blocks.map do |block|
+
+
+ 0
+
+
+
+
+
+
+ 112
+
+
+ case block
+
+
+ 0
+
+
+
+
+
+
+ 113
+
+
+ when /^(h[1-6])\.\s*(.+)$/
+
+
+
+
+
+
+
+
+
+ 114
+
+
+ tag = $1
+
+
+ 0
+
+
+
+
+
+
+ 115
+
+
+ content = $2
+
+
+ 0
+
+
+
+
+
+
+ 116
+
+
+
+
+
+
+
+
+
+
+
+
+ 117
+
+
+ if options[:inline]
+
+
+ 0
+
+
+
+
+
+
+ 118
+
+
+ "<h6>" + parse_inline(content, options) + "</h6>"
+
+
+ 0
+
+
+
+
+
+
+ 119
+
+
+ else
+
+
+
+
+
+
+
+
+
+ 120
+
+
+ "<#{tag}>" + parse_inline(content, options) + "</#{tag}>"
+
+
+ 0
+
+
+
+
+
+
+ 121
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 122
+
+
+
+
+
+
+
+
+
+
+
+
+ 123
+
+
+ when /^\s*\*+ /
+
+
+
+
+
+
+
+
+
+ 124
+
+
+ parse_list(block, options)
+
+
+ 0
+
+
+
+
+
+
+ 125
+
+
+
+
+
+
+
+
+
+
+
+
+ 126
+
+
+ when "[quote]"
+
+
+
+
+
+
+
+
+
+ 127
+
+
+ if options[:inline]
+
+
+ 0
+
+
+
+
+
+
+ 128
+
+
+ ""
+
+
+ 0
+
+
+
+
+
+
+ 129
+
+
+ else
+
+
+
+
+
+
+
+
+
+ 130
+
+
+ '<blockquote>'
+
+
+ 0
+
+
+
+
+
+
+ 131
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 132
+
+
+
+
+
+
+
+
+
+
+
+
+ 133
+
+
+ when "[/quote]"
+
+
+
+
+
+
+
+
+
+ 134
+
+
+ if options[:inline]
+
+
+ 0
+
+
+
+
+
+
+ 135
+
+
+ ""
+
+
+ 0
+
+
+
+
+
+
+ 136
+
+
+ else
+
+
+
+
+
+
+
+
+
+ 137
+
+
+ '</blockquote>'
+
+
+ 0
+
+
+
+
+
+
+ 138
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 139
+
+
+
+
+
+
+
+
+
+
+
+
+ 140
+
+
+ else
+
+
+
+
+
+
+
+
+
+ 141
+
+
+ '<p>' + parse_inline(block) + "</p>"
+
+
+ 0
+
+
+
+
+
+
+ 142
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 143
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 144
+
+
+
+
+
+
+
+
+
+
+
+
+ 145
+
+
+ html.join("").html_safe
+
+
+ 0
+
+
+
+
+
+
+ 146
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 147
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 148
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ./app/logical/date_tag.rb
+ 38.46 % covered
+
+
+
+ #
+
+ Hits
+
+
+
+
+
+
+
+ 1
+
+
+ class DateTag
+
+
+ 1
+
+
+
+
+
+
+ 2
+
+
+ attr_accessor :tag, :start_date, :end_date
+
+
+ 1
+
+
+
+
+
+
+ 3
+
+
+
+
+
+
+
+
+
+
+
+
+ 4
+
+
+ def self.new_from_range(start, stop)
+
+
+ 1
+
+
+
+
+
+
+ 5
+
+
+ new("#{start.to_formatted_s(:db)}..#{stop.to_formatted_s(:db)}")
+
+
+ 0
+
+
+
+
+
+
+ 6
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 7
+
+
+
+
+
+
+
+
+
+
+
+
+ 8
+
+
+ def initialize(tag)
+
+
+ 1
+
+
+
+
+
+
+ 9
+
+
+ @tag = tag
+
+
+ 0
+
+
+
+
+
+
+ 10
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 11
+
+
+
+
+
+
+
+
+
+
+
+
+ 12
+
+
+ def is_single_day?
+
+
+ 1
+
+
+
+
+
+
+ 13
+
+
+ tag =~ /^\d+-\d+-\d+$/
+
+
+ 0
+
+
+
+
+
+
+ 14
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 15
+
+
+
+
+
+
+
+
+
+
+
+
+ 16
+
+
+ def is_range?
+
+
+ 1
+
+
+
+
+
+
+ 17
+
+
+ !is_single_day
+
+
+ 0
+
+
+
+
+
+
+ 18
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 19
+
+
+
+
+
+
+
+
+
+
+
+
+ 20
+
+
+ def start_date
+
+
+ 1
+
+
+
+
+
+
+ 21
+
+
+ return date if is_single_day?
+
+
+ 0
+
+
+
+
+
+
+ 22
+
+
+ extract_ranges
+
+
+ 0
+
+
+
+
+
+
+ 23
+
+
+ start_date
+
+
+ 0
+
+
+
+
+
+
+ 24
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 25
+
+
+
+
+
+
+
+
+
+
+
+
+ 26
+
+
+ def end_date
+
+
+ 1
+
+
+
+
+
+
+ 27
+
+
+ return date if is_single_day?
+
+
+ 0
+
+
+
+
+
+
+ 28
+
+
+ extract_ranges
+
+
+ 0
+
+
+
+
+
+
+ 29
+
+
+ end_date
+
+
+ 0
+
+
+
+
+
+
+ 30
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 31
+
+
+
+
+
+
+
+
+
+
+
+
+ 32
+
+
+ def previous_week
+
+
+ 1
+
+
+
+
+
+
+ 33
+
+
+ DateTag.new_from_range(1.week.ago(start_date), 1.week.ago(end_date))
+
+
+ 0
+
+
+
+
+
+
+ 34
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 35
+
+
+
+
+
+
+
+
+
+
+
+
+ 36
+
+
+ def next_week
+
+
+ 1
+
+
+
+
+
+
+ 37
+
+
+ DateTag.new_from_range(1.week.since(start_date), 1.week.since(end_date))
+
+
+ 0
+
+
+
+
+
+
+ 38
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 39
+
+
+
+
+
+
+
+
+
+
+
+
+ 40
+
+
+ def previous_month
+
+
+ 1
+
+
+
+
+
+
+ 41
+
+
+ DateTag.new_from_range(1.month.ago(start_date), 1.month.ago(end_date))
+
+
+ 0
+
+
+
+
+
+
+ 42
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 43
+
+
+
+
+
+
+
+
+
+
+
+
+ 44
+
+
+ def next_month
+
+
+ 1
+
+
+
+
+
+
+ 45
+
+
+ DateTag.new_from_range(1.month.since(start_date), 1.month.since(end_date))
+
+
+ 0
+
+
+
+
+
+
+ 46
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 47
+
+
+
+
+
+
+
+
+
+
+
+
+ 48
+
+
+ def date
+
+
+ 1
+
+
+
+
+
+
+ 49
+
+
+ Date.parse(tag)
+
+
+ 0
+
+
+
+
+
+
+ 50
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 51
+
+
+
+
+
+
+
+
+
+
+
+
+ 52
+
+
+ private
+
+
+ 1
+
+
+
+
+
+
+ 53
+
+
+ def extract_ranges
+
+
+ 1
+
+
+
+
+
+
+ 54
+
+
+ case tag
+
+
+ 0
+
+
+
+
+
+
+ 55
+
+
+ when /\A(.+?)\.\.(.+)/
+
+
+
+
+
+
+
+
+
+ 56
+
+
+ self.start_date = Date.parse($1)
+
+
+ 0
+
+
+
+
+
+
+ 57
+
+
+ self.end_date = Date.parse($2)
+
+
+ 0
+
+
+
+
+
+
+ 58
+
+
+
+
+
+
+
+
+
+
+
+
+ 59
+
+
+ when /\A<(.+)/, /\A<=(.+)/, /\A\.\.(.+)/
+
+
+
+
+
+
+
+
+
+ 60
+
+
+ self.start_date = 20.years.ago
+
+
+ 0
+
+
+
+
+
+
+ 61
+
+
+ self.end_date = Date.parse($1)
+
+
+ 0
+
+
+
+
+
+
+ 62
+
+
+
+
+
+
+
+
+
+
+
+
+ 63
+
+
+ when /\A>(.+)/, /\A>=(.+)/, /\A(.+)\.\.\Z/
+
+
+
+
+
+
+
+
+
+ 64
+
+
+ self.start_date = Date.parse($1)
+
+
+ 0
+
+
+
+
+
+
+ 65
+
+
+ self.end_date = Date.today
+
+
+ 0
+
+
+
+
+
+
+ 66
+
+
+
+
+
+
+
+
+
+
+
+
+ 67
+
+
+ else
+
+
+
+
+
+
+
+
+
+ 68
+
+
+ self.start_date = Date.today
+
+
+ 0
+
+
+
+
+
+
+ 69
+
+
+ self.end_date = Date.today
+
+
+ 0
+
+
+
+
+
+
+ 70
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 71
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 72
+
+
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ./app/logical/download.rb
+ 16.67 % covered
+
+
+
+ #
+
+ Hits
+
+
+
+
+
+
+
+ 1
+
+
+ class Download
+
+
+ 1
+
+
+
+
+
+
+ 2
+
+
+ class Error < Exception ; end
+
+
+ 1
+
+
+
+
+
+
+ 3
+
+
+
+
+
+
+
+
+
+
+
+
+ 4
+
+
+ attr_accessor :source, :content_type
+
+
+ 1
+
+
+
+
+
+
+ 5
+
+
+
+
+
+
+
+
+
+
+
+
+ 6
+
+
+ def initialize(source, file_path)
+
+
+ 1
+
+
+
+
+
+
+ 7
+
+
+ @source = source
+
+
+ 0
+
+
+
+
+
+
+ 8
+
+
+ @file_path = file_path
+
+
+ 0
+
+
+
+
+
+
+ 9
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 10
+
+
+
+
+
+
+
+
+
+
+
+
+ 11
+
+
+ # Downloads to @file_path
+
+
+
+
+
+
+
+
+
+ 12
+
+
+ def download!
+
+
+ 1
+
+
+
+
+
+
+ 13
+
+
+ http_get_streaming(@source) do |response|
+
+
+ 0
+
+
+
+
+
+
+ 14
+
+
+ self.content_type = response["Content-Type"]
+
+
+ 0
+
+
+
+
+
+
+ 15
+
+
+ File.open(@file_path, "wb") do |out|
+
+
+ 0
+
+
+
+
+
+
+ 16
+
+
+ response.read_body(out)
+
+
+ 0
+
+
+
+
+
+
+ 17
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 18
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 19
+
+
+ @source = fix_image_board_sources(@source)
+
+
+ 0
+
+
+
+
+
+
+ 20
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 21
+
+
+
+
+
+
+
+
+
+
+
+
+ 22
+
+
+ # private
+
+
+
+
+
+
+
+
+
+ 23
+
+
+ def handle_pixiv(source, headers)
+
+
+ 1
+
+
+
+
+
+
+ 24
+
+
+ if source =~ /pixiv\.net/
+
+
+ 0
+
+
+
+
+
+
+ 25
+
+
+ headers["Referer"] = "http://www.pixiv.net"
+
+
+ 0
+
+
+
+
+
+
+ 26
+
+
+
+
+
+
+
+
+
+
+
+
+ 27
+
+
+ # Don't download the small version
+
+
+
+
+
+
+
+
+
+ 28
+
+
+ if source =~ %r!(/img/.+?/.+?)_m.+$!
+
+
+ 0
+
+
+
+
+
+
+ 29
+
+
+ match = $1
+
+
+ 0
+
+
+
+
+
+
+ 30
+
+
+ source.sub!(match + "_m", match)
+
+
+ 0
+
+
+
+
+
+
+ 31
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 32
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 33
+
+
+
+
+
+
+
+
+
+
+
+
+ 34
+
+
+ source
+
+
+ 0
+
+
+
+
+
+
+ 35
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 36
+
+
+
+
+
+
+
+
+
+
+
+
+ 37
+
+
+ def http_get_streaming(source, options = {})
+
+
+ 1
+
+
+
+
+
+
+ 38
+
+
+ max_size = options[:max_size] || Danbooru.config.max_file_size
+
+
+ 0
+
+
+
+
+
+
+ 39
+
+
+ max_size = nil if max_size == 0 # unlimited
+
+
+ 0
+
+
+
+
+
+
+ 40
+
+
+ limit = 4
+
+
+ 0
+
+
+
+
+
+
+ 41
+
+
+
+
+
+
+
+
+
+
+
+
+ 42
+
+
+ while true
+
+
+ 0
+
+
+
+
+
+
+ 43
+
+
+ url = URI.parse(source)
+
+
+ 0
+
+
+
+
+
+
+ 44
+
+
+
+
+
+
+
+
+
+
+
+
+ 45
+
+
+ unless url.is_a?(URI::HTTP)
+
+
+ 0
+
+
+
+
+
+
+ 46
+
+
+ raise Error.new("URL must be HTTP")
+
+
+ 0
+
+
+
+
+
+
+ 47
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 48
+
+
+
+
+
+
+
+
+
+
+
+
+ 49
+
+
+ Net::HTTP.start(url.host, url.port) do |http|
+
+
+ 0
+
+
+
+
+
+
+ 50
+
+
+ http.read_timeout = 10
+
+
+ 0
+
+
+
+
+
+
+ 51
+
+
+ headers = {
+
+
+ 0
+
+
+
+
+
+
+ 52
+
+
+ "User-Agent" => "#{Danbooru.config.safe_app_name}/#{Danbooru.config.version}"
+
+
+
+
+
+
+
+
+
+ 53
+
+
+ }
+
+
+
+
+
+
+
+
+
+ 54
+
+
+ source = handle_pixiv(source, headers)
+
+
+ 0
+
+
+
+
+
+
+ 55
+
+
+ url = URI.parse(source)
+
+
+ 0
+
+
+
+
+
+
+ 56
+
+
+ http.request_get(url.request_uri, headers) do |res|
+
+
+ 0
+
+
+
+
+
+
+ 57
+
+
+ case res
+
+
+ 0
+
+
+
+
+
+
+ 58
+
+
+ when Net::HTTPSuccess then
+
+
+
+
+
+
+
+
+
+ 59
+
+
+ if max_size
+
+
+ 0
+
+
+
+
+
+
+ 60
+
+
+ len = res["Content-Length"]
+
+
+ 0
+
+
+
+
+
+
+ 61
+
+
+ raise Error.new("File is too large (#{len} bytes)") if len && len.to_i > max_size
+
+
+ 0
+
+
+
+
+
+
+ 62
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 63
+
+
+ yield(res)
+
+
+ 0
+
+
+
+
+
+
+ 64
+
+
+ return
+
+
+ 0
+
+
+
+
+
+
+ 65
+
+
+
+
+
+
+
+
+
+
+
+
+ 66
+
+
+ when Net::HTTPRedirection then
+
+
+
+
+
+
+
+
+
+ 67
+
+
+ if limit == 0 then
+
+
+ 0
+
+
+
+
+
+
+ 68
+
+
+ raise Error.new("Too many redirects")
+
+
+ 0
+
+
+
+
+
+
+ 69
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 70
+
+
+ source = res["location"]
+
+
+ 0
+
+
+
+
+
+
+ 71
+
+
+ limit -= 1
+
+
+ 0
+
+
+
+
+
+
+ 72
+
+
+
+
+
+
+
+
+
+
+
+
+ 73
+
+
+ else
+
+
+
+
+
+
+
+
+
+ 74
+
+
+ raise Error.new("HTTP error code: #{res.code} #{res.message}")
+
+
+ 0
+
+
+
+
+
+
+ 75
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 76
+
+
+ end # http.request_get
+
+
+
+
+
+
+
+
+
+ 77
+
+
+ end # http.start
+
+
+
+
+
+
+
+
+
+ 78
+
+
+ end # while
+
+
+
+
+
+
+
+
+
+ 79
+
+
+ end # def
+
+
+
+
+
+
+
+
+
+ 80
+
+
+
+
+
+
+
+
+
+
+
+
+ 81
+
+
+ def fix_image_board_sources(source)
+
+
+ 1
+
+
+
+
+
+
+ 82
+
+
+ if source =~ /\/src\/\d{12,}|urnc\.yi\.org|yui\.cynthia\.bne\.jp/
+
+
+ 0
+
+
+
+
+
+
+ 83
+
+
+ "Image board"
+
+
+ 0
+
+
+
+
+
+
+ 84
+
+
+ else
+
+
+
+
+
+
+
+
+
+ 85
+
+
+ source
+
+
+ 0
+
+
+
+
+
+
+ 86
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 87
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 88
+
+
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ./app/logical/favorite.rb
+ 35.14 % covered
+
+
+
+ #
+
+ Hits
+
+
+
+
+
+
+
+ 1
+
+
+ class Favorite
+
+
+ 1
+
+
+
+
+
+
+ 2
+
+
+ attr_accessor :attributes, :errors
+
+
+ 1
+
+
+
+
+
+
+ 3
+
+
+
+
+
+
+
+
+
+
+
+
+ 4
+
+
+ def self.table_name_for(user_id)
+
+
+ 1
+
+
+
+
+
+
+ 5
+
+
+ "favorites_#{user_id.to_i % 10}"
+
+
+ 0
+
+
+
+
+
+
+ 6
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 7
+
+
+
+
+
+
+
+
+
+
+
+
+ 8
+
+
+ def self.create(attributes)
+
+
+ 1
+
+
+
+
+
+
+ 9
+
+
+ user_id = attributes[:user_id]
+
+
+ 0
+
+
+
+
+
+
+ 10
+
+
+ post_id = attributes[:post_id]
+
+
+ 0
+
+
+
+
+
+
+ 11
+
+
+ execute_sql("INSERT INTO #{table_name_for(user_id)} (user_id, post_id) VALUES (?, ?)", user_id, post_id)
+
+
+ 0
+
+
+
+
+
+
+ 12
+
+
+ rescue ActiveRecord::RecordNotUnique
+
+
+
+
+
+
+
+
+
+ 13
+
+
+ # ignore
+
+
+
+
+
+
+
+
+
+ 14
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 15
+
+
+
+
+
+
+
+
+
+
+
+
+ 16
+
+
+ def self.count(user_id)
+
+
+ 1
+
+
+
+
+
+
+ 17
+
+
+ select_value_sql("SELECT COUNT(*) FROM #{table_name_for(user_id)}").to_i
+
+
+ 0
+
+
+
+
+
+
+ 18
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 19
+
+
+
+
+
+
+
+
+
+
+
+
+ 20
+
+
+ def self.destroy(conditions)
+
+
+ 1
+
+
+
+
+
+
+ 21
+
+
+ if conditions[:user_id] && conditions[:post_id]
+
+
+ 0
+
+
+
+
+
+
+ 22
+
+
+ destroy_for_post_and_user(conditions[:post_id], conditions[:user_id])
+
+
+ 0
+
+
+
+
+
+
+ 23
+
+
+ elsif conditions[:user_id]
+
+
+ 0
+
+
+
+
+
+
+ 24
+
+
+ destroy_for_user(conditions[:user_id])
+
+
+ 0
+
+
+
+
+
+
+ 25
+
+
+ elsif conditions[:post_id]
+
+
+ 0
+
+
+
+
+
+
+ 26
+
+
+ destroy_for_post(conditions[:post_id])
+
+
+ 0
+
+
+
+
+
+
+ 27
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 28
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 29
+
+
+
+
+
+
+
+
+
+
+
+
+ 30
+
+
+ def self.exists?(conditions)
+
+
+ 1
+
+
+
+
+
+
+ 31
+
+
+ if conditions[:user_id] && conditions[:post_id]
+
+
+ 0
+
+
+
+
+
+
+ 32
+
+
+ select_value_sql("SELECT 1 FROM #{table_name_for(conditions[:user_id])} WHERE user_id = ? AND post_id = ?", conditions[:user_id], conditions[:post_id])
+
+
+ 0
+
+
+
+
+
+
+ 33
+
+
+ elsif conditions[:user_id]
+
+
+ 0
+
+
+
+
+
+
+ 34
+
+
+ select_value_sql("SELECT 1 FROM #{table_name_for(conditions[:user_id])} WHERE user_id = ?", conditions[:user_id])
+
+
+ 0
+
+
+
+
+
+
+ 35
+
+
+ elsif conditions[:post_id]
+
+
+ 0
+
+
+
+
+
+
+ 36
+
+
+ select_value_sql("SELECT 1 FROM #{table_name_for(conditions[:user_id])} WHERE post_id = ?", conditions[:post_id])
+
+
+ 0
+
+
+
+
+
+
+ 37
+
+
+ else
+
+
+
+
+
+
+
+
+
+ 38
+
+
+ false
+
+
+ 0
+
+
+
+
+
+
+ 39
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 40
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 41
+
+
+
+
+
+
+
+
+
+
+
+
+ 42
+
+
+ private
+
+
+ 1
+
+
+
+
+
+
+ 43
+
+
+ def self.destroy_for_post_and_user(post_id, user_id)
+
+
+ 1
+
+
+
+
+
+
+ 44
+
+
+ execute_sql("DELETE FROM #{table_name_for(user_id)} WHERE post_id = #{post_id} AND user_id = #{user_id}")
+
+
+ 0
+
+
+
+
+
+
+ 45
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 46
+
+
+
+
+
+
+
+
+
+
+
+
+ 47
+
+
+ def self.destroy_for_post(post)
+
+
+ 1
+
+
+
+
+
+
+ 48
+
+
+ 0.upto(9) do |i|
+
+
+ 0
+
+
+
+
+
+
+ 49
+
+
+ execute_sql("DELETE FROM favorites_#{i} WHERE post_id = #{post.id}")
+
+
+ 0
+
+
+
+
+
+
+ 50
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 51
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 52
+
+
+
+
+
+
+
+
+
+
+
+
+ 53
+
+
+ def self.destroy_for_user(user)
+
+
+ 1
+
+
+
+
+
+
+ 54
+
+
+ execute_sql("DELETE FROM #{table_name_for(user)} WHERE user_id = #{user.id}")
+
+
+ 0
+
+
+
+
+
+
+ 55
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 56
+
+
+
+
+
+
+
+
+
+
+
+
+ 57
+
+
+ def self.select_value_sql(sql, *params)
+
+
+ 1
+
+
+
+
+
+
+ 58
+
+
+ ActiveRecord::Base.select_value_sql(sql, *params)
+
+
+ 0
+
+
+
+
+
+
+ 59
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 60
+
+
+
+
+
+
+
+
+
+
+
+
+ 61
+
+
+ def self.execute_sql(sql, *params)
+
+
+ 1
+
+
+
+
+
+
+ 62
+
+
+ ActiveRecord::Base.execute_sql(sql, *params)
+
+
+ 0
+
+
+
+
+
+
+ 63
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 64
+
+
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ./app/logical/pixiv_proxy.rb
+ 11.86 % covered
+
+
+
+ #
+
+ Hits
+
+
+
+
+
+
+
+ 1
+
+
+ class PixivProxy
+
+
+ 1
+
+
+
+
+
+
+ 2
+
+
+ def self.is_pixiv?(url)
+
+
+ 1
+
+
+
+
+
+
+ 3
+
+
+ url =~ /pixiv\.net/
+
+
+ 0
+
+
+
+
+
+
+ 4
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 5
+
+
+
+
+
+
+
+
+
+
+
+
+ 6
+
+
+ def self.get(url)
+
+
+ 1
+
+
+
+
+
+
+ 7
+
+
+ if url =~ /\/(\d+)(_m)?\.(jpg|jpeg|png|gif)/i
+
+
+ 0
+
+
+
+
+
+
+ 8
+
+
+ url = "http://www.pixiv.net/member_illust.php?mode=medium&illust_id=#{$1}"
+
+
+ 0
+
+
+
+
+
+
+ 9
+
+
+ get_single(url)
+
+
+ 0
+
+
+
+
+
+
+ 10
+
+
+ elsif url =~ /member_illust\.php/ && url =~ /illust_id=/
+
+
+ 0
+
+
+
+
+
+
+ 11
+
+
+ get_single(url)
+
+
+ 0
+
+
+
+
+
+
+ 12
+
+
+ # elsif url =~ /member_illust\.php/ && url =~ /id=/
+
+
+
+
+
+
+
+
+
+ 13
+
+
+ # get_listing(url)
+
+
+
+
+
+
+
+
+
+ 14
+
+
+ # elsif url =~ /member\.php/ && url =~ /id=/
+
+
+
+
+
+
+
+
+
+ 15
+
+
+ # get_profile(url)
+
+
+
+
+
+
+
+
+
+ 16
+
+
+ else
+
+
+
+
+
+
+
+
+
+ 17
+
+
+ {}
+
+
+ 0
+
+
+
+
+
+
+ 18
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 19
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 20
+
+
+
+
+
+
+
+
+
+
+
+
+ 21
+
+
+ def self.get_profile(url)
+
+
+ 1
+
+
+
+
+
+
+ 22
+
+
+ url = URI.parse(url).request_uri
+
+
+ 0
+
+
+
+
+
+
+ 23
+
+
+ mech = create_mechanize
+
+
+ 0
+
+
+
+
+
+
+ 24
+
+
+ hash = {}
+
+
+ 0
+
+
+
+
+
+
+ 25
+
+
+ mech.get(url) do |page|
+
+
+ 0
+
+
+
+
+
+
+ 26
+
+
+ hash[:artist] = page.search("a.avatar_m").attr("title").value
+
+
+ 0
+
+
+
+
+
+
+ 27
+
+
+ hash[:listing_url] = "/member_illust.php?id=" + url[/id=(\d+)/, 1]
+
+
+ 0
+
+
+
+
+
+
+ 28
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 29
+
+
+ hash
+
+
+ 0
+
+
+
+
+
+
+ 30
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 31
+
+
+
+
+
+
+
+
+
+
+
+
+ 32
+
+
+ def self.get_single(url)
+
+
+ 1
+
+
+
+
+
+
+ 33
+
+
+ url = URI.parse(url).request_uri
+
+
+ 0
+
+
+
+
+
+
+ 34
+
+
+ mech = create_mechanize
+
+
+ 0
+
+
+
+
+
+
+ 35
+
+
+ hash = {}
+
+
+ 0
+
+
+
+
+
+
+ 36
+
+
+ mech.get(url) do |page|
+
+
+ 0
+
+
+
+
+
+
+ 37
+
+
+ if page.search("a.avatar_m")
+
+
+ 0
+
+
+
+
+
+
+ 38
+
+
+ hash[:artist] = page.search("a.avatar_m").attr("title").value
+
+
+ 0
+
+
+
+
+
+
+ 39
+
+
+ hash[:image_url] = page.search("div.works_display/a/img").attr("src").value.sub("_m.", ".")
+
+
+ 0
+
+
+
+
+
+
+ 40
+
+
+ hash[:profile_url] = page.search("a.avatar_m").attr("href").value
+
+
+ 0
+
+
+
+
+
+
+ 41
+
+
+ hash[:jp_tags] = page.search("span#tags/a").map do |node|
+
+
+ 0
+
+
+
+
+
+
+ 42
+
+
+ [node.inner_text, node.attribute("href").to_s]
+
+
+ 0
+
+
+
+
+
+
+ 43
+
+
+ end.reject {|x| x[0].empty?}
+
+
+ 0
+
+
+
+
+
+
+ 44
+
+
+ else
+
+
+
+
+
+
+
+
+
+ 45
+
+
+ hash[:artist] = "?"
+
+
+ 0
+
+
+
+
+
+
+ 46
+
+
+ hash[:image_url] = "?"
+
+
+ 0
+
+
+
+
+
+
+ 47
+
+
+ hash[:profile_url] = "?"
+
+
+ 0
+
+
+
+
+
+
+ 48
+
+
+ hash[:jp_tags] = []
+
+
+ 0
+
+
+
+
+
+
+ 49
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 50
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 51
+
+
+ hash
+
+
+ 0
+
+
+
+
+
+
+ 52
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 53
+
+
+
+
+
+
+
+
+
+
+
+
+ 54
+
+
+ def self.get_listing(url)
+
+
+ 1
+
+
+
+
+
+
+ 55
+
+
+ mech = create_mechanize
+
+
+ 0
+
+
+
+
+
+
+ 56
+
+
+ p = 1
+
+
+ 0
+
+
+
+
+
+
+ 57
+
+
+ url = URI.parse(url).request_uri.sub(/&p=\d+/, "") + "&p=1"
+
+
+ 0
+
+
+
+
+
+
+ 58
+
+
+ more = true
+
+
+ 0
+
+
+
+
+
+
+ 59
+
+
+ images = []
+
+
+ 0
+
+
+
+
+
+
+ 60
+
+
+
+
+
+
+
+
+
+
+
+
+ 61
+
+
+ while more
+
+
+ 0
+
+
+
+
+
+
+ 62
+
+
+ mech.get(url) do |page|
+
+
+ 0
+
+
+
+
+
+
+ 63
+
+
+ links = page.search("div#illust_c4/ul/li/a")
+
+
+ 0
+
+
+
+
+
+
+ 64
+
+
+
+
+
+
+
+
+
+
+
+
+ 65
+
+
+ if links.empty?
+
+
+ 0
+
+
+
+
+
+
+ 66
+
+
+ more = false
+
+
+ 0
+
+
+
+
+
+
+ 67
+
+
+ else
+
+
+
+
+
+
+
+
+
+ 68
+
+
+ images += links.map do |node|
+
+
+ 0
+
+
+
+
+
+
+ 69
+
+
+ image_src = node.child.attribute("src").to_s
+
+
+ 0
+
+
+
+
+
+
+ 70
+
+
+ [image_src, image_src.sub("_s.", "."), node.attribute("href").to_s]
+
+
+ 0
+
+
+
+
+
+
+ 71
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 72
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 73
+
+
+
+
+
+
+
+
+
+
+
+
+ 74
+
+
+ p += 1
+
+
+ 0
+
+
+
+
+
+
+ 75
+
+
+ url.sub!(/&p=\d+/, "&p=#{p}")
+
+
+ 0
+
+
+
+
+
+
+ 76
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 77
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 78
+
+
+
+
+
+
+
+
+
+
+
+
+ 79
+
+
+ images
+
+
+ 0
+
+
+
+
+
+
+ 80
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 81
+
+
+
+
+
+
+
+
+
+
+
+
+ 82
+
+
+ def self.create_mechanize
+
+
+ 1
+
+
+
+
+
+
+ 83
+
+
+ mech = Mechanize.new
+
+
+ 0
+
+
+
+
+
+
+ 84
+
+
+
+
+
+
+
+
+
+
+
+
+ 85
+
+
+ mech.get("http://www.pixiv.net") do |page|
+
+
+ 0
+
+
+
+
+
+
+ 86
+
+
+ page.form_with(:action => "/login.php") do |form|
+
+
+ 0
+
+
+
+
+
+
+ 87
+
+
+ form.pixiv_id = "uroobnad"
+
+
+ 0
+
+
+
+
+
+
+ 88
+
+
+ form.pass = "uroobnad556"
+
+
+ 0
+
+
+
+
+
+
+ 89
+
+
+ end.click_button
+
+
+
+
+
+
+
+
+
+ 90
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 91
+
+
+
+
+
+
+
+
+
+
+
+
+ 92
+
+
+ mech
+
+
+ 0
+
+
+
+
+
+
+ 93
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 94
+
+
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ./app/logical/post_sets/base.rb
+ 52.38 % covered
+
+
+
+ #
+
+ Hits
+
+
+
+
+
+
+
+ 1
+
+
+ module PostSets
+
+
+ 1
+
+
+
+
+
+
+ 2
+
+
+ class Base
+
+
+ 1
+
+
+
+
+
+
+ 3
+
+
+ attr_accessor :page, :before_id, :count, :posts
+
+
+ 1
+
+
+
+
+
+
+ 4
+
+
+
+
+
+
+
+
+
+
+
+
+ 5
+
+
+ def initialize(options = {})
+
+
+ 1
+
+
+
+
+
+
+ 6
+
+
+ @page = options[:page].to_i
+
+
+ 0
+
+
+
+
+
+
+ 7
+
+
+ @before_id = options[:before_id]
+
+
+ 0
+
+
+
+
+
+
+ 8
+
+
+ load_posts
+
+
+ 0
+
+
+
+
+
+
+ 9
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 10
+
+
+
+
+
+
+
+
+
+
+
+
+ 11
+
+
+ def has_wiki?
+
+
+ 1
+
+
+
+
+
+
+ 12
+
+
+ false
+
+
+ 0
+
+
+
+
+
+
+ 13
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 14
+
+
+
+
+
+
+
+
+
+
+
+
+ 15
+
+
+ def use_sequential_paginator?
+
+
+ 1
+
+
+
+
+
+
+ 16
+
+
+ !use_numbered_paginator?
+
+
+ 0
+
+
+
+
+
+
+ 17
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 18
+
+
+
+
+
+
+
+
+
+
+
+
+ 19
+
+
+ def use_numbered_paginator?
+
+
+ 1
+
+
+
+
+
+
+ 20
+
+
+ before_id.nil?
+
+
+ 0
+
+
+
+
+
+
+ 21
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 22
+
+
+
+
+
+
+
+
+
+
+
+
+ 23
+
+
+ def load_posts
+
+
+ 1
+
+
+
+
+
+
+ 24
+
+
+ raise NotImplementedError
+
+
+ 0
+
+
+
+
+
+
+ 25
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 26
+
+
+
+
+
+
+
+
+
+
+
+
+ 27
+
+
+ def to_xml
+
+
+ 1
+
+
+
+
+
+
+ 28
+
+
+ posts.to_xml
+
+
+ 0
+
+
+
+
+
+
+ 29
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 30
+
+
+
+
+
+
+
+
+
+
+
+
+ 31
+
+
+ def to_json
+
+
+ 1
+
+
+
+
+
+
+ 32
+
+
+ posts.to_json
+
+
+ 0
+
+
+
+
+
+
+ 33
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 34
+
+
+
+
+
+
+
+
+
+
+
+
+ 35
+
+
+ def presenter
+
+
+ 1
+
+
+
+
+
+
+ 36
+
+
+ @presnter ||= PostSetPresenter.new(self)
+
+
+ 0
+
+
+
+
+
+
+ 37
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 38
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 39
+
+
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ./app/logical/post_sets/favorite.rb
+ 58.33 % covered
+
+
+
+ #
+
+ Hits
+
+
+
+
+
+
+
+ 1
+
+
+ module PostSets
+
+
+ 1
+
+
+
+
+
+
+ 2
+
+
+ class Favorite < Base
+
+
+ 1
+
+
+
+
+
+
+ 3
+
+
+ attr_accessor :user
+
+
+ 1
+
+
+
+
+
+
+ 4
+
+
+
+
+
+
+
+
+
+
+
+
+ 5
+
+
+ def initialize(user)
+
+
+ 1
+
+
+
+
+
+
+ 6
+
+
+ @user = user
+
+
+ 0
+
+
+
+
+
+
+ 7
+
+
+ super()
+
+
+ 0
+
+
+
+
+
+
+ 8
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 9
+
+
+
+
+
+
+
+
+
+
+
+
+ 10
+
+
+ def tags
+
+
+ 1
+
+
+
+
+
+
+ 11
+
+
+ "fav:#{user.name}"
+
+
+ 0
+
+
+
+
+
+
+ 12
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 13
+
+
+
+
+
+
+
+
+
+
+
+
+ 14
+
+
+ def load_posts
+
+
+ 1
+
+
+
+
+
+
+ 15
+
+
+ @posts = user.favorite_posts(:before_id => before_id)
+
+
+ 0
+
+
+
+
+
+
+ 16
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 17
+
+
+
+
+
+
+
+
+
+
+
+
+ 18
+
+
+ def limit
+
+
+ 1
+
+
+
+
+
+
+ 19
+
+
+ Danbooru.config.posts_per_page
+
+
+ 0
+
+
+
+
+
+
+ 20
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 21
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 22
+
+
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ./app/logical/post_sets/post.rb
+ 36.54 % covered
+
+
+
+ #
+
+ Hits
+
+
+
+
+
+
+
+ 1
+
+
+ module PostSets
+
+
+ 1
+
+
+
+
+
+
+ 2
+
+
+ class Post < Base
+
+
+ 1
+
+
+
+
+
+
+ 3
+
+
+ class Error < Exception ; end
+
+
+ 1
+
+
+
+
+
+
+ 4
+
+
+
+
+
+
+
+
+
+
+
+
+ 5
+
+
+ attr_accessor :tags, :errors, :count
+
+
+ 1
+
+
+
+
+
+
+ 6
+
+
+ attr_accessor :wiki_page, :artist, :suggestions
+
+
+ 1
+
+
+
+
+
+
+ 7
+
+
+
+
+
+
+
+
+
+
+
+
+ 8
+
+
+ def initialize(tags, options = {})
+
+
+ 1
+
+
+
+
+
+
+ 9
+
+
+ super(options)
+
+
+ 0
+
+
+
+
+
+
+ 10
+
+
+ @tags = Tag.normalize(tags)
+
+
+ 0
+
+
+
+
+
+
+ 11
+
+
+ @errors = []
+
+
+ 0
+
+
+
+
+
+
+ 12
+
+
+ load_associations
+
+
+ 0
+
+
+
+
+
+
+ 13
+
+
+ load_suggestions
+
+
+ 0
+
+
+
+
+
+
+ 14
+
+
+ validate
+
+
+ 0
+
+
+
+
+
+
+ 15
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 16
+
+
+
+
+
+
+
+
+
+
+
+
+ 17
+
+
+ def has_wiki?
+
+
+ 1
+
+
+
+
+
+
+ 18
+
+
+ is_single_tag?
+
+
+ 0
+
+
+
+
+
+
+ 19
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 20
+
+
+
+
+
+
+
+
+
+
+
+
+ 21
+
+
+ def has_errors?
+
+
+ 1
+
+
+
+
+
+
+ 22
+
+
+ errors.any?
+
+
+ 0
+
+
+
+
+
+
+ 23
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 24
+
+
+
+
+
+
+
+
+
+
+
+
+ 25
+
+
+ def offset
+
+
+ 1
+
+
+
+
+
+
+ 26
+
+
+ x = (page - 1) * limit
+
+
+ 0
+
+
+
+
+
+
+ 27
+
+
+ if x < 0
+
+
+ 0
+
+
+
+
+
+
+ 28
+
+
+ x = 0
+
+
+ 0
+
+
+
+
+
+
+ 29
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 30
+
+
+ x
+
+
+ 0
+
+
+
+
+
+
+ 31
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 32
+
+
+
+
+
+
+
+
+
+
+
+
+ 33
+
+
+ def limit
+
+
+ 1
+
+
+
+
+
+
+ 34
+
+
+ Danbooru.config.posts_per_page
+
+
+ 0
+
+
+
+
+
+
+ 35
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 36
+
+
+
+
+
+
+
+
+
+
+
+
+ 37
+
+
+ def is_single_tag?
+
+
+ 1
+
+
+
+
+
+
+ 38
+
+
+ tag_array.size == 1
+
+
+ 0
+
+
+
+
+
+
+ 39
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 40
+
+
+
+
+
+
+
+
+
+
+
+
+ 41
+
+
+ def date_tag
+
+
+ 1
+
+
+
+
+
+
+ 42
+
+
+ tag_array.grep(/date:/).first
+
+
+ 0
+
+
+
+
+
+
+ 43
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 44
+
+
+
+
+
+
+
+
+
+
+
+
+ 45
+
+
+ def load_associations
+
+
+ 1
+
+
+
+
+
+
+ 46
+
+
+ if is_single_tag?
+
+
+ 0
+
+
+
+
+
+
+ 47
+
+
+ @wiki_page = WikiPage.find_by_title(tags)
+
+
+ 0
+
+
+
+
+
+
+ 48
+
+
+ @artist = Artist.find_by_name(tags)
+
+
+ 0
+
+
+
+
+
+
+ 49
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 50
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 51
+
+
+
+
+
+
+
+
+
+
+
+
+ 52
+
+
+ def load_posts
+
+
+ 1
+
+
+
+
+
+
+ 53
+
+
+ @count = Post.fast_count(tags)
+
+
+ 0
+
+
+
+
+
+
+ 54
+
+
+ @posts = Post.find_by_tags(tags, :before_id => before_id).all(:order => "posts.id desc", :limit => limit, :offset => offset)
+
+
+ 0
+
+
+
+
+
+
+ 55
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 56
+
+
+
+
+
+
+
+
+
+
+
+
+ 57
+
+
+ def load_suggestions
+
+
+ 1
+
+
+
+
+
+
+ 58
+
+
+ if count < limit && is_single_tag?
+
+
+ 0
+
+
+
+
+
+
+ 59
+
+
+ @suggestions = Tag.find_suggestions(tags)
+
+
+ 0
+
+
+
+
+
+
+ 60
+
+
+ else
+
+
+
+
+
+
+
+
+
+ 61
+
+
+ @suggestions = []
+
+
+ 0
+
+
+
+
+
+
+ 62
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 63
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 64
+
+
+
+
+
+
+
+
+
+
+
+
+ 65
+
+
+ def tag_array
+
+
+ 1
+
+
+
+
+
+
+ 66
+
+
+ @tag_array ||= Tag.scan_query(tags)
+
+
+ 0
+
+
+
+
+
+
+ 67
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 68
+
+
+
+
+
+
+
+
+
+
+
+
+ 69
+
+
+ def validate
+
+
+ 1
+
+
+
+
+
+
+ 70
+
+
+ validate_page
+
+
+ 0
+
+
+
+
+
+
+ 71
+
+
+ validate_query_count
+
+
+ 0
+
+
+
+
+
+
+ 72
+
+
+ rescue Error => x
+
+
+
+
+
+
+
+
+
+ 73
+
+
+ @errors << x.to_s
+
+
+ 0
+
+
+
+
+
+
+ 74
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 75
+
+
+
+
+
+
+
+
+
+
+
+
+ 76
+
+
+ def validate_page
+
+
+ 1
+
+
+
+
+
+
+ 77
+
+
+ if page > 1_000
+
+
+ 0
+
+
+
+
+
+
+ 78
+
+
+ raise Error.new("You cannot explicitly specify the page after page 1000")
+
+
+ 0
+
+
+
+
+
+
+ 79
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 80
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 81
+
+
+
+
+
+
+
+
+
+
+
+
+ 82
+
+
+ def validate_query_count
+
+
+ 1
+
+
+
+
+
+
+ 83
+
+
+ if !CurrentUser.is_privileged? && tag_array.size > 2
+
+
+ 0
+
+
+
+
+
+
+ 84
+
+
+ raise Error.new("You can only search up to two tags at once with a basic account")
+
+
+ 0
+
+
+
+
+
+
+ 85
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 86
+
+
+
+
+
+
+
+
+
+
+
+
+ 87
+
+
+ if tag_array.size > 6
+
+
+ 0
+
+
+
+
+
+
+ 88
+
+
+ raise Error.new("You can only search up to six tags at once")
+
+
+ 0
+
+
+
+
+
+
+ 89
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 90
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 91
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 92
+
+
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ./app/logical/related_tag_calculator.rb
+ 24.0 % covered
+
+
+
+ #
+
+ Hits
+
+
+
+
+
+
+
+ 1
+
+
+ class RelatedTagCalculator
+
+
+ 1
+
+
+
+
+
+
+ 2
+
+
+ def self.find_tags(tag, limit)
+
+
+ 1
+
+
+
+
+
+
+ 3
+
+
+ Post.find_by_tags(tag, :limit => limit, :select => "posts.tag_string", :order => "posts.md5").map(&:tag_string)
+
+
+ 0
+
+
+
+
+
+
+ 4
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 5
+
+
+
+
+
+
+
+
+
+
+
+
+ 6
+
+
+ def self.calculate_from_sample_to_array(tags, category_constraint = nil)
+
+
+ 1
+
+
+
+
+
+
+ 7
+
+
+ convert_hash_to_array(calculate_from_sample(tags, Danbooru.config.post_sample_size, category_constraint))
+
+
+ 0
+
+
+
+
+
+
+ 8
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 9
+
+
+
+
+
+
+
+
+
+
+
+
+ 10
+
+
+ def self.calculate_from_sample(tags, limit, category_constraint = nil)
+
+
+ 1
+
+
+
+
+
+
+ 11
+
+
+ counts = Hash.new {|h, k| h[k] = 0}
+
+
+ 0
+
+
+
+
+
+
+ 12
+
+
+
+
+
+
+
+
+
+
+
+
+ 13
+
+
+ case category_constraint
+
+
+ 0
+
+
+
+
+
+
+ 14
+
+
+ when Tag.categories.artist
+
+
+
+
+
+
+
+
+
+ 15
+
+
+ limit *= 4
+
+
+ 0
+
+
+
+
+
+
+ 16
+
+
+
+
+
+
+
+
+
+
+
+
+ 17
+
+
+ when Tag.categories.copyright
+
+
+
+
+
+
+
+
+
+ 18
+
+
+ limit *= 3
+
+
+ 0
+
+
+
+
+
+
+ 19
+
+
+
+
+
+
+
+
+
+
+
+
+ 20
+
+
+ when Tag.categories.character
+
+
+
+
+
+
+
+
+
+ 21
+
+
+ limit *= 2
+
+
+ 0
+
+
+
+
+
+
+ 22
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 23
+
+
+
+
+
+
+
+
+
+
+
+
+ 24
+
+
+ find_tags(tags, limit).each do |tags|
+
+
+ 0
+
+
+
+
+
+
+ 25
+
+
+ tag_array = Tag.scan_tags(tags)
+
+
+ 0
+
+
+
+
+
+
+ 26
+
+
+ if category_constraint
+
+
+ 0
+
+
+
+
+
+
+ 27
+
+
+ tag_array.each do |tag|
+
+
+ 0
+
+
+
+
+
+
+ 28
+
+
+ category = Tag.category_for(tag)
+
+
+ 0
+
+
+
+
+
+
+ 29
+
+
+ if category == category_constraint
+
+
+ 0
+
+
+
+
+
+
+ 30
+
+
+ counts[tag] += 1
+
+
+ 0
+
+
+
+
+
+
+ 31
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 32
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 33
+
+
+ else
+
+
+
+
+
+
+
+
+
+ 34
+
+
+ tag_array.each do |tag|
+
+
+ 0
+
+
+
+
+
+
+ 35
+
+
+ counts[tag] += 1
+
+
+ 0
+
+
+
+
+
+
+ 36
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 37
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 38
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 39
+
+
+
+
+
+
+
+
+
+
+
+
+ 40
+
+
+ counts
+
+
+ 0
+
+
+
+
+
+
+ 41
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 42
+
+
+
+
+
+
+
+
+
+
+
+
+ 43
+
+
+ def self.convert_hash_to_array(hash)
+
+
+ 1
+
+
+
+
+
+
+ 44
+
+
+ hash.to_a.sort_by {|x| -x[1]}.slice(0, 25)
+
+
+ 0
+
+
+
+
+
+
+ 45
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 46
+
+
+
+
+
+
+
+
+
+
+
+
+ 47
+
+
+ def self.convert_hash_to_string(hash)
+
+
+ 1
+
+
+
+
+
+
+ 48
+
+
+ convert_hash_to_array(hash).flatten.join(" ")
+
+
+ 0
+
+
+
+
+
+
+ 49
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 50
+
+
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ./app/logical/remote_server.rb
+ 44.44 % covered
+
+
+
+ #
+
+ Hits
+
+
+
+
+
+
+
+ 1
+
+
+ class RemoteServer
+
+
+ 1
+
+
+
+
+
+
+ 2
+
+
+ attr_accessor :hostname
+
+
+ 1
+
+
+
+
+
+
+ 3
+
+
+
+
+
+
+
+
+
+
+
+
+ 4
+
+
+ def self.other_servers
+
+
+ 1
+
+
+
+
+
+
+ 5
+
+
+ Danbooru.config.other_server_hosts.map {|x| new(x)}
+
+
+ 0
+
+
+
+
+
+
+ 6
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 7
+
+
+
+
+
+
+
+
+
+
+
+
+ 8
+
+
+ def self.copy_to_all(local_path, remote_path)
+
+
+ 1
+
+
+
+
+
+
+ 9
+
+
+ other_servers.each do |server|
+
+
+ 0
+
+
+
+
+
+
+ 10
+
+
+ server.copy(local_path, remote_path)
+
+
+ 0
+
+
+
+
+
+
+ 11
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 12
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 13
+
+
+
+
+
+
+
+
+
+
+
+
+ 14
+
+
+ def self.delete_from_all(remote_path)
+
+
+ 1
+
+
+
+
+
+
+ 15
+
+
+ other_servers.each do |server|
+
+
+ 0
+
+
+
+
+
+
+ 16
+
+
+ server.delete(remote_path)
+
+
+ 0
+
+
+
+
+
+
+ 17
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 18
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 19
+
+
+
+
+
+
+
+
+
+
+
+
+ 20
+
+
+ def initialize(hostname)
+
+
+ 1
+
+
+
+
+
+
+ 21
+
+
+ @hostname = hostname
+
+
+ 0
+
+
+
+
+
+
+ 22
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 23
+
+
+
+
+
+
+
+
+
+
+
+
+ 24
+
+
+ def copy(local_path, remote_path)
+
+
+ 1
+
+
+
+
+
+
+ 25
+
+
+ Net::SFTP.start(hostname, Danbooru.config.remote_server_login) do |ftp|
+
+
+ 0
+
+
+
+
+
+
+ 26
+
+
+ ftp.upload!(local_path, remote_path)
+
+
+ 0
+
+
+
+
+
+
+ 27
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 28
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 29
+
+
+
+
+
+
+
+
+
+
+
+
+ 30
+
+
+ def delete(remote_path)
+
+
+ 1
+
+
+
+
+
+
+ 31
+
+
+ Net::SFTP.start(hostname, Danbooru.config.remote_server_login) do |ftp|
+
+
+ 0
+
+
+
+
+
+
+ 32
+
+
+ ftp.remove(remote_path)
+
+
+ 0
+
+
+
+
+
+
+ 33
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 34
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 35
+
+
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ./app/models/advertisement.rb
+ 38.1 % covered
+
+
+
+ #
+
+ Hits
+
+
+
+
+
+
+
+ 1
+
+
+ class Advertisement < ActiveRecord::Base
+
+
+ 1
+
+
+
+
+
+
+ 2
+
+
+ validates_inclusion_of :ad_type, :in => %w(horizontal vertical)
+
+
+ 1
+
+
+
+
+
+
+ 3
+
+
+ has_many :hits, :class_name => "AdvertisementHit"
+
+
+ 1
+
+
+
+
+
+
+ 4
+
+
+ after_create :copy_to_servers
+
+
+ 1
+
+
+
+
+
+
+ 5
+
+
+ after_destroy :delete_from_servers
+
+
+ 1
+
+
+
+
+
+
+ 6
+
+
+
+
+
+
+
+
+
+
+
+
+ 7
+
+
+ def copy_to_servers
+
+
+ 1
+
+
+
+
+
+
+ 8
+
+
+ RemoteServer.copy_to_all(image_path, image_path)
+
+
+ 0
+
+
+
+
+
+
+ 9
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 10
+
+
+
+
+
+
+
+
+
+
+
+
+ 11
+
+
+ def delete_from_servers
+
+
+ 1
+
+
+
+
+
+
+ 12
+
+
+ RemoteServer.delete_from_all(image_path)
+
+
+ 0
+
+
+
+
+
+
+ 13
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 14
+
+
+
+
+
+
+
+
+
+
+
+
+ 15
+
+
+ def hit!(ip_addr)
+
+
+ 1
+
+
+
+
+
+
+ 16
+
+
+ hits.create(:ip_addr => ip_addr)
+
+
+ 0
+
+
+
+
+
+
+ 17
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 18
+
+
+
+
+
+
+
+
+
+
+
+
+ 19
+
+
+ def hit_sum(start_date, end_date)
+
+
+ 1
+
+
+
+
+
+
+ 20
+
+
+ hits.where(["created_at BETWEEN ? AND ?", start_date, end_date]).count
+
+
+ 0
+
+
+
+
+
+
+ 21
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 22
+
+
+
+
+
+
+
+
+
+
+
+
+ 23
+
+
+ def unique_identifier
+
+
+ 1
+
+
+
+
+
+
+ 24
+
+
+ @unique_identifier ||= ("%.0f" % (Time.now.to_f * 1_000))
+
+
+ 0
+
+
+
+
+
+
+ 25
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 26
+
+
+
+
+
+
+
+
+
+
+
+
+ 27
+
+
+ def image_url
+
+
+ 1
+
+
+
+
+
+
+ 28
+
+
+ "/images/advertisements/#{file_name}"
+
+
+ 0
+
+
+
+
+
+
+ 29
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 30
+
+
+
+
+
+
+
+
+
+
+
+
+ 31
+
+
+ def image_path
+
+
+ 1
+
+
+
+
+
+
+ 32
+
+
+ "#{Rails.root}/public/images/advertisements/#{file_name}"
+
+
+ 0
+
+
+
+
+
+
+ 33
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 34
+
+
+
+
+
+
+
+
+
+
+
+
+ 35
+
+
+ def file
+
+
+ 1
+
+
+
+
+
+
+ 36
+
+
+ nil
+
+
+
+
+
+
+
+
+
+ 37
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 38
+
+
+
+
+
+
+
+
+
+
+
+
+ 39
+
+
+ def file=(f)
+
+
+ 1
+
+
+
+
+
+
+ 40
+
+
+ if f.size > 0
+
+
+ 0
+
+
+
+
+
+
+ 41
+
+
+ self.file_name = unique_identifier + File.extname(f.original_filename)
+
+
+ 0
+
+
+
+
+
+
+ 42
+
+
+
+
+
+
+
+
+
+
+
+
+ 43
+
+
+ if f.local_path
+
+
+ 0
+
+
+
+
+
+
+ 44
+
+
+ FileUtils.cp(f.local_path, image_path)
+
+
+ 0
+
+
+
+
+
+
+ 45
+
+
+ else
+
+
+
+
+
+
+
+
+
+ 46
+
+
+ File.open(image_path, 'wb') {|nf| nf.write(f.read)}
+
+
+ 0
+
+
+
+
+
+
+ 47
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 48
+
+
+
+
+
+
+
+
+
+
+
+
+ 49
+
+
+ File.chmod(0644, image_path)
+
+
+ 0
+
+
+
+
+
+
+ 50
+
+
+ image_size = ImageSize.new(File.open(image_path, "rb"))
+
+
+ 0
+
+
+
+
+
+
+ 51
+
+
+ self.width = image_size.get_width
+
+
+ 0
+
+
+
+
+
+
+ 52
+
+
+ self.height = image_size.get_height
+
+
+ 0
+
+
+
+
+
+
+ 53
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 54
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 55
+
+
+
+
+
+
+
+
+
+
+
+
+ 56
+
+
+ def preview_width
+
+
+ 1
+
+
+
+
+
+
+ 57
+
+
+ if width > 100 || height > 100
+
+
+ 0
+
+
+
+
+
+
+ 58
+
+
+ if width < height
+
+
+ 0
+
+
+
+
+
+
+ 59
+
+
+ ratio = 100.0 / height
+
+
+ 0
+
+
+
+
+
+
+ 60
+
+
+ return (width * ratio).to_i
+
+
+ 0
+
+
+
+
+
+
+ 61
+
+
+ else
+
+
+
+
+
+
+
+
+
+ 62
+
+
+ return 100
+
+
+ 0
+
+
+
+
+
+
+ 63
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 64
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 65
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 66
+
+
+
+
+
+
+
+
+
+
+
+
+ 67
+
+
+ def preview_height
+
+
+ 1
+
+
+
+
+
+
+ 68
+
+
+ if width > 100 || height > 100
+
+
+ 0
+
+
+
+
+
+
+ 69
+
+
+ if height < width
+
+
+ 0
+
+
+
+
+
+
+ 70
+
+
+ ratio = 100.0 / width
+
+
+ 0
+
+
+
+
+
+
+ 71
+
+
+ return (height * ratio)
+
+
+ 0
+
+
+
+
+
+
+ 72
+
+
+ else
+
+
+
+
+
+
+
+
+
+ 73
+
+
+ return 100
+
+
+ 0
+
+
+
+
+
+
+ 74
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 75
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 76
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 77
+
+
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ./app/models/advertisement_hit.rb
+ 100.0 % covered
+
+
+
+ #
+
+ Hits
+
+
+
+
+
+
+
+ 1
+
+
+ class AdvertisementHit < ActiveRecord::Base
+
+
+ 1
+
+
+
+
+
+
+ 2
+
+
+ belongs_to :advertisement
+
+
+ 1
+
+
+
+
+
+
+ 3
+
+
+
+
+
+
+
+
+
+
+
+
+ 4
+
+
+ scope :between, lambda {|start_date, end_date| where("created_at BETWEEN ? AND ?", start_date, end_date)}
+
+
+ 1
+
+
+
+
+
+
+ 5
+
+
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ./app/models/artist.rb
+ 44.26 % covered
+
+
+
+ #
+
+ Hits
+
+
+
+
+
+
+
+ 1
+
+
+ class Artist < ActiveRecord::Base
+
+
+ 1
+
+
+
+
+
+
+ 2
+
+
+ before_create :initialize_creator
+
+
+ 1
+
+
+
+
+
+
+ 3
+
+
+ before_save :normalize_name
+
+
+ 1
+
+
+
+
+
+
+ 4
+
+
+ after_save :create_version
+
+
+ 1
+
+
+
+
+
+
+ 5
+
+
+ after_save :save_url_string
+
+
+ 1
+
+
+
+
+
+
+ 6
+
+
+ validates_uniqueness_of :name
+
+
+ 1
+
+
+
+
+
+
+ 7
+
+
+ belongs_to :creator, :class_name => "User"
+
+
+ 1
+
+
+
+
+
+
+ 8
+
+
+ has_many :members, :class_name => "Artist", :foreign_key => "group_name", :primary_key => "name"
+
+
+ 1
+
+
+
+
+
+
+ 9
+
+
+ has_many :urls, :dependent => :destroy, :class_name => "ArtistUrl"
+
+
+ 1
+
+
+
+
+
+
+ 10
+
+
+ has_many :versions, :order => "artist_versions.id", :class_name => "ArtistVersion"
+
+
+ 1
+
+
+
+
+
+
+ 11
+
+
+ has_one :wiki_page, :foreign_key => "title", :primary_key => "name"
+
+
+ 1
+
+
+
+
+
+
+ 12
+
+
+ has_one :tag_alias, :foreign_key => "antecedent_name", :primary_key => "name"
+
+
+ 1
+
+
+
+
+
+
+ 13
+
+
+ accepts_nested_attributes_for :wiki_page
+
+
+ 1
+
+
+
+
+
+
+ 14
+
+
+ attr_accessible :name, :url_string, :other_names, :group_name, :wiki_page_attributes, :notes
+
+
+ 1
+
+
+
+
+
+
+ 15
+
+
+
+
+
+
+
+
+
+
+
+
+ 16
+
+
+ module UrlMethods
+
+
+ 1
+
+
+
+
+
+
+ 17
+
+
+ module ClassMethods
+
+
+ 1
+
+
+
+
+
+
+ 18
+
+
+ def find_all_by_url(url)
+
+
+ 1
+
+
+
+
+
+
+ 19
+
+
+ url = ArtistUrl.normalize(url)
+
+
+ 0
+
+
+
+
+
+
+ 20
+
+
+ artists = []
+
+
+ 0
+
+
+
+
+
+
+ 21
+
+
+
+
+
+
+
+
+
+
+
+
+ 22
+
+
+ while artists.empty? && url.size > 10
+
+
+ 0
+
+
+
+
+
+
+ 23
+
+
+ u = url.sub(/\/+$/, "") + "/"
+
+
+ 0
+
+
+
+
+
+
+ 24
+
+
+ u = u.to_escaped_for_sql_like.gsub(/\*/, '%') + '%'
+
+
+ 0
+
+
+
+
+
+
+ 25
+
+
+ artists += Artist.joins(:urls).where(["artists.is_active = TRUE AND artist_urls.normalized_url LIKE ? ESCAPE E'\\\\'", u]).all(:order => "artists.name")
+
+
+ 0
+
+
+
+
+
+
+ 26
+
+
+ url = File.dirname(url) + "/"
+
+
+ 0
+
+
+
+
+
+
+ 27
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 28
+
+
+
+
+
+
+
+
+
+
+
+
+ 29
+
+
+ artists.uniq_by {|x| x.name}.slice(0, 20)
+
+
+ 0
+
+
+
+
+
+
+ 30
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 31
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 32
+
+
+
+
+
+
+
+
+
+
+
+
+ 33
+
+
+ def self.included(m)
+
+
+ 1
+
+
+
+
+
+
+ 34
+
+
+ m.extend(ClassMethods)
+
+
+ 1
+
+
+
+
+
+
+ 35
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 36
+
+
+
+
+
+
+
+
+
+
+
+
+ 37
+
+
+ def save_url_string
+
+
+ 1
+
+
+
+
+
+
+ 38
+
+
+ if @url_string
+
+
+ 0
+
+
+
+
+
+
+ 39
+
+
+ urls.clear
+
+
+ 0
+
+
+
+
+
+
+ 40
+
+
+
+
+
+
+
+
+
+
+
+
+ 41
+
+
+ @url_string.scan(/\S+/).each do |url|
+
+
+ 0
+
+
+
+
+
+
+ 42
+
+
+ urls.create(:url => url)
+
+
+ 0
+
+
+
+
+
+
+ 43
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 44
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 45
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 46
+
+
+
+
+
+
+
+
+
+
+
+
+ 47
+
+
+ def url_string=(string)
+
+
+ 1
+
+
+
+
+
+
+ 48
+
+
+ @url_string = string
+
+
+ 0
+
+
+
+
+
+
+ 49
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 50
+
+
+
+
+
+
+
+
+
+
+
+
+ 51
+
+
+ def url_string
+
+
+ 1
+
+
+
+
+
+
+ 52
+
+
+ @url_string || urls.map {|x| x.url}.join("\n")
+
+
+ 0
+
+
+
+
+
+
+ 53
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 54
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 55
+
+
+
+
+
+
+
+
+
+
+
+
+ 56
+
+
+ module NameMethods
+
+
+ 1
+
+
+
+
+
+
+ 57
+
+
+ module ClassMethods
+
+
+ 1
+
+
+
+
+
+
+ 58
+
+
+ def normalize_name(name)
+
+
+ 1
+
+
+
+
+
+
+ 59
+
+
+ name.downcase.strip.gsub(/ /, '_')
+
+
+ 0
+
+
+
+
+
+
+ 60
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 61
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 62
+
+
+
+
+
+
+
+
+
+
+
+
+ 63
+
+
+ def self.included(m)
+
+
+ 1
+
+
+
+
+
+
+ 64
+
+
+ m.extend(ClassMethods)
+
+
+ 1
+
+
+
+
+
+
+ 65
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 66
+
+
+
+
+
+
+
+
+
+
+
+
+ 67
+
+
+ def normalize_name
+
+
+ 1
+
+
+
+
+
+
+ 68
+
+
+ self.name = Artist.normalize_name(name)
+
+
+ 0
+
+
+
+
+
+
+ 69
+
+
+ if other_names
+
+
+ 0
+
+
+
+
+
+
+ 70
+
+
+ self.other_names = other_names.split(/,/).map {|x| Artist.normalize_name(x)}.join(" ")
+
+
+ 0
+
+
+
+
+
+
+ 71
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 72
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 73
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 74
+
+
+
+
+
+
+
+
+
+
+
+
+ 75
+
+
+ module GroupMethods
+
+
+ 1
+
+
+
+
+
+
+ 76
+
+
+ def member_names
+
+
+ 1
+
+
+
+
+
+
+ 77
+
+
+ members.map(&:name).join(", ")
+
+
+ 0
+
+
+
+
+
+
+ 78
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 79
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 80
+
+
+
+
+
+
+
+
+
+
+
+
+ 81
+
+
+ module SearchMethods
+
+
+ 1
+
+
+
+
+
+
+ 82
+
+
+ def find_by_name_or_id(params)
+
+
+ 1
+
+
+
+
+
+
+ 83
+
+
+ if params[:name]
+
+
+ 0
+
+
+
+
+
+
+ 84
+
+
+ find_by_name(params[:name])
+
+
+ 0
+
+
+
+
+
+
+ 85
+
+
+ else
+
+
+
+
+
+
+
+
+
+ 86
+
+
+ find(params[:id])
+
+
+ 0
+
+
+
+
+
+
+ 87
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 88
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 89
+
+
+
+
+
+
+
+
+
+
+
+
+ 90
+
+
+ def find_by_any_name(name)
+
+
+ 1
+
+
+
+
+
+
+ 91
+
+
+ build_relation(:name => name).first
+
+
+ 0
+
+
+
+
+
+
+ 92
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 93
+
+
+
+
+
+
+
+
+
+
+
+
+ 94
+
+
+ def build_relation(params)
+
+
+ 1
+
+
+
+
+
+
+ 95
+
+
+ relation = Artist.where("is_active = TRUE")
+
+
+ 0
+
+
+
+
+
+
+ 96
+
+
+
+
+
+
+
+
+
+
+
+
+ 97
+
+
+ case params[:name]
+
+
+ 0
+
+
+
+
+
+
+ 98
+
+
+ when /^http/
+
+
+
+
+
+
+
+
+
+ 99
+
+
+ relation = relation.where("id IN (?)", find_all_by_url(params[:name]).map(&:id))
+
+
+ 0
+
+
+
+
+
+
+ 100
+
+
+
+
+
+
+
+
+
+
+
+
+ 101
+
+
+ when /name:(.+)/
+
+
+
+
+
+
+
+
+
+ 102
+
+
+ escaped_name = Artist.normalize_name($1).to_escaped_for_sql_like
+
+
+ 0
+
+
+
+
+
+
+ 103
+
+
+ relation = relation.where(["name LIKE ? ESCAPE E'\\\\'", escaped_name])
+
+
+ 0
+
+
+
+
+
+
+ 104
+
+
+
+
+
+
+
+
+
+
+
+
+ 105
+
+
+ when /other:(.+)/
+
+
+
+
+
+
+
+
+
+ 106
+
+
+ escaped_name = Artist.normalize_name($1)
+
+
+ 0
+
+
+
+
+
+
+ 107
+
+
+ relation = relation.where(["other_names_index @@ to_tsquery('danbooru', ?)", escaped_name])
+
+
+ 0
+
+
+
+
+
+
+ 108
+
+
+
+
+
+
+
+
+
+
+
+
+ 109
+
+
+ when /group:(.+)/
+
+
+
+
+
+
+
+
+
+ 110
+
+
+ escaped_name = Artist.normalize_name($1).to_escaped_for_sql_like
+
+
+ 0
+
+
+
+
+
+
+ 111
+
+
+ relation = relation.where(["group_name LIKE ? ESCAPE E'\\\\'", escaped_name])
+
+
+ 0
+
+
+
+
+
+
+ 112
+
+
+
+
+
+
+
+
+
+
+
+
+ 113
+
+
+ when /./
+
+
+
+
+
+
+
+
+
+ 114
+
+
+ normalized_name = Artist.normalize_name($1)
+
+
+ 0
+
+
+
+
+
+
+ 115
+
+
+ escaped_name = normalized_name.to_escaped_for_sql_like
+
+
+ 0
+
+
+
+
+
+
+ 116
+
+
+ relation = relation.where(["name LIKE ? ESCAPE E'\\\\' OR other_names_index @@ to_tsquery('danbooru', ?) OR group_name LIKE ? ESCAPE E'\\\\'", escaped_name, normalized_name, escaped_name])
+
+
+ 0
+
+
+
+
+
+
+ 117
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 118
+
+
+
+
+
+
+
+
+
+
+
+
+ 119
+
+
+ if params[:id]
+
+
+ 0
+
+
+
+
+
+
+ 120
+
+
+ relation = relation.where(["id = ?", params[:id]])
+
+
+ 0
+
+
+
+
+
+
+ 121
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 122
+
+
+
+
+
+
+
+
+
+
+
+
+ 123
+
+
+ if params[:order] == "date"
+
+
+ 0
+
+
+
+
+
+
+ 124
+
+
+ relation = relation.order("updated_at DESC")
+
+
+ 0
+
+
+
+
+
+
+ 125
+
+
+ else
+
+
+
+
+
+
+
+
+
+ 126
+
+
+ relation = relation.order("name")
+
+
+ 0
+
+
+
+
+
+
+ 127
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 128
+
+
+
+
+
+
+
+
+
+
+
+
+ 129
+
+
+ relation
+
+
+ 0
+
+
+
+
+
+
+ 130
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 131
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 132
+
+
+
+
+
+
+
+
+
+
+
+
+ 133
+
+
+ module VersionMethods
+
+
+ 1
+
+
+
+
+
+
+ 134
+
+
+ def create_version
+
+
+ 1
+
+
+
+
+
+
+ 135
+
+
+ ArtistVersion.create(
+
+
+ 0
+
+
+
+
+
+
+ 136
+
+
+ :artist_id => id,
+
+
+
+
+
+
+
+
+
+ 137
+
+
+ :name => name,
+
+
+
+
+
+
+
+
+
+ 138
+
+
+ :updater_id => CurrentUser.user.id,
+
+
+
+
+
+
+
+
+
+ 139
+
+
+ :updater_ip_addr => CurrentUser.ip_addr,
+
+
+
+
+
+
+
+
+
+ 140
+
+
+ :url_string => url_string,
+
+
+
+
+
+
+
+
+
+ 141
+
+
+ :is_active => is_active,
+
+
+
+
+
+
+
+
+
+ 142
+
+
+ :other_names => other_names,
+
+
+
+
+
+
+
+
+
+ 143
+
+
+ :group_name => group_name
+
+
+
+
+
+
+
+
+
+ 144
+
+
+ )
+
+
+
+
+
+
+
+
+
+ 145
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 146
+
+
+
+
+
+
+
+
+
+
+
+
+ 147
+
+
+ def revert_to!(version)
+
+
+ 1
+
+
+
+
+
+
+ 148
+
+
+ self.name = version.name
+
+
+ 0
+
+
+
+
+
+
+ 149
+
+
+ self.url_string = version.url_string
+
+
+ 0
+
+
+
+
+
+
+ 150
+
+
+ self.is_active = version.is_active
+
+
+ 0
+
+
+
+
+
+
+ 151
+
+
+ self.other_names = version.other_names
+
+
+ 0
+
+
+
+
+
+
+ 152
+
+
+ self.group_name = version.group_name
+
+
+ 0
+
+
+
+
+
+
+ 153
+
+
+ save
+
+
+ 0
+
+
+
+
+
+
+ 154
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 155
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 156
+
+
+
+
+
+
+
+
+
+
+
+
+ 157
+
+
+ module FactoryMethods
+
+
+ 1
+
+
+
+
+
+
+ 158
+
+
+ def new_with_defaults(params)
+
+
+ 1
+
+
+
+
+
+
+ 159
+
+
+ Artist.new.tap do |artist|
+
+
+ 0
+
+
+
+
+
+
+ 160
+
+
+ if params[:name]
+
+
+ 0
+
+
+
+
+
+
+ 161
+
+
+ artist.name = params[:name]
+
+
+ 0
+
+
+
+
+
+
+ 162
+
+
+ post = Post.find_by_tags("source:http* #{artist.name}").first
+
+
+ 0
+
+
+
+
+
+
+ 163
+
+
+ unless post.nil? || post.source.blank?
+
+
+ 0
+
+
+
+
+
+
+ 164
+
+
+ artist.url_string = post.source
+
+
+ 0
+
+
+
+
+
+
+ 165
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 166
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 167
+
+
+
+
+
+
+
+
+
+
+
+
+ 168
+
+
+ if params[:other_names]
+
+
+ 0
+
+
+
+
+
+
+ 169
+
+
+ artist.other_names = params[:other_names]
+
+
+ 0
+
+
+
+
+
+
+ 170
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 171
+
+
+
+
+
+
+
+
+
+
+
+
+ 172
+
+
+ if params[:urls]
+
+
+ 0
+
+
+
+
+
+
+ 173
+
+
+ artist.url_string = params[:urls]
+
+
+ 0
+
+
+
+
+
+
+ 174
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 175
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 176
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 177
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 178
+
+
+
+
+
+
+
+
+
+
+
+
+ 179
+
+
+ module NoteMethods
+
+
+ 1
+
+
+
+
+
+
+ 180
+
+
+ def notes
+
+
+ 1
+
+
+
+
+
+
+ 181
+
+
+ if wiki_page
+
+
+ 0
+
+
+
+
+
+
+ 182
+
+
+ wiki_page.body
+
+
+ 0
+
+
+
+
+
+
+ 183
+
+
+ else
+
+
+
+
+
+
+
+
+
+ 184
+
+
+ nil
+
+
+
+
+
+
+
+
+
+ 185
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 186
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 187
+
+
+
+
+
+
+
+
+
+
+
+
+ 188
+
+
+ def notes=(msg)
+
+
+ 1
+
+
+
+
+
+
+ 189
+
+
+ if wiki_page.nil?
+
+
+ 0
+
+
+
+
+
+
+ 190
+
+
+ self.wiki_page = WikiPage.new
+
+
+ 0
+
+
+
+
+
+
+ 191
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 192
+
+
+
+
+
+
+
+
+
+
+
+
+ 193
+
+
+ wiki_page.title = name
+
+
+ 0
+
+
+
+
+
+
+ 194
+
+
+ wiki_page.body = msg
+
+
+ 0
+
+
+
+
+
+
+ 195
+
+
+ wiki_page.save
+
+
+ 0
+
+
+
+
+
+
+ 196
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 197
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 198
+
+
+
+
+
+
+
+
+
+
+
+
+ 199
+
+
+ module TagMethods
+
+
+ 1
+
+
+
+
+
+
+ 200
+
+
+ def has_tag_alias?
+
+
+ 1
+
+
+
+
+
+
+ 201
+
+
+ TagAlias.exists?(["antecedent_name = ?", name])
+
+
+ 0
+
+
+
+
+
+
+ 202
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 203
+
+
+
+
+
+
+
+
+
+
+
+
+ 204
+
+
+ def tag_alias_name
+
+
+ 1
+
+
+
+
+
+
+ 205
+
+
+ TagAlias.find_by_antecedent_name(name).consequent_name
+
+
+ 0
+
+
+
+
+
+
+ 206
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 207
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 208
+
+
+
+
+
+
+
+
+
+
+
+
+ 209
+
+
+ include UrlMethods
+
+
+ 1
+
+
+
+
+
+
+ 210
+
+
+ include NameMethods
+
+
+ 1
+
+
+
+
+
+
+ 211
+
+
+ include GroupMethods
+
+
+ 1
+
+
+
+
+
+
+ 212
+
+
+ extend SearchMethods
+
+
+ 1
+
+
+
+
+
+
+ 213
+
+
+ include VersionMethods
+
+
+ 1
+
+
+
+
+
+
+ 214
+
+
+ extend FactoryMethods
+
+
+ 1
+
+
+
+
+
+
+ 215
+
+
+ include NoteMethods
+
+
+ 1
+
+
+
+
+
+
+ 216
+
+
+ include TagMethods
+
+
+ 1
+
+
+
+
+
+
+ 217
+
+
+
+
+
+
+
+
+
+
+
+
+ 218
+
+
+ def initialize_creator
+
+
+ 1
+
+
+
+
+
+
+ 219
+
+
+ self.creator_id = CurrentUser.user.id
+
+
+ 0
+
+
+
+
+
+
+ 220
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 221
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 222
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ./app/models/artist_url.rb
+ 34.78 % covered
+
+
+
+ #
+
+ Hits
+
+
+
+
+
+
+
+ 1
+
+
+ class ArtistUrl < ActiveRecord::Base
+
+
+ 1
+
+
+
+
+
+
+ 2
+
+
+ before_save :normalize
+
+
+ 1
+
+
+
+
+
+
+ 3
+
+
+ validates_presence_of :url
+
+
+ 1
+
+
+
+
+
+
+ 4
+
+
+ belongs_to :artist
+
+
+ 1
+
+
+
+
+
+
+ 5
+
+
+
+
+
+
+
+
+
+
+
+
+ 6
+
+
+ def self.normalize(url)
+
+
+ 1
+
+
+
+
+
+
+ 7
+
+
+ if url.nil?
+
+
+ 0
+
+
+
+
+
+
+ 8
+
+
+ nil
+
+
+
+
+
+
+
+
+
+ 9
+
+
+ else
+
+
+
+
+
+
+
+
+
+ 10
+
+
+ url = url.gsub(/^http:\/\/blog\d+\.fc2/, "http://blog.fc2")
+
+
+ 0
+
+
+
+
+
+
+ 11
+
+
+ url = url.gsub(/^http:\/\/blog-imgs-\d+\.fc2/, "http://blog.fc2")
+
+
+ 0
+
+
+
+
+
+
+ 12
+
+
+ url = url.gsub(/^http:\/\/blog-imgs-\d+-\w+\.fc2/, "http://blog.fc2")
+
+
+ 0
+
+
+
+
+
+
+ 13
+
+
+ url = url.gsub(/^http:\/\/img\d+\.pixiv\.net/, "http://img.pixiv.net")
+
+
+ 0
+
+
+
+
+
+
+ 14
+
+
+ url = url.gsub(/\/+\Z/, "")
+
+
+ 0
+
+
+
+
+
+
+ 15
+
+
+ url + "/"
+
+
+ 0
+
+
+
+
+
+
+ 16
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 17
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 18
+
+
+
+
+
+
+
+
+
+
+
+
+ 19
+
+
+ def self.normalize_for_search(url)
+
+
+ 1
+
+
+
+
+
+
+ 20
+
+
+ if url =~ /\.\w+\Z/ && url =~ /\w\/\w/
+
+
+ 0
+
+
+
+
+
+
+ 21
+
+
+ url = File.dirname(url)
+
+
+ 0
+
+
+
+
+
+
+ 22
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 23
+
+
+
+
+
+
+
+
+
+
+
+
+ 24
+
+
+ url = url.gsub(/^http:\/\/blog\d+\.fc2/, "http://blog*.fc2")
+
+
+ 0
+
+
+
+
+
+
+ 25
+
+
+ url = url.gsub(/^http:\/\/blog-imgs-\d+\.fc2/, "http://blog*.fc2")
+
+
+ 0
+
+
+
+
+
+
+ 26
+
+
+ url = url.gsub(/^http:\/\/blog-imgs-\d+-\w+\.fc2/, "http://blog*.fc2")
+
+
+ 0
+
+
+
+
+
+
+ 27
+
+
+ url = url.gsub(/^http:\/\/img\d+\.pixiv\.net/, "http://img*.pixiv.net")
+
+
+ 0
+
+
+
+
+
+
+ 28
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 29
+
+
+
+
+
+
+
+
+
+
+
+
+ 30
+
+
+ def normalize
+
+
+ 1
+
+
+
+
+
+
+ 31
+
+
+ self.normalized_url = self.class.normalize(url)
+
+
+ 0
+
+
+
+
+
+
+ 32
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 33
+
+
+
+
+
+
+
+
+
+
+
+
+ 34
+
+
+ def to_s
+
+
+ 1
+
+
+
+
+
+
+ 35
+
+
+ url
+
+
+ 0
+
+
+
+
+
+
+ 36
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 37
+
+
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ./app/models/artist_version.rb
+ 80.0 % covered
+
+
+
+ #
+
+ Hits
+
+
+
+
+
+
+
+ 1
+
+
+ class ArtistVersion < ActiveRecord::Base
+
+
+ 1
+
+
+
+
+
+
+ 2
+
+
+ belongs_to :updater
+
+
+ 1
+
+
+
+
+
+
+ 3
+
+
+ belongs_to :artist
+
+
+ 1
+
+
+
+
+
+
+ 4
+
+
+
+
+
+
+
+
+
+
+
+
+ 5
+
+
+ def updater_name
+
+
+ 1
+
+
+
+
+
+
+ 6
+
+
+ User.id_to_name(updater_id).tr("_", " ")
+
+
+ 0
+
+
+
+
+
+
+ 7
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 8
+
+
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ./app/models/ban.rb
+ 34.21 % covered
+
+
+
+ #
+
+ Hits
+
+
+
+
+
+
+
+ 1
+
+
+ class Ban < ActiveRecord::Base
+
+
+ 1
+
+
+
+
+
+
+ 2
+
+
+ after_create :update_feedback
+
+
+ 1
+
+
+
+
+
+
+ 3
+
+
+ belongs_to :user
+
+
+ 1
+
+
+
+
+
+
+ 4
+
+
+ belongs_to :banner, :class_name => "User"
+
+
+ 1
+
+
+
+
+
+
+ 5
+
+
+ attr_accessible :reason, :duration, :user_id
+
+
+ 1
+
+
+
+
+
+
+ 6
+
+
+ validate :user_is_inferior
+
+
+ 1
+
+
+
+
+
+
+ 7
+
+
+
+
+
+
+
+
+
+
+
+
+ 8
+
+
+ def self.is_banned?(user)
+
+
+ 1
+
+
+
+
+
+
+ 9
+
+
+ exists?(["user_id = ? AND expires_at > ?", user.id, Time.now])
+
+
+ 0
+
+
+
+
+
+
+ 10
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 11
+
+
+
+
+
+
+
+
+
+
+
+
+ 12
+
+
+ def user_is_inferior
+
+
+ 1
+
+
+
+
+
+
+ 13
+
+
+ if user
+
+
+ 0
+
+
+
+
+
+
+ 14
+
+
+ if user.is_admin?
+
+
+ 0
+
+
+
+
+
+
+ 15
+
+
+ errors[:base] << "You can never ban an admin."
+
+
+ 0
+
+
+
+
+
+
+ 16
+
+
+ false
+
+
+ 0
+
+
+
+
+
+
+ 17
+
+
+ elsif user.is_moderator? && banner.is_admin?
+
+
+ 0
+
+
+
+
+
+
+ 18
+
+
+ true
+
+
+ 0
+
+
+
+
+
+
+ 19
+
+
+ elsif user.is_moderator?
+
+
+ 0
+
+
+
+
+
+
+ 20
+
+
+ errors[:base] << "Only admins can ban moderators."
+
+
+ 0
+
+
+
+
+
+
+ 21
+
+
+ false
+
+
+ 0
+
+
+
+
+
+
+ 22
+
+
+ elsif banner.is_admin? || banner.is_moderator?
+
+
+ 0
+
+
+
+
+
+
+ 23
+
+
+ true
+
+
+ 0
+
+
+
+
+
+
+ 24
+
+
+ else
+
+
+
+
+
+
+
+
+
+ 25
+
+
+ errors[:base] << "No one else can ban."
+
+
+ 0
+
+
+
+
+
+
+ 26
+
+
+ false
+
+
+ 0
+
+
+
+
+
+
+ 27
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 28
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 29
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 30
+
+
+
+
+
+
+
+
+
+
+
+
+ 31
+
+
+ def update_feedback
+
+
+ 1
+
+
+
+
+
+
+ 32
+
+
+ if user
+
+
+ 0
+
+
+
+
+
+
+ 33
+
+
+ feedback = user.feedback.build
+
+
+ 0
+
+
+
+
+
+
+ 34
+
+
+ feedback.is_positive = false
+
+
+ 0
+
+
+
+
+
+
+ 35
+
+
+ feedback.body = "Banned: #{reason}"
+
+
+ 0
+
+
+
+
+
+
+ 36
+
+
+ feedback.creator_id = banner_id
+
+
+ 0
+
+
+
+
+
+
+ 37
+
+
+ feedback.save
+
+
+ 0
+
+
+
+
+
+
+ 38
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 39
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 40
+
+
+
+
+
+
+
+
+
+
+
+
+ 41
+
+
+ def user_name
+
+
+ 1
+
+
+
+
+
+
+ 42
+
+
+ user ? user.name : nil
+
+
+ 0
+
+
+
+
+
+
+ 43
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 44
+
+
+
+
+
+
+
+
+
+
+
+
+ 45
+
+
+ def user_name=(username)
+
+
+ 1
+
+
+
+
+
+
+ 46
+
+
+ self.user_id = User.name_to_id(username)
+
+
+ 0
+
+
+
+
+
+
+ 47
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 48
+
+
+
+
+
+
+
+
+
+
+
+
+ 49
+
+
+ def duration=(dur)
+
+
+ 1
+
+
+
+
+
+
+ 50
+
+
+ self.expires_at = dur.to_i.days.from_now
+
+
+ 0
+
+
+
+
+
+
+ 51
+
+
+ @duration = dur
+
+
+ 0
+
+
+
+
+
+
+ 52
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 53
+
+
+
+
+
+
+
+
+
+
+
+
+ 54
+
+
+ def duration
+
+
+ 1
+
+
+
+
+
+
+ 55
+
+
+ @duration
+
+
+ 0
+
+
+
+
+
+
+ 56
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 57
+
+
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ./app/models/comment.rb
+ 54.29 % covered
+
+
+
+ #
+
+ Hits
+
+
+
+
+
+
+
+ 1
+
+
+ class Comment < ActiveRecord::Base
+
+
+ 1
+
+
+
+
+
+
+ 2
+
+
+ validate :validate_creator_is_not_limited
+
+
+ 1
+
+
+
+
+
+
+ 3
+
+
+ validates_format_of :body, :with => /\S/, :message => 'has no content'
+
+
+ 1
+
+
+
+
+
+
+ 4
+
+
+ belongs_to :post
+
+
+ 1
+
+
+
+
+
+
+ 5
+
+
+ belongs_to :creator, :class_name => "User"
+
+
+ 1
+
+
+
+
+
+
+ 6
+
+
+ has_many :votes, :class_name => "CommentVote", :dependent => :destroy
+
+
+ 1
+
+
+
+
+
+
+ 7
+
+
+ before_validation :initialize_creator, :on => :create
+
+
+ 1
+
+
+
+
+
+
+ 8
+
+
+ after_save :update_last_commented_at
+
+
+ 1
+
+
+
+
+
+
+ 9
+
+
+ attr_accessible :body
+
+
+ 1
+
+
+
+
+
+
+ 10
+
+
+ attr_accessor :do_not_bump_post
+
+
+ 1
+
+
+
+
+
+
+ 11
+
+
+
+
+
+
+
+
+
+
+
+
+ 12
+
+
+ scope :recent, :order => "comments.id desc", :limit => 6
+
+
+ 1
+
+
+
+
+
+
+ 13
+
+
+ scope :search_body, lambda {|query| where("body_index @@ plainto_tsquery(?)", query).order("comments.id DESC")}
+
+
+ 1
+
+
+
+
+
+
+ 14
+
+
+ scope :hidden, lambda {|user| where("score < ?", user.comment_threshold)}
+
+
+ 1
+
+
+
+
+
+
+ 15
+
+
+
+
+
+
+
+
+
+
+
+
+ 16
+
+
+ def initialize_creator
+
+
+ 1
+
+
+
+
+
+
+ 17
+
+
+ self.creator_id = CurrentUser.user.id
+
+
+ 0
+
+
+
+
+
+
+ 18
+
+
+ self.ip_addr = CurrentUser.ip_addr
+
+
+ 0
+
+
+
+
+
+
+ 19
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 20
+
+
+
+
+
+
+
+
+
+
+
+
+ 21
+
+
+ def creator_name
+
+
+ 1
+
+
+
+
+
+
+ 22
+
+
+ User.id_to_name(creator_id)
+
+
+ 0
+
+
+
+
+
+
+ 23
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 24
+
+
+
+
+
+
+
+
+
+
+
+
+ 25
+
+
+ def validate_creator_is_not_limited
+
+
+ 1
+
+
+
+
+
+
+ 26
+
+
+ creator.is_privileged? || Comment.where("creator_id = ? AND created_at >= ?", creator_id, 1.hour.ago).count < 5
+
+
+ 0
+
+
+
+
+
+
+ 27
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 28
+
+
+
+
+
+
+
+
+
+
+
+
+ 29
+
+
+ def update_last_commented_at
+
+
+ 1
+
+
+
+
+
+
+ 30
+
+
+ if Comment.where(["post_id = ?", post_id]).count <= Danbooru.config.comment_threshold && !do_not_bump_post
+
+
+ 0
+
+
+
+
+
+
+ 31
+
+
+ execute_sql("UPDATE posts SET last_commented_at = ? WHERE id = ?", created_at, post_id)
+
+
+ 0
+
+
+
+
+
+
+ 32
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 33
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 34
+
+
+
+
+
+
+
+
+
+
+
+
+ 35
+
+
+ def vote!(score)
+
+
+ 1
+
+
+
+
+
+
+ 36
+
+
+ if !CurrentUser.user.can_comment_vote?
+
+
+ 0
+
+
+
+
+
+
+ 37
+
+
+ raise CommentVote::Error.new("You can only vote ten times an hour on comments")
+
+
+ 0
+
+
+
+
+
+
+ 38
+
+
+
+
+
+
+
+
+
+
+
+
+ 39
+
+
+ elsif score == "down" && creator.is_janitor?
+
+
+ 0
+
+
+
+
+
+
+ 40
+
+
+ raise CommentVote::Error.new("You cannot downvote janitor/moderator/admin comments")
+
+
+ 0
+
+
+
+
+
+
+ 41
+
+
+
+
+
+
+
+
+
+
+
+
+ 42
+
+
+ elsif votes.find_by_user_id(CurrentUser.user.id).nil?
+
+
+ 0
+
+
+
+
+
+
+ 43
+
+
+ if score == "up"
+
+
+ 0
+
+
+
+
+
+
+ 44
+
+
+ increment!(:score)
+
+
+ 0
+
+
+
+
+
+
+ 45
+
+
+ elsif score == "down"
+
+
+
+
+
+
+
+
+
+ 46
+
+
+ decrement!(:score)
+
+
+ 0
+
+
+
+
+
+
+ 47
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 48
+
+
+
+
+
+
+
+
+
+
+
+
+ 49
+
+
+ votes.create
+
+
+ 0
+
+
+
+
+
+
+ 50
+
+
+
+
+
+
+
+
+
+
+
+
+ 51
+
+
+ else
+
+
+
+
+
+
+
+
+
+ 52
+
+
+ raise CommentVote::Error.new("You have already voted for this comment")
+
+
+ 0
+
+
+
+
+
+
+ 53
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 54
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 55
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 56
+
+
+
+
+
+
+
+
+
+
+
+
+ 57
+
+
+ Comment.connection.extend(PostgresExtensions)
+
+
+ 1
+
+
+
+
+
+
+
+
+
+
+
+
+ ./app/models/comment_vote.rb
+ 80.0 % covered
+
+
+
+ #
+
+ Hits
+
+
+
+
+
+
+
+ 1
+
+
+ class CommentVote < ActiveRecord::Base
+
+
+ 1
+
+
+
+
+
+
+ 2
+
+
+ class Error < Exception ; end
+
+
+ 1
+
+
+
+
+
+
+ 3
+
+
+
+
+
+
+
+
+
+
+
+
+ 4
+
+
+ belongs_to :comment
+
+
+ 1
+
+
+
+
+
+
+ 5
+
+
+ belongs_to :user
+
+
+ 1
+
+
+
+
+
+
+ 6
+
+
+ before_validation :initialize_user, :on => :create
+
+
+ 1
+
+
+
+
+
+
+ 7
+
+
+ validates_presence_of :user_id, :comment_id
+
+
+ 1
+
+
+
+
+
+
+ 8
+
+
+
+
+
+
+
+
+
+
+
+
+ 9
+
+
+ def self.prune!
+
+
+ 1
+
+
+
+
+
+
+ 10
+
+
+ destroy_all(["created_at < ?", 14.days.ago])
+
+
+ 0
+
+
+
+
+
+
+ 11
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 12
+
+
+
+
+
+
+
+
+
+
+
+
+ 13
+
+
+ def initialize_user
+
+
+ 1
+
+
+
+
+
+
+ 14
+
+
+ self.user_id = CurrentUser.user.id
+
+
+ 0
+
+
+
+
+
+
+ 15
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 16
+
+
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ./app/models/dmail.rb
+ 53.73 % covered
+
+
+
+ #
+
+ Hits
+
+
+
+
+
+
+
+ 1
+
+
+ class Dmail < ActiveRecord::Base
+
+
+ 1
+
+
+
+
+
+
+ 2
+
+
+ validates_presence_of :to_id
+
+
+ 1
+
+
+
+
+
+
+ 3
+
+
+ validates_presence_of :from_id
+
+
+ 1
+
+
+
+
+
+
+ 4
+
+
+ validates_format_of :title, :with => /\S/
+
+
+ 1
+
+
+
+
+
+
+ 5
+
+
+ validates_format_of :body, :with => /\S/
+
+
+ 1
+
+
+
+
+
+
+ 6
+
+
+ before_validation :initialize_from_id, :on => :create
+
+
+ 1
+
+
+
+
+
+
+ 7
+
+
+ belongs_to :owner, :class_name => "User"
+
+
+ 1
+
+
+
+
+
+
+ 8
+
+
+ belongs_to :to, :class_name => "User"
+
+
+ 1
+
+
+
+
+
+
+ 9
+
+
+ belongs_to :from, :class_name => "User"
+
+
+ 1
+
+
+
+
+
+
+ 10
+
+
+ after_create :update_recipient
+
+
+ 1
+
+
+
+
+
+
+ 11
+
+
+ after_create :send_dmail
+
+
+ 1
+
+
+
+
+
+
+ 12
+
+
+ attr_accessible :title, :body, :is_deleted, :to_id, :to
+
+
+ 1
+
+
+
+
+
+
+ 13
+
+
+ scope :for, lambda {|user| where(["owner_id = ?", user])}
+
+
+ 1
+
+
+
+
+
+
+ 14
+
+
+ scope :inbox, where("to_id = owner_id")
+
+
+ 1
+
+
+
+
+
+
+ 15
+
+
+ scope :sent, where("from_id = owner_id")
+
+
+ 1
+
+
+
+
+
+
+ 16
+
+
+ scope :active, where(["is_deleted = ?", false])
+
+
+ 1
+
+
+
+
+
+
+ 17
+
+
+ scope :deleted, where(["is_deleted = ?", true])
+
+
+ 1
+
+
+
+
+
+
+ 18
+
+
+ scope :search_message, lambda {|query| where(["message_index @@ plainto_tsquery(?)", query])}
+
+
+ 1
+
+
+
+
+
+
+ 19
+
+
+
+
+
+
+
+
+
+
+
+
+ 20
+
+
+ module AddressMethods
+
+
+ 1
+
+
+
+
+
+
+ 21
+
+
+ def to_name
+
+
+ 1
+
+
+
+
+
+
+ 22
+
+
+ User.id_to_pretty_name(to_id)
+
+
+ 0
+
+
+
+
+
+
+ 23
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 24
+
+
+
+
+
+
+
+
+
+
+
+
+ 25
+
+
+ def from_name
+
+
+ 1
+
+
+
+
+
+
+ 26
+
+
+ User.id_to_pretty_name(from_id)
+
+
+ 0
+
+
+
+
+
+
+ 27
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 28
+
+
+
+
+
+
+
+
+
+
+
+
+ 29
+
+
+ def to_name=(name)
+
+
+ 1
+
+
+
+
+
+
+ 30
+
+
+ user = User.find_by_name(name)
+
+
+ 0
+
+
+
+
+
+
+ 31
+
+
+ return if user.nil?
+
+
+ 0
+
+
+
+
+
+
+ 32
+
+
+ self.to_id = user.id
+
+
+ 0
+
+
+
+
+
+
+ 33
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 34
+
+
+
+
+
+
+
+
+
+
+
+
+ 35
+
+
+ def initialize_from_id
+
+
+ 1
+
+
+
+
+
+
+ 36
+
+
+ self.from_id = CurrentUser.id
+
+
+ 0
+
+
+
+
+
+
+ 37
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 38
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 39
+
+
+
+
+
+
+
+
+
+
+
+
+ 40
+
+
+ module FactoryMethods
+
+
+ 1
+
+
+
+
+
+
+ 41
+
+
+ extend ActiveSupport::Concern
+
+
+ 1
+
+
+
+
+
+
+ 42
+
+
+
+
+
+
+
+
+
+
+
+
+ 43
+
+
+ module ClassMethods
+
+
+ 1
+
+
+
+
+
+
+ 44
+
+
+ def create_split(params)
+
+
+ 1
+
+
+
+
+
+
+ 45
+
+
+ copy = nil
+
+
+ 0
+
+
+
+
+
+
+ 46
+
+
+
+
+
+
+
+
+
+
+
+
+ 47
+
+
+ Dmail.transaction do
+
+
+ 0
+
+
+
+
+
+
+ 48
+
+
+ copy = Dmail.new(params)
+
+
+ 0
+
+
+
+
+
+
+ 49
+
+
+ copy.owner_id = copy.to_id
+
+
+ 0
+
+
+
+
+
+
+ 50
+
+
+ copy.save!
+
+
+ 0
+
+
+
+
+
+
+ 51
+
+
+
+
+
+
+
+
+
+
+
+
+ 52
+
+
+ copy = Dmail.new(params)
+
+
+ 0
+
+
+
+
+
+
+ 53
+
+
+ copy.owner_id = CurrentUser.id
+
+
+ 0
+
+
+
+
+
+
+ 54
+
+
+ copy.save!
+
+
+ 0
+
+
+
+
+
+
+ 55
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 56
+
+
+
+
+
+
+
+
+
+
+
+
+ 57
+
+
+ copy
+
+
+ 0
+
+
+
+
+
+
+ 58
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 59
+
+
+
+
+
+
+
+
+
+
+
+
+ 60
+
+
+ def new_blank
+
+
+ 1
+
+
+
+
+
+
+ 61
+
+
+ Dmail.new do |dmail|
+
+
+ 0
+
+
+
+
+
+
+ 62
+
+
+ dmail.from_id = CurrentUser.id
+
+
+ 0
+
+
+
+
+
+
+ 63
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 64
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 65
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 66
+
+
+
+
+
+
+
+
+
+
+
+
+ 67
+
+
+ def build_response(options = {})
+
+
+ 1
+
+
+
+
+
+
+ 68
+
+
+ Dmail.new do |dmail|
+
+
+ 0
+
+
+
+
+
+
+ 69
+
+
+ dmail.title = "Re: #{title}"
+
+
+ 0
+
+
+
+
+
+
+ 70
+
+
+ dmail.owner_id = from_id
+
+
+ 0
+
+
+
+
+
+
+ 71
+
+
+ dmail.body = quoted_body
+
+
+ 0
+
+
+
+
+
+
+ 72
+
+
+ dmail.to_id = from_id unless options[:forward]
+
+
+ 0
+
+
+
+
+
+
+ 73
+
+
+ dmail.from_id = to_id
+
+
+ 0
+
+
+
+
+
+
+ 74
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 75
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 76
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 77
+
+
+
+
+
+
+
+
+
+
+
+
+ 78
+
+
+ include AddressMethods
+
+
+ 1
+
+
+
+
+
+
+ 79
+
+
+ include FactoryMethods
+
+
+ 1
+
+
+
+
+
+
+ 80
+
+
+
+
+
+
+
+
+
+
+
+
+ 81
+
+
+ def quoted_body
+
+
+ 1
+
+
+
+
+
+
+ 82
+
+
+ "[quote]#{body}[/quote]"
+
+
+ 0
+
+
+
+
+
+
+ 83
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 84
+
+
+
+
+
+
+
+
+
+
+
+
+ 85
+
+
+ def send_dmail
+
+
+ 1
+
+
+
+
+
+
+ 86
+
+
+ if to.receive_email_notifications? && to.email.include?("@")
+
+
+ 0
+
+
+
+
+
+
+ 87
+
+
+ UserMailer.dmail_notice(self).deliver
+
+
+ 0
+
+
+
+
+
+
+ 88
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 89
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 90
+
+
+
+
+
+
+
+
+
+
+
+
+ 91
+
+
+ def mark_as_read!
+
+
+ 1
+
+
+
+
+
+
+ 92
+
+
+ update_attribute(:is_read, true)
+
+
+ 0
+
+
+
+
+
+
+ 93
+
+
+
+
+
+
+
+
+
+
+
+
+ 94
+
+
+ unless Dmail.exists?(["to_id = ? AND is_read = false", to_id])
+
+
+ 0
+
+
+
+
+
+
+ 95
+
+
+ to.update_attribute(:has_mail, false)
+
+
+ 0
+
+
+
+
+
+
+ 96
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 97
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 98
+
+
+
+
+
+
+
+
+
+
+
+
+ 99
+
+
+ def update_recipient
+
+
+ 1
+
+
+
+
+
+
+ 100
+
+
+ to.update_attribute(:has_mail, true)
+
+
+ 0
+
+
+
+
+
+
+ 101
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 102
+
+
+
+
+
+
+
+
+
+
+
+
+ 103
+
+
+ def visible_to?(user)
+
+
+ 1
+
+
+
+
+
+
+ 104
+
+
+ user.is_moderator? || owner_id == user.id
+
+
+ 0
+
+
+
+
+
+
+ 105
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 106
+
+
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ./app/models/forum_post.rb
+ 77.78 % covered
+
+
+
+ #
+
+ Hits
+
+
+
+
+
+
+
+ 1
+
+
+ class ForumPost < ActiveRecord::Base
+
+
+ 1
+
+
+
+
+
+
+ 2
+
+
+ attr_accessible :body, :topic_id
+
+
+ 1
+
+
+
+
+
+
+ 3
+
+
+ belongs_to :creator, :class_name => "User"
+
+
+ 1
+
+
+
+
+
+
+ 4
+
+
+ belongs_to :topic, :class_name => "ForumTopic"
+
+
+ 1
+
+
+
+
+
+
+ 5
+
+
+ before_validation :initialize_creator, :on => :create
+
+
+ 1
+
+
+
+
+
+
+ 6
+
+
+ before_validation :initialize_updater
+
+
+ 1
+
+
+
+
+
+
+ 7
+
+
+ after_save :update_topic_updated_at
+
+
+ 1
+
+
+
+
+
+
+ 8
+
+
+ validates_presence_of :body, :creator_id
+
+
+ 1
+
+
+
+
+
+
+ 9
+
+
+ scope :body_matches, lambda {|body| where(["text_index @@ plainto_tsquery(?)", body])}
+
+
+ 1
+
+
+
+
+
+
+ 10
+
+
+ search_method :body_matches
+
+
+ 1
+
+
+
+
+
+
+ 11
+
+
+
+
+
+
+
+
+
+
+
+
+ 12
+
+
+ def editable_by?(user)
+
+
+ 1
+
+
+
+
+
+
+ 13
+
+
+ creator_id == user.id || user.is_moderator?
+
+
+ 0
+
+
+
+
+
+
+ 14
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 15
+
+
+
+
+
+
+
+
+
+
+
+
+ 16
+
+
+ def update_topic_updated_at
+
+
+ 1
+
+
+
+
+
+
+ 17
+
+
+ topic.update_attributes(:updater_id => CurrentUser.id)
+
+
+ 0
+
+
+
+
+
+
+ 18
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 19
+
+
+
+
+
+
+
+
+
+
+
+
+ 20
+
+
+ def initialize_creator
+
+
+ 1
+
+
+
+
+
+
+ 21
+
+
+ self.creator_id = CurrentUser.id
+
+
+ 0
+
+
+
+
+
+
+ 22
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 23
+
+
+
+
+
+
+
+
+
+
+
+
+ 24
+
+
+ def initialize_updater
+
+
+ 1
+
+
+
+
+
+
+ 25
+
+
+ self.updater_id = CurrentUser.id
+
+
+ 0
+
+
+
+
+
+
+ 26
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 27
+
+
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ./app/models/forum_topic.rb
+ 83.33 % covered
+
+
+
+ #
+
+ Hits
+
+
+
+
+
+
+
+ 1
+
+
+ class ForumTopic < ActiveRecord::Base
+
+
+ 1
+
+
+
+
+
+
+ 2
+
+
+ attr_accessible :title, :original_post_attributes
+
+
+ 1
+
+
+
+
+
+
+ 3
+
+
+ belongs_to :creator, :class_name => "User"
+
+
+ 1
+
+
+
+
+
+
+ 4
+
+
+ belongs_to :updater, :class_name => "User"
+
+
+ 1
+
+
+
+
+
+
+ 5
+
+
+ has_many :posts, :class_name => "ForumPost", :order => "forum_posts.id asc", :foreign_key => "topic_id", :dependent => :destroy
+
+
+ 1
+
+
+
+
+
+
+ 6
+
+
+ has_one :original_post, :class_name => "ForumPost", :order => "forum_posts.id asc", :foreign_key => "topic_id"
+
+
+ 1
+
+
+
+
+
+
+ 7
+
+
+ before_validation :initialize_creator, :on => :create
+
+
+ 1
+
+
+
+
+
+
+ 8
+
+
+ before_validation :initialize_updater
+
+
+ 1
+
+
+
+
+
+
+ 9
+
+
+ validates_presence_of :title, :creator_id
+
+
+ 1
+
+
+
+
+
+
+ 10
+
+
+ scope :title_matches, lambda {|title| where(["text_index @@ plainto_tsquery(?)", title])}
+
+
+ 1
+
+
+
+
+
+
+ 11
+
+
+ search_methods :title_matches
+
+
+ 1
+
+
+
+
+
+
+ 12
+
+
+ accepts_nested_attributes_for :original_post
+
+
+ 1
+
+
+
+
+
+
+ 13
+
+
+
+
+
+
+
+
+
+
+
+
+ 14
+
+
+ def editable_by?(user)
+
+
+ 1
+
+
+
+
+
+
+ 15
+
+
+ creator_id == user.id || user.is_moderator?
+
+
+ 0
+
+
+
+
+
+
+ 16
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 17
+
+
+
+
+
+
+
+
+
+
+
+
+ 18
+
+
+ def initialize_creator
+
+
+ 1
+
+
+
+
+
+
+ 19
+
+
+ self.creator_id = CurrentUser.id
+
+
+ 0
+
+
+
+
+
+
+ 20
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 21
+
+
+
+
+
+
+
+
+
+
+
+
+ 22
+
+
+ def initialize_updater
+
+
+ 1
+
+
+
+
+
+
+ 23
+
+
+ self.updater_id = CurrentUser.id
+
+
+ 0
+
+
+
+
+
+
+ 24
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 25
+
+
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ./app/models/ip_ban.rb
+ 58.82 % covered
+
+
+
+ #
+
+ Hits
+
+
+
+
+
+
+
+ 1
+
+
+ class IpBan < ActiveRecord::Base
+
+
+ 1
+
+
+
+
+
+
+ 2
+
+
+ belongs_to :creator, :class_name => "User"
+
+
+ 1
+
+
+
+
+
+
+ 3
+
+
+ before_validation :initialize_creator, :on => :create
+
+
+ 1
+
+
+
+
+
+
+ 4
+
+
+ validates_presence_of :reason, :creator
+
+
+ 1
+
+
+
+
+
+
+ 5
+
+
+ validates_uniqueness_of :ip_addr
+
+
+ 1
+
+
+
+
+
+
+ 6
+
+
+
+
+
+
+
+
+
+
+
+
+ 7
+
+
+ def self.is_banned?(ip_addr)
+
+
+ 1
+
+
+
+
+
+
+ 8
+
+
+ exists?(["ip_addr = ?", ip_addr])
+
+
+ 19
+
+
+
+
+
+
+ 9
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 10
+
+
+
+
+
+
+
+
+
+
+
+
+ 11
+
+
+ def self.query(user_ids)
+
+
+ 1
+
+
+
+
+
+
+ 12
+
+
+ comments = count_by_ip_addr("comments", user_ids, "creator_id", "ip_addr")
+
+
+ 0
+
+
+
+
+
+
+ 13
+
+
+ notes = count_by_ip_addr("note_versions", user_ids, "updater_id", "updater_ip_addr")
+
+
+ 0
+
+
+
+
+
+
+ 14
+
+
+ pools = count_by_ip_addr("pool_versions", user_ids, "updater_id", "updater_ip_addr")
+
+
+ 0
+
+
+
+
+
+
+ 15
+
+
+ wiki_pages = count_by_ip_addr("wiki_page_versions", user_ids, "updater_id", "updater_ip_addr")
+
+
+ 0
+
+
+
+
+
+
+ 16
+
+
+
+
+
+
+
+
+
+
+
+
+ 17
+
+
+ return {
+
+
+
+
+
+
+
+
+
+ 18
+
+
+ "comments" => comments,
+
+
+
+
+
+
+
+
+
+ 19
+
+
+ "notes" => notes,
+
+
+
+
+
+
+
+
+
+ 20
+
+
+ "pools" => pools,
+
+
+
+
+
+
+
+
+
+ 21
+
+
+ "wiki_pages" => wiki_pages
+
+
+
+
+
+
+
+
+
+ 22
+
+
+ }
+
+
+ 0
+
+
+
+
+
+
+ 23
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 24
+
+
+
+
+
+
+
+
+
+
+
+
+ 25
+
+
+ def self.count_by_ip_addr(table, user_ids, user_id_field = "user_id", ip_addr_field = "ip_addr")
+
+
+ 1
+
+
+
+
+
+
+ 26
+
+
+ select_all_sql("SELECT #{ip_addr_field}, count(*) FROM #{table} WHERE #{user_id_field} IN (?) GROUP BY #{ip_addr_field} ORDER BY count(*) DESC", user_ids)
+
+
+ 0
+
+
+
+
+
+
+ 27
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 28
+
+
+
+
+
+
+
+
+
+
+
+
+ 29
+
+
+ def initialize_creator
+
+
+ 1
+
+
+
+
+
+
+ 30
+
+
+ self.creator_id = CurrentUser.id
+
+
+ 0
+
+
+
+
+
+
+ 31
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 32
+
+
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ./app/models/janitor_trial.rb
+ 61.11 % covered
+
+
+
+ #
+
+ Hits
+
+
+
+
+
+
+
+ 1
+
+
+ class JanitorTrial < ActiveRecord::Base
+
+
+ 1
+
+
+
+
+
+
+ 2
+
+
+ belongs_to :user
+
+
+ 1
+
+
+
+
+
+
+ 3
+
+
+ after_create :send_dmail
+
+
+ 1
+
+
+
+
+
+
+ 4
+
+
+ after_create :promote_user
+
+
+ 1
+
+
+
+
+
+
+ 5
+
+
+ after_destroy :create_feedback
+
+
+ 1
+
+
+
+
+
+
+ 6
+
+
+ validates_presence_of :user
+
+
+ 1
+
+
+
+
+
+
+ 7
+
+
+
+
+
+
+
+
+
+
+
+
+ 8
+
+
+ def send_dmail
+
+
+ 1
+
+
+
+
+
+
+ 9
+
+
+ body = "You have been selected as a test janitor. You can now approve pending posts and have access to the moderation interface.\n\nOver the next several weeks your approvals will be monitored. If the majority of them are quality uploads, then you will be promoted to full janitor status which grants you the ability to delete and undelete posts, ban users, and revert tag changes from vandals. If you fail the trial period, you will be demoted back to your original level and you'll receive a negative user record indicating you previously attempted and failed a test janitor trial.\n\nThere is a minimum quota of 5 approvals a week to indicate that you are being active. Remember, the goal isn't to approve as much as possible. It's to filter out borderline-quality art.\n\nIf you have any questions please respond to this message."
+
+
+ 0
+
+
+
+
+
+
+ 10
+
+
+
+
+
+
+
+
+
+
+
+
+ 11
+
+
+ Dmail.create_split(:title => "Test Janitor Trial Period", :body => body, :to_id => user_id)
+
+
+ 0
+
+
+
+
+
+
+ 12
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 13
+
+
+
+
+
+
+
+
+
+
+
+
+ 14
+
+
+ def promote_user
+
+
+ 1
+
+
+
+
+
+
+ 15
+
+
+ user.update_attribute(:is_janitor, true)
+
+
+ 0
+
+
+
+
+
+
+ 16
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 17
+
+
+
+
+
+
+
+
+
+
+
+
+ 18
+
+
+ def create_feedback
+
+
+ 1
+
+
+
+
+
+
+ 19
+
+
+ user.feedback.create(
+
+
+ 0
+
+
+
+
+
+
+ 20
+
+
+ :is_positive => false,
+
+
+
+
+
+
+
+
+
+ 21
+
+
+ :body => "Demoted from janitor trial"
+
+
+
+
+
+
+
+
+
+ 22
+
+
+ )
+
+
+
+
+
+
+
+
+
+ 23
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 24
+
+
+
+
+
+
+
+
+
+
+
+
+ 25
+
+
+ def promote!
+
+
+ 1
+
+
+
+
+
+
+ 26
+
+
+ destroy
+
+
+ 0
+
+
+
+
+
+
+ 27
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 28
+
+
+
+
+
+
+
+
+
+
+
+
+ 29
+
+
+ def demote!
+
+
+ 1
+
+
+
+
+
+
+ 30
+
+
+ user.update_attribute(:is_janitor, false)
+
+
+ 0
+
+
+
+
+
+
+ 31
+
+
+ destroy
+
+
+ 0
+
+
+
+
+
+
+ 32
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 33
+
+
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ./app/models/jobs/backup_to_s3.rb
+ 21.43 % covered
+
+
+
+ #
+
+ Hits
+
+
+
+
+
+
+
+ 1
+
+
+ module Jobs
+
+
+ 1
+
+
+
+
+
+
+ 2
+
+
+ class BackupToS3 < Struct.new(:last_id)
+
+
+ 1
+
+
+
+
+
+
+ 3
+
+
+ def perform
+
+
+ 1
+
+
+
+
+
+
+ 4
+
+
+ Post.find(:all, :conditions => ["id > ?", last_id], :limit => 200, :order => "id").each do |post|
+
+
+ 0
+
+
+
+
+
+
+ 5
+
+
+ AWS::S3::Base.establish_connection!(:access_key_id => CONFIG["amazon_s3_access_key_id"], :secret_access_key => CONFIG["amazon_s3_secret_access_key"])
+
+
+ 0
+
+
+
+
+
+
+ 6
+
+
+ if File.exists?(post.file_path)
+
+
+ 0
+
+
+
+
+
+
+ 7
+
+
+ base64_md5 = Base64.encode64(Digest::MD5.digest(File.read(post.file_path)))
+
+
+ 0
+
+
+
+
+
+
+ 8
+
+
+ AWS::S3::S3Object.store(post.file_name, open(post.file_path, "rb"), CONFIG["amazon_s3_bucket_name"], "Content-MD5" => base64_md5)
+
+
+ 0
+
+
+
+
+
+
+ 9
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 10
+
+
+
+
+
+
+
+
+
+
+
+
+ 11
+
+
+ if post.image? && File.exists?(post.preview_path)
+
+
+ 0
+
+
+
+
+
+
+ 12
+
+
+ AWS::S3::S3Object.store("preview/#{post.md5}.jpg", open(post.preview_path, "rb"), CONFIG["amazon_s3_bucket_name"])
+
+
+ 0
+
+
+
+
+
+
+ 13
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 14
+
+
+
+
+
+
+
+
+
+
+
+
+ 15
+
+
+ if File.exists?(post.sample_path)
+
+
+ 0
+
+
+
+
+
+
+ 16
+
+
+ AWS::S3::S3Object.store("sample/" + CONFIG["sample_filename_prefix"] + "#{post.md5}.jpg", open(post.sample_path, "rb"), CONFIG["amazon_s3_bucket_name"])
+
+
+ 0
+
+
+
+
+
+
+ 17
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 18
+
+
+
+
+
+
+
+
+
+
+
+
+ 19
+
+
+ self.last_id = post.id
+
+
+ 0
+
+
+
+
+
+
+ 20
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 21
+
+
+
+
+
+
+
+
+
+
+
+
+ 22
+
+
+ Delayed::Job.enqueue(BackupToS3.new(last_id))
+
+
+ 0
+
+
+
+
+
+
+ 23
+
+
+ rescue Exception => x
+
+
+
+
+
+
+
+
+
+ 24
+
+
+ # probably some network error, retry next time
+
+
+
+
+
+
+
+
+
+ 25
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 26
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 27
+
+
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ./app/models/jobs/calculate_post_count.rb
+ 75.0 % covered
+
+
+
+ #
+
+ Hits
+
+
+
+
+
+
+
+ 1
+
+
+ module Jobs
+
+
+ 1
+
+
+
+
+
+
+ 2
+
+
+ class CalculatePostCount < Struct.new(:tag_name)
+
+
+ 1
+
+
+
+
+
+
+ 3
+
+
+ def perform
+
+
+ 1
+
+
+
+
+
+
+ 4
+
+
+ Tag.recalculate_post_count(tag_name)
+
+
+ 0
+
+
+
+
+
+
+ 5
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 6
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 7
+
+
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ./app/models/jobs/calculate_related_tags.rb
+ 42.86 % covered
+
+
+
+ #
+
+ Hits
+
+
+
+
+
+
+
+ 1
+
+
+ module Jobs
+
+
+ 1
+
+
+
+
+
+
+ 2
+
+
+ class CalculateRelatedTags < Struct.new(:tag_id)
+
+
+ 1
+
+
+
+
+
+
+ 3
+
+
+ def perform
+
+
+ 1
+
+
+
+
+
+
+ 4
+
+
+ tag = Tag.find_by_id(tag_id)
+
+
+ 0
+
+
+
+
+
+
+ 5
+
+
+
+
+
+
+
+
+
+
+
+
+ 6
+
+
+ if tag
+
+
+ 0
+
+
+
+
+
+
+ 7
+
+
+ tag.update_related
+
+
+ 0
+
+
+
+
+
+
+ 8
+
+
+ tag.save
+
+
+ 0
+
+
+
+
+
+
+ 9
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 10
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 11
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 12
+
+
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ./app/models/jobs/calculate_uploaded_tags.rb
+ 37.5 % covered
+
+
+
+ #
+
+ Hits
+
+
+
+
+
+
+
+ 1
+
+
+ module Jobs
+
+
+ 1
+
+
+
+
+
+
+ 2
+
+
+ class CalculateUploadedTags < Struct.new(:user_id)
+
+
+ 1
+
+
+
+
+
+
+ 3
+
+
+ def perform
+
+
+ 1
+
+
+
+
+
+
+ 4
+
+
+ tags = []
+
+
+ 0
+
+
+
+
+
+
+ 5
+
+
+ user = User.find(user_id)
+
+
+ 0
+
+
+
+
+
+
+ 6
+
+
+ CONFIG["tag_types"].values.uniq.each do |tag_type|
+
+
+ 0
+
+
+
+
+
+
+ 7
+
+
+ tags += user.calculate_uploaded_tags(tag_type)
+
+
+ 0
+
+
+
+
+
+
+ 8
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 9
+
+
+ user.update_attribute(:uploaded_tags, tags.join("\n"))
+
+
+ 0
+
+
+
+
+
+
+ 10
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 11
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 12
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 13
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ./app/models/jobs/create_tag_alias.rb
+ 75.0 % covered
+
+
+
+ #
+
+ Hits
+
+
+
+
+
+
+
+ 1
+
+
+ module Jobs
+
+
+ 1
+
+
+
+
+
+
+ 2
+
+
+ class CreateTagAlias < Struct.new(:antecedent_name, :consequent_name, :creator_id, :creator_ip_addr)
+
+
+ 1
+
+
+
+
+
+
+ 3
+
+
+ def execute
+
+
+ 1
+
+
+
+
+
+
+ 4
+
+
+ TagAlias.create(
+
+
+ 0
+
+
+
+
+
+
+ 5
+
+
+ :antecedent_name => antecedent_name,
+
+
+
+
+
+
+
+
+
+ 6
+
+
+ :consequent_name => consequent_name,
+
+
+
+
+
+
+
+
+
+ 7
+
+
+ :creator_id => creator_id,
+
+
+
+
+
+
+
+
+
+ 8
+
+
+ :creator_ip_addr => creator_ip_addr
+
+
+
+
+
+
+
+
+
+ 9
+
+
+ )
+
+
+
+
+
+
+
+
+
+ 10
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 11
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 12
+
+
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ./app/models/jobs/create_tag_implication.rb
+ 75.0 % covered
+
+
+
+ #
+
+ Hits
+
+
+
+
+
+
+
+ 1
+
+
+ module Jobs
+
+
+ 1
+
+
+
+
+
+
+ 2
+
+
+ class CreateTagImplication < Struct.new(:antecedent_name, :consequent_name, :creator_id, :creator_ip_addr)
+
+
+ 1
+
+
+
+
+
+
+ 3
+
+
+ def perform
+
+
+ 1
+
+
+
+
+
+
+ 4
+
+
+ TagImplication.create(
+
+
+ 0
+
+
+
+
+
+
+ 5
+
+
+ :antecedent_name => antecedent_name,
+
+
+
+
+
+
+
+
+
+ 6
+
+
+ :consequent_name => consequent_name,
+
+
+
+
+
+
+
+
+
+ 7
+
+
+ :creator_id => creator_id,
+
+
+
+
+
+
+
+
+
+ 8
+
+
+ :creator_ip_addr => creator_ip_addr
+
+
+
+
+
+
+
+
+
+ 9
+
+
+ )
+
+
+
+
+
+
+
+
+
+ 10
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 11
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 12
+
+
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ./app/models/jobs/fix_pixiv_uploads.rb
+ 42.86 % covered
+
+
+
+ #
+
+ Hits
+
+
+
+
+
+
+
+ 1
+
+
+ module Jobs
+
+
+ 1
+
+
+
+
+
+
+ 2
+
+
+ class FixPixivUploads < Struct.new(:last_post_id)
+
+
+ 1
+
+
+
+
+
+
+ 3
+
+
+ def perform
+
+
+ 1
+
+
+
+
+
+
+ 4
+
+
+ post_id = nil
+
+
+ 0
+
+
+
+
+
+
+ 5
+
+
+
+
+
+
+
+
+
+
+
+
+ 6
+
+
+ Post.find_each(:conditions => ["GREATEST(width, height) IN (150, 600) AND source LIKE ? AND id > ?", "%pixiv%", last_post_id]) do |post|
+
+
+ 0
+
+
+
+
+
+
+ 7
+
+
+ post_id = post.id
+
+
+ 0
+
+
+
+
+
+
+ 8
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 9
+
+
+
+
+
+
+
+
+
+
+
+
+ 10
+
+
+ update_attributes(:data => {:last_post_id => post_id})
+
+
+ 0
+
+
+
+
+
+
+ 11
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 12
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 13
+
+
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ./app/models/jobs/mass_tag_edit.rb
+ 75.0 % covered
+
+
+
+ #
+
+ Hits
+
+
+
+
+
+
+
+ 1
+
+
+ module Jobs
+
+
+ 1
+
+
+
+
+
+
+ 2
+
+
+ class MassTagEdit < Struct.new(:start_tags, :result_tags, :updater_id, :updater_ip_addr)
+
+
+ 1
+
+
+
+
+
+
+ 3
+
+
+ def perform
+
+
+ 1
+
+
+
+
+
+
+ 4
+
+
+ Tag.mass_edit(start_tags, result_tags, updater_id, updater_ip_addr)
+
+
+ 0
+
+
+
+
+
+
+ 5
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 6
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 7
+
+
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ./app/models/jobs/process_tag_subscriptions.rb
+ 50.0 % covered
+
+
+
+ #
+
+ Hits
+
+
+
+
+
+
+
+ 1
+
+
+ module Jobs
+
+
+ 1
+
+
+
+
+
+
+ 2
+
+
+ class ProcessTagSubscriptions < Struct.new(:last_run)
+
+
+ 1
+
+
+
+
+
+
+ 3
+
+
+ def perform
+
+
+ 1
+
+
+
+
+
+
+ 4
+
+
+ if last_run.nil? || last_run < 20.minutes.ago
+
+
+ 0
+
+
+
+
+
+
+ 5
+
+
+ TagSubscription.process_all
+
+
+ 0
+
+
+
+
+
+
+ 6
+
+
+ Delayed::Job.enqueue(ProcessTagSubscriptions.new(Time.now))
+
+
+ 0
+
+
+
+
+
+
+ 7
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 8
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 9
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 10
+
+
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ./app/models/jobs/process_uploads.rb
+ 60.0 % covered
+
+
+
+ #
+
+ Hits
+
+
+
+
+
+
+
+ 1
+
+
+ module Jobs
+
+
+ 1
+
+
+
+
+
+
+ 2
+
+
+ class ProcessUploads
+
+
+ 1
+
+
+
+
+
+
+ 3
+
+
+ def perform
+
+
+ 1
+
+
+
+
+
+
+ 4
+
+
+ Upload.find_each(:conditions => ["status = ?", "pending"]) do |upload|
+
+
+ 0
+
+
+
+
+
+
+ 5
+
+
+ upload.process!
+
+
+ 0
+
+
+
+
+
+
+ 6
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 7
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 8
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 9
+
+
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ./app/models/note.rb
+ 67.65 % covered
+
+
+
+ #
+
+ Hits
+
+
+
+
+
+
+
+ 1
+
+
+ class Note < ActiveRecord::Base
+
+
+ 1
+
+
+
+
+
+
+ 2
+
+
+ attr_accessor :updater_id, :updater_ip_addr
+
+
+ 1
+
+
+
+
+
+
+ 3
+
+
+ belongs_to :post
+
+
+ 1
+
+
+
+
+
+
+ 4
+
+
+ belongs_to :creator, :class_name => "User"
+
+
+ 1
+
+
+
+
+
+
+ 5
+
+
+ belongs_to :updater, :class_name => "User"
+
+
+ 1
+
+
+
+
+
+
+ 6
+
+
+ before_validation :initialize_creator, :on => :create
+
+
+ 1
+
+
+
+
+
+
+ 7
+
+
+ before_validation :initialize_updater
+
+
+ 1
+
+
+
+
+
+
+ 8
+
+
+ before_validation :blank_body
+
+
+ 1
+
+
+
+
+
+
+ 9
+
+
+ has_many :versions, :class_name => "NoteVersion", :order => "note_versions.id ASC"
+
+
+ 1
+
+
+
+
+
+
+ 10
+
+
+ after_save :update_post
+
+
+ 1
+
+
+
+
+
+
+ 11
+
+
+ after_save :create_version
+
+
+ 1
+
+
+
+
+
+
+ 12
+
+
+ validate :post_must_not_be_note_locked
+
+
+ 1
+
+
+
+
+
+
+ 13
+
+
+ validates_presence_of :updater_id, :updater_ip_addr
+
+
+ 1
+
+
+
+
+
+
+ 14
+
+
+ attr_accessible :x, :y, :width, :height, :body, :updater_id, :updater_ip_addr, :is_active
+
+
+ 1
+
+
+
+
+
+
+ 15
+
+
+ scope :active, where("is_active = TRUE")
+
+
+ 1
+
+
+
+
+
+
+ 16
+
+
+ scope :body_matches, lambda {|query| where("text_index @@ plainto_tsquery(?)", query)}
+
+
+ 2
+
+
+
+
+
+
+ 17
+
+
+ search_method :body_matches
+
+
+ 1
+
+
+
+
+
+
+ 18
+
+
+
+
+
+
+
+
+
+
+
+
+ 19
+
+
+ def presenter
+
+
+ 1
+
+
+
+
+
+
+ 20
+
+
+ @presenter ||= NotePresenter.new(self)
+
+
+ 0
+
+
+
+
+
+
+ 21
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 22
+
+
+
+
+
+
+
+
+
+
+
+
+ 23
+
+
+ def initialize_creator
+
+
+ 1
+
+
+
+
+
+
+ 24
+
+
+ self.creator_id = CurrentUser.id
+
+
+ 7
+
+
+
+
+
+
+ 25
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 26
+
+
+
+
+
+
+
+
+
+
+
+
+ 27
+
+
+ def initialize_updater
+
+
+ 1
+
+
+
+
+
+
+ 28
+
+
+ self.updater_id = CurrentUser.id
+
+
+ 10
+
+
+
+
+
+
+ 29
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 30
+
+
+
+
+
+
+
+
+
+
+
+
+ 31
+
+
+ def post_must_not_be_note_locked
+
+
+ 1
+
+
+
+
+
+
+ 32
+
+
+ if is_locked?
+
+
+ 10
+
+
+
+
+
+
+ 33
+
+
+ errors.add :post, "is note locked"
+
+
+ 0
+
+
+
+
+
+
+ 34
+
+
+ return false
+
+
+ 0
+
+
+
+
+
+
+ 35
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 36
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 37
+
+
+
+
+
+
+
+
+
+
+
+
+ 38
+
+
+ def is_locked?
+
+
+ 1
+
+
+
+
+
+
+ 39
+
+
+ Post.exists?(["id = ? AND is_note_locked = ?", post_id, true])
+
+
+ 10
+
+
+
+
+
+
+ 40
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 41
+
+
+
+
+
+
+
+
+
+
+
+
+ 42
+
+
+ def blank_body
+
+
+ 1
+
+
+
+
+
+
+ 43
+
+
+ self.body = "(empty)" if body.blank?
+
+
+ 10
+
+
+
+
+
+
+ 44
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 45
+
+
+
+
+
+
+
+
+
+
+
+
+ 46
+
+
+ def creator_name
+
+
+ 1
+
+
+
+
+
+
+ 47
+
+
+ User.id_to_name(creator_id)
+
+
+ 0
+
+
+
+
+
+
+ 48
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 49
+
+
+
+
+
+
+
+
+
+
+
+
+ 50
+
+
+ def update_post
+
+
+ 1
+
+
+
+
+
+
+ 51
+
+
+ if Note.exists?(["is_active = ? AND post_id = ?", true, post_id])
+
+
+ 8
+
+
+
+
+
+
+ 52
+
+
+ execute_sql("UPDATE posts SET last_noted_at = ? WHERE id = ?", updated_at, post_id)
+
+
+ 8
+
+
+
+
+
+
+ 53
+
+
+ else
+
+
+
+
+
+
+
+
+
+ 54
+
+
+ execute_sql("UPDATE posts SET last_noted_at = NULL WHERE id = ?", post_id)
+
+
+ 0
+
+
+
+
+
+
+ 55
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 56
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 57
+
+
+
+
+
+
+
+
+
+
+
+
+ 58
+
+
+ def create_version
+
+
+ 1
+
+
+
+
+
+
+ 59
+
+
+ versions.create(
+
+
+ 8
+
+
+
+
+
+
+ 60
+
+
+ :updater_id => updater_id,
+
+
+
+
+
+
+
+
+
+ 61
+
+
+ :updater_ip_addr => updater_ip_addr,
+
+
+
+
+
+
+
+
+
+ 62
+
+
+ :x => x,
+
+
+
+
+
+
+
+
+
+ 63
+
+
+ :y => y,
+
+
+
+
+
+
+
+
+
+ 64
+
+
+ :width => width,
+
+
+
+
+
+
+
+
+
+ 65
+
+
+ :height => height,
+
+
+
+
+
+
+
+
+
+ 66
+
+
+ :is_active => is_active,
+
+
+
+
+
+
+
+
+
+ 67
+
+
+ :body => body
+
+
+
+
+
+
+
+
+
+ 68
+
+
+ )
+
+
+
+
+
+
+
+
+
+ 69
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 70
+
+
+
+
+
+
+
+
+
+
+
+
+ 71
+
+
+ def revert_to(version)
+
+
+ 1
+
+
+
+
+
+
+ 72
+
+
+ self.x = version.x
+
+
+ 1
+
+
+
+
+
+
+ 73
+
+
+ self.y = version.y
+
+
+ 1
+
+
+
+
+
+
+ 74
+
+
+ self.body = version.body
+
+
+ 1
+
+
+
+
+
+
+ 75
+
+
+ self.width = version.width
+
+
+ 1
+
+
+
+
+
+
+ 76
+
+
+ self.height = version.height
+
+
+ 1
+
+
+
+
+
+
+ 77
+
+
+ self.is_active = version.is_active
+
+
+ 1
+
+
+
+
+
+
+ 78
+
+
+ self.updater_id = CurrentUser.id
+
+
+ 1
+
+
+
+
+
+
+ 79
+
+
+ self.updater_ip_addr = CurrentUser.ip_addr
+
+
+ 1
+
+
+
+
+
+
+ 80
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 81
+
+
+
+
+
+
+
+
+
+
+
+
+ 82
+
+
+ def revert_to!(version)
+
+
+ 1
+
+
+
+
+
+
+ 83
+
+
+ revert_to(version)
+
+
+ 0
+
+
+
+
+
+
+ 84
+
+
+ save!
+
+
+ 0
+
+
+
+
+
+
+ 85
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 86
+
+
+
+
+
+
+
+
+
+
+
+
+ 87
+
+
+ def self.undo_changes_by_user(user_id)
+
+
+ 1
+
+
+
+
+
+
+ 88
+
+
+ transaction do
+
+
+ 0
+
+
+
+
+
+
+ 89
+
+
+ notes = Note.joins(:versions).where(["note_versions.updater_id = ?", user_id]).select("DISTINCT notes.*").all
+
+
+ 0
+
+
+
+
+
+
+ 90
+
+
+ NoteVersion.destroy_all(["updater_id = ?", user_id])
+
+
+ 0
+
+
+
+
+
+
+ 91
+
+
+ notes.each do |note|
+
+
+ 0
+
+
+
+
+
+
+ 92
+
+
+ first = note.versions.first
+
+
+ 0
+
+
+
+
+
+
+ 93
+
+
+ if first
+
+
+ 0
+
+
+
+
+
+
+ 94
+
+
+ note.revert_to!(first)
+
+
+ 0
+
+
+
+
+
+
+ 95
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 96
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 97
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 98
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 99
+
+
+
+
+
+
+
+
+
+
+
+
+ 100
+
+
+ def self.build_relation(params)
+
+
+ 1
+
+
+
+
+
+
+ 101
+
+
+ relation = where("TRUE")
+
+
+ 0
+
+
+
+
+
+
+ 102
+
+
+
+
+
+
+
+
+
+
+
+
+ 103
+
+
+ if !params[:query].blank?
+
+
+ 0
+
+
+
+
+
+
+ 104
+
+
+ query = params[:query].scan(/\S+/).join(" & ")
+
+
+ 0
+
+
+
+
+
+
+ 105
+
+
+ relation = relation.where(["text_index @@ plainto_tsquery(?)", query])
+
+
+ 0
+
+
+
+
+
+
+ 106
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 107
+
+
+
+
+
+
+
+
+
+
+
+
+ 108
+
+
+ if params[:status] == "Active"
+
+
+ 0
+
+
+
+
+
+
+ 109
+
+
+ relation = relation.where("is_active = TRUE")
+
+
+ 0
+
+
+
+
+
+
+ 110
+
+
+ elsif params[:status] == "Deleted"
+
+
+
+
+
+
+
+
+
+ 111
+
+
+ relation = relation.where("is_active = FALSE")
+
+
+ 0
+
+
+
+
+
+
+ 112
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 113
+
+
+
+
+
+
+
+
+
+
+
+
+ 114
+
+
+ relation
+
+
+ 0
+
+
+
+
+
+
+ 115
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 116
+
+
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ./app/models/note_version.rb
+ 66.67 % covered
+
+
+
+ #
+
+ Hits
+
+
+
+
+
+
+
+ 1
+
+
+ class NoteVersion < ActiveRecord::Base
+
+
+ 1
+
+
+
+
+
+
+ 2
+
+
+ def updater_name
+
+
+ 1
+
+
+
+
+
+
+ 3
+
+
+ User.id_to_name(updater_id)
+
+
+ 0
+
+
+
+
+
+
+ 4
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 5
+
+
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ./app/models/pool.rb
+ 37.7 % covered
+
+
+
+ #
+
+ Hits
+
+
+
+
+
+
+
+ 1
+
+
+ class Pool < ActiveRecord::Base
+
+
+ 1
+
+
+
+
+
+
+ 2
+
+
+ attr_accessor :updater_id, :updater_ip_addr
+
+
+ 1
+
+
+
+
+
+
+ 3
+
+
+ validates_uniqueness_of :name
+
+
+ 1
+
+
+
+
+
+
+ 4
+
+
+ validates_presence_of :name, :updater_id, :updater_ip_addr
+
+
+ 1
+
+
+
+
+
+
+ 5
+
+
+ validates_format_of :name, :with => /\A[^\s;,]+\Z/, :on => :create, :message => "cannot have whitespace, commas, or semicolons"
+
+
+ 1
+
+
+
+
+
+
+ 6
+
+
+ belongs_to :creator, :class_name => "User"
+
+
+ 1
+
+
+
+
+
+
+ 7
+
+
+ belongs_to :updater, :class_name => "User"
+
+
+ 1
+
+
+
+
+
+
+ 8
+
+
+ has_many :versions, :class_name => "PoolVersion", :dependent => :destroy
+
+
+ 1
+
+
+
+
+
+
+ 9
+
+
+ before_save :normalize_name
+
+
+ 1
+
+
+
+
+
+
+ 10
+
+
+ after_save :create_version
+
+
+ 1
+
+
+
+
+
+
+ 11
+
+
+ attr_accessible :name, :description, :post_ids, :is_public, :is_active
+
+
+ 1
+
+
+
+
+
+
+ 12
+
+
+
+
+
+
+
+
+
+
+
+
+ 13
+
+
+ def self.name_to_id(name)
+
+
+ 1
+
+
+
+
+
+
+ 14
+
+
+ select_value_sql("SELECT id FROM pools WHERE name = ?", name.downcase)
+
+
+ 0
+
+
+
+
+
+
+ 15
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 16
+
+
+
+
+
+
+
+
+
+
+
+
+ 17
+
+
+ def self.create_anonymous(creator, creator_ip_addr)
+
+
+ 1
+
+
+
+
+
+
+ 18
+
+
+ Pool.new do |pool|
+
+
+ 0
+
+
+
+
+
+
+ 19
+
+
+ pool.name = "TEMP:#{Time.now.to_f}.#{rand(1_000_000)}"
+
+
+ 0
+
+
+
+
+
+
+ 20
+
+
+ pool.creator = creator
+
+
+ 0
+
+
+
+
+
+
+ 21
+
+
+ pool.updater_id = creator.id
+
+
+ 0
+
+
+
+
+
+
+ 22
+
+
+ pool.updater_ip_addr = creator_ip_addr
+
+
+ 0
+
+
+
+
+
+
+ 23
+
+
+ pool.save
+
+
+ 0
+
+
+
+
+
+
+ 24
+
+
+ pool.name = "anonymous:#{pool.id}"
+
+
+ 0
+
+
+
+
+
+
+ 25
+
+
+ pool.save
+
+
+ 0
+
+
+
+
+
+
+ 26
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 27
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 28
+
+
+
+
+
+
+
+
+
+
+
+
+ 29
+
+
+ def normalize_name
+
+
+ 1
+
+
+
+
+
+
+ 30
+
+
+ self.name = name.downcase
+
+
+ 0
+
+
+
+
+
+
+ 31
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 32
+
+
+
+
+
+
+
+
+
+
+
+
+ 33
+
+
+ def revert_to!(version)
+
+
+ 1
+
+
+
+
+
+
+ 34
+
+
+ self.post_ids = version.post_ids
+
+
+ 0
+
+
+
+
+
+
+ 35
+
+
+ save
+
+
+ 0
+
+
+
+
+
+
+ 36
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 37
+
+
+
+
+
+
+
+
+
+
+
+
+ 38
+
+
+ def add_post!(post)
+
+
+ 1
+
+
+
+
+
+
+ 39
+
+
+ return if post_ids =~ /(?:\A| )#{post.id}(?:\Z| )/
+
+
+ 0
+
+
+
+
+
+
+ 40
+
+
+
+
+
+
+
+
+
+
+
+
+ 41
+
+
+ self.post_ids += " #{post.id}"
+
+
+ 0
+
+
+
+
+
+
+ 42
+
+
+ self.post_ids.strip!
+
+
+ 0
+
+
+
+
+
+
+ 43
+
+
+ save
+
+
+ 0
+
+
+
+
+
+
+ 44
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 45
+
+
+
+
+
+
+
+
+
+
+
+
+ 46
+
+
+ def remove_post!(post)
+
+
+ 1
+
+
+
+
+
+
+ 47
+
+
+ post_ids.gsub!(/(?:\A| )#{post.id}(?:\Z| )/, " ")
+
+
+ 0
+
+
+
+
+
+
+ 48
+
+
+ post_ids.strip!
+
+
+ 0
+
+
+
+
+
+
+ 49
+
+
+ save
+
+
+ 0
+
+
+
+
+
+
+ 50
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 51
+
+
+
+
+
+
+
+
+
+
+
+
+ 52
+
+
+ def posts(options = {})
+
+
+ 1
+
+
+
+
+
+
+ 53
+
+
+ offset = options[:offset] || 0
+
+
+ 0
+
+
+
+
+
+
+ 54
+
+
+ limit = options[:limit] || 20
+
+
+ 0
+
+
+
+
+
+
+ 55
+
+
+ ids = post_id_array[offset, limit]
+
+
+ 0
+
+
+
+
+
+
+ 56
+
+
+ Post.where(["id IN (?)", ids])
+
+
+ 0
+
+
+
+
+
+
+ 57
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 58
+
+
+
+
+
+
+
+
+
+
+
+
+ 59
+
+
+ def post_id_array
+
+
+ 1
+
+
+
+
+
+
+ 60
+
+
+ @post_id_array ||= post_ids.scan(/\d+/).map(&:to_i)
+
+
+ 0
+
+
+
+
+
+
+ 61
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 62
+
+
+
+
+
+
+
+
+
+
+
+
+ 63
+
+
+ def clear_post_id_array
+
+
+ 1
+
+
+
+
+
+
+ 64
+
+
+ @post_id_array = nil
+
+
+ 0
+
+
+
+
+
+
+ 65
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 66
+
+
+
+
+
+
+
+
+
+
+
+
+ 67
+
+
+ def neighbor_posts(post)
+
+
+ 1
+
+
+
+
+
+
+ 68
+
+
+ post_ids =~ /\A#{post.id} (\d+)|(\d+) #{post.id} (\d+)|(\d+) #{post.id}\Z/
+
+
+ 0
+
+
+
+
+
+
+ 69
+
+
+
+
+
+
+
+
+
+
+
+
+ 70
+
+
+ if $2 && $3
+
+
+ 0
+
+
+
+
+
+
+ 71
+
+
+ {:previous => $2.to_i, :next => $3.to_i}
+
+
+ 0
+
+
+
+
+
+
+ 72
+
+
+ elsif $1
+
+
+ 0
+
+
+
+
+
+
+ 73
+
+
+ {:next => $1.to_i}
+
+
+ 0
+
+
+
+
+
+
+ 74
+
+
+ elsif $4
+
+
+ 0
+
+
+
+
+
+
+ 75
+
+
+ {:previous => $4.to_i}
+
+
+ 0
+
+
+
+
+
+
+ 76
+
+
+ else
+
+
+
+
+
+
+
+
+
+ 77
+
+
+ nil
+
+
+
+
+
+
+
+
+
+ 78
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 79
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 80
+
+
+
+
+
+
+
+
+
+
+
+
+ 81
+
+
+ def create_version
+
+
+ 1
+
+
+
+
+
+
+ 82
+
+
+ last_version = versions.last
+
+
+ 0
+
+
+
+
+
+
+ 83
+
+
+
+
+
+
+
+
+
+
+
+
+ 84
+
+
+ if last_version && updater_ip_addr == last_version.updater_ip_addr && updater_id == last_version.updater_id
+
+
+ 0
+
+
+
+
+
+
+ 85
+
+
+ last_version.update_attribute(:post_ids, post_ids)
+
+
+ 0
+
+
+
+
+
+
+ 86
+
+
+ else
+
+
+
+
+
+
+
+
+
+ 87
+
+
+ versions.create(
+
+
+ 0
+
+
+
+
+
+
+ 88
+
+
+ :post_ids => post_ids,
+
+
+
+
+
+
+
+
+
+ 89
+
+
+ :updater_id => updater_id,
+
+
+
+
+
+
+
+
+
+ 90
+
+
+ :updater_ip_addr => updater_ip_addr
+
+
+
+
+
+
+
+
+
+ 91
+
+
+ )
+
+
+
+
+
+
+
+
+
+ 92
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 93
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 94
+
+
+
+
+
+
+
+
+
+
+
+
+ 95
+
+
+ def reload(options = {})
+
+
+ 1
+
+
+
+
+
+
+ 96
+
+
+ super
+
+
+ 0
+
+
+
+
+
+
+ 97
+
+
+ clear_post_id_array
+
+
+ 0
+
+
+
+
+
+
+ 98
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 99
+
+
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ./app/models/pool_version.rb
+ 100.0 % covered
+
+
+
+ #
+
+ Hits
+
+
+
+
+
+
+
+ 1
+
+
+ class PoolVersion < ActiveRecord::Base
+
+
+ 1
+
+
+
+
+
+
+ 2
+
+
+ class Error < Exception ; end
+
+
+ 1
+
+
+
+
+
+
+ 3
+
+
+
+
+
+
+
+
+
+
+
+
+ 4
+
+
+ validates_presence_of :updater_id, :updater_ip_addr
+
+
+ 1
+
+
+
+
+
+
+ 5
+
+
+ belongs_to :pool
+
+
+ 1
+
+
+
+
+
+
+ 6
+
+
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ./app/models/post.rb
+ 51.38 % covered
+
+
+
+ #
+
+ Hits
+
+
+
+
+
+
+
+ 1
+
+
+ class Post < ActiveRecord::Base
+
+
+ 1
+
+
+
+
+
+
+ 2
+
+
+ class ApprovalError < Exception ; end
+
+
+ 1
+
+
+
+
+
+
+ 3
+
+
+
+
+
+
+
+
+
+
+
+
+ 4
+
+
+ attr_accessor :old_tag_string, :old_parent_id
+
+
+ 1
+
+
+
+
+
+
+ 5
+
+
+ after_destroy :delete_files
+
+
+ 1
+
+
+
+
+
+
+ 6
+
+
+ after_save :update_history
+
+
+ 1
+
+
+
+
+
+
+ 7
+
+
+ after_save :update_parent_on_save
+
+
+ 1
+
+
+
+
+
+
+ 8
+
+
+ before_save :merge_old_tags
+
+
+ 1
+
+
+
+
+
+
+ 9
+
+
+ before_save :normalize_tags
+
+
+ 1
+
+
+
+
+
+
+ 10
+
+
+ before_save :create_tags
+
+
+ 1
+
+
+
+
+
+
+ 11
+
+
+ before_save :update_tag_post_counts
+
+
+ 1
+
+
+
+
+
+
+ 12
+
+
+ before_save :set_tag_counts
+
+
+ 1
+
+
+
+
+
+
+ 13
+
+
+ before_validation :initialize_uploader, :on => :create
+
+
+ 1
+
+
+
+
+
+
+ 14
+
+
+ belongs_to :updater, :class_name => "User"
+
+
+ 1
+
+
+
+
+
+
+ 15
+
+
+ belongs_to :approver, :class_name => "User"
+
+
+ 1
+
+
+
+
+
+
+ 16
+
+
+ belongs_to :parent, :class_name => "Post"
+
+
+ 1
+
+
+
+
+
+
+ 17
+
+
+ has_one :unapproval, :dependent => :destroy
+
+
+ 1
+
+
+
+
+
+
+ 18
+
+
+ has_one :upload, :dependent => :destroy
+
+
+ 1
+
+
+
+
+
+
+ 19
+
+
+ has_one :moderation_detail, :class_name => "PostModerationDetail", :dependent => :destroy
+
+
+ 1
+
+
+
+
+
+
+ 20
+
+
+ has_one :history, :class_name => "PostHistory"
+
+
+ 1
+
+
+
+
+
+
+ 21
+
+
+ has_many :votes, :class_name => "PostVote", :dependent => :destroy
+
+
+ 1
+
+
+
+
+
+
+ 22
+
+
+ has_many :notes, :dependent => :destroy
+
+
+ 1
+
+
+
+
+
+
+ 23
+
+
+ has_many :comments
+
+
+ 1
+
+
+
+
+
+
+ 24
+
+
+ has_many :children, :class_name => "Post", :foreign_key => "parent_id", :order => "posts.id"
+
+
+ 1
+
+
+
+
+
+
+ 25
+
+
+ validates_uniqueness_of :md5
+
+
+ 1
+
+
+
+
+
+
+ 26
+
+
+ validates_presence_of :parent, :if => lambda {|rec| !rec.parent_id.nil?}
+
+
+ 7
+
+
+
+
+
+
+ 27
+
+
+ validate :validate_parent_does_not_have_a_parent
+
+
+ 1
+
+
+
+
+
+
+ 28
+
+
+ attr_accessible :source, :rating, :tag_string, :old_tag_string, :last_noted_at
+
+
+ 1
+
+
+
+
+
+
+ 29
+
+
+ scope :visible, lambda {|user| Danbooru.config.can_user_see_post_conditions(user)}
+
+
+ 1
+
+
+
+
+
+
+ 30
+
+
+ scope :commented_before, lambda {|date| where("last_commented_at < ?", date).order("last_commented_at DESC")}
+
+
+ 1
+
+
+
+
+
+
+ 31
+
+
+
+
+
+
+
+
+
+
+
+
+ 32
+
+
+ module FileMethods
+
+
+ 1
+
+
+
+
+
+
+ 33
+
+
+ def delete_files
+
+
+ 1
+
+
+
+
+
+
+ 34
+
+
+ FileUtils.rm_f(file_path)
+
+
+ 0
+
+
+
+
+
+
+ 35
+
+
+ FileUtils.rm_f(medium_file_path)
+
+
+ 0
+
+
+
+
+
+
+ 36
+
+
+ FileUtils.rm_f(large_file_path)
+
+
+ 0
+
+
+
+
+
+
+ 37
+
+
+ FileUtils.rm_f(preview_file_path)
+
+
+ 0
+
+
+
+
+
+
+ 38
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 39
+
+
+
+
+
+
+
+
+
+
+
+
+ 40
+
+
+ def file_path_prefix
+
+
+ 1
+
+
+
+
+
+
+ 41
+
+
+ Rails.env == "test" ? "test." : ""
+
+
+ 0
+
+
+
+
+
+
+ 42
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 43
+
+
+
+
+
+
+
+
+
+
+
+
+ 44
+
+
+ def file_path
+
+
+ 1
+
+
+
+
+
+
+ 45
+
+
+ "#{Rails.root}/public/data/original/#{file_path_prefix}#{md5}.#{file_ext}"
+
+
+ 0
+
+
+
+
+
+
+ 46
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 47
+
+
+
+
+
+
+
+
+
+
+
+
+ 48
+
+
+ def medium_file_path
+
+
+ 1
+
+
+
+
+
+
+ 49
+
+
+ if has_medium?
+
+
+ 0
+
+
+
+
+
+
+ 50
+
+
+ "#{Rails.root}/public/data/medium/#{file_path_prefix}#{md5}.jpg"
+
+
+ 0
+
+
+
+
+
+
+ 51
+
+
+ else
+
+
+
+
+
+
+
+
+
+ 52
+
+
+ file_path
+
+
+ 0
+
+
+
+
+
+
+ 53
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 54
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 55
+
+
+
+
+
+
+
+
+
+
+
+
+ 56
+
+
+ def large_file_path
+
+
+ 1
+
+
+
+
+
+
+ 57
+
+
+ if has_large?
+
+
+ 0
+
+
+
+
+
+
+ 58
+
+
+ "#{Rails.root}/public/data/large/#{file_path_prefix}#{md5}.jpg"
+
+
+ 0
+
+
+
+
+
+
+ 59
+
+
+ else
+
+
+
+
+
+
+
+
+
+ 60
+
+
+ file_path
+
+
+ 0
+
+
+
+
+
+
+ 61
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 62
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 63
+
+
+
+
+
+
+
+
+
+
+
+
+ 64
+
+
+ def preview_file_path
+
+
+ 1
+
+
+
+
+
+
+ 65
+
+
+ "#{Rails.root}/public/data/preview/#{file_path_prefix}#{md5}.jpg"
+
+
+ 0
+
+
+
+
+
+
+ 66
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 67
+
+
+
+
+
+
+
+
+
+
+
+
+ 68
+
+
+ def file_url
+
+
+ 1
+
+
+
+
+
+
+ 69
+
+
+ "/data/original/#{file_path_prefix}#{md5}.#{file_ext}"
+
+
+ 0
+
+
+
+
+
+
+ 70
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 71
+
+
+
+
+
+
+
+
+
+
+
+
+ 72
+
+
+ def medium_file_url
+
+
+ 1
+
+
+
+
+
+
+ 73
+
+
+ "/data/medium/#{file_path_prefix}#{md5}.jpg"
+
+
+ 0
+
+
+
+
+
+
+ 74
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 75
+
+
+
+
+
+
+
+
+
+
+
+
+ 76
+
+
+ def large_file_url
+
+
+ 1
+
+
+
+
+
+
+ 77
+
+
+ "/data/large/#{file_path_prefix}#{md5}.jpg"
+
+
+ 0
+
+
+
+
+
+
+ 78
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 79
+
+
+
+
+
+
+
+
+
+
+
+
+ 80
+
+
+ def preview_file_url
+
+
+ 1
+
+
+
+
+
+
+ 81
+
+
+ "/data/preview/#{file_path_prefix}#{md5}.jpg"
+
+
+ 0
+
+
+
+
+
+
+ 82
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 83
+
+
+
+
+
+
+
+
+
+
+
+
+ 84
+
+
+ def file_url_for(user)
+
+
+ 1
+
+
+
+
+
+
+ 85
+
+
+ case user.default_image_size
+
+
+ 0
+
+
+
+
+
+
+ 86
+
+
+ when "medium"
+
+
+
+
+
+
+
+
+
+ 87
+
+
+ if image_width > Danbooru.config.medium_image_width
+
+
+ 0
+
+
+
+
+
+
+ 88
+
+
+ medium_file_url
+
+
+ 0
+
+
+
+
+
+
+ 89
+
+
+ else
+
+
+
+
+
+
+
+
+
+ 90
+
+
+ file_url
+
+
+ 0
+
+
+
+
+
+
+ 91
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 92
+
+
+
+
+
+
+
+
+
+
+
+
+ 93
+
+
+ when "large"
+
+
+
+
+
+
+
+
+
+ 94
+
+
+ if image_width > Danbooru.config.large_image_width
+
+
+ 0
+
+
+
+
+
+
+ 95
+
+
+ large_file_url
+
+
+ 0
+
+
+
+
+
+
+ 96
+
+
+ else
+
+
+
+
+
+
+
+
+
+ 97
+
+
+ file_url
+
+
+ 0
+
+
+
+
+
+
+ 98
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 99
+
+
+
+
+
+
+
+
+
+
+
+
+ 100
+
+
+ else
+
+
+
+
+
+
+
+
+
+ 101
+
+
+ file_url
+
+
+ 0
+
+
+
+
+
+
+ 102
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 103
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 104
+
+
+
+
+
+
+
+
+
+
+
+
+ 105
+
+
+ def file_path_for(user)
+
+
+ 1
+
+
+
+
+
+
+ 106
+
+
+ case user.default_image_size
+
+
+ 0
+
+
+
+
+
+
+ 107
+
+
+ when "medium"
+
+
+
+
+
+
+
+
+
+ 108
+
+
+ if image_width > Danbooru.config.medium_image_width
+
+
+ 0
+
+
+
+
+
+
+ 109
+
+
+ medium_file_path
+
+
+ 0
+
+
+
+
+
+
+ 110
+
+
+ else
+
+
+
+
+
+
+
+
+
+ 111
+
+
+ file_path
+
+
+ 0
+
+
+
+
+
+
+ 112
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 113
+
+
+
+
+
+
+
+
+
+
+
+
+ 114
+
+
+ when "large"
+
+
+
+
+
+
+
+
+
+ 115
+
+
+ if image_width > Danbooru.config.large_image_width
+
+
+ 0
+
+
+
+
+
+
+ 116
+
+
+ large_file_path
+
+
+ 0
+
+
+
+
+
+
+ 117
+
+
+ else
+
+
+
+
+
+
+
+
+
+ 118
+
+
+ file_path
+
+
+ 0
+
+
+
+
+
+
+ 119
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 120
+
+
+
+
+
+
+
+
+
+
+
+
+ 121
+
+
+ else
+
+
+
+
+
+
+
+
+
+ 122
+
+
+ file_path
+
+
+ 0
+
+
+
+
+
+
+ 123
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 124
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 125
+
+
+
+
+
+
+
+
+
+
+
+
+ 126
+
+
+ def is_image?
+
+
+ 1
+
+
+
+
+
+
+ 127
+
+
+ file_ext =~ /jpg|gif|png/
+
+
+ 0
+
+
+
+
+
+
+ 128
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 129
+
+
+
+
+
+
+
+
+
+
+
+
+ 130
+
+
+ def is_flash?
+
+
+ 1
+
+
+
+
+
+
+ 131
+
+
+ file_ext =~ /swf/
+
+
+ 0
+
+
+
+
+
+
+ 132
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 133
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 134
+
+
+
+
+
+
+
+
+
+
+
+
+ 135
+
+
+ module ImageMethods
+
+
+ 1
+
+
+
+
+
+
+ 136
+
+
+ def has_medium?
+
+
+ 1
+
+
+
+
+
+
+ 137
+
+
+ image_width > Danbooru.config.medium_image_width
+
+
+ 0
+
+
+
+
+
+
+ 138
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 139
+
+
+
+
+
+
+
+
+
+
+
+
+ 140
+
+
+ def has_large?
+
+
+ 1
+
+
+
+
+
+
+ 141
+
+
+ image_width > Danbooru.config.large_image_width
+
+
+ 0
+
+
+
+
+
+
+ 142
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 143
+
+
+
+
+
+
+
+
+
+
+
+
+ 144
+
+
+ def medium_image_width
+
+
+ 1
+
+
+
+
+
+
+ 145
+
+
+ [Danbooru.config.medium_image_width, image_width].min
+
+
+ 0
+
+
+
+
+
+
+ 146
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 147
+
+
+
+
+
+
+
+
+
+
+
+
+ 148
+
+
+ def large_image_width
+
+
+ 1
+
+
+
+
+
+
+ 149
+
+
+ [Danbooru.config.large_image_width, image_width].min
+
+
+ 0
+
+
+
+
+
+
+ 150
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 151
+
+
+
+
+
+
+
+
+
+
+
+
+ 152
+
+
+ def medium_image_height
+
+
+ 1
+
+
+
+
+
+
+ 153
+
+
+ ratio = Danbooru.config.medium_image_width.to_f / image_width.to_f
+
+
+ 0
+
+
+
+
+
+
+ 154
+
+
+ if ratio < 1
+
+
+ 0
+
+
+
+
+
+
+ 155
+
+
+ (image_height * ratio).to_i
+
+
+ 0
+
+
+
+
+
+
+ 156
+
+
+ else
+
+
+
+
+
+
+
+
+
+ 157
+
+
+ image_height
+
+
+ 0
+
+
+
+
+
+
+ 158
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 159
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 160
+
+
+
+
+
+
+
+
+
+
+
+
+ 161
+
+
+ def large_image_height
+
+
+ 1
+
+
+
+
+
+
+ 162
+
+
+ ratio = Danbooru.config.large_image_width.to_f / image_width.to_f
+
+
+ 0
+
+
+
+
+
+
+ 163
+
+
+ if ratio < 1
+
+
+ 0
+
+
+
+
+
+
+ 164
+
+
+ (image_height * ratio).to_i
+
+
+ 0
+
+
+
+
+
+
+ 165
+
+
+ else
+
+
+
+
+
+
+
+
+
+ 166
+
+
+ image_height
+
+
+ 0
+
+
+
+
+
+
+ 167
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 168
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 169
+
+
+
+
+
+
+
+
+
+
+
+
+ 170
+
+
+ def image_width_for(user)
+
+
+ 1
+
+
+
+
+
+
+ 171
+
+
+ case user.default_image_size
+
+
+ 0
+
+
+
+
+
+
+ 172
+
+
+ when "medium"
+
+
+
+
+
+
+
+
+
+ 173
+
+
+ medium_image_width
+
+
+ 0
+
+
+
+
+
+
+ 174
+
+
+
+
+
+
+
+
+
+
+
+
+ 175
+
+
+ when "large"
+
+
+
+
+
+
+
+
+
+ 176
+
+
+ large_image_width
+
+
+ 0
+
+
+
+
+
+
+ 177
+
+
+
+
+
+
+
+
+
+
+
+
+ 178
+
+
+ else
+
+
+
+
+
+
+
+
+
+ 179
+
+
+ image_width
+
+
+ 0
+
+
+
+
+
+
+ 180
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 181
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 182
+
+
+
+
+
+
+
+
+
+
+
+
+ 183
+
+
+ def image_height_for(user)
+
+
+ 1
+
+
+
+
+
+
+ 184
+
+
+ case user.default_image_size
+
+
+ 0
+
+
+
+
+
+
+ 185
+
+
+ when "medium"
+
+
+
+
+
+
+
+
+
+ 186
+
+
+ medium_image_height
+
+
+ 0
+
+
+
+
+
+
+ 187
+
+
+
+
+
+
+
+
+
+
+
+
+ 188
+
+
+ when "large"
+
+
+
+
+
+
+
+
+
+ 189
+
+
+ large_image_height
+
+
+ 0
+
+
+
+
+
+
+ 190
+
+
+
+
+
+
+
+
+
+
+
+
+ 191
+
+
+ else
+
+
+
+
+
+
+
+
+
+ 192
+
+
+ image_height
+
+
+ 0
+
+
+
+
+
+
+ 193
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 194
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 195
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 196
+
+
+
+
+
+
+
+
+
+
+
+
+ 197
+
+
+ module ApprovalMethods
+
+
+ 1
+
+
+
+
+
+
+ 198
+
+
+ def unapprove!(reason)
+
+
+ 1
+
+
+
+
+
+
+ 199
+
+
+ raise Unapproval::Error.new("This post has already been flagged") if is_flagged?
+
+
+ 0
+
+
+
+
+
+
+ 200
+
+
+ raise Unapproval::Error.new("This post has already been unapproved once") unless unapproval.nil?
+
+
+ 0
+
+
+
+
+
+
+ 201
+
+
+
+
+
+
+
+
+
+
+
+
+ 202
+
+
+ unapproval = create_unapproval(
+
+
+ 0
+
+
+
+
+
+
+ 203
+
+
+ :unapprover_id => CurrentUser.user.id,
+
+
+
+
+
+
+
+
+
+ 204
+
+
+ :unapprover_ip_addr => CurrentUser.ip_addr,
+
+
+
+
+
+
+
+
+
+ 205
+
+
+ :reason => reason
+
+
+
+
+
+
+
+
+
+ 206
+
+
+ )
+
+
+
+
+
+
+
+
+
+ 207
+
+
+
+
+
+
+
+
+
+
+
+
+ 208
+
+
+ if unapproval.errors.any?
+
+
+ 0
+
+
+
+
+
+
+ 209
+
+
+ raise Unapproval::Error.new(unapproval.errors.full_messages.join("; "))
+
+
+ 0
+
+
+
+
+
+
+ 210
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 211
+
+
+
+
+
+
+
+
+
+
+
+
+ 212
+
+
+ update_attribute(:is_flagged, true)
+
+
+ 0
+
+
+
+
+
+
+ 213
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 214
+
+
+
+
+
+
+
+
+
+
+
+
+ 215
+
+
+ def approve!
+
+
+ 1
+
+
+
+
+
+
+ 216
+
+
+ raise ApprovalError.new("You have already approved this post previously") if approver_string == "approver:#{CurrentUser.name}"
+
+
+ 0
+
+
+
+
+
+
+ 217
+
+
+
+
+
+
+
+
+
+
+
+
+ 218
+
+
+ self.is_flagged = false
+
+
+ 0
+
+
+
+
+
+
+ 219
+
+
+ self.is_pending = false
+
+
+ 0
+
+
+
+
+
+
+ 220
+
+
+ self.approver_string = "approver:#{CurrentUser.name}"
+
+
+ 0
+
+
+
+
+
+
+ 221
+
+
+ save!
+
+
+ 0
+
+
+
+
+
+
+ 222
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 223
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 224
+
+
+
+
+
+
+
+
+
+
+
+
+ 225
+
+
+ module PresenterMethods
+
+
+ 1
+
+
+
+
+
+
+ 226
+
+
+ def pretty_rating
+
+
+ 1
+
+
+
+
+
+
+ 227
+
+
+ case rating
+
+
+ 0
+
+
+
+
+
+
+ 228
+
+
+ when "q"
+
+
+
+
+
+
+
+
+
+ 229
+
+
+ "Questionable"
+
+
+ 0
+
+
+
+
+
+
+ 230
+
+
+
+
+
+
+
+
+
+
+
+
+ 231
+
+
+ when "e"
+
+
+
+
+
+
+
+
+
+ 232
+
+
+ "Explicit"
+
+
+ 0
+
+
+
+
+
+
+ 233
+
+
+
+
+
+
+
+
+
+
+
+
+ 234
+
+
+ when "s"
+
+
+
+
+
+
+
+
+
+ 235
+
+
+ "Safe"
+
+
+ 0
+
+
+
+
+
+
+ 236
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 237
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 238
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 239
+
+
+
+
+
+
+
+
+
+
+
+
+ 240
+
+
+ module HistoryMethods
+
+
+ 1
+
+
+
+
+
+
+ 241
+
+
+ def revisions
+
+
+ 1
+
+
+
+
+
+
+ 242
+
+
+ if history.nil?
+
+
+ 0
+
+
+
+
+
+
+ 243
+
+
+ update_history
+
+
+ 0
+
+
+
+
+
+
+ 244
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 245
+
+
+
+
+
+
+
+
+
+
+
+
+ 246
+
+
+ history.revisions
+
+
+ 0
+
+
+
+
+
+
+ 247
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 248
+
+
+
+
+
+
+
+
+
+
+
+
+ 249
+
+
+ def update_history
+
+
+ 1
+
+
+
+
+
+
+ 250
+
+
+ if history.nil?
+
+
+ 6
+
+
+
+
+
+
+ 251
+
+
+ create_history
+
+
+ 6
+
+
+
+
+
+
+ 252
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 253
+
+
+
+
+
+
+
+
+
+
+
+
+ 254
+
+
+ history << self
+
+
+ 6
+
+
+
+
+
+
+ 255
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 256
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 257
+
+
+
+
+
+
+
+
+
+
+
+
+ 258
+
+
+ module TagMethods
+
+
+ 1
+
+
+
+
+
+
+ 259
+
+
+ def tag_array
+
+
+ 1
+
+
+
+
+
+
+ 260
+
+
+ @tag_array ||= Tag.scan_tags(tag_string)
+
+
+ 24
+
+
+
+
+
+
+ 261
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 262
+
+
+
+
+
+
+
+
+
+
+
+
+ 263
+
+
+ def tag_array_was
+
+
+ 1
+
+
+
+
+
+
+ 264
+
+
+ @tag_array_was ||= Tag.scan_tags(tag_string_was)
+
+
+ 12
+
+
+
+
+
+
+ 265
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 266
+
+
+
+
+
+
+
+
+
+
+
+
+ 267
+
+
+ def create_tags
+
+
+ 1
+
+
+
+
+
+
+ 268
+
+
+ set_tag_string(tag_array.map {|x| Tag.find_or_create_by_name(x).name}.join(" "))
+
+
+ 18
+
+
+
+
+
+
+ 269
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 270
+
+
+
+
+
+
+
+
+
+
+
+
+ 271
+
+
+ def increment_tag_post_counts
+
+
+ 1
+
+
+
+
+
+
+ 272
+
+
+ execute_sql("UPDATE tags SET post_count = post_count + 1 WHERE name IN (?)", tag_array) if tag_array.any?
+
+
+ 0
+
+
+
+
+
+
+ 273
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 274
+
+
+
+
+
+
+
+
+
+
+
+
+ 275
+
+
+ def decrement_tag_post_counts
+
+
+ 1
+
+
+
+
+
+
+ 276
+
+
+ execute_sql("UPDATE tags SET post_count = post_count - 1 WHERE name IN (?)", tag_array) if tag_array.any?
+
+
+ 0
+
+
+
+
+
+
+ 277
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 278
+
+
+
+
+
+
+
+
+
+
+
+
+ 279
+
+
+ def update_tag_post_counts
+
+
+ 1
+
+
+
+
+
+
+ 280
+
+
+ decrement_tags = tag_array_was - tag_array
+
+
+ 6
+
+
+
+
+
+
+ 281
+
+
+ increment_tags = tag_array - tag_array_was
+
+
+ 6
+
+
+
+
+
+
+ 282
+
+
+ execute_sql("UPDATE tags SET post_count = post_count - 1 WHERE name IN (?)", decrement_tags) if decrement_tags.any?
+
+
+ 6
+
+
+
+
+
+
+ 283
+
+
+ execute_sql("UPDATE tags SET post_count = post_count + 1 WHERE name IN (?)", increment_tags) if increment_tags.any?
+
+
+ 6
+
+
+
+
+
+
+ 284
+
+
+ decrement_tags.each do |tag|
+
+
+ 6
+
+
+
+
+
+
+ 285
+
+
+ expire_cache(tag)
+
+
+ 0
+
+
+
+
+
+
+ 286
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 287
+
+
+ increment_tags.each do |tag|
+
+
+ 6
+
+
+
+
+
+
+ 288
+
+
+ expire_cache(tag)
+
+
+ 12
+
+
+
+
+
+
+ 289
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 290
+
+
+ expire_cache("")
+
+
+ 6
+
+
+
+
+
+
+ 291
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 292
+
+
+
+
+
+
+
+
+
+
+
+
+ 293
+
+
+ def set_tag_counts
+
+
+ 1
+
+
+
+
+
+
+ 294
+
+
+ self.tag_count = 0
+
+
+ 6
+
+
+
+
+
+
+ 295
+
+
+ self.tag_count_general = 0
+
+
+ 6
+
+
+
+
+
+
+ 296
+
+
+ self.tag_count_artist = 0
+
+
+ 6
+
+
+
+
+
+
+ 297
+
+
+ self.tag_count_copyright = 0
+
+
+ 6
+
+
+
+
+
+
+ 298
+
+
+ self.tag_count_character = 0
+
+
+ 6
+
+
+
+
+
+
+ 299
+
+
+
+
+
+
+
+
+
+
+
+
+ 300
+
+
+ categories = Tag.categories_for(tag_array)
+
+
+ 6
+
+
+
+
+
+
+ 301
+
+
+ categories.each_value do |category|
+
+
+ 6
+
+
+
+
+
+
+ 302
+
+
+ self.tag_count += 1
+
+
+ 12
+
+
+
+
+
+
+ 303
+
+
+
+
+
+
+
+
+
+
+
+
+ 304
+
+
+ case category
+
+
+ 12
+
+
+
+
+
+
+ 305
+
+
+ when Tag.categories.general
+
+
+
+
+
+
+
+
+
+ 306
+
+
+ self.tag_count_general += 1
+
+
+ 12
+
+
+
+
+
+
+ 307
+
+
+
+
+
+
+
+
+
+
+
+
+ 308
+
+
+ when Tag.categories.artist
+
+
+
+
+
+
+
+
+
+ 309
+
+
+ self.tag_count_artist += 1
+
+
+ 0
+
+
+
+
+
+
+ 310
+
+
+
+
+
+
+
+
+
+
+
+
+ 311
+
+
+ when Tag.categories.copyright
+
+
+
+
+
+
+
+
+
+ 312
+
+
+ self.tag_count_copyright += 1
+
+
+ 0
+
+
+
+
+
+
+ 313
+
+
+
+
+
+
+
+
+
+
+
+
+ 314
+
+
+ when Tag.categories.character
+
+
+
+
+
+
+
+
+
+ 315
+
+
+ self.tag_count_character += 1
+
+
+ 0
+
+
+
+
+
+
+ 316
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 317
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 318
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 319
+
+
+
+
+
+
+
+
+
+
+
+
+ 320
+
+
+ def merge_old_tags
+
+
+ 1
+
+
+
+
+
+
+ 321
+
+
+ if old_tag_string
+
+
+ 6
+
+
+
+
+
+
+ 322
+
+
+ # If someone else committed changes to this post before we did,
+
+
+
+
+
+
+
+
+
+ 323
+
+
+ # then try to merge the tag changes together.
+
+
+
+
+
+
+
+
+
+ 324
+
+
+ current_tags = tag_array_was()
+
+
+ 0
+
+
+
+
+
+
+ 325
+
+
+ new_tags = tag_array()
+
+
+ 0
+
+
+
+
+
+
+ 326
+
+
+ old_tags = Tag.scan_tags(old_tag_string)
+
+
+ 0
+
+
+
+
+
+
+ 327
+
+
+ set_tag_string(((current_tags + new_tags) - old_tags + (current_tags & new_tags)).uniq.join(" "))
+
+
+ 0
+
+
+
+
+
+
+ 328
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 329
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 330
+
+
+
+
+
+
+
+
+
+
+
+
+ 331
+
+
+ def reset_tag_array_cache
+
+
+ 1
+
+
+
+
+
+
+ 332
+
+
+ @tag_array = nil
+
+
+ 12
+
+
+
+
+
+
+ 333
+
+
+ @tag_array_was = nil
+
+
+ 12
+
+
+
+
+
+
+ 334
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 335
+
+
+
+
+
+
+
+
+
+
+
+
+ 336
+
+
+ def set_tag_string(string)
+
+
+ 1
+
+
+
+
+
+
+ 337
+
+
+ self.tag_string = string
+
+
+ 12
+
+
+
+
+
+
+ 338
+
+
+ reset_tag_array_cache
+
+
+ 12
+
+
+
+
+
+
+ 339
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 340
+
+
+
+
+
+
+
+
+
+
+
+
+ 341
+
+
+ def normalize_tags
+
+
+ 1
+
+
+
+
+
+
+ 342
+
+
+ normalized_tags = Tag.scan_tags(tag_string)
+
+
+ 6
+
+
+
+
+
+
+ 343
+
+
+ normalized_tags = TagAlias.to_aliased(normalized_tags)
+
+
+ 6
+
+
+
+
+
+
+ 344
+
+
+ normalized_tags = TagImplication.with_descendants(normalized_tags)
+
+
+ 6
+
+
+
+
+
+
+ 345
+
+
+ normalized_tags = filter_metatags(normalized_tags)
+
+
+ 6
+
+
+
+
+
+
+ 346
+
+
+ set_tag_string(normalized_tags.uniq.join(" "))
+
+
+ 6
+
+
+
+
+
+
+ 347
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 348
+
+
+
+
+
+
+
+
+
+
+
+
+ 349
+
+
+ def filter_metatags(tags)
+
+
+ 1
+
+
+
+
+
+
+ 350
+
+
+ tags.reject {|tag| tag =~ /\A(?:pool|rating|fav|approver|uploader):/}
+
+
+ 30
+
+
+
+
+
+
+ 351
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 352
+
+
+
+
+
+
+
+
+
+
+
+
+ 353
+
+
+ def has_tag?(tag)
+
+
+ 1
+
+
+
+
+
+
+ 354
+
+
+ tag_string =~ /(?:^| )#{tag}(?:$| )/
+
+
+ 0
+
+
+
+
+
+
+ 355
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 356
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 357
+
+
+
+
+
+
+
+
+
+
+
+
+ 358
+
+
+ module FavoriteMethods
+
+
+ 1
+
+
+
+
+
+
+ 359
+
+
+ def delete_favorites
+
+
+ 1
+
+
+
+
+
+
+ 360
+
+
+ Favorite.destroy_for_post(self)
+
+
+ 0
+
+
+
+
+
+
+ 361
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 362
+
+
+
+
+
+
+
+
+
+
+
+
+ 363
+
+
+ def add_favorite(user)
+
+
+ 1
+
+
+
+
+
+
+ 364
+
+
+ if user.is_a?(ActiveRecord::Base)
+
+
+ 0
+
+
+
+
+
+
+ 365
+
+
+ user_id = user.id
+
+
+ 0
+
+
+
+
+
+
+ 366
+
+
+ else
+
+
+
+
+
+
+
+
+
+ 367
+
+
+ user_id = user
+
+
+ 0
+
+
+
+
+
+
+ 368
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 369
+
+
+
+
+
+
+
+
+
+
+
+
+ 370
+
+
+ return false if fav_string =~ /(?:\A| )fav:#{user_id}(?:\Z| )/
+
+
+ 0
+
+
+
+
+
+
+ 371
+
+
+ self.fav_string += " fav:#{user_id}"
+
+
+ 0
+
+
+
+
+
+
+ 372
+
+
+ self.fav_string.strip!
+
+
+ 0
+
+
+
+
+
+
+ 373
+
+
+
+
+
+
+
+
+
+
+
+
+ 374
+
+
+ # in order to avoid rerunning the callbacks, just update through raw sql
+
+
+
+
+
+
+
+
+
+ 375
+
+
+ execute_sql("UPDATE posts SET fav_string = ? WHERE id = ?", fav_string, id)
+
+
+ 0
+
+
+
+
+
+
+ 376
+
+
+
+
+
+
+
+
+
+
+
+
+ 377
+
+
+ Favorite.create(:user_id => user_id, :post_id => id)
+
+
+ 0
+
+
+
+
+
+
+ 378
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 379
+
+
+
+
+
+
+
+
+
+
+
+
+ 380
+
+
+ def remove_favorite(user)
+
+
+ 1
+
+
+
+
+
+
+ 381
+
+
+ if user.is_a?(ActiveRecord::Base)
+
+
+ 0
+
+
+
+
+
+
+ 382
+
+
+ user_id = user.id
+
+
+ 0
+
+
+
+
+
+
+ 383
+
+
+ else
+
+
+
+
+
+
+
+
+
+ 384
+
+
+ user_id = user
+
+
+ 0
+
+
+
+
+
+
+ 385
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 386
+
+
+
+
+
+
+
+
+
+
+
+
+ 387
+
+
+ self.fav_string.gsub!(/(?:\A| )fav:#{user_id}(?:\Z| )/, " ")
+
+
+ 0
+
+
+
+
+
+
+ 388
+
+
+ self.fav_string.strip!
+
+
+ 0
+
+
+
+
+
+
+ 389
+
+
+
+
+
+
+
+
+
+
+
+
+ 390
+
+
+ # in order to avoid rerunning the callbacks, just update through raw sql
+
+
+
+
+
+
+
+
+
+ 391
+
+
+ execute_sql("UPDATE posts SET fav_string = ? WHERE id = ?", fav_string, id)
+
+
+ 0
+
+
+
+
+
+
+ 392
+
+
+
+
+
+
+
+
+
+
+
+
+ 393
+
+
+ Favorite.destroy(:user_id => user_id, :post_id => id)
+
+
+ 0
+
+
+
+
+
+
+ 394
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 395
+
+
+
+
+
+
+
+
+
+
+
+
+ 396
+
+
+ def favorited_user_ids
+
+
+ 1
+
+
+
+
+
+
+ 397
+
+
+ fav_string.scan(/\d+/)
+
+
+ 0
+
+
+
+
+
+
+ 398
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 399
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 400
+
+
+
+
+
+
+
+
+
+
+
+
+ 401
+
+
+ module SearchMethods
+
+
+ 1
+
+
+
+
+
+
+ 402
+
+
+ class SearchError < Exception ; end
+
+
+ 1
+
+
+
+
+
+
+ 403
+
+
+
+
+
+
+
+
+
+
+
+
+ 404
+
+
+ def add_range_relation(arr, field, relation)
+
+
+ 1
+
+
+
+
+
+
+ 405
+
+
+ case arr[0]
+
+
+ 216
+
+
+
+
+
+
+ 406
+
+
+ when :eq
+
+
+
+
+
+
+
+
+
+ 407
+
+
+ relation.where(["#{field} = ?", arr[1]])
+
+
+ 0
+
+
+
+
+
+
+ 408
+
+
+
+
+
+
+
+
+
+
+
+
+ 409
+
+
+ when :gt
+
+
+
+
+
+
+
+
+
+ 410
+
+
+ relation.where(["#{field} > ?", arr[1]])
+
+
+ 0
+
+
+
+
+
+
+ 411
+
+
+
+
+
+
+
+
+
+
+
+
+ 412
+
+
+ when :gte
+
+
+
+
+
+
+
+
+
+ 413
+
+
+ relation.where(["#{field} >= ?", arr[1]])
+
+
+ 0
+
+
+
+
+
+
+ 414
+
+
+
+
+
+
+
+
+
+
+
+
+ 415
+
+
+ when :lt
+
+
+
+
+
+
+
+
+
+ 416
+
+
+ relation.where(["#{field} < ?", arr[1]])
+
+
+ 0
+
+
+
+
+
+
+ 417
+
+
+
+
+
+
+
+
+
+
+
+
+ 418
+
+
+ when :lte
+
+
+
+
+
+
+
+
+
+ 419
+
+
+ relation.where(["#{field} <= ?", arr[1]])
+
+
+ 0
+
+
+
+
+
+
+ 420
+
+
+
+
+
+
+
+
+
+
+
+
+ 421
+
+
+ when :between
+
+
+
+
+
+
+
+
+
+ 422
+
+
+ relation.where(["#{field} BETWEEN ? AND ?", arr[1], arr[2]])
+
+
+ 0
+
+
+
+
+
+
+ 423
+
+
+
+
+
+
+
+
+
+
+
+
+ 424
+
+
+ else
+
+
+
+
+
+
+
+
+
+ 425
+
+
+ relation
+
+
+ 216
+
+
+
+
+
+
+ 426
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 427
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 428
+
+
+
+
+
+
+
+
+
+
+
+
+ 429
+
+
+ def escape_string_for_tsquery(array)
+
+
+ 1
+
+
+
+
+
+
+ 430
+
+
+ array.map do |token|
+
+
+ 0
+
+
+
+
+
+
+ 431
+
+
+ escaped_token = token.gsub(/\\|'/, '\0\0\0\0').gsub("?", "\\\\77").gsub("%", "\\\\37")
+
+
+ 0
+
+
+
+
+
+
+ 432
+
+
+ "''" + escaped_token + "''"
+
+
+ 0
+
+
+
+
+
+
+ 433
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 434
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 435
+
+
+
+
+
+
+
+
+
+
+
+
+ 436
+
+
+ def add_tag_string_search_relation(tags, relation)
+
+
+ 1
+
+
+
+
+
+
+ 437
+
+
+ tag_query_sql = []
+
+
+ 18
+
+
+
+
+
+
+ 438
+
+
+
+
+
+
+
+
+
+
+
+
+ 439
+
+
+ if tags[:include].any?
+
+
+ 18
+
+
+
+
+
+
+ 440
+
+
+ tag_query_sql << "(" + escape_string_for_tsquery(tags[:include]).join(" | ") + ")"
+
+
+ 0
+
+
+
+
+
+
+ 441
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 442
+
+
+
+
+
+
+
+
+
+
+
+
+ 443
+
+
+ if tags[:related].any?
+
+
+ 18
+
+
+
+
+
+
+ 444
+
+
+ raise SearchError.new("You cannot search for more than #{Danbooru.config.tag_query_limit} tags at a time") if tags[:related].size > Danbooru.config.tag_query_limit
+
+
+ 0
+
+
+
+
+
+
+ 445
+
+
+ tag_query_sql << "(" + escape_string_for_tsquery(tags[:related]).join(" & ") + ")"
+
+
+ 0
+
+
+
+
+
+
+ 446
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 447
+
+
+
+
+
+
+
+
+
+
+
+
+ 448
+
+
+ if tags[:exclude].any?
+
+
+ 18
+
+
+
+
+
+
+ 449
+
+
+ raise SearchError.new("You cannot search for more than #{Danbooru.config.tag_query_limit} tags at a time") if tags[:exclude].size > Danbooru.config.tag_query_limit
+
+
+ 0
+
+
+
+
+
+
+ 450
+
+
+
+
+
+
+
+
+
+
+
+
+ 451
+
+
+ if tags[:related].any? || tags[:include].any?
+
+
+ 0
+
+
+
+
+
+
+ 452
+
+
+ tag_query_sql << "!(" + escape_string_for_tsquery(tags[:exclude]).join(" | ") + ")"
+
+
+ 0
+
+
+
+
+
+
+ 453
+
+
+ else
+
+
+
+
+
+
+
+
+
+ 454
+
+
+ raise SearchError.new("You cannot search for only excluded tags")
+
+
+ 0
+
+
+
+
+
+
+ 455
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 456
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 457
+
+
+
+
+
+
+
+
+
+
+
+
+ 458
+
+
+ if tag_query_sql.any?
+
+
+ 18
+
+
+
+
+
+
+ 459
+
+
+ relation = relation.where("posts.tag_index @@ to_tsquery('danbooru', E'" + tag_query_sql.join(" & ") + "')")
+
+
+ 0
+
+
+
+
+
+
+ 460
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 461
+
+
+
+
+
+
+
+
+
+
+
+
+ 462
+
+
+ relation
+
+
+ 18
+
+
+
+
+
+
+ 463
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 464
+
+
+
+
+
+
+
+
+
+
+
+
+ 465
+
+
+ def add_tag_subscription_relation(subscriptions, relation)
+
+
+ 1
+
+
+
+
+
+
+ 466
+
+
+ subscriptions.each do |subscription|
+
+
+ 0
+
+
+
+
+
+
+ 467
+
+
+ subscription =~ /^(.+?):(.+)$/
+
+
+ 0
+
+
+
+
+
+
+ 468
+
+
+ user_name = $1 || subscription
+
+
+ 0
+
+
+
+
+
+
+ 469
+
+
+ subscription_name = $2
+
+
+ 0
+
+
+
+
+
+
+ 470
+
+
+
+
+
+
+
+
+
+
+
+
+ 471
+
+
+ user = User.find_by_name(user_name)
+
+
+ 0
+
+
+
+
+
+
+ 472
+
+
+
+
+
+
+
+
+
+
+
+
+ 473
+
+
+ if user
+
+
+ 0
+
+
+
+
+
+
+ 474
+
+
+ post_ids = TagSubscription.find_post_ids(user.id, subscription_name)
+
+
+ 0
+
+
+
+
+
+
+ 475
+
+
+ relation = relation.where(["posts.id IN (?)", post_ids])
+
+
+ 0
+
+
+
+
+
+
+ 476
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 477
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 478
+
+
+
+
+
+
+
+
+
+
+
+
+ 479
+
+
+ relation
+
+
+ 0
+
+
+
+
+
+
+ 480
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 481
+
+
+
+
+
+
+
+
+
+
+
+
+ 482
+
+
+ def find_by_tags(q, options = {})
+
+
+ 1
+
+
+
+
+
+
+ 483
+
+
+ unless q.is_a?(Hash)
+
+
+ 18
+
+
+
+
+
+
+ 484
+
+
+ q = Tag.parse_query(q)
+
+
+ 18
+
+
+
+
+
+
+ 485
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 486
+
+
+
+
+
+
+
+
+
+
+
+
+ 487
+
+
+ if q[:status] == "deleted"
+
+
+ 18
+
+
+
+
+
+
+ 488
+
+
+ relation = RemovedPost.where("TRUE")
+
+
+ 0
+
+
+
+
+
+
+ 489
+
+
+ else
+
+
+
+
+
+
+
+
+
+ 490
+
+
+ relation = where("TRUE")
+
+
+ 18
+
+
+
+
+
+
+ 491
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 492
+
+
+
+
+
+
+
+
+
+
+
+
+ 493
+
+
+ relation = add_range_relation(q[:post_id], "posts.id", relation)
+
+
+ 18
+
+
+
+
+
+
+ 494
+
+
+ relation = add_range_relation(q[:mpixels], "posts.width * posts.height / 1000000.0", relation)
+
+
+ 18
+
+
+
+
+
+
+ 495
+
+
+ relation = add_range_relation(q[:width], "posts.image_width", relation)
+
+
+ 18
+
+
+
+
+
+
+ 496
+
+
+ relation = add_range_relation(q[:height], "posts.image_height", relation)
+
+
+ 18
+
+
+
+
+
+
+ 497
+
+
+ relation = add_range_relation(q[:score], "posts.score", relation)
+
+
+ 18
+
+
+
+
+
+
+ 498
+
+
+ relation = add_range_relation(q[:filesize], "posts.file_size", relation)
+
+
+ 18
+
+
+
+
+
+
+ 499
+
+
+ relation = add_range_relation(q[:date], "posts.created_at::date", relation)
+
+
+ 18
+
+
+
+
+
+
+ 500
+
+
+ relation = add_range_relation(q[:general_tag_count], "posts.tag_count_general", relation)
+
+
+ 18
+
+
+
+
+
+
+ 501
+
+
+ relation = add_range_relation(q[:artist_tag_count], "posts.tag_count_artist", relation)
+
+
+ 18
+
+
+
+
+
+
+ 502
+
+
+ relation = add_range_relation(q[:copyright_tag_count], "posts.tag_count_copyright", relation)
+
+
+ 18
+
+
+
+
+
+
+ 503
+
+
+ relation = add_range_relation(q[:character_tag_count], "posts.tag_count_character", relation)
+
+
+ 18
+
+
+
+
+
+
+ 504
+
+
+ relation = add_range_relation(q[:tag_count], "posts.tag_count", relation)
+
+
+ 18
+
+
+
+
+
+
+ 505
+
+
+
+
+
+
+
+
+
+
+
+
+ 506
+
+
+ if options[:before_id]
+
+
+ 18
+
+
+
+
+
+
+ 507
+
+
+ relation = relation.where(["posts.id < ?", options[:before_id]])
+
+
+ 0
+
+
+
+
+
+
+ 508
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 509
+
+
+
+
+
+
+
+
+
+
+
+
+ 510
+
+
+ if q[:md5].any?
+
+
+ 18
+
+
+
+
+
+
+ 511
+
+
+ relation = relation.where(["posts.md5 IN (?)", q[:md5]])
+
+
+ 0
+
+
+
+
+
+
+ 512
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 513
+
+
+
+
+
+
+
+
+
+
+
+
+ 514
+
+
+ if q[:status] == "pending"
+
+
+ 18
+
+
+
+
+
+
+ 515
+
+
+ relation = relation.where("posts.is_pending = TRUE")
+
+
+ 0
+
+
+
+
+
+
+ 516
+
+
+ elsif q[:status] == "flagged"
+
+
+
+
+
+
+
+
+
+ 517
+
+
+ relation = relation.where("posts.is_flagged = TRUE")
+
+
+ 0
+
+
+
+
+
+
+ 518
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 519
+
+
+
+
+
+
+
+
+
+
+
+
+ 520
+
+
+ if q[:source].is_a?(String)
+
+
+ 18
+
+
+
+
+
+
+ 521
+
+
+ relation = relation.where(["posts.source LIKE ? ESCAPE E'\\\\'", q[:source]])
+
+
+ 0
+
+
+
+
+
+
+ 522
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 523
+
+
+
+
+
+
+
+
+
+
+
+
+ 524
+
+
+ if q[:subscriptions].any?
+
+
+ 18
+
+
+
+
+
+
+ 525
+
+
+ relation = add_tag_subscription_relation(q[:subscriptions], relation)
+
+
+ 0
+
+
+
+
+
+
+ 526
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 527
+
+
+
+
+
+
+
+
+
+
+
+
+ 528
+
+
+ relation = add_tag_string_search_relation(q[:tags], relation)
+
+
+ 18
+
+
+
+
+
+
+ 529
+
+
+
+
+
+
+
+
+
+
+
+
+ 530
+
+
+ if q[:rating] == "q"
+
+
+ 18
+
+
+
+
+
+
+ 531
+
+
+ relation = relation.where("posts.rating = 'q'")
+
+
+ 0
+
+
+
+
+
+
+ 532
+
+
+ elsif q[:rating] == "s"
+
+
+
+
+
+
+
+
+
+ 533
+
+
+ relation = relation.where("posts.rating = 's'")
+
+
+ 0
+
+
+
+
+
+
+ 534
+
+
+ elsif q[:rating] == "e"
+
+
+
+
+
+
+
+
+
+ 535
+
+
+ relation = relation.where("posts.rating = 'e'")
+
+
+ 0
+
+
+
+
+
+
+ 536
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 537
+
+
+
+
+
+
+
+
+
+
+
+
+ 538
+
+
+ if q[:rating_negated] == "q"
+
+
+ 18
+
+
+
+
+
+
+ 539
+
+
+ relation = relation.where("posts.rating <> 'q'")
+
+
+ 0
+
+
+
+
+
+
+ 540
+
+
+ elsif q[:rating_negated] == "s"
+
+
+
+
+
+
+
+
+
+ 541
+
+
+ relation = relation.where("posts.rating <> 's'")
+
+
+ 0
+
+
+
+
+
+
+ 542
+
+
+ elsif q[:rating_negated] == "e"
+
+
+
+
+
+
+
+
+
+ 543
+
+
+ relation = relation.where("posts.rating <> 'e'")
+
+
+ 0
+
+
+
+
+
+
+ 544
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 545
+
+
+
+
+
+
+
+
+
+
+
+
+ 546
+
+
+ case q[:order]
+
+
+ 18
+
+
+
+
+
+
+ 547
+
+
+ when "id", "id_asc"
+
+
+
+
+
+
+
+
+
+ 548
+
+
+ relation = relation.order("posts.id")
+
+
+ 0
+
+
+
+
+
+
+ 549
+
+
+
+
+
+
+
+
+
+
+
+
+ 550
+
+
+ when "id_desc"
+
+
+
+
+
+
+
+
+
+ 551
+
+
+ relation = relation.order("posts.id DESC")
+
+
+ 0
+
+
+
+
+
+
+ 552
+
+
+
+
+
+
+
+
+
+
+
+
+ 553
+
+
+ when "score", "score_desc"
+
+
+
+
+
+
+
+
+
+ 554
+
+
+ relation = relation.order("posts.score DESC, posts.id DESC")
+
+
+ 0
+
+
+
+
+
+
+ 555
+
+
+
+
+
+
+
+
+
+
+
+
+ 556
+
+
+ when "score_asc"
+
+
+
+
+
+
+
+
+
+ 557
+
+
+ relation = relation.order("posts.score, posts.id DESC")
+
+
+ 0
+
+
+
+
+
+
+ 558
+
+
+
+
+
+
+
+
+
+
+
+
+ 559
+
+
+ when "mpixels", "mpixels_desc"
+
+
+
+
+
+
+
+
+
+ 560
+
+
+ # Use "w*h/1000000", even though "w*h" would give the same result, so this can use
+
+
+
+
+
+
+
+
+
+ 561
+
+
+ # the posts_mpixels index.
+
+
+
+
+
+
+
+
+
+ 562
+
+
+ relation = relation.order("posts.image_width * posts.image_height / 1000000.0 DESC, posts.id DESC")
+
+
+ 0
+
+
+
+
+
+
+ 563
+
+
+
+
+
+
+
+
+
+
+
+
+ 564
+
+
+ when "mpixels_asc"
+
+
+
+
+
+
+
+
+
+ 565
+
+
+ relation = relation.order("posts.image_width * posts.image_height / 1000000.0, posts.id DESC")
+
+
+ 0
+
+
+
+
+
+
+ 566
+
+
+
+
+
+
+
+
+
+
+
+
+ 567
+
+
+ when "portrait"
+
+
+
+
+
+
+
+
+
+ 568
+
+
+ relation = relation.order("1.0 * posts.image_width / GREATEST(1, posts.image_height), posts.id DESC")
+
+
+ 0
+
+
+
+
+
+
+ 569
+
+
+
+
+
+
+
+
+
+
+
+
+ 570
+
+
+ when "landscape"
+
+
+
+
+
+
+
+
+
+ 571
+
+
+ relation = relation.order("1.0 * posts.image_width / GREATEST(1, posts.image_height) DESC, posts.id DESC")
+
+
+ 0
+
+
+
+
+
+
+ 572
+
+
+
+
+
+
+
+
+
+
+
+
+ 573
+
+
+ when "filesize", "filesize_desc"
+
+
+
+
+
+
+
+
+
+ 574
+
+
+ relation = relation.order("posts.file_size DESC")
+
+
+ 0
+
+
+
+
+
+
+ 575
+
+
+
+
+
+
+
+
+
+
+
+
+ 576
+
+
+ when "filesize_asc"
+
+
+
+
+
+
+
+
+
+ 577
+
+
+ relation = relation.order("posts.file_size")
+
+
+ 0
+
+
+
+
+
+
+ 578
+
+
+
+
+
+
+
+
+
+
+
+
+ 579
+
+
+ else
+
+
+
+
+
+
+
+
+
+ 580
+
+
+ relation = relation.order("posts.id DESC")
+
+
+ 18
+
+
+
+
+
+
+ 581
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 582
+
+
+
+
+
+
+
+
+
+
+
+
+ 583
+
+
+ if options[:limit]
+
+
+ 18
+
+
+
+
+
+
+ 584
+
+
+ relation = relation.limit(options[:limit])
+
+
+ 0
+
+
+
+
+
+
+ 585
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 586
+
+
+
+
+
+
+
+
+
+
+
+
+ 587
+
+
+ if options[:offset]
+
+
+ 18
+
+
+
+
+
+
+ 588
+
+
+ relation = relation.offset(options[:offset])
+
+
+ 0
+
+
+
+
+
+
+ 589
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 590
+
+
+
+
+
+
+
+
+
+
+
+
+ 591
+
+
+ if options[:select]
+
+
+ 18
+
+
+
+
+
+
+ 592
+
+
+ relation = relation.select(options[:select])
+
+
+ 0
+
+
+
+
+
+
+ 593
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 594
+
+
+
+
+
+
+
+
+
+
+
+
+ 595
+
+
+ relation
+
+
+ 18
+
+
+
+
+
+
+ 596
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 597
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 598
+
+
+
+
+
+
+
+
+
+
+
+
+ 599
+
+
+ module UploaderMethods
+
+
+ 1
+
+
+
+
+
+
+ 600
+
+
+ def initialize_uploader
+
+
+ 1
+
+
+
+
+
+
+ 601
+
+
+ self.uploader = CurrentUser.user
+
+
+ 6
+
+
+
+
+
+
+ 602
+
+
+ self.uploader_ip_addr = CurrentUser.ip_addr
+
+
+ 6
+
+
+
+
+
+
+ 603
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 604
+
+
+
+
+
+
+
+
+
+
+
+
+ 605
+
+
+ def uploader_id=(user_id)
+
+
+ 1
+
+
+
+
+
+
+ 606
+
+
+ self.uploader = User.find(user_id)
+
+
+ 0
+
+
+
+
+
+
+ 607
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 608
+
+
+
+
+
+
+
+
+
+
+
+
+ 609
+
+
+ def uploader_id
+
+
+ 1
+
+
+
+
+
+
+ 610
+
+
+ uploader_string[9..-1].to_i
+
+
+ 0
+
+
+
+
+
+
+ 611
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 612
+
+
+
+
+
+
+
+
+
+
+
+
+ 613
+
+
+ def uploader_name
+
+
+ 1
+
+
+
+
+
+
+ 614
+
+
+ User.id_to_name(uploader_id)
+
+
+ 0
+
+
+
+
+
+
+ 615
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 616
+
+
+
+
+
+
+
+
+
+
+
+
+ 617
+
+
+ def uploader
+
+
+ 1
+
+
+
+
+
+
+ 618
+
+
+ User.find(uploader_id)
+
+
+ 0
+
+
+
+
+
+
+ 619
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 620
+
+
+
+
+
+
+
+
+
+
+
+
+ 621
+
+
+ def uploader=(user)
+
+
+ 1
+
+
+
+
+
+
+ 622
+
+
+ self.uploader_string = "uploader:#{user.id}"
+
+
+ 12
+
+
+
+
+
+
+ 623
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 624
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 625
+
+
+
+
+
+
+
+
+
+
+
+
+ 626
+
+
+ module PoolMethods
+
+
+ 1
+
+
+
+
+
+
+ 627
+
+
+ def add_pool(pool)
+
+
+ 1
+
+
+
+
+
+
+ 628
+
+
+ return if pool_string =~ /(?:\A| )pool:#{pool.id}(?:\Z| )/
+
+
+ 0
+
+
+
+
+
+
+ 629
+
+
+ self.pool_string += " pool:#{pool.id}"
+
+
+ 0
+
+
+
+
+
+
+ 630
+
+
+ self.pool_string.strip!
+
+
+ 0
+
+
+
+
+
+
+ 631
+
+
+ execute_sql("UPDATE posts SET pool_string = ? WHERE id = ?", pool_string, id)
+
+
+ 0
+
+
+
+
+
+
+ 632
+
+
+ pool.add_post!(self)
+
+
+ 0
+
+
+
+
+
+
+ 633
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 634
+
+
+
+
+
+
+
+
+
+
+
+
+ 635
+
+
+ def remove_pool(pool)
+
+
+ 1
+
+
+
+
+
+
+ 636
+
+
+ self.pool_string.gsub!(/(?:\A| )pool:#{pool.id}(?:\Z| )/, " ")
+
+
+ 0
+
+
+
+
+
+
+ 637
+
+
+ self.pool_string.strip!
+
+
+ 0
+
+
+
+
+
+
+ 638
+
+
+ execute_sql("UPDATE posts SET pool_string = ? WHERE id = ?", pool_string, id)
+
+
+ 0
+
+
+
+
+
+
+ 639
+
+
+ pool.remove_post!(self)
+
+
+ 0
+
+
+
+
+
+
+ 640
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 641
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 642
+
+
+
+
+
+
+
+
+
+
+
+
+ 643
+
+
+ module VoteMethods
+
+
+ 1
+
+
+
+
+
+
+ 644
+
+
+ def can_be_voted_by?(user)
+
+
+ 1
+
+
+
+
+
+
+ 645
+
+
+ !votes.exists?(["user_id = ?", user.id])
+
+
+ 0
+
+
+
+
+
+
+ 646
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 647
+
+
+
+
+
+
+
+
+
+
+
+
+ 648
+
+
+ def vote!(score)
+
+
+ 1
+
+
+
+
+
+
+ 649
+
+
+ if can_be_voted_by?(CurrentUser.user)
+
+
+ 0
+
+
+
+
+
+
+ 650
+
+
+ if score == "up"
+
+
+ 0
+
+
+
+
+
+
+ 651
+
+
+ increment!(:score)
+
+
+ 0
+
+
+
+
+
+
+ 652
+
+
+ elsif score == "down"
+
+
+
+
+
+
+
+
+
+ 653
+
+
+ decrement!(:score)
+
+
+ 0
+
+
+
+
+
+
+ 654
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 655
+
+
+
+
+
+
+
+
+
+
+
+
+ 656
+
+
+ votes.create(:score => score)
+
+
+ 0
+
+
+
+
+
+
+ 657
+
+
+ else
+
+
+
+
+
+
+
+
+
+ 658
+
+
+ raise PostVote::Error.new("You have already voted for this comment")
+
+
+ 0
+
+
+
+
+
+
+ 659
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 660
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 661
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 662
+
+
+
+
+
+
+
+
+
+
+
+
+ 663
+
+
+ module CountMethods
+
+
+ 1
+
+
+
+
+
+
+ 664
+
+
+ def fast_count(tags = "")
+
+
+ 1
+
+
+
+
+
+
+ 665
+
+
+ tags = tags.to_s
+
+
+ 18
+
+
+
+
+
+
+ 666
+
+
+ count = Cache.get("pfc:#{Cache.sanitize(tags)}")
+
+
+ 18
+
+
+
+
+
+
+ 667
+
+
+ if count.nil?
+
+
+ 18
+
+
+
+
+
+
+ 668
+
+
+ count = Post.find_by_tags("#{tags}").count
+
+
+ 18
+
+
+
+
+
+
+ 669
+
+
+ if count > Danbooru.config.posts_per_page * 10
+
+
+ 18
+
+
+
+
+
+
+ 670
+
+
+ Cache.put("pfc:#{Cache.sanitize(tags)}", count, (count * 4).minutes)
+
+
+ 0
+
+
+
+
+
+
+ 671
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 672
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 673
+
+
+ count
+
+
+ 18
+
+
+
+
+
+
+ 674
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 675
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 676
+
+
+
+
+
+
+
+
+
+
+
+
+ 677
+
+
+ module CacheMethods
+
+
+ 1
+
+
+
+
+
+
+ 678
+
+
+ def expire_cache(tag_name)
+
+
+ 1
+
+
+
+
+
+
+ 679
+
+
+ if Post.fast_count("") < 1000
+
+
+ 18
+
+
+
+
+
+
+ 680
+
+
+ Cache.delete("pfc:")
+
+
+ 18
+
+
+
+
+
+
+ 681
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 682
+
+
+ Cache.delete("pfc:#{Cache.sanitize(tag_name)}")
+
+
+ 18
+
+
+
+
+
+
+ 683
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 684
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 685
+
+
+
+
+
+
+
+
+
+
+
+
+ 686
+
+
+ module ParentMethods
+
+
+ 1
+
+
+
+
+
+
+ 687
+
+
+ # A parent has many children. A child belongs to a parent.
+
+
+
+
+
+
+
+
+
+ 688
+
+
+ # A parent cannot have a parent.
+
+
+
+
+
+
+
+
+
+ 689
+
+
+ #
+
+
+
+
+
+
+
+
+
+ 690
+
+
+ # After deleting a child:
+
+
+
+
+
+
+
+
+
+ 691
+
+
+ # - Move favorites to parent.
+
+
+
+
+
+
+
+
+
+ 692
+
+
+ # - Does the parent have any active children?
+
+
+
+
+
+
+
+
+
+ 693
+
+
+ # - Yes: Done.
+
+
+
+
+
+
+
+
+
+ 694
+
+
+ # - No: Update parent's has_children flag to false.
+
+
+
+
+
+
+
+
+
+ 695
+
+
+ #
+
+
+
+
+
+
+
+
+
+ 696
+
+
+ # After deleting a parent:
+
+
+
+
+
+
+
+
+
+ 697
+
+
+ # - Move favorites to the first child.
+
+
+
+
+
+
+
+
+
+ 698
+
+
+ # - Reparent all active children to the first active child.
+
+
+
+
+
+
+
+
+
+ 699
+
+
+
+
+
+
+
+
+
+
+
+
+ 700
+
+
+ module ClassMethods
+
+
+ 1
+
+
+
+
+
+
+ 701
+
+
+ def update_has_children_flag_for(post_id)
+
+
+ 1
+
+
+
+
+
+
+ 702
+
+
+ has_children = Post.exists?(["parent_id = ?", post_id])
+
+
+ 0
+
+
+
+
+
+
+ 703
+
+
+ execute_sql("UPDATE posts SET has_children = ? WHERE id = ?", has_children, post_id)
+
+
+ 0
+
+
+
+
+
+
+ 704
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 705
+
+
+
+
+
+
+
+
+
+
+
+
+ 706
+
+
+ def recalculate_has_children_for_all_posts
+
+
+ 1
+
+
+
+
+
+
+ 707
+
+
+ transaction do
+
+
+ 0
+
+
+
+
+
+
+ 708
+
+
+ execute_sql("UPDATE posts SET has_children = false WHERE has_children = true")
+
+
+ 0
+
+
+
+
+
+
+ 709
+
+
+ execute_sql("UPDATE posts SET has_children = true WHERE id IN (SELECT p.parent_id FROM posts p WHERE p.parent_id IS NOT NULL)")
+
+
+ 0
+
+
+
+
+
+
+ 710
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 711
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 712
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 713
+
+
+
+
+
+
+
+
+
+
+
+
+ 714
+
+
+ def self.included(m)
+
+
+ 1
+
+
+
+
+
+
+ 715
+
+
+ m.extend(ClassMethods)
+
+
+ 1
+
+
+
+
+
+
+ 716
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 717
+
+
+
+
+
+
+
+
+
+
+
+
+ 718
+
+
+ def validate_parent_does_not_have_a_parent
+
+
+ 1
+
+
+
+
+
+
+ 719
+
+
+ return if parent.nil?
+
+
+ 6
+
+
+
+
+
+
+ 720
+
+
+ if !parent.parent.nil?
+
+
+ 0
+
+
+
+
+
+
+ 721
+
+
+ errors.add(:parent, "can not have a parent")
+
+
+ 0
+
+
+
+
+
+
+ 722
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 723
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 724
+
+
+
+
+
+
+
+
+
+
+
+
+ 725
+
+
+ def update_parent_on_destroy
+
+
+ 1
+
+
+
+
+
+
+ 726
+
+
+ Post.update_has_children_flag_for(parent_id)
+
+
+ 0
+
+
+
+
+
+
+ 727
+
+
+ Post.update_has_children_flag_for(parent_id_was) if parent_id_was && parent_id != parent_id_was
+
+
+ 0
+
+
+
+
+
+
+ 728
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 729
+
+
+
+
+
+
+
+
+
+
+
+
+ 730
+
+
+ def update_children_on_destroy
+
+
+ 1
+
+
+
+
+
+
+ 731
+
+
+ if children.size == 0
+
+
+ 0
+
+
+
+
+
+
+ 732
+
+
+ # do nothing
+
+
+
+
+
+
+
+
+
+ 733
+
+
+ elsif children.size == 1
+
+
+ 0
+
+
+
+
+
+
+ 734
+
+
+ children.first.update_attribute(:parent_id, nil)
+
+
+ 0
+
+
+
+
+
+
+ 735
+
+
+ else
+
+
+
+
+
+
+
+
+
+ 736
+
+
+ cached_children = children
+
+
+ 0
+
+
+
+
+
+
+ 737
+
+
+ cached_children[1..-1].each do |child|
+
+
+ 0
+
+
+
+
+
+
+ 738
+
+
+ child.update_attribute(:parent_id, cached_children[0].id)
+
+
+ 0
+
+
+
+
+
+
+ 739
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 740
+
+
+ cached_children[0].update_attribute(:parent_id, nil)
+
+
+ 0
+
+
+
+
+
+
+ 741
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 742
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 743
+
+
+
+
+
+
+
+
+
+
+
+
+ 744
+
+
+ def update_parent_on_save
+
+
+ 1
+
+
+
+
+
+
+ 745
+
+
+ if parent_id == parent_id_was
+
+
+ 6
+
+
+
+
+
+
+ 746
+
+
+ # do nothing
+
+
+
+
+
+
+
+
+
+ 747
+
+
+ elsif !parent_id_was.nil?
+
+
+ 0
+
+
+
+
+
+
+ 748
+
+
+ Post.update_has_children_flag_for(parent_id)
+
+
+ 0
+
+
+
+
+
+
+ 749
+
+
+ Post.update_has_children_flag_for(parent_id_was)
+
+
+ 0
+
+
+
+
+
+
+ 750
+
+
+ else
+
+
+
+
+
+
+
+
+
+ 751
+
+
+ Post.update_has_children_flag_for(parent_id)
+
+
+ 0
+
+
+
+
+
+
+ 752
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 753
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 754
+
+
+
+
+
+
+
+
+
+
+
+
+ 755
+
+
+ def give_favorites_to_parent
+
+
+ 1
+
+
+
+
+
+
+ 756
+
+
+ return if parent.nil?
+
+
+ 0
+
+
+
+
+
+
+ 757
+
+
+
+
+
+
+
+
+
+
+
+
+ 758
+
+
+ favorited_user_ids.each do |user_id|
+
+
+ 0
+
+
+
+
+
+
+ 759
+
+
+ parent.add_favorite(user_id)
+
+
+ 0
+
+
+
+
+
+
+ 760
+
+
+ remove_favorite(user_id)
+
+
+ 0
+
+
+
+
+
+
+ 761
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 762
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 763
+
+
+
+
+
+
+
+
+
+
+
+
+ 764
+
+
+ def delete_favorites
+
+
+ 1
+
+
+
+
+
+
+ 765
+
+
+ Favorite.destroy_for_post(self)
+
+
+ 0
+
+
+
+
+
+
+ 766
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 767
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 768
+
+
+
+
+
+
+
+
+
+
+
+
+ 769
+
+
+ module RemovalMethods
+
+
+ 1
+
+
+
+
+
+
+ 770
+
+
+ def remove!
+
+
+ 1
+
+
+
+
+
+
+ 771
+
+
+ Post.transaction do
+
+
+ 0
+
+
+
+
+
+
+ 772
+
+
+ execute_sql("INSERT INTO removed_posts (#{Post.column_names.join(', ')}) SELECT #{Post.column_names.join(', ')} FROM posts WHERE posts.id = #{id}")
+
+
+ 0
+
+
+
+
+
+
+ 773
+
+
+ give_favorites_to_parent
+
+
+ 0
+
+
+
+
+
+
+ 774
+
+
+ update_children_on_destroy
+
+
+ 0
+
+
+
+
+
+
+ 775
+
+
+ delete_favorites
+
+
+ 0
+
+
+
+
+
+
+ 776
+
+
+ decrement_tag_post_counts
+
+
+ 0
+
+
+
+
+
+
+ 777
+
+
+ execute_sql("DELETE FROM posts WHERE id = #{id}")
+
+
+ 0
+
+
+
+
+
+
+ 778
+
+
+ update_parent_on_destroy
+
+
+ 0
+
+
+
+
+
+
+ 779
+
+
+ tag_array.each {|x| expire_cache(x)}
+
+
+ 0
+
+
+
+
+
+
+ 780
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 781
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 782
+
+
+
+
+
+
+
+
+
+
+
+
+ 783
+
+
+ def is_removed?
+
+
+ 1
+
+
+
+
+
+
+ 784
+
+
+ false
+
+
+ 0
+
+
+
+
+
+
+ 785
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 786
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 787
+
+
+
+
+
+
+
+
+
+
+
+
+ 788
+
+
+ include FileMethods
+
+
+ 1
+
+
+
+
+
+
+ 789
+
+
+ include ImageMethods
+
+
+ 1
+
+
+
+
+
+
+ 790
+
+
+ include ApprovalMethods
+
+
+ 1
+
+
+
+
+
+
+ 791
+
+
+ include PresenterMethods
+
+
+ 1
+
+
+
+
+
+
+ 792
+
+
+ include HistoryMethods
+
+
+ 1
+
+
+
+
+
+
+ 793
+
+
+ include TagMethods
+
+
+ 1
+
+
+
+
+
+
+ 794
+
+
+ include FavoriteMethods
+
+
+ 1
+
+
+
+
+
+
+ 795
+
+
+ include UploaderMethods
+
+
+ 1
+
+
+
+
+
+
+ 796
+
+
+ include PoolMethods
+
+
+ 1
+
+
+
+
+
+
+ 797
+
+
+ extend SearchMethods
+
+
+ 1
+
+
+
+
+
+
+ 798
+
+
+ include VoteMethods
+
+
+ 1
+
+
+
+
+
+
+ 799
+
+
+ extend CountMethods
+
+
+ 1
+
+
+
+
+
+
+ 800
+
+
+ include CacheMethods
+
+
+ 1
+
+
+
+
+
+
+ 801
+
+
+ include ParentMethods
+
+
+ 1
+
+
+
+
+
+
+ 802
+
+
+ include RemovalMethods
+
+
+ 1
+
+
+
+
+
+
+ 803
+
+
+
+
+
+
+
+
+
+
+
+
+ 804
+
+
+ def reload(options = nil)
+
+
+ 1
+
+
+
+
+
+
+ 805
+
+
+ super
+
+
+ 0
+
+
+
+
+
+
+ 806
+
+
+ reset_tag_array_cache
+
+
+ 0
+
+
+
+
+
+
+ 807
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 808
+
+
+
+
+
+
+
+
+
+
+
+
+ 809
+
+
+ def presenter
+
+
+ 1
+
+
+
+
+
+
+ 810
+
+
+ @presenter ||= PostPresenter.new(self)
+
+
+ 0
+
+
+
+
+
+
+ 811
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 812
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 813
+
+
+
+
+
+
+
+
+
+
+
+
+ 814
+
+
+ Post.connection.extend(PostgresExtensions)
+
+
+ 1
+
+
+
+
+
+
+
+
+
+
+
+
+ ./app/models/post_history.rb
+ 50.0 % covered
+
+
+
+ #
+
+ Hits
+
+
+
+
+
+
+
+ 1
+
+
+ class PostHistory < ActiveRecord::Base
+
+
+ 1
+
+
+
+
+
+
+ 2
+
+
+ class Error < Exception ; end
+
+
+ 1
+
+
+
+
+
+
+ 3
+
+
+
+
+
+
+
+
+
+
+
+
+ 4
+
+
+ class Revision
+
+
+ 1
+
+
+
+
+
+
+ 5
+
+
+ attr_accessor :prev, :hash, :diff, :tag_array
+
+
+ 1
+
+
+
+
+
+
+ 6
+
+
+
+
+
+
+
+
+
+
+
+
+ 7
+
+
+ def initialize(hash)
+
+
+ 1
+
+
+
+
+
+
+ 8
+
+
+ @hash = hash
+
+
+ 0
+
+
+
+
+
+
+ 9
+
+
+ @diff = {}
+
+
+ 0
+
+
+
+
+
+
+ 10
+
+
+ @tag_array = Tag.scan_tags(@hash["tag_string"])
+
+
+ 0
+
+
+
+
+
+
+ 11
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 12
+
+
+
+
+
+
+
+
+
+
+
+
+ 13
+
+
+ def calculate_diff
+
+
+ 1
+
+
+
+
+
+
+ 14
+
+
+ if prev.nil?
+
+
+ 0
+
+
+
+
+
+
+ 15
+
+
+ diff[:add] = tag_array
+
+
+ 0
+
+
+
+
+
+
+ 16
+
+
+ diff[:del] = []
+
+
+ 0
+
+
+
+
+
+
+ 17
+
+
+ diff[:rating] = rating
+
+
+ 0
+
+
+
+
+
+
+ 18
+
+
+ diff[:source] = source
+
+
+ 0
+
+
+
+
+
+
+ 19
+
+
+ diff[:parent_id] = parent_id
+
+
+ 0
+
+
+
+
+
+
+ 20
+
+
+ else
+
+
+
+
+
+
+
+
+
+ 21
+
+
+ diff[:del] = prev.tag_array - tag_array
+
+
+ 0
+
+
+
+
+
+
+ 22
+
+
+ diff[:add] = tag_array - prev.tag_array
+
+
+ 0
+
+
+
+
+
+
+ 23
+
+
+
+
+
+
+
+
+
+
+
+
+ 24
+
+
+ if prev.rating != rating
+
+
+ 0
+
+
+
+
+
+
+ 25
+
+
+ diff[:rating] = rating
+
+
+ 0
+
+
+
+
+
+
+ 26
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 27
+
+
+
+
+
+
+
+
+
+
+
+
+ 28
+
+
+ if prev.source != source
+
+
+ 0
+
+
+
+
+
+
+ 29
+
+
+ diff[:source] = source
+
+
+ 0
+
+
+
+
+
+
+ 30
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 31
+
+
+
+
+
+
+
+
+
+
+
+
+ 32
+
+
+ if prev.parent_id != parent_id
+
+
+ 0
+
+
+
+
+
+
+ 33
+
+
+ diff[:parent_id]= parent_id
+
+
+ 0
+
+
+
+
+
+
+ 34
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 35
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 36
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 37
+
+
+
+
+
+
+
+
+
+
+
+
+ 38
+
+
+ def rating
+
+
+ 1
+
+
+
+
+
+
+ 39
+
+
+ hash["rating"]
+
+
+ 0
+
+
+
+
+
+
+ 40
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 41
+
+
+
+
+
+
+
+
+
+
+
+
+ 42
+
+
+ def source
+
+
+ 1
+
+
+
+
+
+
+ 43
+
+
+ hash["source"]
+
+
+ 0
+
+
+
+
+
+
+ 44
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 45
+
+
+
+
+
+
+
+
+
+
+
+
+ 46
+
+
+ def parent_id
+
+
+ 1
+
+
+
+
+
+
+ 47
+
+
+ hash["parent_id"]
+
+
+ 0
+
+
+
+
+
+
+ 48
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 49
+
+
+
+
+
+
+
+
+
+
+
+
+ 50
+
+
+ def updated_at
+
+
+ 1
+
+
+
+
+
+
+ 51
+
+
+ hash["updated_at"]
+
+
+ 0
+
+
+
+
+
+
+ 52
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 53
+
+
+
+
+
+
+
+
+
+
+
+
+ 54
+
+
+ def user_id
+
+
+ 1
+
+
+
+
+
+
+ 55
+
+
+ hash["user_id"]
+
+
+ 0
+
+
+
+
+
+
+ 56
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 57
+
+
+
+
+
+
+
+
+
+
+
+
+ 58
+
+
+ def presenter
+
+
+ 1
+
+
+
+
+
+
+ 59
+
+
+ @presenter ||= PostHistoryRevisionPresenter.new(self)
+
+
+ 0
+
+
+
+
+
+
+ 60
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 61
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 62
+
+
+
+
+
+
+
+
+
+
+
+
+ 63
+
+
+ before_validation :initialize_revisions, :on => :create
+
+
+ 1
+
+
+
+
+
+
+ 64
+
+
+ belongs_to :post
+
+
+ 1
+
+
+
+
+
+
+ 65
+
+
+
+
+
+
+
+
+
+
+
+
+ 66
+
+
+ def self.build_revision_for_post(post)
+
+
+ 1
+
+
+
+
+
+
+ 67
+
+
+ hash = {
+
+
+ 6
+
+
+
+
+
+
+ 68
+
+
+ :source => post.source,
+
+
+
+
+
+
+
+
+
+ 69
+
+
+ :rating => post.rating,
+
+
+
+
+
+
+
+
+
+ 70
+
+
+ :tag_string => post.tag_string,
+
+
+
+
+
+
+
+
+
+ 71
+
+
+ :parent_id => post.parent_id,
+
+
+
+
+
+
+
+
+
+ 72
+
+
+ :user_id => CurrentUser.id,
+
+
+
+
+
+
+
+
+
+ 73
+
+
+ :ip_addr => CurrentUser.ip_addr,
+
+
+
+
+
+
+
+
+
+ 74
+
+
+ :updated_at => revision_time
+
+
+
+
+
+
+
+
+
+ 75
+
+
+ }
+
+
+
+
+
+
+
+
+
+ 76
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 77
+
+
+
+
+
+
+
+
+
+
+
+
+ 78
+
+
+ def self.revision_time
+
+
+ 1
+
+
+
+
+
+
+ 79
+
+
+ Time.now
+
+
+ 6
+
+
+
+
+
+
+ 80
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 81
+
+
+
+
+
+
+
+
+
+
+
+
+ 82
+
+
+ def initialize_revisions
+
+
+ 1
+
+
+
+
+
+
+ 83
+
+
+ write_attribute(:revisions, "[]")
+
+
+ 6
+
+
+
+
+
+
+ 84
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 85
+
+
+
+
+
+
+
+
+
+
+
+
+ 86
+
+
+ def revisions
+
+
+ 1
+
+
+
+
+
+
+ 87
+
+
+ if read_attribute(:revisions).blank?
+
+
+ 18
+
+
+
+
+
+
+ 88
+
+
+ []
+
+
+ 0
+
+
+
+
+
+
+ 89
+
+
+ else
+
+
+
+
+
+
+
+
+
+ 90
+
+
+ JSON.parse(read_attribute(:revisions))
+
+
+ 18
+
+
+
+
+
+
+ 91
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 92
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 93
+
+
+
+
+
+
+
+
+
+
+
+
+ 94
+
+
+ def <<(post)
+
+
+ 1
+
+
+
+
+
+
+ 95
+
+
+ revision = self.class.build_revision_for_post(post)
+
+
+ 6
+
+
+
+
+
+
+ 96
+
+
+ write_attribute(:revisions, (revisions << revision).to_json)
+
+
+ 6
+
+
+
+
+
+
+ 97
+
+
+ save
+
+
+ 6
+
+
+
+
+
+
+ 98
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 99
+
+
+
+
+
+
+
+
+
+
+
+
+ 100
+
+
+ def each_revision(&block)
+
+
+ 1
+
+
+
+
+
+
+ 101
+
+
+ array = revisions.map {|x| Revision.new(x)}
+
+
+ 0
+
+
+
+
+
+
+ 102
+
+
+ link_revisions(array)
+
+
+ 0
+
+
+
+
+
+
+ 103
+
+
+ array.each {|x| x.calculate_diff}
+
+
+ 0
+
+
+
+
+
+
+ 104
+
+
+ array.each(&block)
+
+
+ 0
+
+
+
+
+
+
+ 105
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 106
+
+
+
+
+
+
+
+
+
+
+
+
+ 107
+
+
+ private
+
+
+ 1
+
+
+
+
+
+
+ 108
+
+
+ def link_revisions(array)
+
+
+ 1
+
+
+
+
+
+
+ 109
+
+
+ 1.upto(array.size - 1) do |i|
+
+
+ 0
+
+
+
+
+
+
+ 110
+
+
+ array[i].prev = array[i - 1]
+
+
+ 0
+
+
+
+
+
+
+ 111
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 112
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 113
+
+
+
+
+
+
+
+
+
+
+
+
+ 114
+
+
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ./app/models/post_moderation_detail.rb
+ 45.45 % covered
+
+
+
+ #
+
+ Hits
+
+
+
+
+
+
+
+ 1
+
+
+ class PostModerationDetail < ActiveRecord::Base
+
+
+ 1
+
+
+
+
+
+
+ 2
+
+
+ belongs_to :post
+
+
+ 1
+
+
+
+
+
+
+ 3
+
+
+ belongs_to :user
+
+
+ 1
+
+
+
+
+
+
+ 4
+
+
+
+
+
+
+
+
+
+
+
+
+ 5
+
+
+ def self.filter(posts, user, select_hidden = false)
+
+
+ 1
+
+
+
+
+
+
+ 6
+
+
+ hidden = where(:user_id => user.id).select("post_id").map(&:post_id)
+
+
+ 0
+
+
+
+
+
+
+ 7
+
+
+ if select_hidden
+
+
+ 0
+
+
+
+
+
+
+ 8
+
+
+ posts.select {|x| hidden.include?(x.id)}
+
+
+ 0
+
+
+
+
+
+
+ 9
+
+
+ else
+
+
+
+
+
+
+
+
+
+ 10
+
+
+ posts.reject {|x| hidden.include?(x.id)}
+
+
+ 0
+
+
+
+
+
+
+ 11
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 12
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 13
+
+
+
+
+
+
+
+
+
+
+
+
+ 14
+
+
+ def self.prune!
+
+
+ 1
+
+
+
+
+
+
+ 15
+
+
+ joins(:post).where("posts.is_pending = FALSE AND posts.is_flagged = FALSE").each do |hidden_post|
+
+
+ 0
+
+
+
+
+
+
+ 16
+
+
+ hidden_post.destroy
+
+
+ 0
+
+
+
+
+
+
+ 17
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 18
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 19
+
+
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ./app/models/post_vote.rb
+ 61.54 % covered
+
+
+
+ #
+
+ Hits
+
+
+
+
+
+
+
+ 1
+
+
+ class PostVote < ActiveRecord::Base
+
+
+ 1
+
+
+
+
+
+
+ 2
+
+
+ class Error < Exception ; end
+
+
+ 1
+
+
+
+
+
+
+ 3
+
+
+
+
+
+
+
+
+
+
+
+
+ 4
+
+
+ belongs_to :post
+
+
+ 1
+
+
+
+
+
+
+ 5
+
+
+ before_validation :initialize_user, :on => :create
+
+
+ 1
+
+
+
+
+
+
+ 6
+
+
+ validates_presence_of :post_id, :user_id, :score
+
+
+ 1
+
+
+
+
+
+
+ 7
+
+
+ validates_inclusion_of :score, :in => [1, -1]
+
+
+ 1
+
+
+
+
+
+
+ 8
+
+
+
+
+
+
+
+
+
+
+
+
+ 9
+
+
+ def score=(x)
+
+
+ 1
+
+
+
+
+
+
+ 10
+
+
+ if x == "up"
+
+
+ 0
+
+
+
+
+
+
+ 11
+
+
+ write_attribute(:score, 1)
+
+
+ 0
+
+
+
+
+
+
+ 12
+
+
+ elsif x == "down"
+
+
+ 0
+
+
+
+
+
+
+ 13
+
+
+ write_attribute(:score, -1)
+
+
+ 0
+
+
+
+
+
+
+ 14
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 15
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 16
+
+
+
+
+
+
+
+
+
+
+
+
+ 17
+
+
+ def initialize_user
+
+
+ 1
+
+
+
+
+
+
+ 18
+
+
+ self.user_id = CurrentUser.user.id
+
+
+ 0
+
+
+
+
+
+
+ 19
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 20
+
+
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ./app/models/removed_post.rb
+ 60.0 % covered
+
+
+
+ #
+
+ Hits
+
+
+
+
+
+
+
+ 1
+
+
+ class RemovedPost < ActiveRecord::Base
+
+
+ 1
+
+
+
+
+
+
+ 2
+
+
+ has_one :unapproval, :dependent => :destroy, :foreign_key => "post_id"
+
+
+ 1
+
+
+
+
+
+
+ 3
+
+
+
+
+
+
+
+
+
+
+
+
+ 4
+
+
+ module RemovalMethods
+
+
+ 1
+
+
+
+
+
+
+ 5
+
+
+ def unremove!
+
+
+ 1
+
+
+
+
+
+
+ 6
+
+
+ Post.transaction do
+
+
+ 0
+
+
+
+
+
+
+ 7
+
+
+ execute_sql("INSERT INTO posts (#{Post.column_names.join(', ')}) SELECT #{Post.column_names.join(', ')} FROM removed_posts WHERE id = #{id}")
+
+
+ 0
+
+
+
+
+
+
+ 8
+
+
+ execute_sql("DELETE FROM removed_posts WHERE id = #{id}")
+
+
+ 0
+
+
+
+
+
+
+ 9
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 10
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 11
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 12
+
+
+
+
+
+
+
+
+
+
+
+
+ 13
+
+
+ def fast_count(tags)
+
+
+ 1
+
+
+
+
+
+
+ 14
+
+
+ count = Cache.get("rpfc:#{Cache.sanitize(tags)}")
+
+
+ 0
+
+
+
+
+
+
+ 15
+
+
+ if count.nil?
+
+
+ 0
+
+
+
+
+
+
+ 16
+
+
+ count = RemovedPost.find_by_tags("#{tags}").count
+
+
+ 0
+
+
+
+
+
+
+ 17
+
+
+ if count > Danbooru.config.posts_per_page * 10
+
+
+ 0
+
+
+
+
+
+
+ 18
+
+
+ Cache.put("rpfc:#{Cache.sanitize(tags)}", count, (count * 4).minutes)
+
+
+ 0
+
+
+
+
+
+
+ 19
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 20
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 21
+
+
+ count
+
+
+ 0
+
+
+
+
+
+
+ 22
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 23
+
+
+
+
+
+
+
+
+
+
+
+
+ 24
+
+
+ def is_removed?
+
+
+ 1
+
+
+
+
+
+
+ 25
+
+
+ true
+
+
+ 0
+
+
+
+
+
+
+ 26
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 27
+
+
+
+
+
+
+
+
+
+
+
+
+ 28
+
+
+ include Post::FileMethods
+
+
+ 1
+
+
+
+
+
+
+ 29
+
+
+ include Post::ImageMethods
+
+
+ 1
+
+
+
+
+
+
+ 30
+
+
+ include Post::TagMethods
+
+
+ 1
+
+
+
+
+
+
+ 31
+
+
+ include Post::SearchMethods
+
+
+ 1
+
+
+
+
+
+
+ 32
+
+
+ include Post::UploaderMethods
+
+
+ 1
+
+
+
+
+
+
+ 33
+
+
+ include Post::PoolMethods
+
+
+ 1
+
+
+
+
+
+
+ 34
+
+
+ include Post::CountMethods
+
+
+ 1
+
+
+
+
+
+
+ 35
+
+
+ include Post::CacheMethods
+
+
+ 1
+
+
+
+
+
+
+ 36
+
+
+ include RemovalMethods
+
+
+ 1
+
+
+
+
+
+
+ 37
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 38
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ./app/models/report_mailer.rb
+ 75.0 % covered
+
+
+
+ #
+
+ Hits
+
+
+
+
+
+
+
+ 1
+
+
+ class ReportMailer < ActionMailer::Base
+
+
+ 1
+
+
+
+
+
+
+ 2
+
+
+ default :host => Danbooru.config.server_host, :from => Danbooru.config.contact_email, :content_type => "text/html"
+
+
+ 1
+
+
+
+
+
+
+ 3
+
+
+
+
+
+
+
+
+
+
+
+
+ 4
+
+
+ def moderator_report(email)
+
+
+ 1
+
+
+
+
+
+
+ 5
+
+
+ mail(:to => email, :subject => "#{Danbooru.config.app_name} - Moderator Report")
+
+
+ 0
+
+
+
+
+
+
+ 6
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 7
+
+
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ./app/models/tag.rb
+ 47.4 % covered
+
+
+
+ #
+
+ Hits
+
+
+
+
+
+
+
+ 1
+
+
+ class Tag < ActiveRecord::Base
+
+
+ 1
+
+
+
+
+
+
+ 2
+
+
+ attr_accessible :category
+
+
+ 1
+
+
+
+
+
+
+ 3
+
+
+ after_save :update_category_cache
+
+
+ 1
+
+
+
+
+
+
+ 4
+
+
+ has_one :wiki_page, :foreign_key => "name", :primary_key => "title"
+
+
+ 1
+
+
+
+
+
+
+ 5
+
+
+ scope :by_pattern, lambda {|name| where(["name LIKE ? ESCAPE E'\\\\'", name.to_escaped_for_sql_like])}
+
+
+ 1
+
+
+
+
+
+
+ 6
+
+
+
+
+
+
+
+
+
+
+
+
+ 7
+
+
+ class CategoryMapping
+
+
+ 1
+
+
+
+
+
+
+ 8
+
+
+ Danbooru.config.reverse_tag_category_mapping.each do |value, category|
+
+
+ 1
+
+
+
+
+
+
+ 9
+
+
+ define_method(category.downcase) do
+
+
+ 4
+
+
+
+
+
+
+ 10
+
+
+ value
+
+
+ 24
+
+
+
+
+
+
+ 11
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 12
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 13
+
+
+
+
+
+
+
+
+
+
+
+
+ 14
+
+
+ def regexp
+
+
+ 1
+
+
+
+
+
+
+ 15
+
+
+ @regexp ||= Regexp.compile(Danbooru.config.tag_category_mapping.keys.sort_by {|x| -x.size}.join("|"))
+
+
+ 22
+
+
+
+
+
+
+ 16
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 17
+
+
+
+
+
+
+
+
+
+
+
+
+ 18
+
+
+ def value_for(string)
+
+
+ 1
+
+
+
+
+
+
+ 19
+
+
+ Danbooru.config.tag_category_mapping[string.downcase] || 0
+
+
+ 0
+
+
+
+
+
+
+ 20
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 21
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 22
+
+
+
+
+
+
+
+
+
+
+
+
+ 23
+
+
+ module ViewCountMethods
+
+
+ 1
+
+
+
+
+
+
+ 24
+
+
+ def increment_view_count(name)
+
+
+ 1
+
+
+
+
+
+
+ 25
+
+
+ Cache.incr("tvc:#{Cache.sanitize(name)}")
+
+
+ 0
+
+
+
+
+
+
+ 26
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 27
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 28
+
+
+
+
+
+
+
+
+
+
+
+
+ 29
+
+
+ module CategoryMethods
+
+
+ 1
+
+
+
+
+
+
+ 30
+
+
+ module ClassMethods
+
+
+ 1
+
+
+
+
+
+
+ 31
+
+
+ def categories
+
+
+ 1
+
+
+
+
+
+
+ 32
+
+
+ @category_mapping ||= CategoryMapping.new
+
+
+ 36
+
+
+
+
+
+
+ 33
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 34
+
+
+
+
+
+
+
+
+
+
+
+
+ 35
+
+
+ def select_category_for(tag_name)
+
+
+ 1
+
+
+
+
+
+
+ 36
+
+
+ select_value_sql("SELECT category FROM tags WHERE name = ?", tag_name).to_i
+
+
+ 0
+
+
+
+
+
+
+ 37
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 38
+
+
+
+
+
+
+
+
+
+
+
+
+ 39
+
+
+ def category_for(tag_name)
+
+
+ 1
+
+
+
+
+
+
+ 40
+
+
+ Cache.get("tc:#{Cache.sanitize(tag_name)}") do
+
+
+ 0
+
+
+
+
+
+
+ 41
+
+
+ select_category_for(tag_name)
+
+
+ 0
+
+
+
+
+
+
+ 42
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 43
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 44
+
+
+
+
+
+
+
+
+
+
+
+
+ 45
+
+
+ def categories_for(tag_names)
+
+
+ 1
+
+
+
+
+
+
+ 46
+
+
+ Cache.get_multi(tag_names, "tc") do |name|
+
+
+ 6
+
+
+
+
+
+
+ 47
+
+
+ select_category_for(name)
+
+
+ 0
+
+
+
+
+
+
+ 48
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 49
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 50
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 51
+
+
+
+
+
+
+
+
+
+
+
+
+ 52
+
+
+ def self.included(m)
+
+
+ 1
+
+
+
+
+
+
+ 53
+
+
+ m.extend(ClassMethods)
+
+
+ 1
+
+
+
+
+
+
+ 54
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 55
+
+
+
+
+
+
+
+
+
+
+
+
+ 56
+
+
+ def category_name
+
+
+ 1
+
+
+
+
+
+
+ 57
+
+
+ Danbooru.config.reverse_tag_category_mapping[category]
+
+
+ 0
+
+
+
+
+
+
+ 58
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 59
+
+
+
+
+
+
+
+
+
+
+
+
+ 60
+
+
+ def update_category_cache
+
+
+ 1
+
+
+
+
+
+
+ 61
+
+
+ Cache.put("tc:#{Cache.sanitize(name)}", category)
+
+
+ 12
+
+
+
+
+
+
+ 62
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 63
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 64
+
+
+
+
+
+
+
+
+
+
+
+
+ 65
+
+
+ module StatisticsMethods
+
+
+ 1
+
+
+
+
+
+
+ 66
+
+
+ def trending
+
+
+ 1
+
+
+
+
+
+
+ 67
+
+
+ raise NotImplementedError
+
+
+ 0
+
+
+
+
+
+
+ 68
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 69
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 70
+
+
+
+
+
+
+
+
+
+
+
+
+ 71
+
+
+ module NameMethods
+
+
+ 1
+
+
+
+
+
+
+ 72
+
+
+ module ClassMethods
+
+
+ 1
+
+
+
+
+
+
+ 73
+
+
+ def normalize_name(name)
+
+
+ 1
+
+
+
+
+
+
+ 74
+
+
+ name.downcase.tr(" ", "_").gsub(/\A[-~*]+/, "")
+
+
+ 12
+
+
+
+
+
+
+ 75
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 76
+
+
+
+
+
+
+
+
+
+
+
+
+ 77
+
+
+ def find_or_create_by_name(name, options = {})
+
+
+ 1
+
+
+
+
+
+
+ 78
+
+
+ name = normalize_name(name)
+
+
+ 12
+
+
+
+
+
+
+ 79
+
+
+ category = categories.general
+
+
+ 12
+
+
+
+
+
+
+ 80
+
+
+
+
+
+
+
+
+
+
+
+
+ 81
+
+
+ if name =~ /\A(#{categories.regexp}):(.+)\Z/
+
+
+ 12
+
+
+
+
+
+
+ 82
+
+
+ category = categories.value_for($1)
+
+
+ 0
+
+
+
+
+
+
+ 83
+
+
+ name = $2
+
+
+ 0
+
+
+
+
+
+
+ 84
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 85
+
+
+
+
+
+
+
+
+
+
+
+
+ 86
+
+
+ tag = find_by_name(name)
+
+
+ 12
+
+
+
+
+
+
+ 87
+
+
+
+
+
+
+
+
+
+
+
+
+ 88
+
+
+ if tag
+
+
+ 12
+
+
+
+
+
+
+ 89
+
+
+ if category > 0 && !(options[:user] && !options[:user].is_privileged? && tag.post_count > 10)
+
+
+ 0
+
+
+
+
+
+
+ 90
+
+
+ tag.update_attribute(:category, category)
+
+
+ 0
+
+
+
+
+
+
+ 91
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 92
+
+
+
+
+
+
+
+
+
+
+
+
+ 93
+
+
+ tag
+
+
+ 0
+
+
+
+
+
+
+ 94
+
+
+ else
+
+
+
+
+
+
+
+
+
+ 95
+
+
+ Tag.new.tap do |tag|
+
+
+ 12
+
+
+
+
+
+
+ 96
+
+
+ tag.name = name
+
+
+ 12
+
+
+
+
+
+
+ 97
+
+
+ tag.category = category
+
+
+ 12
+
+
+
+
+
+
+ 98
+
+
+ tag.save
+
+
+ 12
+
+
+
+
+
+
+ 99
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 100
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 101
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 102
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 103
+
+
+
+
+
+
+
+
+
+
+
+
+ 104
+
+
+ def self.included(m)
+
+
+ 1
+
+
+
+
+
+
+ 105
+
+
+ m.extend(ClassMethods)
+
+
+ 1
+
+
+
+
+
+
+ 106
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 107
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 108
+
+
+
+
+
+
+
+
+
+
+
+
+ 109
+
+
+ module UpdateMethods
+
+
+ 1
+
+
+
+
+
+
+ 110
+
+
+ def mass_edit(start_tags, result_tags, updater_id, updater_ip_addr)
+
+
+ 1
+
+
+
+
+
+
+ 111
+
+
+ updater = User.find(updater_id)
+
+
+ 0
+
+
+
+
+
+
+ 112
+
+
+ Post.find_by_tags(start_tags).each do |p|
+
+
+ 0
+
+
+
+
+
+
+ 113
+
+
+ start = TagAlias.to_aliased(scan_tags(start_tags))
+
+
+ 0
+
+
+
+
+
+
+ 114
+
+
+ result = TagAlias.to_aliased(scan_tags(result_tags))
+
+
+ 0
+
+
+
+
+
+
+ 115
+
+
+ tags = (p.tag_array - start + result).join(" ")
+
+
+ 0
+
+
+
+
+
+
+ 116
+
+
+ CurrentUser.scoped(updater, updater_ip_addr) do
+
+
+ 0
+
+
+
+
+
+
+ 117
+
+
+ p.update_attributes(:tag_string => tags)
+
+
+ 0
+
+
+
+
+
+
+ 118
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 119
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 120
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 121
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 122
+
+
+
+
+
+
+
+
+
+
+
+
+ 123
+
+
+ module ParseMethods
+
+
+ 1
+
+
+
+
+
+
+ 124
+
+
+ def normalize(query)
+
+
+ 1
+
+
+
+
+
+
+ 125
+
+
+ query.to_s.downcase.strip
+
+
+ 42
+
+
+
+
+
+
+ 126
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 127
+
+
+
+
+
+
+
+
+
+
+
+
+ 128
+
+
+ def scan_query(query)
+
+
+ 1
+
+
+
+
+
+
+ 129
+
+
+ normalize(query).scan(/\S+/).uniq
+
+
+ 18
+
+
+
+
+
+
+ 130
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 131
+
+
+
+
+
+
+
+
+
+
+
+
+ 132
+
+
+ def scan_tags(tags)
+
+
+ 1
+
+
+
+
+
+
+ 133
+
+
+ normalize(tags).gsub(/[,;*]/, "_").scan(/\S+/).uniq
+
+
+ 24
+
+
+
+
+
+
+ 134
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 135
+
+
+
+
+
+
+
+
+
+
+
+
+ 136
+
+
+ def parse_cast(object, type)
+
+
+ 1
+
+
+
+
+
+
+ 137
+
+
+ case type
+
+
+ 0
+
+
+
+
+
+
+ 138
+
+
+ when :integer
+
+
+
+
+
+
+
+
+
+ 139
+
+
+ object.to_i
+
+
+ 0
+
+
+
+
+
+
+ 140
+
+
+
+
+
+
+
+
+
+
+
+
+ 141
+
+
+ when :float
+
+
+
+
+
+
+
+
+
+ 142
+
+
+ object.to_f
+
+
+ 0
+
+
+
+
+
+
+ 143
+
+
+
+
+
+
+
+
+
+
+
+
+ 144
+
+
+ when :date
+
+
+
+
+
+
+
+
+
+ 145
+
+
+ begin
+
+
+ 0
+
+
+
+
+
+
+ 146
+
+
+ object.to_date
+
+
+ 0
+
+
+
+
+
+
+ 147
+
+
+ rescue Exception
+
+
+ 0
+
+
+
+
+
+
+ 148
+
+
+ nil
+
+
+ 0
+
+
+
+
+
+
+ 149
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 150
+
+
+
+
+
+
+
+
+
+
+
+
+ 151
+
+
+ when :filesize
+
+
+
+
+
+
+
+
+
+ 152
+
+
+ object =~ /\A(\d+(?:\.\d*)?|\d*\.\d+)([kKmM]?)[bB]?\Z/
+
+
+ 0
+
+
+
+
+
+
+ 153
+
+
+
+
+
+
+
+
+
+
+
+
+ 154
+
+
+ size = $1.to_f
+
+
+ 0
+
+
+
+
+
+
+ 155
+
+
+ unit = $2
+
+
+ 0
+
+
+
+
+
+
+ 156
+
+
+
+
+
+
+
+
+
+
+
+
+ 157
+
+
+ conversion_factor = case unit
+
+
+ 0
+
+
+
+
+
+
+ 158
+
+
+ when /m/i
+
+
+
+
+
+
+
+
+
+ 159
+
+
+ 1024 * 1024
+
+
+ 0
+
+
+
+
+
+
+ 160
+
+
+ when /k/i
+
+
+
+
+
+
+
+
+
+ 161
+
+
+ 1024
+
+
+ 0
+
+
+
+
+
+
+ 162
+
+
+ else
+
+
+
+
+
+
+
+
+
+ 163
+
+
+ 1
+
+
+ 0
+
+
+
+
+
+
+ 164
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 165
+
+
+
+
+
+
+
+
+
+
+
+
+ 166
+
+
+ (size * conversion_factor).to_i
+
+
+ 0
+
+
+
+
+
+
+ 167
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 168
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 169
+
+
+
+
+
+
+
+
+
+
+
+
+ 170
+
+
+ def parse_helper(range, type = :integer)
+
+
+ 1
+
+
+
+
+
+
+ 171
+
+
+ # "1", "0.5", "5.", ".5":
+
+
+
+
+
+
+
+
+
+ 172
+
+
+ # (-?(\d+(\.\d*)?|\d*\.\d+))
+
+
+
+
+
+
+
+
+
+ 173
+
+
+ case range
+
+
+ 0
+
+
+
+
+
+
+ 174
+
+
+ when /\A(.+?)\.\.(.+)/
+
+
+
+
+
+
+
+
+
+ 175
+
+
+ return [:between, parse_cast($1, type), parse_cast($2, type)]
+
+
+ 0
+
+
+
+
+
+
+ 176
+
+
+
+
+
+
+
+
+
+
+
+
+ 177
+
+
+ when /\A<=(.+)/, /\A\.\.(.+)/
+
+
+
+
+
+
+
+
+
+ 178
+
+
+ return [:lte, parse_cast($1, type)]
+
+
+ 0
+
+
+
+
+
+
+ 179
+
+
+
+
+
+
+
+
+
+
+
+
+ 180
+
+
+ when /\A<(.+)/
+
+
+
+
+
+
+
+
+
+ 181
+
+
+ return [:lt, parse_cast($1, type)]
+
+
+ 0
+
+
+
+
+
+
+ 182
+
+
+
+
+
+
+
+
+
+
+
+
+ 183
+
+
+ when /\A>=(.+)/, /\A(.+)\.\.\Z/
+
+
+
+
+
+
+
+
+
+ 184
+
+
+ return [:gte, parse_cast($1, type)]
+
+
+ 0
+
+
+
+
+
+
+ 185
+
+
+
+
+
+
+
+
+
+
+
+
+ 186
+
+
+ when /\A>(.+)/
+
+
+
+
+
+
+
+
+
+ 187
+
+
+ return [:gt, parse_cast($1, type)]
+
+
+ 0
+
+
+
+
+
+
+ 188
+
+
+
+
+
+
+
+
+
+
+
+
+ 189
+
+
+ else
+
+
+
+
+
+
+
+
+
+ 190
+
+
+ return [:eq, parse_cast(range, type)]
+
+
+ 0
+
+
+
+
+
+
+ 191
+
+
+
+
+
+
+
+
+
+
+
+
+ 192
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 193
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 194
+
+
+
+
+
+
+
+
+
+
+
+
+ 195
+
+
+ def parse_tag(tag, output)
+
+
+ 1
+
+
+
+
+
+
+ 196
+
+
+ if tag[0] == "-" && tag.size > 1
+
+
+ 0
+
+
+
+
+
+
+ 197
+
+
+ output[:exclude] << tag[1..-1]
+
+
+ 0
+
+
+
+
+
+
+ 198
+
+
+
+
+
+
+
+
+
+
+
+
+ 199
+
+
+ elsif tag =~ /\*/
+
+
+ 0
+
+
+
+
+
+
+ 200
+
+
+ matches = Tag.by_pattern(tag).all(:select => "name", :limit => 25, :order => "post_count DESC").map(&:name)
+
+
+ 0
+
+
+
+
+
+
+ 201
+
+
+ matches = ["~no_matches~"] if matches.empty?
+
+
+ 0
+
+
+
+
+
+
+ 202
+
+
+ output[:include] += matches
+
+
+ 0
+
+
+
+
+
+
+ 203
+
+
+
+
+
+
+
+
+
+
+
+
+ 204
+
+
+ else
+
+
+
+
+
+
+
+
+
+ 205
+
+
+ output[:related] << tag
+
+
+ 0
+
+
+
+
+
+
+ 206
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 207
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 208
+
+
+
+
+
+
+
+
+
+
+
+
+ 209
+
+
+ def parse_query(query, options = {})
+
+
+ 1
+
+
+
+
+
+
+ 210
+
+
+ q = Hash.new {|h, k| h[k] = []}
+
+
+ 360
+
+
+
+
+
+
+ 211
+
+
+ q[:tags] = {
+
+
+ 18
+
+
+
+
+
+
+ 212
+
+
+ :related => [],
+
+
+
+
+
+
+
+
+
+ 213
+
+
+ :include => [],
+
+
+
+
+
+
+
+
+
+ 214
+
+
+ :exclude => []
+
+
+
+
+
+
+
+
+
+ 215
+
+
+ }
+
+
+
+
+
+
+
+
+
+ 216
+
+
+
+
+
+
+
+
+
+
+
+
+ 217
+
+
+ scan_query(query).each do |token|
+
+
+ 18
+
+
+
+
+
+
+ 218
+
+
+ if token =~ /\A(-uploader|uploader|-pool|pool|-fav|fav|sub|md5|-rating|rating|width|height|mpixels|score|filesize|source|id|date|order|status|tagcount|gentags|arttags|chartags|copytags):(.+)\Z/
+
+
+ 0
+
+
+
+
+
+
+ 219
+
+
+ case $1
+
+
+ 0
+
+
+
+
+
+
+ 220
+
+
+ when "-uploader"
+
+
+
+
+
+
+
+
+
+ 221
+
+
+ q[:tags][:exclude] << "uploader:#{User.name_to_id($2)}"
+
+
+ 0
+
+
+
+
+
+
+ 222
+
+
+
+
+
+
+
+
+
+
+
+
+ 223
+
+
+ when "uploader"
+
+
+
+
+
+
+
+
+
+ 224
+
+
+ q[:tags][:related] << "uploader:#{User.name_to_id($2)}"
+
+
+ 0
+
+
+
+
+
+
+ 225
+
+
+
+
+
+
+
+
+
+
+
+
+ 226
+
+
+ when "-pool"
+
+
+
+
+
+
+
+
+
+ 227
+
+
+ q[:tags][:exclude] << "pool:#{Pool.name_to_id($2)}"
+
+
+ 0
+
+
+
+
+
+
+ 228
+
+
+
+
+
+
+
+
+
+
+
+
+ 229
+
+
+ when "pool"
+
+
+
+
+
+
+
+
+
+ 230
+
+
+ q[:tags][:related] << "pool:#{Pool.name_to_id($2)}"
+
+
+ 0
+
+
+
+
+
+
+ 231
+
+
+
+
+
+
+
+
+
+
+
+
+ 232
+
+
+ when "-fav"
+
+
+
+
+
+
+
+
+
+ 233
+
+
+ q[:tags][:exclude] << "fav:#{User.name_to_id($2)}"
+
+
+ 0
+
+
+
+
+
+
+ 234
+
+
+
+
+
+
+
+
+
+
+
+
+ 235
+
+
+ when "fav"
+
+
+
+
+
+
+
+
+
+ 236
+
+
+ q[:tags][:related] << "fav:#{User.name_to_id($2)}"
+
+
+ 0
+
+
+
+
+
+
+ 237
+
+
+
+
+
+
+
+
+
+
+
+
+ 238
+
+
+ when "sub"
+
+
+
+
+
+
+
+
+
+ 239
+
+
+ q[:subscriptions] << $2
+
+
+ 0
+
+
+
+
+
+
+ 240
+
+
+
+
+
+
+
+
+
+
+
+
+ 241
+
+
+ when "md5"
+
+
+
+
+
+
+
+
+
+ 242
+
+
+ q[:md5] = $2.split(/,/)
+
+
+ 0
+
+
+
+
+
+
+ 243
+
+
+
+
+
+
+
+
+
+
+
+
+ 244
+
+
+ when "-rating"
+
+
+
+
+
+
+
+
+
+ 245
+
+
+ q[:rating_negated] = $2
+
+
+ 0
+
+
+
+
+
+
+ 246
+
+
+
+
+
+
+
+
+
+
+
+
+ 247
+
+
+ when "rating"
+
+
+
+
+
+
+
+
+
+ 248
+
+
+ q[:rating] = $2
+
+
+ 0
+
+
+
+
+
+
+ 249
+
+
+
+
+
+
+
+
+
+
+
+
+ 250
+
+
+ when "id"
+
+
+
+
+
+
+
+
+
+ 251
+
+
+ q[:post_id] = parse_helper($2)
+
+
+ 0
+
+
+
+
+
+
+ 252
+
+
+
+
+
+
+
+
+
+
+
+
+ 253
+
+
+ when "width"
+
+
+
+
+
+
+
+
+
+ 254
+
+
+ q[:width] = parse_helper($2)
+
+
+ 0
+
+
+
+
+
+
+ 255
+
+
+
+
+
+
+
+
+
+
+
+
+ 256
+
+
+ when "height"
+
+
+
+
+
+
+
+
+
+ 257
+
+
+ q[:height] = parse_helper($2)
+
+
+ 0
+
+
+
+
+
+
+ 258
+
+
+
+
+
+
+
+
+
+
+
+
+ 259
+
+
+ when "mpixels"
+
+
+
+
+
+
+
+
+
+ 260
+
+
+ q[:mpixels] = parse_helper($2, :float)
+
+
+ 0
+
+
+
+
+
+
+ 261
+
+
+
+
+
+
+
+
+
+
+
+
+ 262
+
+
+ when "score"
+
+
+
+
+
+
+
+
+
+ 263
+
+
+ q[:score] = parse_helper($2)
+
+
+ 0
+
+
+
+
+
+
+ 264
+
+
+
+
+
+
+
+
+
+
+
+
+ 265
+
+
+ when "filesize"
+
+
+
+
+
+
+
+
+
+ 266
+
+
+ q[:filesize] = parse_helper($2, :filesize)
+
+
+ 0
+
+
+
+
+
+
+ 267
+
+
+
+
+
+
+
+
+
+
+
+
+ 268
+
+
+ when "source"
+
+
+
+
+
+
+
+
+
+ 269
+
+
+ q[:source] = $2.to_escaped_for_sql_like + "%"
+
+
+ 0
+
+
+
+
+
+
+ 270
+
+
+
+
+
+
+
+
+
+
+
+
+ 271
+
+
+ when "date"
+
+
+
+
+
+
+
+
+
+ 272
+
+
+ q[:date] = parse_helper($2, :date)
+
+
+ 0
+
+
+
+
+
+
+ 273
+
+
+
+
+
+
+
+
+
+
+
+
+ 274
+
+
+ when "tagcount"
+
+
+
+
+
+
+
+
+
+ 275
+
+
+ q[:tag_count] = parse_helper($2)
+
+
+ 0
+
+
+
+
+
+
+ 276
+
+
+
+
+
+
+
+
+
+
+
+
+ 277
+
+
+ when "gentags"
+
+
+
+
+
+
+
+
+
+ 278
+
+
+ q[:general_tag_count] = parse_helper($2)
+
+
+ 0
+
+
+
+
+
+
+ 279
+
+
+
+
+
+
+
+
+
+
+
+
+ 280
+
+
+ when "arttags"
+
+
+
+
+
+
+
+
+
+ 281
+
+
+ q[:artist_tag_count] = parse_helper($2)
+
+
+ 0
+
+
+
+
+
+
+ 282
+
+
+
+
+
+
+
+
+
+
+
+
+ 283
+
+
+ when "chartags"
+
+
+
+
+
+
+
+
+
+ 284
+
+
+ q[:character_tag_count] = parse_helper($2)
+
+
+ 0
+
+
+
+
+
+
+ 285
+
+
+
+
+
+
+
+
+
+
+
+
+ 286
+
+
+ when "copytags"
+
+
+
+
+
+
+
+
+
+ 287
+
+
+ q[:copyright_tag_count] = parse_helper($2)
+
+
+ 0
+
+
+
+
+
+
+ 288
+
+
+
+
+
+
+
+
+
+
+
+
+ 289
+
+
+ when "order"
+
+
+
+
+
+
+
+
+
+ 290
+
+
+ q[:order] = $2
+
+
+ 0
+
+
+
+
+
+
+ 291
+
+
+
+
+
+
+
+
+
+
+
+
+ 292
+
+
+ when "status"
+
+
+
+
+
+
+
+
+
+ 293
+
+
+ q[:status] = $2
+
+
+ 0
+
+
+
+
+
+
+ 294
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 295
+
+
+
+
+
+
+
+
+
+
+
+
+ 296
+
+
+ else
+
+
+
+
+
+
+
+
+
+ 297
+
+
+ parse_tag(token, q[:tags])
+
+
+ 0
+
+
+
+
+
+
+ 298
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 299
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 300
+
+
+
+
+
+
+
+
+
+
+
+
+ 301
+
+
+ normalize_tags_in_query(q)
+
+
+ 18
+
+
+
+
+
+
+ 302
+
+
+
+
+
+
+
+
+
+
+
+
+ 303
+
+
+ return q
+
+
+ 18
+
+
+
+
+
+
+ 304
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 305
+
+
+
+
+
+
+
+
+
+
+
+
+ 306
+
+
+ def normalize_tags_in_query(query_hash)
+
+
+ 1
+
+
+
+
+
+
+ 307
+
+
+ query_hash[:tags][:exclude] = TagAlias.to_aliased(query_hash[:tags][:exclude])
+
+
+ 18
+
+
+
+
+
+
+ 308
+
+
+ query_hash[:tags][:include] = TagAlias.to_aliased(query_hash[:tags][:include])
+
+
+ 18
+
+
+
+
+
+
+ 309
+
+
+ query_hash[:tags][:related] = TagAlias.to_aliased(query_hash[:tags][:related])
+
+
+ 18
+
+
+
+
+
+
+ 310
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 311
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 312
+
+
+
+
+
+
+
+
+
+
+
+
+ 313
+
+
+ module RelationMethods
+
+
+ 1
+
+
+
+
+
+
+ 314
+
+
+ def update_related
+
+
+ 1
+
+
+
+
+
+
+ 315
+
+
+ counts = RelatedTagCalculator.calculate_from_sample(Danbooru.config.post_sample_size, name)
+
+
+ 0
+
+
+
+
+
+
+ 316
+
+
+ self.related_tags = RelatedTagCalculator.convert_hash_to_string(counts)
+
+
+ 0
+
+
+
+
+
+
+ 317
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 318
+
+
+
+
+
+
+
+
+
+
+
+
+ 319
+
+
+ def update_related_if_outdated
+
+
+ 1
+
+
+
+
+
+
+ 320
+
+
+ updated_related if should_update_related?
+
+
+ 0
+
+
+
+
+
+
+ 321
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 322
+
+
+
+
+
+
+
+
+
+
+
+
+ 323
+
+
+ def related_cache_expiry
+
+
+ 1
+
+
+
+
+
+
+ 324
+
+
+ base = Math.sqrt(post_count)
+
+
+ 0
+
+
+
+
+
+
+ 325
+
+
+ if base > 24
+
+
+ 0
+
+
+
+
+
+
+ 326
+
+
+ 24
+
+
+ 0
+
+
+
+
+
+
+ 327
+
+
+ else
+
+
+
+
+
+
+
+
+
+ 328
+
+
+ base
+
+
+ 0
+
+
+
+
+
+
+ 329
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 330
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 331
+
+
+
+
+
+
+
+
+
+
+
+
+ 332
+
+
+ def should_update_related?
+
+
+ 1
+
+
+
+
+
+
+ 333
+
+
+ related_tags.blank? || related_tags_updated_at < related_cache_expiry.hours.ago
+
+
+ 0
+
+
+
+
+
+
+ 334
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 335
+
+
+
+
+
+
+
+
+
+
+
+
+ 336
+
+
+ def related_tag_array
+
+
+ 1
+
+
+
+
+
+
+ 337
+
+
+ related_tags.split(/ /).in_groups_of(2)
+
+
+ 0
+
+
+
+
+
+
+ 338
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 339
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 340
+
+
+
+
+
+
+
+
+
+
+
+
+ 341
+
+
+ module SuggestionMethods
+
+
+ 1
+
+
+
+
+
+
+ 342
+
+
+ def find_suggestions(query)
+
+
+ 1
+
+
+
+
+
+
+ 343
+
+
+ query_tokens = query.split(/_/)
+
+
+ 0
+
+
+
+
+
+
+ 344
+
+
+
+
+
+
+
+
+
+
+
+
+ 345
+
+
+ if query_tokens.size == 2
+
+
+ 0
+
+
+
+
+
+
+ 346
+
+
+ search_for = query_tokens.reverse.join("_").to_escaped_for_sql_like
+
+
+ 0
+
+
+
+
+
+
+ 347
+
+
+ else
+
+
+
+
+
+
+
+
+
+ 348
+
+
+ search_for = "%" + query.to_escaped_for_sql_like + "%"
+
+
+ 0
+
+
+
+
+
+
+ 349
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 350
+
+
+
+
+
+
+
+
+
+
+
+
+ 351
+
+
+ Tag.where(["name LIKE ? ESCAPE E'\\\\' AND post_count > 0 AND name <> ?", search_for, query]).all(:order => "post_count DESC", :limit => 6, :select => "name").map(&:name).sort
+
+
+ 0
+
+
+
+
+
+
+ 352
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 353
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 354
+
+
+
+
+
+
+
+
+
+
+
+
+ 355
+
+
+ extend ViewCountMethods
+
+
+ 1
+
+
+
+
+
+
+ 356
+
+
+ include CategoryMethods
+
+
+ 1
+
+
+
+
+
+
+ 357
+
+
+ extend StatisticsMethods
+
+
+ 1
+
+
+
+
+
+
+ 358
+
+
+ include NameMethods
+
+
+ 1
+
+
+
+
+
+
+ 359
+
+
+ extend UpdateMethods
+
+
+ 1
+
+
+
+
+
+
+ 360
+
+
+ extend ParseMethods
+
+
+ 1
+
+
+
+
+
+
+ 361
+
+
+ extend SuggestionMethods
+
+
+ 1
+
+
+
+
+
+
+ 362
+
+
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ./app/models/tag_alias.rb
+ 57.89 % covered
+
+
+
+ #
+
+ Hits
+
+
+
+
+
+
+
+ 1
+
+
+ class TagAlias < ActiveRecord::Base
+
+
+ 1
+
+
+
+
+
+
+ 2
+
+
+ attr_accessor :creator_ip_addr
+
+
+ 1
+
+
+
+
+
+
+ 3
+
+
+ after_save :update_posts
+
+
+ 1
+
+
+
+
+
+
+ 4
+
+
+ after_save :clear_cache
+
+
+ 1
+
+
+
+
+
+
+ 5
+
+
+ after_save :clear_remote_cache
+
+
+ 1
+
+
+
+
+
+
+ 6
+
+
+ after_save :update_cache
+
+
+ 1
+
+
+
+
+
+
+ 7
+
+
+ after_destroy :clear_cache
+
+
+ 1
+
+
+
+
+
+
+ 8
+
+
+ after_destroy :clear_remote_cache
+
+
+ 1
+
+
+
+
+
+
+ 9
+
+
+ before_validation :initialize_creator, :on => :create
+
+
+ 1
+
+
+
+
+
+
+ 10
+
+
+ validates_presence_of :creator_id
+
+
+ 1
+
+
+
+
+
+
+ 11
+
+
+ validates_uniqueness_of :antecedent_name
+
+
+ 1
+
+
+
+
+
+
+ 12
+
+
+ validate :absence_of_transitive_relation
+
+
+ 1
+
+
+
+
+
+
+ 13
+
+
+ belongs_to :creator, :class_name => "User"
+
+
+ 1
+
+
+
+
+
+
+ 14
+
+
+
+
+
+
+
+
+
+
+
+
+ 15
+
+
+ def self.to_aliased(names)
+
+
+ 1
+
+
+
+
+
+
+ 16
+
+
+ alias_hash = Cache.get_multi(names.flatten, "ta") do |name|
+
+
+ 60
+
+
+
+
+
+
+ 17
+
+
+ ta = TagAlias.find_by_antecedent_name(name)
+
+
+ 0
+
+
+
+
+
+
+ 18
+
+
+ if ta
+
+
+ 0
+
+
+
+
+
+
+ 19
+
+
+ ta.consequent_name
+
+
+ 0
+
+
+
+
+
+
+ 20
+
+
+ else
+
+
+
+
+
+
+
+
+
+ 21
+
+
+ name
+
+
+ 0
+
+
+
+
+
+
+ 22
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 23
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 24
+
+
+
+
+
+
+
+
+
+
+
+
+ 25
+
+
+ alias_hash.values.flatten.uniq
+
+
+ 60
+
+
+
+
+
+
+ 26
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 27
+
+
+
+
+
+
+
+
+
+
+
+
+ 28
+
+
+ def initialize_creator
+
+
+ 1
+
+
+
+
+
+
+ 29
+
+
+ self.creator_id = CurrentUser.user.id
+
+
+ 0
+
+
+
+
+
+
+ 30
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 31
+
+
+
+
+
+
+
+
+
+
+
+
+ 32
+
+
+ def absence_of_transitive_relation
+
+
+ 1
+
+
+
+
+
+
+ 33
+
+
+ # We don't want a -> b && b -> c chains
+
+
+
+
+
+
+
+
+
+ 34
+
+
+ if self.class.exists?(["antecedent_name = ?", consequent_name]) || self.class.exists?(["consequent_name = ?", antecedent_name])
+
+
+ 0
+
+
+
+
+
+
+ 35
+
+
+ self.errors[:base] << "Tag alias can not create a transitive relation with another tag alias"
+
+
+ 0
+
+
+
+
+
+
+ 36
+
+
+ false
+
+
+ 0
+
+
+
+
+
+
+ 37
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 38
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 39
+
+
+
+
+
+
+
+
+
+
+
+
+ 40
+
+
+ def clear_cache
+
+
+ 1
+
+
+
+
+
+
+ 41
+
+
+ Cache.delete("ta:#{Cache.sanitize(antecedent_name)}")
+
+
+ 0
+
+
+
+
+
+
+ 42
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 43
+
+
+
+
+
+
+
+
+
+
+
+
+ 44
+
+
+ def clear_remote_cache
+
+
+ 1
+
+
+
+
+
+
+ 45
+
+
+ Danbooru.config.other_server_hosts.each do |server|
+
+
+ 0
+
+
+
+
+
+
+ 46
+
+
+ Net::HTTP.delete(URI.parse("http://#{server}/tag_aliases/#{id}/cache"))
+
+
+ 0
+
+
+
+
+
+
+ 47
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 48
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 49
+
+
+
+
+
+
+
+
+
+
+
+
+ 50
+
+
+ def update_cache
+
+
+ 1
+
+
+
+
+
+
+ 51
+
+
+ Cache.put("ta:#{Cache.sanitize(antecedent_name)}", consequent_name)
+
+
+ 0
+
+
+
+
+
+
+ 52
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 53
+
+
+
+
+
+
+
+
+
+
+
+
+ 54
+
+
+ def update_posts
+
+
+ 1
+
+
+
+
+
+
+ 55
+
+
+ Post.find_by_tags(antecedent_name).find_each do |post|
+
+
+ 0
+
+
+
+
+
+
+ 56
+
+
+ escaped_antecedent_name = Regexp.escape(antecedent_name)
+
+
+ 0
+
+
+
+
+
+
+ 57
+
+
+ fixed_tags = post.tag_string.sub(/(?:\A| )#{escaped_antecedent_name}(?:\Z| )/, " #{consequent_name} ").strip
+
+
+ 0
+
+
+
+
+
+
+ 58
+
+
+
+
+
+
+
+
+
+
+
+
+ 59
+
+
+ post.update_attributes(
+
+
+ 0
+
+
+
+
+
+
+ 60
+
+
+ :tag_string => fixed_tags
+
+
+
+
+
+
+
+
+
+ 61
+
+
+ )
+
+
+
+
+
+
+
+
+
+ 62
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 63
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 64
+
+
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ./app/models/tag_implication.rb
+ 51.35 % covered
+
+
+
+ #
+
+ Hits
+
+
+
+
+
+
+
+ 1
+
+
+ class TagImplication < ActiveRecord::Base
+
+
+ 1
+
+
+
+
+
+
+ 2
+
+
+ before_save :clear_cache
+
+
+ 1
+
+
+
+
+
+
+ 3
+
+
+ before_save :update_descendant_names
+
+
+ 1
+
+
+
+
+
+
+ 4
+
+
+ after_save :update_descendant_names_for_parent
+
+
+ 1
+
+
+
+
+
+
+ 5
+
+
+ after_save :update_cache
+
+
+ 1
+
+
+
+
+
+
+ 6
+
+
+ after_save :update_posts
+
+
+ 1
+
+
+
+
+
+
+ 7
+
+
+ after_destroy :clear_cache
+
+
+ 1
+
+
+
+
+
+
+ 8
+
+
+ after_destroy :clear_remote_cache
+
+
+ 1
+
+
+
+
+
+
+ 9
+
+
+ belongs_to :creator, :class_name => "User"
+
+
+ 1
+
+
+
+
+
+
+ 10
+
+
+ before_validation :initialize_creator, :on => :create
+
+
+ 1
+
+
+
+
+
+
+ 11
+
+
+ validates_presence_of :creator_id
+
+
+ 1
+
+
+
+
+
+
+ 12
+
+
+ validates_uniqueness_of :antecedent_name, :scope => :consequent_name
+
+
+ 1
+
+
+
+
+
+
+ 13
+
+
+ validate :absence_of_circular_relation
+
+
+ 1
+
+
+
+
+
+
+ 14
+
+
+
+
+
+
+
+
+
+
+
+
+ 15
+
+
+ module CacheMethods
+
+
+ 1
+
+
+
+
+
+
+ 16
+
+
+ def clear_cache
+
+
+ 1
+
+
+
+
+
+
+ 17
+
+
+ Cache.delete("ti:#{Cache.sanitize(antecedent_name)}")
+
+
+ 0
+
+
+
+
+
+
+ 18
+
+
+ @descendants = nil
+
+
+ 0
+
+
+
+
+
+
+ 19
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 20
+
+
+
+
+
+
+
+
+
+
+
+
+ 21
+
+
+ def clear_remote_cache
+
+
+ 1
+
+
+
+
+
+
+ 22
+
+
+ Danbooru.config.other_server_hosts.each do |server|
+
+
+ 0
+
+
+
+
+
+
+ 23
+
+
+ Net::HTTP.delete(URI.parse("http://#{server}/tag_implications/#{id}/cache"))
+
+
+ 0
+
+
+
+
+
+
+ 24
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 25
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 26
+
+
+
+
+
+
+
+
+
+
+
+
+ 27
+
+
+ def update_cache
+
+
+ 1
+
+
+
+
+
+
+ 28
+
+
+ descendant_names_array
+
+
+ 0
+
+
+
+
+
+
+ 29
+
+
+ true
+
+
+ 0
+
+
+
+
+
+
+ 30
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 31
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 32
+
+
+
+
+
+
+
+
+
+
+
+
+ 33
+
+
+ module DescendantMethods
+
+
+ 1
+
+
+
+
+
+
+ 34
+
+
+ extend ActiveSupport::Concern
+
+
+ 1
+
+
+
+
+
+
+ 35
+
+
+
+
+
+
+
+
+
+
+
+
+ 36
+
+
+ module ClassMethods
+
+
+ 1
+
+
+
+
+
+
+ 37
+
+
+ def with_descendants(names)
+
+
+ 1
+
+
+
+
+
+
+ 38
+
+
+ names + Cache.get_multi(names.flatten, "ti") do |name|
+
+
+
+
+
+
+
+
+
+ 39
+
+
+ ([name] + where(["antecedent_name = ?", name]).all.map {|x| x.descendant_names_array}).flatten
+
+
+ 0
+
+
+
+
+
+
+ 40
+
+
+ end.values.flatten.uniq
+
+
+ 6
+
+
+
+
+
+
+ 41
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 42
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 43
+
+
+
+
+
+
+
+
+
+
+
+
+ 44
+
+
+ def descendants
+
+
+ 1
+
+
+
+
+
+
+ 45
+
+
+ @descendants ||= begin
+
+
+
+
+
+
+
+
+
+ 46
+
+
+ [].tap do |all|
+
+
+ 0
+
+
+
+
+
+
+ 47
+
+
+ children = [consequent_name]
+
+
+ 0
+
+
+
+
+
+
+ 48
+
+
+
+
+
+
+
+
+
+
+
+
+ 49
+
+
+ until children.empty?
+
+
+ 0
+
+
+
+
+
+
+ 50
+
+
+ all.concat(children)
+
+
+ 0
+
+
+
+
+
+
+ 51
+
+
+ children = self.class.where(["antecedent_name IN (?)", children]).all.map(&:consequent_name)
+
+
+ 0
+
+
+
+
+
+
+ 52
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 53
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 54
+
+
+ end
+
+
+ 0
+
+
+
+
+
+
+ 55
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 56
+
+
+
+
+
+
+
+
+
+
+
+
+ 57
+
+
+ def descendant_names_array
+
+
+ 1
+
+
+
+
+
+
+ 58
+
+
+ Cache.get("ti:#{Cache.sanitize(antecedent_name)}") do
+
+
+ 0
+
+
+
+
+
+
+ 59
+
+
+ descendant_names.split(/ /)
+
+
+ 0
+
+
+
+
+
+
+ 60
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 61
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 62
+
+
+
+
+
+
+
+
+
+
+
+
+ 63
+
+
+ def update_descendant_names
+
+
+ 1
+
+
+
+
+
+
+ 64
+
+
+ self.descendant_names = descendants.join(" ")
+
+
+ 0
+
+
+
+
+
+
+ 65
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 66
+
+
+
+
+
+
+
+
+
+
+
+
+ 67
+
+
+ def update_descendant_names!
+
+
+ 1
+
+
+
+
+
+
+ 68
+
+
+ update_descendant_names
+
+
+ 0
+
+
+
+
+
+
+ 69
+
+
+ save!
+
+
+ 0
+
+
+
+
+
+
+ 70
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 71
+
+
+
+
+
+
+
+
+
+
+
+
+ 72
+
+
+ def update_descendant_names_for_parent
+
+
+ 1
+
+
+
+
+
+
+ 73
+
+
+ p = parent
+
+
+ 0
+
+
+
+
+
+
+ 74
+
+
+
+
+
+
+
+
+
+
+
+
+ 75
+
+
+ while p
+
+
+ 0
+
+
+
+
+
+
+ 76
+
+
+ p.update_descendant_names!
+
+
+ 0
+
+
+
+
+
+
+ 77
+
+
+ p = p.parent
+
+
+ 0
+
+
+
+
+
+
+ 78
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 79
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 80
+
+
+
+
+
+
+
+
+
+
+
+
+ 81
+
+
+ def clear_descendants_cache
+
+
+ 1
+
+
+
+
+
+
+ 82
+
+
+ @descendants = nil
+
+
+ 0
+
+
+
+
+
+
+ 83
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 84
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 85
+
+
+
+
+
+
+
+
+
+
+
+
+ 86
+
+
+ module ParentMethods
+
+
+ 1
+
+
+
+
+
+
+ 87
+
+
+ def parent
+
+
+ 1
+
+
+
+
+
+
+ 88
+
+
+ @parent ||= self.class.where(["consequent_name = ?", antecedent_name]).first
+
+
+ 0
+
+
+
+
+
+
+ 89
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 90
+
+
+
+
+
+
+
+
+
+
+
+
+ 91
+
+
+ def clear_parent_cache
+
+
+ 1
+
+
+
+
+
+
+ 92
+
+
+ @parent = nil
+
+
+ 0
+
+
+
+
+
+
+ 93
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 94
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 95
+
+
+
+
+
+
+
+
+
+
+
+
+ 96
+
+
+ include CacheMethods
+
+
+ 1
+
+
+
+
+
+
+ 97
+
+
+ include DescendantMethods
+
+
+ 1
+
+
+
+
+
+
+ 98
+
+
+ include ParentMethods
+
+
+ 1
+
+
+
+
+
+
+ 99
+
+
+
+
+
+
+
+
+
+
+
+
+ 100
+
+
+ def initialize_creator
+
+
+ 1
+
+
+
+
+
+
+ 101
+
+
+ self.creator_id = CurrentUser.user.id
+
+
+ 0
+
+
+
+
+
+
+ 102
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 103
+
+
+
+
+
+
+
+
+
+
+
+
+ 104
+
+
+ def absence_of_circular_relation
+
+
+ 1
+
+
+
+
+
+
+ 105
+
+
+ # We don't want a -> b && b -> a chains
+
+
+
+
+
+
+
+
+
+ 106
+
+
+ if self.class.exists?(["antecedent_name = ? and consequent_name = ?", consequent_name, antecedent_name])
+
+
+ 0
+
+
+
+
+
+
+ 107
+
+
+ self.errors[:base] << "Tag implication can not create a circular relation with another tag implication"
+
+
+ 0
+
+
+
+
+
+
+ 108
+
+
+ false
+
+
+ 0
+
+
+
+
+
+
+ 109
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 110
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 111
+
+
+
+
+
+
+
+
+
+
+
+
+ 112
+
+
+ def update_posts
+
+
+ 1
+
+
+
+
+
+
+ 113
+
+
+ Post.find_by_tags(antecedent_name).find_each do |post|
+
+
+ 0
+
+
+
+
+
+
+ 114
+
+
+ escaped_antecedent_name = Regexp.escape(antecedent_name)
+
+
+ 0
+
+
+
+
+
+
+ 115
+
+
+ fixed_tags = post.tag_string.sub(/(?:\A| )#{escaped_antecedent_name}(?:\Z| )/, " #{antecedent_name} #{descendant_names} ").strip
+
+
+ 0
+
+
+
+
+
+
+ 116
+
+
+ post.update_attributes(
+
+
+ 0
+
+
+
+
+
+
+ 117
+
+
+ :tag_string => fixed_tags
+
+
+
+
+
+
+
+
+
+ 118
+
+
+ )
+
+
+
+
+
+
+
+
+
+ 119
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 120
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 121
+
+
+
+
+
+
+
+
+
+
+
+
+ 122
+
+
+ def reload(options = {})
+
+
+ 1
+
+
+
+
+
+
+ 123
+
+
+ super
+
+
+ 0
+
+
+
+
+
+
+ 124
+
+
+ clear_parent_cache
+
+
+ 0
+
+
+
+
+
+
+ 125
+
+
+ clear_descendants_cache
+
+
+ 0
+
+
+
+
+
+
+ 126
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 127
+
+
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ./app/models/tag_subscription.rb
+ 34.78 % covered
+
+
+
+ #
+
+ Hits
+
+
+
+
+
+
+
+ 1
+
+
+ class TagSubscription < ActiveRecord::Base
+
+
+ 1
+
+
+
+
+
+
+ 2
+
+
+ belongs_to :owner, :class_name => "User"
+
+
+ 1
+
+
+
+
+
+
+ 3
+
+
+ before_create :initialize_post_ids
+
+
+ 1
+
+
+
+
+
+
+ 4
+
+
+ before_save :normalize_name
+
+
+ 1
+
+
+
+
+
+
+ 5
+
+
+ before_save :limit_tag_count
+
+
+ 1
+
+
+
+
+
+
+ 6
+
+
+ scope :visible, :conditions => "is_visible_on_profile = TRUE"
+
+
+ 1
+
+
+
+
+
+
+ 7
+
+
+ attr_accessible :name, :tag_query, :post_ids, :is_visible_on_profile
+
+
+ 1
+
+
+
+
+
+
+ 8
+
+
+
+
+
+
+
+
+
+
+
+
+ 9
+
+
+ def normalize_name
+
+
+ 1
+
+
+
+
+
+
+ 10
+
+
+ self.name = name.gsub(/\W/, "_")
+
+
+ 0
+
+
+
+
+
+
+ 11
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 12
+
+
+
+
+
+
+
+
+
+
+
+
+ 13
+
+
+ def initialize_post_ids
+
+
+ 1
+
+
+
+
+
+
+ 14
+
+
+ process
+
+
+ 0
+
+
+
+
+
+
+ 15
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 16
+
+
+
+
+
+
+
+
+
+
+
+
+ 17
+
+
+ def tag_query_array
+
+
+ 1
+
+
+
+
+
+
+ 18
+
+
+ Tag.scan_query(tag_query)
+
+
+ 0
+
+
+
+
+
+
+ 19
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 20
+
+
+
+
+
+
+
+
+
+
+
+
+ 21
+
+
+ def limit_tag_count
+
+
+ 1
+
+
+
+
+
+
+ 22
+
+
+ self.tag_query = tag_query_array.slice(0, 20).join(" ")
+
+
+ 0
+
+
+
+
+
+
+ 23
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 24
+
+
+
+
+
+
+
+
+
+
+
+
+ 25
+
+
+ def process
+
+
+ 1
+
+
+
+
+
+
+ 26
+
+
+ post_ids = tag_query_array.inject([]) do |all, tag|
+
+
+ 0
+
+
+
+
+
+
+ 27
+
+
+ all += Post.find_by_tags(tag, :limit => Danbooru.config.tag_subscription_post_limit / 3, :select => "posts.id", :order => "posts.id desc").map(&:id)
+
+
+ 0
+
+
+
+
+
+
+ 28
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 29
+
+
+ self.post_ids = post_ids.sort.reverse.slice(0, Danbooru.config.tag_subscription_post_limit).join(",")
+
+
+ 0
+
+
+
+
+
+
+ 30
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 31
+
+
+
+
+
+
+
+
+
+
+
+
+ 32
+
+
+ def self.find_tags(subscription_name)
+
+
+ 1
+
+
+
+
+
+
+ 33
+
+
+ if subscription_name =~ /^(.+?):(.+)$/
+
+
+ 0
+
+
+
+
+
+
+ 34
+
+
+ user_name = $1
+
+
+ 0
+
+
+
+
+
+
+ 35
+
+
+ sub_group = $2
+
+
+ 0
+
+
+
+
+
+
+ 36
+
+
+ else
+
+
+
+
+
+
+
+
+
+ 37
+
+
+ user_name = subscription_name
+
+
+ 0
+
+
+
+
+
+
+ 38
+
+
+ sub_group = nil
+
+
+ 0
+
+
+
+
+
+
+ 39
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 40
+
+
+
+
+
+
+
+
+
+
+
+
+ 41
+
+
+ user = User.find_by_name(user_name)
+
+
+ 0
+
+
+
+
+
+
+ 42
+
+
+ if user
+
+
+ 0
+
+
+
+
+
+
+ 43
+
+
+ relation = where(["owner_id = ?", user.id])
+
+
+ 0
+
+
+
+
+
+
+ 44
+
+
+
+
+
+
+
+
+
+
+
+
+ 45
+
+
+ if sub_group
+
+
+ 0
+
+
+
+
+
+
+ 46
+
+
+ relation = relation.where(["name ILIKE ? ESCAPE E'\\\\'", sub_group.to_escaped_for_sql_like])
+
+
+ 0
+
+
+
+
+
+
+ 47
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 48
+
+
+
+
+
+
+
+
+
+
+
+
+ 49
+
+
+ relation.map {|x| x.tag_query.split(/ /)}.flatten
+
+
+ 0
+
+
+
+
+
+
+ 50
+
+
+ else
+
+
+
+
+
+
+
+
+
+ 51
+
+
+ []
+
+
+ 0
+
+
+
+
+
+
+ 52
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 53
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 54
+
+
+
+
+
+
+
+
+
+
+
+
+ 55
+
+
+ def self.find_post_ids(user_id, name = nil, limit = Danbooru.config.tag_subscription_post_limit)
+
+
+ 1
+
+
+
+
+
+
+ 56
+
+
+ relation = where(["owner_id = ?", user_id])
+
+
+ 0
+
+
+
+
+
+
+ 57
+
+
+
+
+
+
+
+
+
+
+
+
+ 58
+
+
+ if name
+
+
+ 0
+
+
+
+
+
+
+ 59
+
+
+ relation = relation.where(["name ILIKE ? ESCAPE E'\\\\'", name.to_escaped_for_sql_like])
+
+
+ 0
+
+
+
+
+
+
+ 60
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 61
+
+
+
+
+
+
+
+
+
+
+
+
+ 62
+
+
+ relation.map {|x| x.post_ids.split(/,/)}.flatten.uniq.map(&:to_i).sort.reverse.slice(0, limit)
+
+
+ 0
+
+
+
+
+
+
+ 63
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 64
+
+
+
+
+
+
+
+
+
+
+
+
+ 65
+
+
+ def self.find_posts(user_id, name = nil, limit = Danbooru.config.tag_subscription_post_limit)
+
+
+ 1
+
+
+
+
+
+
+ 66
+
+
+ Post.where(["id in (?)", find_post_ids(user_id, name, limit)]).all(:order => "id DESC", :limit => limit)
+
+
+ 0
+
+
+
+
+
+
+ 67
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 68
+
+
+
+
+
+
+
+
+
+
+
+
+ 69
+
+
+ def self.process_all
+
+
+ 1
+
+
+
+
+
+
+ 70
+
+
+ all.each do |tag_subscription|
+
+
+ 0
+
+
+
+
+
+
+ 71
+
+
+ if $job_task_daemon_active != false && tag_subscription.owner.is_privileged?
+
+
+ 0
+
+
+
+
+
+
+ 72
+
+
+ begin
+
+
+ 0
+
+
+
+
+
+
+ 73
+
+
+ tag_subscription.process
+
+
+ 0
+
+
+
+
+
+
+ 74
+
+
+ tag_subscription.save
+
+
+ 0
+
+
+
+
+
+
+ 75
+
+
+ rescue Exception => x
+
+
+
+
+
+
+
+
+
+ 76
+
+
+ raise if Rails.environment != "production"
+
+
+ 0
+
+
+
+
+
+
+ 77
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 78
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 79
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 80
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 81
+
+
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ./app/models/unapproval.rb
+ 100.0 % covered
+
+
+
+ #
+
+ Hits
+
+
+
+
+
+
+
+ 1
+
+
+ class Unapproval < ActiveRecord::Base
+
+
+ 1
+
+
+
+
+
+
+ 2
+
+
+ class Error < Exception ; end
+
+
+ 1
+
+
+
+
+
+
+ 3
+
+
+
+
+
+
+
+
+
+
+
+
+ 4
+
+
+ belongs_to :unapprover, :class_name => "User"
+
+
+ 1
+
+
+
+
+
+
+ 5
+
+
+ validates_presence_of :reason, :unapprover_id, :unapprover_ip_addr
+
+
+ 1
+
+
+
+
+
+
+ 6
+
+
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ./app/models/upload.rb
+ 36.99 % covered
+
+
+
+ #
+
+ Hits
+
+
+
+
+
+
+
+ 1
+
+
+ require "danbooru_image_resizer/danbooru_image_resizer"
+
+
+ 1
+
+
+
+
+
+
+ 2
+
+
+ require "tmpdir"
+
+
+ 1
+
+
+
+
+
+
+ 3
+
+
+
+
+
+
+
+
+
+
+
+
+ 4
+
+
+ class Upload < ActiveRecord::Base
+
+
+ 1
+
+
+
+
+
+
+ 5
+
+
+ class Error < Exception ; end
+
+
+ 1
+
+
+
+
+
+
+ 6
+
+
+
+
+
+
+
+
+
+
+
+
+ 7
+
+
+ attr_accessor :file, :image_width, :image_height, :file_ext, :md5, :file_size
+
+
+ 1
+
+
+
+
+
+
+ 8
+
+
+ belongs_to :uploader, :class_name => "User"
+
+
+ 1
+
+
+
+
+
+
+ 9
+
+
+ belongs_to :post
+
+
+ 1
+
+
+
+
+
+
+ 10
+
+
+ before_validation :initialize_uploader, :on => :create
+
+
+ 1
+
+
+
+
+
+
+ 11
+
+
+ before_validation :initialize_status, :on => :create
+
+
+ 1
+
+
+
+
+
+
+ 12
+
+
+ before_create :convert_cgi_file
+
+
+ 1
+
+
+
+
+
+
+ 13
+
+
+ after_destroy :delete_temp_file
+
+
+ 1
+
+
+
+
+
+
+ 14
+
+
+ validate :uploader_is_not_limited
+
+
+ 1
+
+
+
+
+
+
+ 15
+
+
+
+
+
+
+
+
+
+
+
+
+ 16
+
+
+ module ValidationMethods
+
+
+ 1
+
+
+
+
+
+
+ 17
+
+
+ def uploader_is_not_limited
+
+
+ 1
+
+
+
+
+
+
+ 18
+
+
+ if !uploader.can_upload?
+
+
+ 0
+
+
+
+
+
+
+ 19
+
+
+ update_attribute(:status, "error: uploader has reached their daily limit")
+
+
+ 0
+
+
+
+
+
+
+ 20
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 21
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 22
+
+
+
+
+
+
+
+
+
+
+
+
+ 23
+
+
+ # Because uploads are processed serially, there's no race condition here.
+
+
+
+
+
+
+
+
+
+ 24
+
+
+ def validate_md5_uniqueness
+
+
+ 1
+
+
+
+
+
+
+ 25
+
+
+ md5_post = Post.find_by_md5(md5)
+
+
+ 0
+
+
+
+
+
+
+ 26
+
+
+ merge_tags(md5_post) if md5_post
+
+
+ 0
+
+
+
+
+
+
+ 27
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 28
+
+
+
+
+
+
+
+
+
+
+
+
+ 29
+
+
+ def validate_file_exists
+
+
+ 1
+
+
+
+
+
+
+ 30
+
+
+ unless File.exists?(file_path)
+
+
+ 0
+
+
+
+
+
+
+ 31
+
+
+ update_attribute(:status, "error: file does not exist")
+
+
+ 0
+
+
+
+
+
+
+ 32
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 33
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 34
+
+
+
+
+
+
+
+
+
+
+
+
+ 35
+
+
+ def validate_file_content_type
+
+
+ 1
+
+
+
+
+
+
+ 36
+
+
+ unless is_valid_content_type?
+
+
+ 0
+
+
+
+
+
+
+ 37
+
+
+ update_attribute(:status, "error: invalid content type (#{file_ext} not allowed)")
+
+
+ 0
+
+
+
+
+
+
+ 38
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 39
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 40
+
+
+
+
+
+
+
+
+
+
+
+
+ 41
+
+
+ def validate_md5_confirmation
+
+
+ 1
+
+
+
+
+
+
+ 42
+
+
+ if !md5_confirmation.blank? && md5_confirmation != md5
+
+
+ 0
+
+
+
+
+
+
+ 43
+
+
+ update_attribute(:status, "error: md5 mismatch")
+
+
+ 0
+
+
+
+
+
+
+ 44
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 45
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 46
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 47
+
+
+
+
+
+
+
+
+
+
+
+
+ 48
+
+
+ module ConversionMethods
+
+
+ 1
+
+
+
+
+
+
+ 49
+
+
+ def process!
+
+
+ 1
+
+
+
+
+
+
+ 50
+
+
+ CurrentUser.scoped(uploader, uploader_ip_addr) do
+
+
+ 0
+
+
+
+
+
+
+ 51
+
+
+ update_attribute(:status, "processing")
+
+
+ 0
+
+
+
+
+
+
+ 52
+
+
+ if is_downloadable?
+
+
+ 0
+
+
+
+
+
+
+ 53
+
+
+ download_from_source(temp_file_path)
+
+
+ 0
+
+
+
+
+
+
+ 54
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 55
+
+
+ validate_file_exists
+
+
+ 0
+
+
+
+
+
+
+ 56
+
+
+ self.file_ext = content_type_to_file_ext(content_type)
+
+
+ 0
+
+
+
+
+
+
+ 57
+
+
+ validate_file_content_type
+
+
+ 0
+
+
+
+
+
+
+ 58
+
+
+ calculate_hash(file_path)
+
+
+ 0
+
+
+
+
+
+
+ 59
+
+
+ validate_md5_uniqueness
+
+
+ 0
+
+
+
+
+
+
+ 60
+
+
+ validate_md5_confirmation
+
+
+ 0
+
+
+
+
+
+
+ 61
+
+
+ calculate_file_size(file_path)
+
+
+ 0
+
+
+
+
+
+
+ 62
+
+
+ calculate_dimensions(file_path) if has_dimensions?
+
+
+ 0
+
+
+
+
+
+
+ 63
+
+
+ generate_resizes(file_path)
+
+
+ 0
+
+
+
+
+
+
+ 64
+
+
+ move_file
+
+
+ 0
+
+
+
+
+
+
+ 65
+
+
+ post = convert_to_post
+
+
+ 0
+
+
+
+
+
+
+ 66
+
+
+ if post.save
+
+
+ 0
+
+
+
+
+
+
+ 67
+
+
+ update_attributes(:status => "completed", :post_id => post.id)
+
+
+ 0
+
+
+
+
+
+
+ 68
+
+
+ else
+
+
+
+
+
+
+
+
+
+ 69
+
+
+ update_attribute(:status, "error: " + post.errors.full_messages.join(", "))
+
+
+ 0
+
+
+
+
+
+
+ 70
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 71
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 72
+
+
+ rescue Exception => x
+
+
+
+
+
+
+
+
+
+ 73
+
+
+ update_attribute(:status, "error: #{x} - #{x.message}")
+
+
+ 0
+
+
+
+
+
+
+ 74
+
+
+ ensure
+
+
+
+
+
+
+
+
+
+ 75
+
+
+ delete_temp_file
+
+
+ 0
+
+
+
+
+
+
+ 76
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 77
+
+
+
+
+
+
+
+
+
+
+
+
+ 78
+
+
+ def convert_to_post
+
+
+ 1
+
+
+
+
+
+
+ 79
+
+
+ Post.new.tap do |p|
+
+
+ 0
+
+
+
+
+
+
+ 80
+
+
+ p.tag_string = tag_string
+
+
+ 0
+
+
+
+
+
+
+ 81
+
+
+ p.md5 = md5
+
+
+ 0
+
+
+
+
+
+
+ 82
+
+
+ p.file_ext = file_ext
+
+
+ 0
+
+
+
+
+
+
+ 83
+
+
+ p.image_width = image_width
+
+
+ 0
+
+
+
+
+
+
+ 84
+
+
+ p.image_height = image_height
+
+
+ 0
+
+
+
+
+
+
+ 85
+
+
+ p.rating = rating
+
+
+ 0
+
+
+
+
+
+
+ 86
+
+
+ p.source = source
+
+
+ 0
+
+
+
+
+
+
+ 87
+
+
+ p.file_size = file_size
+
+
+ 0
+
+
+
+
+
+
+ 88
+
+
+
+
+
+
+
+
+
+
+
+
+ 89
+
+
+ unless uploader.is_contributor?
+
+
+ 0
+
+
+
+
+
+
+ 90
+
+
+ p.is_pending = true
+
+
+ 0
+
+
+
+
+
+
+ 91
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 92
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 93
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 94
+
+
+
+
+
+
+
+
+
+
+
+
+ 95
+
+
+ def merge_tags(post)
+
+
+ 1
+
+
+
+
+
+
+ 96
+
+
+ post.tag_string += " #{tag_string}"
+
+
+ 0
+
+
+
+
+
+
+ 97
+
+
+ post.updater_id = uploader_id
+
+
+ 0
+
+
+
+
+
+
+ 98
+
+
+ post.updater_ip_addr = uploader_ip_addr
+
+
+ 0
+
+
+
+
+
+
+ 99
+
+
+ post.save
+
+
+ 0
+
+
+
+
+
+
+ 100
+
+
+ update_attribute(:status, "duplicate: #{post.id}")
+
+
+ 0
+
+
+
+
+
+
+ 101
+
+
+ raise
+
+
+ 0
+
+
+
+
+
+
+ 102
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 103
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 104
+
+
+
+
+
+
+
+
+
+
+
+
+ 105
+
+
+ module FileMethods
+
+
+ 1
+
+
+
+
+
+
+ 106
+
+
+ def delete_temp_file
+
+
+ 1
+
+
+
+
+
+
+ 107
+
+
+ FileUtils.rm_f(temp_file_path)
+
+
+ 0
+
+
+
+
+
+
+ 108
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 109
+
+
+
+
+
+
+
+
+
+
+
+
+ 110
+
+
+ def move_file
+
+
+ 1
+
+
+
+
+
+
+ 111
+
+
+ FileUtils.mv(file_path, md5_file_path)
+
+
+ 0
+
+
+
+
+
+
+ 112
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 113
+
+
+
+
+
+
+
+
+
+
+
+
+ 114
+
+
+ def calculate_file_size(source_path)
+
+
+ 1
+
+
+
+
+
+
+ 115
+
+
+ self.file_size = File.size(source_path)
+
+
+ 0
+
+
+
+
+
+
+ 116
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 117
+
+
+
+
+
+
+
+
+
+
+
+
+ 118
+
+
+ # Calculates the MD5 based on whatever is in temp_file_path
+
+
+
+
+
+
+
+
+
+ 119
+
+
+ def calculate_hash(source_path)
+
+
+ 1
+
+
+
+
+
+
+ 120
+
+
+ self.md5 = Digest::MD5.file(source_path).hexdigest
+
+
+ 0
+
+
+
+
+
+
+ 121
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 122
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 123
+
+
+
+
+
+
+
+
+
+
+
+
+ 124
+
+
+ module ResizerMethods
+
+
+ 1
+
+
+
+
+
+
+ 125
+
+
+ def generate_resizes(source_path)
+
+
+ 1
+
+
+
+
+
+
+ 126
+
+
+ generate_resize_for(Danbooru.config.small_image_width, Danbooru.config.small_image_width, source_path)
+
+
+ 0
+
+
+
+
+
+
+ 127
+
+
+ generate_resize_for(Danbooru.config.medium_image_width, nil, source_path)
+
+
+ 0
+
+
+
+
+
+
+ 128
+
+
+ generate_resize_for(Danbooru.config.large_image_width, nil, source_path)
+
+
+ 0
+
+
+
+
+
+
+ 129
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 130
+
+
+
+
+
+
+
+
+
+
+
+
+ 131
+
+
+ def generate_resize_for(width, height, source_path)
+
+
+ 1
+
+
+
+
+
+
+ 132
+
+
+ return if width.nil?
+
+
+ 0
+
+
+
+
+
+
+ 133
+
+
+ return unless image_width > width
+
+
+ 0
+
+
+
+
+
+
+ 134
+
+
+ return unless height.nil? || image_height > height
+
+
+ 0
+
+
+
+
+
+
+ 135
+
+
+
+
+
+
+
+
+
+
+
+
+ 136
+
+
+ unless File.exists?(source_path)
+
+
+ 0
+
+
+
+
+
+
+ 137
+
+
+ raise Error.new("file not found")
+
+
+ 0
+
+
+
+
+
+
+ 138
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 139
+
+
+
+
+
+
+
+
+
+
+
+
+ 140
+
+
+ size = Danbooru.reduce_to({:width => image_width, :height => image_height}, {:width => width, :height => height})
+
+
+ 0
+
+
+
+
+
+
+ 141
+
+
+
+
+
+
+
+
+
+
+
+
+ 142
+
+
+ # If we're not reducing the resolution, only reencode if the source image larger than
+
+
+
+
+
+
+
+
+
+ 143
+
+
+ # 200 kilobytes.
+
+
+
+
+
+
+
+
+
+ 144
+
+
+ if size[:width] == image_width && size[:height] == image_height && File.size?(source_path) < 200.kilobytes
+
+
+ 0
+
+
+
+
+
+
+ 145
+
+
+ return
+
+
+ 0
+
+
+
+
+
+
+ 146
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 147
+
+
+
+
+
+
+
+
+
+
+
+
+ 148
+
+
+ Danbooru.resize(file_ext, source_path, resized_file_path_for(width), size, 90)
+
+
+ 0
+
+
+
+
+
+
+ 149
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 150
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 151
+
+
+
+
+
+
+
+
+
+
+
+
+ 152
+
+
+ module DimensionMethods
+
+
+ 1
+
+
+
+
+
+
+ 153
+
+
+ # Figures out the dimensions of the image.
+
+
+
+
+
+
+
+
+
+ 154
+
+
+ def calculate_dimensions(file_path)
+
+
+ 1
+
+
+
+
+
+
+ 155
+
+
+ image_size = ImageSize.new(File.open(file_path, "rb"))
+
+
+ 0
+
+
+
+
+
+
+ 156
+
+
+ self.image_width = image_size.get_width
+
+
+ 0
+
+
+
+
+
+
+ 157
+
+
+ self.image_height = image_size.get_height
+
+
+ 0
+
+
+
+
+
+
+ 158
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 159
+
+
+
+
+
+
+
+
+
+
+
+
+ 160
+
+
+ # Does this file have image dimensions?
+
+
+
+
+
+
+
+
+
+ 161
+
+
+ def has_dimensions?
+
+
+ 1
+
+
+
+
+
+
+ 162
+
+
+ %w(jpg gif png swf).include?(file_ext)
+
+
+ 0
+
+
+
+
+
+
+ 163
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 164
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 165
+
+
+
+
+
+
+
+
+
+
+
+
+ 166
+
+
+ module ContentTypeMethods
+
+
+ 1
+
+
+
+
+
+
+ 167
+
+
+ def is_valid_content_type?
+
+
+ 1
+
+
+
+
+
+
+ 168
+
+
+ file_ext =~ /jpg|gif|png|swf/
+
+
+ 0
+
+
+
+
+
+
+ 169
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 170
+
+
+
+
+
+
+
+
+
+
+
+
+ 171
+
+
+ def content_type_to_file_ext(content_type)
+
+
+ 1
+
+
+
+
+
+
+ 172
+
+
+ case content_type
+
+
+ 0
+
+
+
+
+
+
+ 173
+
+
+ when "image/jpeg"
+
+
+
+
+
+
+
+
+
+ 174
+
+
+ "jpg"
+
+
+ 0
+
+
+
+
+
+
+ 175
+
+
+
+
+
+
+
+
+
+
+
+
+ 176
+
+
+ when "image/gif"
+
+
+
+
+
+
+
+
+
+ 177
+
+
+ "gif"
+
+
+ 0
+
+
+
+
+
+
+ 178
+
+
+
+
+
+
+
+
+
+
+
+
+ 179
+
+
+ when "image/png"
+
+
+
+
+
+
+
+
+
+ 180
+
+
+ "png"
+
+
+ 0
+
+
+
+
+
+
+ 181
+
+
+
+
+
+
+
+
+
+
+
+
+ 182
+
+
+ when "application/x-shockwave-flash"
+
+
+
+
+
+
+
+
+
+ 183
+
+
+ "swf"
+
+
+ 0
+
+
+
+
+
+
+ 184
+
+
+
+
+
+
+
+
+
+
+
+
+ 185
+
+
+ else
+
+
+
+
+
+
+
+
+
+ 186
+
+
+ "bin"
+
+
+ 0
+
+
+
+
+
+
+ 187
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 188
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 189
+
+
+
+
+
+
+
+
+
+
+
+
+ 190
+
+
+ # Converts a content type string to a file extension
+
+
+
+
+
+
+
+
+
+ 191
+
+
+ def file_ext_to_content_type(file_ext)
+
+
+ 1
+
+
+
+
+
+
+ 192
+
+
+ case file_ext
+
+
+ 0
+
+
+
+
+
+
+ 193
+
+
+ when /\.jpeg$|\.jpg$/
+
+
+
+
+
+
+
+
+
+ 194
+
+
+ "image/jpeg"
+
+
+ 0
+
+
+
+
+
+
+ 195
+
+
+
+
+
+
+
+
+
+
+
+
+ 196
+
+
+ when /\.gif$/
+
+
+
+
+
+
+
+
+
+ 197
+
+
+ "image/gif"
+
+
+ 0
+
+
+
+
+
+
+ 198
+
+
+
+
+
+
+
+
+
+
+
+
+ 199
+
+
+ when /\.png$/
+
+
+
+
+
+
+
+
+
+ 200
+
+
+ "image/png"
+
+
+ 0
+
+
+
+
+
+
+ 201
+
+
+
+
+
+
+
+
+
+
+
+
+ 202
+
+
+ when /\.swf$/
+
+
+
+
+
+
+
+
+
+ 203
+
+
+ "application/x-shockwave-flash"
+
+
+ 0
+
+
+
+
+
+
+ 204
+
+
+
+
+
+
+
+
+
+
+
+
+ 205
+
+
+ else
+
+
+
+
+
+
+
+
+
+ 206
+
+
+ "application/octet-stream"
+
+
+ 0
+
+
+
+
+
+
+ 207
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 208
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 209
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 210
+
+
+
+
+
+
+
+
+
+
+
+
+ 211
+
+
+ module FilePathMethods
+
+
+ 1
+
+
+
+
+
+
+ 212
+
+
+ def md5_file_path
+
+
+ 1
+
+
+
+
+
+
+ 213
+
+
+ prefix = Rails.env == "test" ? "test." : ""
+
+
+ 0
+
+
+
+
+
+
+ 214
+
+
+ "#{Rails.root}/public/data/original/#{prefix}#{md5}.#{file_ext}"
+
+
+ 0
+
+
+
+
+
+
+ 215
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 216
+
+
+
+
+
+
+
+
+
+
+
+
+ 217
+
+
+ def resized_file_path_for(width)
+
+
+ 1
+
+
+
+
+
+
+ 218
+
+
+ prefix = Rails.env == "test" ? "test." : ""
+
+
+ 0
+
+
+
+
+
+
+ 219
+
+
+
+
+
+
+
+
+
+
+
+
+ 220
+
+
+ case width
+
+
+ 0
+
+
+
+
+
+
+ 221
+
+
+ when Danbooru.config.small_image_width
+
+
+
+
+
+
+
+
+
+ 222
+
+
+ "#{Rails.root}/public/data/preview/#{prefix}#{md5}.jpg"
+
+
+ 0
+
+
+
+
+
+
+ 223
+
+
+
+
+
+
+
+
+
+
+
+
+ 224
+
+
+ when Danbooru.config.medium_image_width
+
+
+
+
+
+
+
+
+
+ 225
+
+
+ "#{Rails.root}/public/data/medium/#{prefix}#{md5}.jpg"
+
+
+ 0
+
+
+
+
+
+
+ 226
+
+
+
+
+
+
+
+
+
+
+
+
+ 227
+
+
+ when Danbooru.config.large_image_width
+
+
+
+
+
+
+
+
+
+ 228
+
+
+ "#{Rails.root}/public/data/large/#{prefix}#{md5}.jpg"
+
+
+ 0
+
+
+
+
+
+
+ 229
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 230
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 231
+
+
+
+
+
+
+
+
+
+
+
+
+ 232
+
+
+ def temp_file_path
+
+
+ 1
+
+
+
+
+
+
+ 233
+
+
+ @temp_file_path ||= File.join(Rails.root, "tmp", "#{Time.now.to_f}.#{$PROCESS_ID}")
+
+
+ 0
+
+
+
+
+
+
+ 234
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 235
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 236
+
+
+
+
+
+
+
+
+
+
+
+
+ 237
+
+
+ module DownloaderMethods
+
+
+ 1
+
+
+
+
+
+
+ 238
+
+
+ # Determines whether the source is downloadable
+
+
+
+
+
+
+
+
+
+ 239
+
+
+ def is_downloadable?
+
+
+ 1
+
+
+
+
+
+
+ 240
+
+
+ source =~ /^http:\/\// && file_path.blank?
+
+
+ 0
+
+
+
+
+
+
+ 241
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 242
+
+
+
+
+
+
+
+
+
+
+
+
+ 243
+
+
+ # Downloads the file to destination_path
+
+
+
+
+
+
+
+
+
+ 244
+
+
+ def download_from_source(destination_path)
+
+
+ 1
+
+
+
+
+
+
+ 245
+
+
+ download = Download.new(source, destination_path)
+
+
+ 0
+
+
+
+
+
+
+ 246
+
+
+ download.download!
+
+
+ 0
+
+
+
+
+
+
+ 247
+
+
+ self.file_path = destination_path
+
+
+ 0
+
+
+
+
+
+
+ 248
+
+
+ self.content_type = download.content_type || file_ext_to_content_type(source)
+
+
+ 0
+
+
+
+
+
+
+ 249
+
+
+ self.file_ext = content_type_to_file_ext(content_type)
+
+
+ 0
+
+
+
+
+
+
+ 250
+
+
+ self.source = download.source
+
+
+ 0
+
+
+
+
+
+
+ 251
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 252
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 253
+
+
+
+
+
+
+
+
+
+
+
+
+ 254
+
+
+ module CgiFileMethods
+
+
+ 1
+
+
+
+
+
+
+ 255
+
+
+ def convert_cgi_file
+
+
+ 1
+
+
+
+
+
+
+ 256
+
+
+ return if file.blank? || file.size == 0
+
+
+ 0
+
+
+
+
+
+
+ 257
+
+
+
+
+
+
+
+
+
+
+
+
+ 258
+
+
+ self.file_path = temp_file_path
+
+
+ 0
+
+
+
+
+
+
+ 259
+
+
+
+
+
+
+
+
+
+
+
+
+ 260
+
+
+ if file.local_path
+
+
+ 0
+
+
+
+
+
+
+ 261
+
+
+ FileUtils.cp(file.local_path, file_path)
+
+
+ 0
+
+
+
+
+
+
+ 262
+
+
+ else
+
+
+
+
+
+
+
+
+
+ 263
+
+
+ File.open(file_path, 'wb') do |out|
+
+
+ 0
+
+
+
+
+
+
+ 264
+
+
+ out.write(file.read)
+
+
+ 0
+
+
+
+
+
+
+ 265
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 266
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 267
+
+
+ self.content_type = file.content_type || file_ext_to_content_type(file.original_filename)
+
+
+ 0
+
+
+
+
+
+
+ 268
+
+
+ self.file_ext = content_type_to_file_ext(content_type)
+
+
+ 0
+
+
+
+
+
+
+ 269
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 270
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 271
+
+
+
+
+
+
+
+
+
+
+
+
+ 272
+
+
+ module StatusMethods
+
+
+ 1
+
+
+
+
+
+
+ 273
+
+
+ def initialize_status
+
+
+ 1
+
+
+
+
+
+
+ 274
+
+
+ self.status = "pending"
+
+
+ 0
+
+
+
+
+
+
+ 275
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 276
+
+
+
+
+
+
+
+
+
+
+
+
+ 277
+
+
+ def is_pending?
+
+
+ 1
+
+
+
+
+
+
+ 278
+
+
+ status == "pending"
+
+
+ 0
+
+
+
+
+
+
+ 279
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 280
+
+
+
+
+
+
+
+
+
+
+
+
+ 281
+
+
+ def is_completed?
+
+
+ 1
+
+
+
+
+
+
+ 282
+
+
+ status == "completed"
+
+
+ 0
+
+
+
+
+
+
+ 283
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 284
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 285
+
+
+
+
+
+
+
+
+
+
+
+
+ 286
+
+
+ module UploaderMethods
+
+
+ 1
+
+
+
+
+
+
+ 287
+
+
+ def initialize_uploader
+
+
+ 1
+
+
+
+
+
+
+ 288
+
+
+ self.uploader_id = CurrentUser.user.id
+
+
+ 0
+
+
+
+
+
+
+ 289
+
+
+ self.uploader_ip_addr = CurrentUser.ip_addr
+
+
+ 0
+
+
+
+
+
+
+ 290
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 291
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 292
+
+
+
+
+
+
+
+
+
+
+
+
+ 293
+
+
+ include ConversionMethods
+
+
+ 1
+
+
+
+
+
+
+ 294
+
+
+ include ValidationMethods
+
+
+ 1
+
+
+
+
+
+
+ 295
+
+
+ include FileMethods
+
+
+ 1
+
+
+
+
+
+
+ 296
+
+
+ include ResizerMethods
+
+
+ 1
+
+
+
+
+
+
+ 297
+
+
+ include DimensionMethods
+
+
+ 1
+
+
+
+
+
+
+ 298
+
+
+ include ContentTypeMethods
+
+
+ 1
+
+
+
+
+
+
+ 299
+
+
+ include DownloaderMethods
+
+
+ 1
+
+
+
+
+
+
+ 300
+
+
+ include FilePathMethods
+
+
+ 1
+
+
+
+
+
+
+ 301
+
+
+ include CgiFileMethods
+
+
+ 1
+
+
+
+
+
+
+ 302
+
+
+ include StatusMethods
+
+
+ 1
+
+
+
+
+
+
+ 303
+
+
+ include UploaderMethods
+
+
+ 1
+
+
+
+
+
+
+ 304
+
+
+
+
+
+
+
+
+
+
+
+
+ 305
+
+
+ def presenter
+
+
+ 1
+
+
+
+
+
+
+ 306
+
+
+ @presenter ||= UploadPresenter.new(self)
+
+
+ 0
+
+
+
+
+
+
+ 307
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 308
+
+
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ./app/models/user.rb
+ 55.63 % covered
+
+
+
+ #
+
+ Hits
+
+
+
+
+
+
+
+ 1
+
+
+ require 'digest/sha1'
+
+
+ 1
+
+
+
+
+
+
+ 2
+
+
+
+
+
+
+
+
+
+
+
+
+ 3
+
+
+ class User < ActiveRecord::Base
+
+
+ 1
+
+
+
+
+
+
+ 4
+
+
+ class Error < Exception ; end
+
+
+ 1
+
+
+
+
+
+
+ 5
+
+
+ class PrivilegeError < Exception ; end
+
+
+ 1
+
+
+
+
+
+
+ 6
+
+
+
+
+
+
+
+
+
+
+
+
+ 7
+
+
+ attr_accessor :password, :old_password, :ip_addr
+
+
+ 1
+
+
+
+
+
+
+ 8
+
+
+ attr_accessible :password, :old_password, :password_confirmation, :password_hash, :email, :last_logged_in_at, :last_forum_read_at, :has_mail, :receive_email_notifications, :comment_threshold, :always_resize_images, :favorite_tags, :blacklisted_tags, :name, :ip_addr
+
+
+ 1
+
+
+
+
+
+
+ 9
+
+
+ validates_length_of :name, :within => 2..20, :on => :create
+
+
+ 1
+
+
+
+
+
+
+ 10
+
+
+ validates_format_of :name, :with => /\A[^\s;,]+\Z/, :on => :create, :message => "cannot have whitespace, commas, or semicolons"
+
+
+ 1
+
+
+
+
+
+
+ 11
+
+
+ validates_uniqueness_of :name, :case_sensitive => false, :on => :create
+
+
+ 1
+
+
+
+
+
+
+ 12
+
+
+ validates_uniqueness_of :email, :case_sensitive => false, :on => :create, :if => lambda {|rec| !rec.email.blank?}
+
+
+ 20
+
+
+
+
+
+
+ 13
+
+
+ validates_length_of :password, :minimum => 5, :if => lambda {|rec| rec.new_record? || !rec.password.blank?}
+
+
+ 20
+
+
+
+
+
+
+ 14
+
+
+ validates_inclusion_of :default_image_size, :in => %w(medium large original)
+
+
+ 1
+
+
+
+
+
+
+ 15
+
+
+ validates_confirmation_of :password
+
+
+ 1
+
+
+
+
+
+
+ 16
+
+
+ validates_presence_of :email, :if => lambda {|rec| rec.new_record? && Danbooru.config.enable_email_verification?}
+
+
+ 20
+
+
+
+
+
+
+ 17
+
+
+ validates_presence_of :ip_addr, :on => :create
+
+
+ 1
+
+
+
+
+
+
+ 18
+
+
+ validate :validate_ip_addr_is_not_banned, :on => :create
+
+
+ 1
+
+
+
+
+
+
+ 19
+
+
+ before_save :encrypt_password
+
+
+ 1
+
+
+
+
+
+
+ 20
+
+
+ after_save :update_cache
+
+
+ 1
+
+
+
+
+
+
+ 21
+
+
+ before_create :promote_to_admin_if_first_user
+
+
+ 1
+
+
+
+
+
+
+ 22
+
+
+ before_create :normalize_level
+
+
+ 1
+
+
+
+
+
+
+ 23
+
+
+ has_many :feedback, :class_name => "UserFeedback", :dependent => :destroy
+
+
+ 1
+
+
+
+
+
+
+ 24
+
+
+ has_one :ban
+
+
+ 1
+
+
+
+
+
+
+ 25
+
+
+ belongs_to :inviter, :class_name => "User"
+
+
+ 1
+
+
+
+
+
+
+ 26
+
+
+ scope :named, lambda {|name| where(["lower(name) = ?", name])}
+
+
+ 1
+
+
+
+
+
+
+ 27
+
+
+ scope :admins, where("is_admin = TRUE")
+
+
+ 1
+
+
+
+
+
+
+ 28
+
+
+
+
+
+
+
+
+
+
+
+
+ 29
+
+
+ module BanMethods
+
+
+ 1
+
+
+
+
+
+
+ 30
+
+
+ def validate_ip_addr_is_not_banned
+
+
+ 1
+
+
+
+
+
+
+ 31
+
+
+ if IpBan.is_banned?(ip_addr)
+
+
+ 19
+
+
+
+
+
+
+ 32
+
+
+ self.errors[:base] << "IP address is banned"
+
+
+ 0
+
+
+
+
+
+
+ 33
+
+
+ return false
+
+
+ 0
+
+
+
+
+
+
+ 34
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 35
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 36
+
+
+
+
+
+
+
+
+
+
+
+
+ 37
+
+
+ def unban!
+
+
+ 1
+
+
+
+
+
+
+ 38
+
+
+ update_attribute(:is_banned, false)
+
+
+ 0
+
+
+
+
+
+
+ 39
+
+
+ ban.destroy
+
+
+ 0
+
+
+
+
+
+
+ 40
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 41
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 42
+
+
+
+
+
+
+
+
+
+
+
+
+ 43
+
+
+ module NameMethods
+
+
+ 1
+
+
+
+
+
+
+ 44
+
+
+ extend ActiveSupport::Concern
+
+
+ 1
+
+
+
+
+
+
+ 45
+
+
+
+
+
+
+
+
+
+
+
+
+ 46
+
+
+ module ClassMethods
+
+
+ 1
+
+
+
+
+
+
+ 47
+
+
+ def name_to_id(name)
+
+
+ 1
+
+
+
+
+
+
+ 48
+
+
+ Cache.get("uni:#{Cache.sanitize(name)}") do
+
+
+ 0
+
+
+
+
+
+
+ 49
+
+
+ select_value_sql("SELECT id FROM users WHERE lower(name) = ?", name.downcase)
+
+
+ 0
+
+
+
+
+
+
+ 50
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 51
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 52
+
+
+
+
+
+
+
+
+
+
+
+
+ 53
+
+
+ def id_to_name(user_id)
+
+
+ 1
+
+
+
+
+
+
+ 54
+
+
+ Cache.get("uin:#{user_id}") do
+
+
+ 0
+
+
+
+
+
+
+ 55
+
+
+ select_value_sql("SELECT name FROM users WHERE id = ?", user_id) || Danbooru.config.default_guest_name
+
+
+ 0
+
+
+
+
+
+
+ 56
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 57
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 58
+
+
+
+
+
+
+
+
+
+
+
+
+ 59
+
+
+ def find_by_name(name)
+
+
+ 1
+
+
+
+
+
+
+ 60
+
+
+ where(["lower(name) = ?", name.downcase]).first
+
+
+ 0
+
+
+
+
+
+
+ 61
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 62
+
+
+
+
+
+
+
+
+
+
+
+
+ 63
+
+
+ def id_to_pretty_name(user_id)
+
+
+ 1
+
+
+
+
+
+
+ 64
+
+
+ id_to_name(user_id).tr("_", " ")
+
+
+ 0
+
+
+
+
+
+
+ 65
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 66
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 67
+
+
+
+
+
+
+
+
+
+
+
+
+ 68
+
+
+ def pretty_name
+
+
+ 1
+
+
+
+
+
+
+ 69
+
+
+ name.tr("_", " ")
+
+
+ 0
+
+
+
+
+
+
+ 70
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 71
+
+
+
+
+
+
+
+
+
+
+
+
+ 72
+
+
+ def update_cache
+
+
+ 1
+
+
+
+
+
+
+ 73
+
+
+ Cache.put("uin:#{id}", name)
+
+
+ 19
+
+
+
+
+
+
+ 74
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 75
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 76
+
+
+
+
+
+
+
+
+
+
+
+
+ 77
+
+
+ module PasswordMethods
+
+
+ 1
+
+
+
+
+
+
+ 78
+
+
+ def encrypt_password
+
+
+ 1
+
+
+
+
+
+
+ 79
+
+
+ self.password_hash = self.class.sha1(password) if password
+
+
+ 19
+
+
+
+
+
+
+ 80
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 81
+
+
+
+
+
+
+
+
+
+
+
+
+ 82
+
+
+ def reset_password
+
+
+ 1
+
+
+
+
+
+
+ 83
+
+
+ consonants = "bcdfghjklmnpqrstvqxyz"
+
+
+ 0
+
+
+
+
+
+
+ 84
+
+
+ vowels = "aeiou"
+
+
+ 0
+
+
+
+
+
+
+ 85
+
+
+ pass = ""
+
+
+ 0
+
+
+
+
+
+
+ 86
+
+
+
+
+
+
+
+
+
+
+
+
+ 87
+
+
+ 4.times do
+
+
+ 0
+
+
+
+
+
+
+ 88
+
+
+ pass << consonants[rand(21), 1]
+
+
+ 0
+
+
+
+
+
+
+ 89
+
+
+ pass << vowels[rand(5), 1]
+
+
+ 0
+
+
+
+
+
+
+ 90
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 91
+
+
+
+
+
+
+
+
+
+
+
+
+ 92
+
+
+ pass << rand(100).to_s
+
+
+ 0
+
+
+
+
+
+
+ 93
+
+
+ execute_sql("UPDATE users SET password_hash = ? WHERE id = ?", self.class.sha1(pass), id)
+
+
+ 0
+
+
+
+
+
+
+ 94
+
+
+ pass
+
+
+ 0
+
+
+
+
+
+
+ 95
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 96
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 97
+
+
+
+
+
+
+
+
+
+
+
+
+ 98
+
+
+ module AuthenticationMethods
+
+
+ 1
+
+
+
+
+
+
+ 99
+
+
+ def authenticate(name, pass)
+
+
+ 1
+
+
+
+
+
+
+ 100
+
+
+ authenticate_hash(name, sha1(pass))
+
+
+ 0
+
+
+
+
+
+
+ 101
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 102
+
+
+
+
+
+
+
+
+
+
+
+
+ 103
+
+
+ def authenticate_hash(name, pass)
+
+
+ 1
+
+
+
+
+
+
+ 104
+
+
+ where(["lower(name) = ? AND password_hash = ?", name.downcase, pass]).first != nil
+
+
+ 0
+
+
+
+
+
+
+ 105
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 106
+
+
+
+
+
+
+
+
+
+
+
+
+ 107
+
+
+ def sha1(pass)
+
+
+ 1
+
+
+
+
+
+
+ 108
+
+
+ Digest::SHA1.hexdigest("#{Danbooru.config.password_salt}--#{pass}--")
+
+
+ 38
+
+
+
+
+
+
+ 109
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 110
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 111
+
+
+
+
+
+
+
+
+
+
+
+
+ 112
+
+
+ module FavoriteMethods
+
+
+ 1
+
+
+
+
+
+
+ 113
+
+
+ def favorite_posts(options = {})
+
+
+ 1
+
+
+
+
+
+
+ 114
+
+
+ favorites_table = Favorite.table_name_for(id)
+
+
+ 0
+
+
+
+
+
+
+ 115
+
+
+ if options[:before_id]
+
+
+ 0
+
+
+
+
+
+
+ 116
+
+
+ before_id_sql_fragment = ["favorites.id < ?", options[:before_id]]
+
+
+ 0
+
+
+
+
+
+
+ 117
+
+
+ else
+
+
+
+
+
+
+
+
+
+ 118
+
+
+ before_id_sql_fragment = "TRUE"
+
+
+ 0
+
+
+
+
+
+
+ 119
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 120
+
+
+ limit = options[:limit] || 20
+
+
+ 0
+
+
+
+
+
+
+ 121
+
+
+
+
+
+
+
+
+
+
+
+
+ 122
+
+
+ Post.joins("JOIN #{favorites_table} AS favorites ON favorites.post_id = posts.id").where("favorites.user_id = ?", id).where(before_id_sql_fragment).order("favorite_id DESC").limit(limit).select("posts.*, favorites.id AS favorite_id")
+
+
+ 0
+
+
+
+
+
+
+ 123
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 124
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 125
+
+
+
+
+
+
+
+
+
+
+
+
+ 126
+
+
+ module LevelMethods
+
+
+ 1
+
+
+
+
+
+
+ 127
+
+
+ def promote_to_admin_if_first_user
+
+
+ 1
+
+
+
+
+
+
+ 128
+
+
+ return if Rails.env.test?
+
+
+ 19
+
+
+
+
+
+
+ 129
+
+
+
+
+
+
+
+
+
+
+
+
+ 130
+
+
+ if User.count == 0
+
+
+ 0
+
+
+
+
+
+
+ 131
+
+
+ self.is_admin = true
+
+
+ 0
+
+
+
+
+
+
+ 132
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 133
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 134
+
+
+
+
+
+
+
+
+
+
+
+
+ 135
+
+
+ def normalize_level
+
+
+ 1
+
+
+
+
+
+
+ 136
+
+
+ if is_admin?
+
+
+ 19
+
+
+
+
+
+
+ 137
+
+
+ self.is_moderator = true
+
+
+ 0
+
+
+
+
+
+
+ 138
+
+
+ self.is_janitor = true
+
+
+ 0
+
+
+
+
+
+
+ 139
+
+
+ self.is_contributor = true
+
+
+ 0
+
+
+
+
+
+
+ 140
+
+
+ self.is_privileged = true
+
+
+ 0
+
+
+
+
+
+
+ 141
+
+
+ elsif is_moderator?
+
+
+ 19
+
+
+
+
+
+
+ 142
+
+
+ self.is_janitor = true
+
+
+ 0
+
+
+
+
+
+
+ 143
+
+
+ self.is_privileged = true
+
+
+ 0
+
+
+
+
+
+
+ 144
+
+
+ elsif is_janitor?
+
+
+ 19
+
+
+
+
+
+
+ 145
+
+
+ self.is_privileged = true
+
+
+ 0
+
+
+
+
+
+
+ 146
+
+
+ elsif is_contributor?
+
+
+ 19
+
+
+
+
+
+
+ 147
+
+
+ self.is_privileged = true
+
+
+ 0
+
+
+
+
+
+
+ 148
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 149
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 150
+
+
+
+
+
+
+
+
+
+
+
+
+ 151
+
+
+ def is_anonymous?
+
+
+ 1
+
+
+
+
+
+
+ 152
+
+
+ false
+
+
+ 12
+
+
+
+
+
+
+ 153
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 154
+
+
+
+
+
+
+
+
+
+
+
+
+ 155
+
+
+ def is_member?
+
+
+ 1
+
+
+
+
+
+
+ 156
+
+
+ true
+
+
+ 4
+
+
+
+
+
+
+ 157
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 158
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 159
+
+
+
+
+
+
+
+
+
+
+
+
+ 160
+
+
+ module EmailVerificationMethods
+
+
+ 1
+
+
+
+
+
+
+ 161
+
+
+ def is_verified?
+
+
+ 1
+
+
+
+
+
+
+ 162
+
+
+ email_verification_key.blank?
+
+
+ 0
+
+
+
+
+
+
+ 163
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 164
+
+
+
+
+
+
+
+
+
+
+
+
+ 165
+
+
+ def generate_email_verification_key
+
+
+ 1
+
+
+
+
+
+
+ 166
+
+
+ self.email_verification_key = Digest::SHA1.hexdigest("#{Time.now.to_f}--#{name}--#{rand(1_000_000)}--")
+
+
+ 0
+
+
+
+
+
+
+ 167
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 168
+
+
+
+
+
+
+
+
+
+
+
+
+ 169
+
+
+ def verify!(key)
+
+
+ 1
+
+
+
+
+
+
+ 170
+
+
+ if email_verification_key == key
+
+
+ 0
+
+
+
+
+
+
+ 171
+
+
+ self.update_attribute(:email_verification_key, nil)
+
+
+ 0
+
+
+
+
+
+
+ 172
+
+
+ else
+
+
+
+
+
+
+
+
+
+ 173
+
+
+ raise User::Error.new("Verification key does not match")
+
+
+ 0
+
+
+
+
+
+
+ 174
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 175
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 176
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 177
+
+
+
+
+
+
+
+
+
+
+
+
+ 178
+
+
+ module BlacklistMethods
+
+
+ 1
+
+
+
+
+
+
+ 179
+
+
+ def blacklisted_tag_array
+
+
+ 1
+
+
+
+
+
+
+ 180
+
+
+ Tag.scan_query(blacklisted_tags)
+
+
+ 0
+
+
+
+
+
+
+ 181
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 182
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 183
+
+
+
+
+
+
+
+
+
+
+
+
+ 184
+
+
+ module ForumMethods
+
+
+ 1
+
+
+
+
+
+
+ 185
+
+
+ def has_forum_been_updated?
+
+
+ 1
+
+
+
+
+
+
+ 186
+
+
+ return false unless is_privileged?
+
+
+ 5
+
+
+
+
+
+
+ 187
+
+
+ newest_topic = ForumPost.first(:order => "updated_at desc", :select => "updated_at")
+
+
+ 0
+
+
+
+
+
+
+ 188
+
+
+ return false if newest_topic.nil?
+
+
+ 0
+
+
+
+
+
+
+ 189
+
+
+ return true if last_forum_read_at.nil?
+
+
+ 0
+
+
+
+
+
+
+ 190
+
+
+ return newest_topic.updated_at > last_forum_read_at
+
+
+ 0
+
+
+
+
+
+
+ 191
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 192
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 193
+
+
+
+
+
+
+
+
+
+
+
+
+ 194
+
+
+ module LimitMethods
+
+
+ 1
+
+
+
+
+
+
+ 195
+
+
+ def can_upload?
+
+
+ 1
+
+
+
+
+
+
+ 196
+
+
+ if is_contributor?
+
+
+ 0
+
+
+
+
+
+
+ 197
+
+
+ true
+
+
+ 0
+
+
+
+
+
+
+ 198
+
+
+ elsif created_at > 1.week.ago
+
+
+ 0
+
+
+
+
+
+
+ 199
+
+
+ false
+
+
+ 0
+
+
+
+
+
+
+ 200
+
+
+ else
+
+
+
+
+
+
+
+
+
+ 201
+
+
+ upload_limit > 0
+
+
+ 0
+
+
+
+
+
+
+ 202
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 203
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 204
+
+
+
+
+
+
+
+
+
+
+
+
+ 205
+
+
+ def can_comment?
+
+
+ 1
+
+
+
+
+
+
+ 206
+
+
+ if is_privileged?
+
+
+ 0
+
+
+
+
+
+
+ 207
+
+
+ true
+
+
+ 0
+
+
+
+
+
+
+ 208
+
+
+ elsif created_at > 1.week.ago
+
+
+ 0
+
+
+
+
+
+
+ 209
+
+
+ false
+
+
+ 0
+
+
+
+
+
+
+ 210
+
+
+ else
+
+
+
+
+
+
+
+
+
+ 211
+
+
+ Comment.where("creator_id = ? and created_at > ?", id, 1.hour.ago).count <= Danbooru.config.member_comment_limit
+
+
+ 0
+
+
+
+
+
+
+ 212
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 213
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 214
+
+
+
+
+
+
+
+
+
+
+
+
+ 215
+
+
+ def can_comment_vote?
+
+
+ 1
+
+
+
+
+
+
+ 216
+
+
+ CommentVote.where("user_id = ? and created_at > ?", id, 1.hour.ago).count < 10
+
+
+ 0
+
+
+
+
+
+
+ 217
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 218
+
+
+
+
+
+
+
+
+
+
+
+
+ 219
+
+
+ def can_remove_from_pools?
+
+
+ 1
+
+
+
+
+
+
+ 220
+
+
+ created_at <= 1.week.ago
+
+
+ 0
+
+
+
+
+
+
+ 221
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 222
+
+
+
+
+
+
+
+
+
+
+
+
+ 223
+
+
+ def upload_limit
+
+
+ 1
+
+
+
+
+
+
+ 224
+
+
+ deleted_count = RemovedPost.where("user_id = ?", id).count
+
+
+ 0
+
+
+
+
+
+
+ 225
+
+
+ unapproved_count = Post.where("is_pending = true and user_id = ?", id).count
+
+
+ 0
+
+
+
+
+
+
+ 226
+
+
+ approved_count = Post.where("is_flagged = false and is_pending = false and user_id = ?", id).count
+
+
+ 0
+
+
+
+
+
+
+ 227
+
+
+
+
+
+
+
+
+
+
+
+
+ 228
+
+
+ limit = base_upload_limit + (approved_count / 10) - (deleted_count / 4) - unapproved_count
+
+
+ 0
+
+
+
+
+
+
+ 229
+
+
+
+
+
+
+
+
+
+
+
+
+ 230
+
+
+ if limit > 20
+
+
+ 0
+
+
+
+
+
+
+ 231
+
+
+ limit = 20
+
+
+ 0
+
+
+
+
+
+
+ 232
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 233
+
+
+
+
+
+
+
+
+
+
+
+
+ 234
+
+
+ if limit < 0
+
+
+ 0
+
+
+
+
+
+
+ 235
+
+
+ limit = 0
+
+
+ 0
+
+
+
+
+
+
+ 236
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 237
+
+
+
+
+
+
+
+
+
+
+
+
+ 238
+
+
+ limit
+
+
+ 0
+
+
+
+
+
+
+ 239
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 240
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 241
+
+
+
+
+
+
+
+
+
+
+
+
+ 242
+
+
+ include BanMethods
+
+
+ 1
+
+
+
+
+
+
+ 243
+
+
+ include NameMethods
+
+
+ 1
+
+
+
+
+
+
+ 244
+
+
+ include PasswordMethods
+
+
+ 1
+
+
+
+
+
+
+ 245
+
+
+ extend AuthenticationMethods
+
+
+ 1
+
+
+
+
+
+
+ 246
+
+
+ include FavoriteMethods
+
+
+ 1
+
+
+
+
+
+
+ 247
+
+
+ include LevelMethods
+
+
+ 1
+
+
+
+
+
+
+ 248
+
+
+ include EmailVerificationMethods
+
+
+ 1
+
+
+
+
+
+
+ 249
+
+
+ include BlacklistMethods
+
+
+ 1
+
+
+
+
+
+
+ 250
+
+
+ include ForumMethods
+
+
+ 1
+
+
+
+
+
+
+ 251
+
+
+ include LimitMethods
+
+
+ 1
+
+
+
+
+
+
+ 252
+
+
+
+
+
+
+
+
+
+
+
+
+ 253
+
+
+ def initialize_default_image_size
+
+
+ 1
+
+
+
+
+
+
+ 254
+
+
+ self.default_image_size = "Medium"
+
+
+ 0
+
+
+
+
+
+
+ 255
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 256
+
+
+
+
+
+
+
+
+
+
+
+
+ 257
+
+
+ def can_update?(object, foreign_key = :user_id)
+
+
+ 1
+
+
+
+
+
+
+ 258
+
+
+ is_moderator? || is_admin? || object.__send__(foreign_key) == id
+
+
+ 0
+
+
+
+
+
+
+ 259
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 260
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 261
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ./app/models/user_feedback.rb
+ 76.92 % covered
+
+
+
+ #
+
+ Hits
+
+
+
+
+
+
+
+ 1
+
+
+ class UserFeedback < ActiveRecord::Base
+
+
+ 1
+
+
+
+
+
+
+ 2
+
+
+ set_table_name "user_feedback"
+
+
+ 1
+
+
+
+
+
+
+ 3
+
+
+ belongs_to :user
+
+
+ 1
+
+
+
+
+
+
+ 4
+
+
+ belongs_to :creator, :class_name => "User"
+
+
+ 1
+
+
+
+
+
+
+ 5
+
+
+ before_validation :initialize_creator, :on => :create
+
+
+ 1
+
+
+
+
+
+
+ 6
+
+
+ attr_accessible :body, :user_id, :is_positive
+
+
+ 1
+
+
+
+
+
+
+ 7
+
+
+ validates_presence_of :user, :creator, :body
+
+
+ 1
+
+
+
+
+
+
+ 8
+
+
+ validate :creator_is_privileged
+
+
+ 1
+
+
+
+
+
+
+ 9
+
+
+
+
+
+
+
+
+
+
+
+
+ 10
+
+
+ def initialize_creator
+
+
+ 1
+
+
+
+
+
+
+ 11
+
+
+ self.creator_id = CurrentUser.id
+
+
+ 0
+
+
+
+
+
+
+ 12
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 13
+
+
+
+
+
+
+
+
+
+
+
+
+ 14
+
+
+ def creator_is_privileged
+
+
+ 1
+
+
+
+
+
+
+ 15
+
+
+ if !creator.is_privileged?
+
+
+ 0
+
+
+
+
+
+
+ 16
+
+
+ errors[:creator] << "must be privileged"
+
+
+ 0
+
+
+
+
+
+
+ 17
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 18
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 19
+
+
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ./app/models/user_mailer.rb
+ 40.0 % covered
+
+
+
+ #
+
+ Hits
+
+
+
+
+
+
+
+ 1
+
+
+ class UserMailer < ActionMailer::Base
+
+
+ 1
+
+
+
+
+
+
+ 2
+
+
+ default :host => Danbooru.config.server_host, :from => Danbooru.config.contact_email, :content_type => "text/html"
+
+
+ 1
+
+
+
+
+
+
+ 3
+
+
+
+
+
+
+
+
+
+
+
+
+ 4
+
+
+ def password_reset(user, new_password)
+
+
+ 1
+
+
+
+
+
+
+ 5
+
+
+ @user = user
+
+
+ 0
+
+
+
+
+
+
+ 6
+
+
+ @new_password = new_password
+
+
+ 0
+
+
+
+
+
+
+ 7
+
+
+ mail(:to => @user.email, :subject => "#{Danbooru.config.app_name} - Password Reset")
+
+
+ 0
+
+
+
+
+
+
+ 8
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 9
+
+
+
+
+
+
+
+
+
+
+
+
+ 10
+
+
+ def name_reminder(user)
+
+
+ 1
+
+
+
+
+
+
+ 11
+
+
+ @user = user
+
+
+ 0
+
+
+
+
+
+
+ 12
+
+
+ mail(:to => user.email, :subject => "#{Danbooru.config.app_name} - Name Reminder")
+
+
+ 0
+
+
+
+
+
+
+ 13
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 14
+
+
+
+
+
+
+
+
+
+
+
+
+ 15
+
+
+ def deletion(user)
+
+
+ 1
+
+
+
+
+
+
+ 16
+
+
+ @user = user
+
+
+ 0
+
+
+
+
+
+
+ 17
+
+
+ mail(:to => user.email, :subject => "#{}")
+
+
+ 0
+
+
+
+
+
+
+ 18
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 19
+
+
+
+
+
+
+
+
+
+
+
+
+ 20
+
+
+ def dmail_notice(dmail)
+
+
+ 1
+
+
+
+
+
+
+ 21
+
+
+ @dmail = dmail
+
+
+ 0
+
+
+
+
+
+
+ 22
+
+
+ mail(:to => dmail.to.email, :subject => "#{Danbooru.config.app_name} - Message received from #{dmail.from.name}")
+
+
+ 0
+
+
+
+
+
+
+ 23
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 24
+
+
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ./app/models/wiki_page.rb
+ 53.85 % covered
+
+
+
+ #
+
+ Hits
+
+
+
+
+
+
+
+ 1
+
+
+ class WikiPage < ActiveRecord::Base
+
+
+ 1
+
+
+
+
+
+
+ 2
+
+
+ before_save :normalize_title
+
+
+ 1
+
+
+
+
+
+
+ 3
+
+
+ before_create :initialize_creator
+
+
+ 1
+
+
+
+
+
+
+ 4
+
+
+ after_save :create_version
+
+
+ 1
+
+
+
+
+
+
+ 5
+
+
+ belongs_to :creator, :class_name => "User"
+
+
+ 1
+
+
+
+
+
+
+ 6
+
+
+ validates_uniqueness_of :title, :case_sensitive => false
+
+
+ 1
+
+
+
+
+
+
+ 7
+
+
+ validates_presence_of :body
+
+
+ 1
+
+
+
+
+
+
+ 8
+
+
+ attr_accessible :title, :body
+
+
+ 1
+
+
+
+
+
+
+ 9
+
+
+ scope :titled, lambda {|title| where(["title = ?", title.downcase.tr(" ", "_")])}
+
+
+ 1
+
+
+
+
+
+
+ 10
+
+
+ has_one :tag, :foreign_key => "name", :primary_key => "title"
+
+
+ 1
+
+
+
+
+
+
+ 11
+
+
+ has_one :artist, :foreign_key => "name", :primary_key => "title"
+
+
+ 1
+
+
+
+
+
+
+ 12
+
+
+ has_many :versions, :class_name => "WikiPageVersion"
+
+
+ 1
+
+
+
+
+
+
+ 13
+
+
+
+
+
+
+
+
+
+
+
+
+ 14
+
+
+ def self.build_relation(options = {})
+
+
+ 1
+
+
+
+
+
+
+ 15
+
+
+ relation = where()
+
+
+ 0
+
+
+
+
+
+
+ 16
+
+
+
+
+
+
+
+
+
+
+
+
+ 17
+
+
+ if options[:title]
+
+
+ 0
+
+
+
+
+
+
+ 18
+
+
+ relation = relation.where(["title LIKE ? ESCAPE E'\\\\'", options[:title].downcase.tr(" ", "_").to_escaped_for_sql_like])
+
+
+ 0
+
+
+
+
+
+
+ 19
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 20
+
+
+
+
+
+
+
+
+
+
+
+
+ 21
+
+
+ if options[:creator_id]
+
+
+ 0
+
+
+
+
+
+
+ 22
+
+
+ relation = relation.where(["creator_id = ?", options[:creator_id]])
+
+
+ 0
+
+
+
+
+
+
+ 23
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 24
+
+
+
+
+
+
+
+
+
+
+
+
+ 25
+
+
+ relation
+
+
+ 0
+
+
+
+
+
+
+ 26
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 27
+
+
+
+
+
+
+
+
+
+
+
+
+ 28
+
+
+ def self.find_title_and_id(title)
+
+
+ 1
+
+
+
+
+
+
+ 29
+
+
+ titled(title).select("title, id").first
+
+
+ 0
+
+
+
+
+
+
+ 30
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 31
+
+
+
+
+
+
+
+
+
+
+
+
+ 32
+
+
+ def revert_to(version)
+
+
+ 1
+
+
+
+
+
+
+ 33
+
+
+ self.title = version.title
+
+
+ 0
+
+
+
+
+
+
+ 34
+
+
+ self.body = version.body
+
+
+ 0
+
+
+
+
+
+
+ 35
+
+
+ self.is_locked = version.is_locked
+
+
+ 0
+
+
+
+
+
+
+ 36
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 37
+
+
+
+
+
+
+
+
+
+
+
+
+ 38
+
+
+ def revert_to!(version)
+
+
+ 1
+
+
+
+
+
+
+ 39
+
+
+ revert_to(version)
+
+
+ 0
+
+
+
+
+
+
+ 40
+
+
+ save!
+
+
+ 0
+
+
+
+
+
+
+ 41
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 42
+
+
+
+
+
+
+
+
+
+
+
+
+ 43
+
+
+ def normalize_title
+
+
+ 1
+
+
+
+
+
+
+ 44
+
+
+ self.title = title.downcase.tr(" ", "_")
+
+
+ 0
+
+
+
+
+
+
+ 45
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 46
+
+
+
+
+
+
+
+
+
+
+
+
+ 47
+
+
+ def creator_name
+
+
+ 1
+
+
+
+
+
+
+ 48
+
+
+ User.id_to_name(user_id).tr("_", " ")
+
+
+ 0
+
+
+
+
+
+
+ 49
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 50
+
+
+
+
+
+
+
+
+
+
+
+
+ 51
+
+
+ def pretty_title
+
+
+ 1
+
+
+
+
+
+
+ 52
+
+
+ title.tr("_", " ")
+
+
+ 0
+
+
+
+
+
+
+ 53
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 54
+
+
+
+
+
+
+
+
+
+
+
+
+ 55
+
+
+ def create_version
+
+
+ 1
+
+
+
+
+
+
+ 56
+
+
+ if title_changed? || body_changed? || is_locked_changed?
+
+
+ 0
+
+
+
+
+
+
+ 57
+
+
+ versions.create(
+
+
+ 0
+
+
+
+
+
+
+ 58
+
+
+ :updater_id => CurrentUser.user.id,
+
+
+
+
+
+
+
+
+
+ 59
+
+
+ :updater_ip_addr => CurrentUser.ip_addr,
+
+
+
+
+
+
+
+
+
+ 60
+
+
+ :title => title,
+
+
+
+
+
+
+
+
+
+ 61
+
+
+ :body => body,
+
+
+
+
+
+
+
+
+
+ 62
+
+
+ :is_locked => is_locked
+
+
+
+
+
+
+
+
+
+ 63
+
+
+ )
+
+
+
+
+
+
+
+
+
+ 64
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 65
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 66
+
+
+
+
+
+
+
+
+
+
+
+
+ 67
+
+
+ def initialize_creator
+
+
+ 1
+
+
+
+
+
+
+ 68
+
+
+ self.creator_id = CurrentUser.user.id
+
+
+ 0
+
+
+
+
+
+
+ 69
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 70
+
+
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ./app/models/wiki_page_version.rb
+ 71.43 % covered
+
+
+
+ #
+
+ Hits
+
+
+
+
+
+
+
+ 1
+
+
+ class WikiPageVersion < ActiveRecord::Base
+
+
+ 1
+
+
+
+
+
+
+ 2
+
+
+ belongs_to :wiki_page
+
+
+ 1
+
+
+
+
+
+
+ 3
+
+
+ belongs_to :updater
+
+
+ 1
+
+
+
+
+
+
+ 4
+
+
+
+
+
+
+
+
+
+
+
+
+ 5
+
+
+ def updater_name
+
+
+ 1
+
+
+
+
+
+
+ 6
+
+
+ User.id_to_name(updater_id)
+
+
+ 0
+
+
+
+
+
+
+ 7
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 8
+
+
+
+
+
+
+
+
+
+
+
+
+ 9
+
+
+ def pretty_title
+
+
+ 1
+
+
+
+
+
+
+ 10
+
+
+ title.tr("_", " ")
+
+
+ 0
+
+
+
+
+
+
+ 11
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 12
+
+
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ./app/presenters/note_presenter.rb
+ 60.0 % covered
+
+
+
+ #
+
+ Hits
+
+
+
+
+
+
+
+ 1
+
+
+ class NotePresenter
+
+
+ 1
+
+
+
+
+
+
+ 2
+
+
+ def initialize(note)
+
+
+ 1
+
+
+
+
+
+
+ 3
+
+
+ @note = note
+
+
+ 0
+
+
+
+
+
+
+ 4
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 5
+
+
+
+
+
+
+
+
+
+
+
+
+ 6
+
+
+ def formatted_body
+
+
+ 1
+
+
+
+
+
+
+ 7
+
+
+ note.body.gsub(/<tn>(.+?)<\/tn>/m, '<br><p class="tn">\1</p>').gsub(/\n/, '<br>')
+
+
+ 0
+
+
+
+
+
+
+ 8
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 9
+
+
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ./app/presenters/paginators/base.rb
+ 19.61 % covered
+
+
+
+ #
+
+ Hits
+
+
+
+
+
+
+
+ 1
+
+
+ module Paginators
+
+
+ 1
+
+
+
+
+
+
+ 2
+
+
+ class Base < Presenter
+
+
+ 1
+
+
+
+
+
+
+ 3
+
+
+ def sequential_pagination_html(template)
+
+
+ 1
+
+
+
+
+
+
+ 4
+
+
+ html = "<menu>"
+
+
+ 0
+
+
+
+
+
+
+ 5
+
+
+ prev_url = template.request.env["HTTP_REFERER"]
+
+
+ 0
+
+
+
+
+
+
+ 6
+
+
+ next_url = sequential_link(template)
+
+
+ 0
+
+
+
+
+
+
+ 7
+
+
+ html << %{<li><a href="#{prev_url}">« Previous</a></li>}
+
+
+ 0
+
+
+
+
+
+
+ 8
+
+
+ if post_set.posts.any?
+
+
+ 0
+
+
+
+
+
+
+ 9
+
+
+ html << %{<li><a href="#{next_url}">Next »</a></li>}
+
+
+ 0
+
+
+
+
+
+
+ 10
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 11
+
+
+ html << "</menu>"
+
+
+ 0
+
+
+
+
+
+
+ 12
+
+
+ html.html_safe
+
+
+ 0
+
+
+
+
+
+
+ 13
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 14
+
+
+
+
+
+
+
+
+
+
+
+
+ 15
+
+
+ def numbered_pagination_html(template)
+
+
+ 1
+
+
+
+
+
+
+ 16
+
+
+ html = "<menu>"
+
+
+ 0
+
+
+
+
+
+
+ 17
+
+
+ window = 3
+
+
+ 0
+
+
+
+
+
+
+ 18
+
+
+ if total_pages <= (window * 2) + 5
+
+
+ 0
+
+
+
+
+
+
+ 19
+
+
+ 1.upto(total_pages) do |page|
+
+
+ 0
+
+
+
+
+
+
+ 20
+
+
+ html << numbered_pagination_item(template, page, current_page)
+
+
+ 0
+
+
+
+
+
+
+ 21
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 22
+
+
+ elsif current_page <= window + 2
+
+
+
+
+
+
+
+
+
+ 23
+
+
+ 1.upto(current_page + window) do |page|
+
+
+ 0
+
+
+
+
+
+
+ 24
+
+
+ html << numbered_pagination_item(template, page, current_page)
+
+
+ 0
+
+
+
+
+
+
+ 25
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 26
+
+
+ html << numbered_pagination_item(template, "...", current_page)
+
+
+ 0
+
+
+
+
+
+
+ 27
+
+
+ html << numbered_pagination_item(template, total_pages, current_page)
+
+
+ 0
+
+
+
+
+
+
+ 28
+
+
+
+
+
+
+
+
+
+
+
+
+ 29
+
+
+ elsif current_page >= total_pages - (window + 1)
+
+
+ 0
+
+
+
+
+
+
+ 30
+
+
+ html << numbered_pagination_item(template, 1, current_page)
+
+
+ 0
+
+
+
+
+
+
+ 31
+
+
+ html << numbered_pagination_item(template, "...", current_page)
+
+
+ 0
+
+
+
+
+
+
+ 32
+
+
+ (current_page - window).upto(total_pages) do |page|
+
+
+ 0
+
+
+
+
+
+
+ 33
+
+
+ html << numbered_pagination_item(template, page, current_page)
+
+
+ 0
+
+
+
+
+
+
+ 34
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 35
+
+
+ else
+
+
+
+
+
+
+
+
+
+ 36
+
+
+ html << numbered_pagination_item(template, 1, current_page)
+
+
+ 0
+
+
+
+
+
+
+ 37
+
+
+ html << numbered_pagination_item(template, "...", current_page)
+
+
+ 0
+
+
+
+
+
+
+ 38
+
+
+ (current_page - window).upto(current_page + window) do |page|
+
+
+ 0
+
+
+
+
+
+
+ 39
+
+
+ html << numbered_pagination_item(template, page, current_page)
+
+
+ 0
+
+
+
+
+
+
+ 40
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 41
+
+
+ html << numbered_pagination_item(template, "...", current_page)
+
+
+ 0
+
+
+
+
+
+
+ 42
+
+
+ html << numbered_pagination_item(template, total_pages, current_page)
+
+
+ 0
+
+
+
+
+
+
+ 43
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 44
+
+
+ html << "</menu>"
+
+
+ 0
+
+
+
+
+
+
+ 45
+
+
+ html.html_safe
+
+
+ 0
+
+
+
+
+
+
+ 46
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 47
+
+
+
+
+
+
+
+
+
+
+
+
+ 48
+
+
+ protected
+
+
+ 1
+
+
+
+
+
+
+ 49
+
+
+ def numbered_pagination_item(template, page, current_page)
+
+
+ 1
+
+
+
+
+
+
+ 50
+
+
+ html = "<li>"
+
+
+ 0
+
+
+
+
+
+
+ 51
+
+
+ if page == "..."
+
+
+ 0
+
+
+
+
+
+
+ 52
+
+
+ html << "..."
+
+
+ 0
+
+
+
+
+
+
+ 53
+
+
+ elsif page == current_page
+
+
+
+
+
+
+
+
+
+ 54
+
+
+ html << page.to_s
+
+
+ 0
+
+
+
+
+
+
+ 55
+
+
+ else
+
+
+
+
+
+
+
+
+
+ 56
+
+
+ html << paginated_link(template, page)
+
+
+ 0
+
+
+
+
+
+
+ 57
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 58
+
+
+ html << "</li>"
+
+
+ 0
+
+
+
+
+
+
+ 59
+
+
+ html.html_safe
+
+
+ 0
+
+
+
+
+
+
+ 60
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 61
+
+
+
+
+
+
+
+
+
+
+
+
+ 62
+
+
+ def total_pages
+
+
+ 1
+
+
+
+
+
+
+ 63
+
+
+ raise NotImplementedError
+
+
+ 0
+
+
+
+
+
+
+ 64
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 65
+
+
+
+
+
+
+
+
+
+
+
+
+ 66
+
+
+ def current_page
+
+
+ 1
+
+
+
+
+
+
+ 67
+
+
+ raise NotImplementedError
+
+
+ 0
+
+
+
+
+
+
+ 68
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 69
+
+
+
+
+
+
+
+
+
+
+
+
+ 70
+
+
+ def sequential_link(template)
+
+
+ 1
+
+
+
+
+
+
+ 71
+
+
+ raise NotImplementedError
+
+
+ 0
+
+
+
+
+
+
+ 72
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 73
+
+
+
+
+
+
+
+
+
+
+
+
+ 74
+
+
+ def paginated_link(template, page)
+
+
+ 1
+
+
+
+
+
+
+ 75
+
+
+ raise NotImplementedError
+
+
+ 0
+
+
+
+
+
+
+ 76
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 77
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 78
+
+
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ./app/presenters/paginators/post.rb
+ 64.29 % covered
+
+
+
+ #
+
+ Hits
+
+
+
+
+
+
+
+ 1
+
+
+ module Paginators
+
+
+ 1
+
+
+
+
+
+
+ 2
+
+
+ class Post < Base
+
+
+ 1
+
+
+
+
+
+
+ 3
+
+
+ attr_accessor :post_set
+
+
+ 1
+
+
+
+
+
+
+ 4
+
+
+
+
+
+
+
+
+
+
+
+
+ 5
+
+
+ def initialize(post_set)
+
+
+ 1
+
+
+
+
+
+
+ 6
+
+
+ @post_set = post_set
+
+
+ 0
+
+
+
+
+
+
+ 7
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 8
+
+
+
+
+
+
+
+
+
+
+
+
+ 9
+
+
+ protected
+
+
+ 1
+
+
+
+
+
+
+ 10
+
+
+ def total_pages
+
+
+ 1
+
+
+
+
+
+
+ 11
+
+
+ (post_set.count.to_f / post_set.limit.to_f).ceil
+
+
+ 0
+
+
+
+
+
+
+ 12
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 13
+
+
+
+
+
+
+
+
+
+
+
+
+ 14
+
+
+ def current_page
+
+
+ 1
+
+
+
+
+
+
+ 15
+
+
+ [1, post_set.page].max
+
+
+ 0
+
+
+
+
+
+
+ 16
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 17
+
+
+
+
+
+
+
+
+
+
+
+
+ 18
+
+
+ def sequential_link(template)
+
+
+ 1
+
+
+
+
+
+
+ 19
+
+
+ template.posts_path(:tags => template.params[:tags], before_id => post_set.posts[-1].id, :page => nil)
+
+
+ 0
+
+
+
+
+
+
+ 20
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 21
+
+
+
+
+
+
+
+
+
+
+
+
+ 22
+
+
+ def paginated_link(template, page)
+
+
+ 1
+
+
+
+
+
+
+ 23
+
+
+ template.link_to(page, template.posts_path(:tags => template.params[:tags], :page => page))
+
+
+ 0
+
+
+
+
+
+
+ 24
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 25
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 26
+
+
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ./app/presenters/paginators/post_version.rb
+ 70.0 % covered
+
+
+
+ #
+
+ Hits
+
+
+
+
+
+
+
+ 1
+
+
+ module Paginators
+
+
+ 1
+
+
+
+
+
+
+ 2
+
+
+ class PostVersion < Base
+
+
+ 1
+
+
+
+
+
+
+ 3
+
+
+ attr_accessor :post_set
+
+
+ 1
+
+
+
+
+
+
+ 4
+
+
+
+
+
+
+
+
+
+
+
+
+ 5
+
+
+ def initialize(post_set)
+
+
+ 1
+
+
+
+
+
+
+ 6
+
+
+ @post_set = post_set
+
+
+ 0
+
+
+
+
+
+
+ 7
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 8
+
+
+
+
+
+
+
+
+
+
+
+
+ 9
+
+
+ def numbered_pagination_html(template)
+
+
+ 1
+
+
+
+
+
+
+ 10
+
+
+ raise NotImplementedError
+
+
+ 0
+
+
+
+
+
+
+ 11
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 12
+
+
+
+
+
+
+
+
+
+
+
+
+ 13
+
+
+ protected
+
+
+ 1
+
+
+
+
+
+
+ 14
+
+
+ def sequential_link(template)
+
+
+ 1
+
+
+
+
+
+
+ 15
+
+
+ template.post_versions_path(:before_time => post_set.posts[-1].last_commented_at, :page => nil)
+
+
+ 0
+
+
+
+
+
+
+ 16
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 17
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 18
+
+
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ./app/presenters/post_history_revision_presenter.rb
+ 37.5 % covered
+
+
+
+ #
+
+ Hits
+
+
+
+
+
+
+
+ 1
+
+
+ class PostHistoryRevisionPresenter < Presenter
+
+
+ 1
+
+
+
+
+
+
+ 2
+
+
+ attr_reader :revision
+
+
+ 1
+
+
+
+
+
+
+ 3
+
+
+
+
+
+
+
+
+
+
+
+
+ 4
+
+
+ def initialize(revision)
+
+
+ 1
+
+
+
+
+
+
+ 5
+
+
+ @revision = revision
+
+
+ 0
+
+
+
+
+
+
+ 6
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 7
+
+
+
+
+
+
+
+
+
+
+
+
+ 8
+
+
+ def changes
+
+
+ 1
+
+
+
+
+
+
+ 9
+
+
+ html = []
+
+
+ 0
+
+
+
+
+
+
+ 10
+
+
+ html << revision.diff[:del].map {|x| "<del>#{h(x)}</del>"}
+
+
+ 0
+
+
+
+
+
+
+ 11
+
+
+ html << revision.diff[:add].map {|x| "<ins>#{h(x)}</ins>"}
+
+
+ 0
+
+
+
+
+
+
+ 12
+
+
+ html << "<ins>source:#{h(revision.diff[:source])}</ins>" if revision.diff[:source].present?
+
+
+ 0
+
+
+
+
+
+
+ 13
+
+
+ html << "<ins>rating:#{h(revision.diff[:rating])}</ins>" if revision.diff[:rating].present?
+
+
+ 0
+
+
+
+
+
+
+ 14
+
+
+ html << "<ins>parent:#{revision.diff[:parent_id]}</ins>" if revision.diff[:parent_id].present?
+
+
+ 0
+
+
+
+
+
+
+ 15
+
+
+ html.join(" ").html_safe
+
+
+ 0
+
+
+
+
+
+
+ 16
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 17
+
+
+
+
+
+
+
+
+
+
+
+
+ 18
+
+
+ def updated_at
+
+
+ 1
+
+
+
+
+
+
+ 19
+
+
+ Time.parse(revision.updated_at)
+
+
+ 0
+
+
+
+
+
+
+ 20
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 21
+
+
+
+
+
+
+
+
+
+
+
+
+ 22
+
+
+ def updater_name
+
+
+ 1
+
+
+
+
+
+
+ 23
+
+
+ User.id_to_name(revision.user_id)
+
+
+ 0
+
+
+
+
+
+
+ 24
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 25
+
+
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ./app/presenters/post_presenter.rb
+ 23.08 % covered
+
+
+
+ #
+
+ Hits
+
+
+
+
+
+
+
+ 1
+
+
+ class PostPresenter < Presenter
+
+
+ 1
+
+
+
+
+
+
+ 2
+
+
+ def self.preview(post)
+
+
+ 1
+
+
+
+
+
+
+ 3
+
+
+ flags = []
+
+
+ 0
+
+
+
+
+
+
+ 4
+
+
+ flags << "pending" if post.is_pending?
+
+
+ 0
+
+
+
+
+
+
+ 5
+
+
+ flags << "flagged" if post.is_flagged?
+
+
+ 0
+
+
+
+
+
+
+ 6
+
+
+ flags << "removed" if post.is_removed?
+
+
+ 0
+
+
+
+
+
+
+ 7
+
+
+
+
+
+
+
+
+
+
+
+
+ 8
+
+
+ html = %{<article id="post_#{post.id}" data-id="#{post.id}" data-tags="#{h(post.tag_string)}" data-uploader="#{h(post.uploader_name)}" data-rating="#{post.rating}" data-width="#{post.image_width}" data-height="#{post.image_height}" data-flags="#{flags.join(' ')}">}
+
+
+ 0
+
+
+
+
+
+
+ 9
+
+
+ html << %{<a href="/posts/#{post.id}">}
+
+
+ 0
+
+
+
+
+
+
+ 10
+
+
+ html << %{<img src="#{post.preview_file_url}">}
+
+
+ 0
+
+
+
+
+
+
+ 11
+
+
+ html << %{</a>}
+
+
+ 0
+
+
+
+
+
+
+ 12
+
+
+ html << %{</article>}
+
+
+ 0
+
+
+
+
+
+
+ 13
+
+
+ html.html_safe
+
+
+ 0
+
+
+
+
+
+
+ 14
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 15
+
+
+
+
+
+
+
+
+
+
+
+
+ 16
+
+
+ def initialize(post)
+
+
+ 1
+
+
+
+
+
+
+ 17
+
+
+ @post = post
+
+
+ 0
+
+
+
+
+
+
+ 18
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 19
+
+
+
+
+
+
+
+
+
+
+
+
+ 20
+
+
+ def preview_html
+
+
+ 1
+
+
+
+
+
+
+ 21
+
+
+ PostPresenter.preview(@post)
+
+
+ 0
+
+
+
+
+
+
+ 22
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 23
+
+
+
+
+
+
+
+
+
+
+
+
+ 24
+
+
+ def image_html(template)
+
+
+ 1
+
+
+
+
+
+
+ 25
+
+
+ return template.content_tag("p", "This image was deleted.") if @post.is_removed? && !CurrentUser.user.is_janitor?
+
+
+ 0
+
+
+
+
+
+
+ 26
+
+
+ return template.content_tag("p", "You need a privileged account to see this image.") if !Danbooru.config.can_see_post?(@post, CurrentUser.user)
+
+
+ 0
+
+
+
+
+
+
+ 27
+
+
+
+
+
+
+
+
+
+
+
+
+ 28
+
+
+ if @post.is_flash?
+
+
+ 0
+
+
+
+
+
+
+ 29
+
+
+ template.render(:partial => "posts/partials/show/flash", :locals => {:post => @post})
+
+
+ 0
+
+
+
+
+
+
+ 30
+
+
+ elsif @post.is_image?
+
+
+ 0
+
+
+
+
+
+
+ 31
+
+
+ template.render(:partial => "posts/partials/show/image", :locals => {:post => @post})
+
+
+ 0
+
+
+
+
+
+
+ 32
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 33
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 34
+
+
+
+
+
+
+
+
+
+
+
+
+ 35
+
+
+ def tag_list_html(template)
+
+
+ 1
+
+
+
+
+
+
+ 36
+
+
+ @tag_set_presenter ||= TagSetPresenter.new(@post.tag_array)
+
+
+ 0
+
+
+
+
+
+
+ 37
+
+
+ @tag_set_presenter.tag_list_html(template, :show_extra_links => CurrentUser.user.is_privileged?)
+
+
+ 0
+
+
+
+
+
+
+ 38
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 39
+
+
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ./app/presenters/post_set_presenter.rb
+ 25.0 % covered
+
+
+
+ #
+
+ Hits
+
+
+
+
+
+
+
+ 1
+
+
+ require 'pp'
+
+
+ 1
+
+
+
+
+
+
+ 2
+
+
+
+
+
+
+
+
+
+
+
+
+ 3
+
+
+ class PostSetPresenter < Presenter
+
+
+ 1
+
+
+
+
+
+
+ 4
+
+
+ attr_accessor :post_set, :tag_set_presenter
+
+
+ 1
+
+
+
+
+
+
+ 5
+
+
+
+
+
+
+
+
+
+
+
+
+ 6
+
+
+ def initialize(post_set)
+
+
+ 1
+
+
+
+
+
+
+ 7
+
+
+ @post_set = post_set
+
+
+ 0
+
+
+
+
+
+
+ 8
+
+
+ @tag_set_presenter = TagSetPresenter.new(RelatedTagCalculator.calculate_from_sample_to_array(@post_set.tags).map {|x| x[0]})
+
+
+ 0
+
+
+
+
+
+
+ 9
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 10
+
+
+
+
+
+
+
+
+
+
+
+
+ 11
+
+
+ def posts
+
+
+ 1
+
+
+
+
+
+
+ 12
+
+
+ post_set.posts
+
+
+ 0
+
+
+
+
+
+
+ 13
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 14
+
+
+
+
+
+
+
+
+
+
+
+
+ 15
+
+
+ def tag_list_html(template)
+
+
+ 1
+
+
+
+
+
+
+ 16
+
+
+ tag_set_presenter.tag_list_html(template)
+
+
+ 0
+
+
+
+
+
+
+ 17
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 18
+
+
+
+
+
+
+
+
+
+
+
+
+ 19
+
+
+ def wiki_html(template)
+
+
+ 1
+
+
+
+
+
+
+ 20
+
+
+ if post_set.has_wiki?
+
+
+ 0
+
+
+
+
+
+
+ 21
+
+
+ wiki_page = WikiPage.find_by_title(post_set.tags)
+
+
+ 0
+
+
+
+
+
+
+ 22
+
+
+ html = '<section>'
+
+
+ 0
+
+
+
+
+
+
+ 23
+
+
+ if wiki_page.nil?
+
+
+ 0
+
+
+
+
+
+
+ 24
+
+
+ html << '<p>'
+
+
+ 0
+
+
+
+
+
+
+ 25
+
+
+ html << 'There is no wiki for this tag.'
+
+
+ 0
+
+
+
+
+
+
+ 26
+
+
+ html << ' '
+
+
+ 0
+
+
+
+
+
+
+ 27
+
+
+ html << template.link_to("Create a new page", template.new_wiki_page_path(:title => post_set.tags))
+
+
+ 0
+
+
+
+
+
+
+ 28
+
+
+ html << '.'
+
+
+ 0
+
+
+
+
+
+
+ 29
+
+
+ html << '</p>'
+
+
+ 0
+
+
+
+
+
+
+ 30
+
+
+ else
+
+
+
+
+
+
+
+
+
+ 31
+
+
+ html << '<h2>'
+
+
+ 0
+
+
+
+
+
+
+ 32
+
+
+ html << template.h(wiki_page.title)
+
+
+ 0
+
+
+
+
+
+
+ 33
+
+
+ html << '</h2>'
+
+
+ 0
+
+
+
+
+
+
+ 34
+
+
+ html << template.format_text(wiki_page.body)
+
+
+ 0
+
+
+
+
+
+
+ 35
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 36
+
+
+ html << '</section>'
+
+
+ 0
+
+
+
+
+
+
+ 37
+
+
+ html.html_safe
+
+
+ 0
+
+
+
+
+
+
+ 38
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 39
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 40
+
+
+
+
+
+
+
+
+
+
+
+
+ 41
+
+
+ def pagination_html(template)
+
+
+ 1
+
+
+
+
+
+
+ 42
+
+
+ if post_set.use_sequential_paginator?
+
+
+ 0
+
+
+
+
+
+
+ 43
+
+
+ Paginators::Post.new(post_set).sequential_pagination_html(template)
+
+
+ 0
+
+
+
+
+
+
+ 44
+
+
+ else
+
+
+
+
+
+
+
+
+
+ 45
+
+
+ Paginators::Post.new(post_set).numbered_pagination_html(template)
+
+
+ 0
+
+
+
+
+
+
+ 46
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 47
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 48
+
+
+
+
+
+
+
+
+
+
+
+
+ 49
+
+
+ def post_previews_html
+
+
+ 1
+
+
+
+
+
+
+ 50
+
+
+ html = ""
+
+
+ 0
+
+
+
+
+
+
+ 51
+
+
+
+
+
+
+
+
+
+
+
+
+ 52
+
+
+ posts.each do |post|
+
+
+ 0
+
+
+
+
+
+
+ 53
+
+
+ html << PostPresenter.preview(post)
+
+
+ 0
+
+
+
+
+
+
+ 54
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 55
+
+
+
+
+
+
+
+
+
+
+
+
+ 56
+
+
+ html.html_safe
+
+
+ 0
+
+
+
+
+
+
+ 57
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 58
+
+
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ./app/presenters/presenter.rb
+ 55.56 % covered
+
+
+
+ #
+
+ Hits
+
+
+
+
+
+
+
+ 1
+
+
+ class Presenter
+
+
+ 1
+
+
+
+
+
+
+ 2
+
+
+ def self.h(s)
+
+
+ 1
+
+
+
+
+
+
+ 3
+
+
+ CGI.escapeHTML(s)
+
+
+ 0
+
+
+
+
+
+
+ 4
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 5
+
+
+
+
+
+
+
+
+
+
+
+
+ 6
+
+
+ def self.u(s)
+
+
+ 1
+
+
+
+
+
+
+ 7
+
+
+ URI.escape(s)
+
+
+ 0
+
+
+
+
+
+
+ 8
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 9
+
+
+
+
+
+
+
+
+
+
+
+
+ 10
+
+
+ def h(s)
+
+
+ 1
+
+
+
+
+
+
+ 11
+
+
+ CGI.escapeHTML(s)
+
+
+ 0
+
+
+
+
+
+
+ 12
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 13
+
+
+
+
+
+
+
+
+
+
+
+
+ 14
+
+
+ def u(s)
+
+
+ 1
+
+
+
+
+
+
+ 15
+
+
+ URI.escape(s)
+
+
+ 0
+
+
+
+
+
+
+ 16
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 17
+
+
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ./app/presenters/tag_set_presenter.rb
+ 25.93 % covered
+
+
+
+ #
+
+ Hits
+
+
+
+
+
+
+
+ 1
+
+
+ =begin rdoc
+
+
+
+
+
+
+
+
+
+ 2
+
+
+ A tag set represents a set of tags that are displayed together.
+
+
+
+
+
+
+
+
+
+ 3
+
+
+ This class makes it easy to fetch the categories for all the
+
+
+
+
+
+
+
+
+
+ 4
+
+
+ tags in one call instead of fetching them sequentially.
+
+
+
+
+
+
+
+
+
+ 5
+
+
+ =end
+
+
+
+
+
+
+
+
+
+ 6
+
+
+
+
+
+
+
+
+
+
+
+
+ 7
+
+
+ class TagSetPresenter < Presenter
+
+
+ 1
+
+
+
+
+
+
+ 8
+
+
+ def initialize(tags)
+
+
+ 1
+
+
+
+
+
+
+ 9
+
+
+ @tags = tags
+
+
+ 0
+
+
+
+
+
+
+ 10
+
+
+ fetch_categories
+
+
+ 0
+
+
+
+
+
+
+ 11
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 12
+
+
+
+
+
+
+
+
+
+
+
+
+ 13
+
+
+ def tag_list_html(template, options = {})
+
+
+ 1
+
+
+
+
+
+
+ 14
+
+
+ html = ""
+
+
+ 0
+
+
+
+
+
+
+ 15
+
+
+ html << "<ul>"
+
+
+ 0
+
+
+
+
+
+
+ 16
+
+
+ @tags.each do |tag|
+
+
+ 0
+
+
+
+
+
+
+ 17
+
+
+ html << build_list_item(tag, template, options)
+
+
+ 0
+
+
+
+
+
+
+ 18
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 19
+
+
+ html << "</ul>"
+
+
+ 0
+
+
+
+
+
+
+ 20
+
+
+ html.html_safe
+
+
+ 0
+
+
+
+
+
+
+ 21
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 22
+
+
+
+
+
+
+
+
+
+
+
+
+ 23
+
+
+ private
+
+
+ 1
+
+
+
+
+
+
+ 24
+
+
+ def fetch_categories
+
+
+ 1
+
+
+
+
+
+
+ 25
+
+
+ @category_cache ||= Tag.categories_for(@tags)
+
+
+ 0
+
+
+
+
+
+
+ 26
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 27
+
+
+
+
+
+
+
+
+
+
+
+
+ 28
+
+
+ def category_for(tag)
+
+
+ 1
+
+
+
+
+
+
+ 29
+
+
+ @category_cache[tag]
+
+
+ 0
+
+
+
+
+
+
+ 30
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 31
+
+
+
+
+
+
+
+
+
+
+
+
+ 32
+
+
+ def build_list_item(tag, template, options)
+
+
+ 1
+
+
+
+
+
+
+ 33
+
+
+ html = ""
+
+
+ 0
+
+
+
+
+
+
+ 34
+
+
+ html << %{<li data-tag-type="#{category_for(tag)}" data-tag-name="#{u(tag)}">}
+
+
+ 0
+
+
+
+
+
+
+ 35
+
+
+
+
+
+
+
+
+
+
+
+
+ 36
+
+
+ if CurrentUser.user.is_privileged?
+
+
+ 0
+
+
+
+
+
+
+ 37
+
+
+ html << %{<a href="/wiki_pages?title=#{u(tag)}">?</a> }
+
+
+ 0
+
+
+
+
+
+
+ 38
+
+
+ html << %{<a href="#" class="search-inc-tag">+</a> }
+
+
+ 0
+
+
+
+
+
+
+ 39
+
+
+ html << %{<a href="#" class="search-exl-tag">–</a> }
+
+
+ 0
+
+
+
+
+
+
+ 40
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 41
+
+
+
+
+
+
+
+
+
+
+
+
+ 42
+
+
+ humanized_tag = tag.tr("_", " ")
+
+
+ 0
+
+
+
+
+
+
+ 43
+
+
+ html << %{<a href="/posts?tags=#{u(tag)}">#{h(humanized_tag)}</a>}
+
+
+ 0
+
+
+
+
+
+
+ 44
+
+
+ html << "</li>"
+
+
+ 0
+
+
+
+
+
+
+ 45
+
+
+ html
+
+
+ 0
+
+
+
+
+
+
+ 46
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 47
+
+
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ./app/presenters/upload_presenter.rb
+ 42.86 % covered
+
+
+
+ #
+
+ Hits
+
+
+
+
+
+
+
+ 1
+
+
+ class UploadPresenter < Presenter
+
+
+ 1
+
+
+
+
+
+
+ 2
+
+
+ def initialize(upload)
+
+
+ 1
+
+
+
+
+
+
+ 3
+
+
+ @upload = upload
+
+
+ 0
+
+
+
+
+
+
+ 4
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 5
+
+
+
+
+
+
+
+
+
+
+
+
+ 6
+
+
+ def status(template)
+
+
+ 1
+
+
+
+
+
+
+ 7
+
+
+ case @upload.status
+
+
+ 0
+
+
+
+
+
+
+ 8
+
+
+ when /duplicate: (\d+)/
+
+
+
+
+
+
+
+
+
+ 9
+
+
+ template.link_to(@upload.status, template.__send__(:post_path, $1))
+
+
+ 0
+
+
+
+
+
+
+ 10
+
+
+
+
+
+
+
+
+
+
+
+
+ 11
+
+
+ else
+
+
+
+
+
+
+
+
+
+ 12
+
+
+ @upload.status
+
+
+ 0
+
+
+
+
+
+
+ 13
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 14
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 15
+
+
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ./app/presenters/wiki_page_presenter.rb
+ 6.9 % covered
+
+
+
+ #
+
+ Hits
+
+
+
+
+
+
+
+ 1
+
+
+ class WikiPagePresenter
+
+
+ 1
+
+
+
+
+
+
+ 2
+
+
+
+
+
+
+
+
+
+
+
+
+ 3
+
+
+ # Produce a formatted page that shows the difference between two versions of a page.
+
+
+
+
+
+
+
+
+
+ 4
+
+
+ def diff(other_version)
+
+
+ 1
+
+
+
+
+
+
+ 5
+
+
+ pattern = Regexp.new('(?:<.+?>)|(?:[0-9_A-Za-z\x80-\xff]+[\x09\x20]?)|(?:[ \t]+)|(?:\r?\n)|(?:.+?)')
+
+
+ 0
+
+
+
+
+
+
+ 6
+
+
+
+
+
+
+
+
+
+
+
+
+ 7
+
+
+ thisarr = self.body.scan(pattern)
+
+
+ 0
+
+
+
+
+
+
+ 8
+
+
+ otharr = other_version.body.scan(pattern)
+
+
+ 0
+
+
+
+
+
+
+ 9
+
+
+
+
+
+
+
+
+
+
+
+
+ 10
+
+
+ cbo = Diff::LCS::ContextDiffCallbacks.new
+
+
+ 0
+
+
+
+
+
+
+ 11
+
+
+ diffs = thisarr.diff(otharr, cbo)
+
+
+ 0
+
+
+
+
+
+
+ 12
+
+
+
+
+
+
+
+
+
+
+
+
+ 13
+
+
+ escape_html = lambda {|str| str.gsub(/&/,'&').gsub(/</,'<').gsub(/>/,'>')}
+
+
+ 0
+
+
+
+
+
+
+ 14
+
+
+
+
+
+
+
+
+
+
+
+
+ 15
+
+
+ output = thisarr;
+
+
+ 0
+
+
+
+
+
+
+ 16
+
+
+ output.each { |q| q.replace(CGI.escape_html(q)) }
+
+
+ 0
+
+
+
+
+
+
+ 17
+
+
+
+
+
+
+
+
+
+
+
+
+ 18
+
+
+ diffs.reverse_each do |hunk|
+
+
+ 0
+
+
+
+
+
+
+ 19
+
+
+ newchange = hunk.max{|a,b| a.old_position <=> b.old_position}
+
+
+ 0
+
+
+
+
+
+
+ 20
+
+
+ newstart = newchange.old_position
+
+
+ 0
+
+
+
+
+
+
+ 21
+
+
+ oldstart = hunk.min{|a,b| a.old_position <=> b.old_position}.old_position
+
+
+ 0
+
+
+
+
+
+
+ 22
+
+
+
+
+
+
+
+
+
+
+
+
+ 23
+
+
+ if newchange.action == '+'
+
+
+ 0
+
+
+
+
+
+
+ 24
+
+
+ output.insert(newstart, "</ins>")
+
+
+ 0
+
+
+
+
+
+
+ 25
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 26
+
+
+
+
+
+
+
+
+
+
+
+
+ 27
+
+
+ hunk.reverse_each do |chg|
+
+
+ 0
+
+
+
+
+
+
+ 28
+
+
+ case chg.action
+
+
+ 0
+
+
+
+
+
+
+ 29
+
+
+ when '-'
+
+
+
+
+
+
+
+
+
+ 30
+
+
+ oldstart = chg.old_position
+
+
+ 0
+
+
+
+
+
+
+ 31
+
+
+ output[chg.old_position] = "" if chg.old_element.match(/^\r?\n$/)
+
+
+ 0
+
+
+
+
+
+
+ 32
+
+
+ when '+'
+
+
+
+
+
+
+
+
+
+ 33
+
+
+ if chg.new_element.match(/^\r?\n$/)
+
+
+ 0
+
+
+
+
+
+
+ 34
+
+
+ output.insert(chg.old_position, "[nl]")
+
+
+ 0
+
+
+
+
+
+
+ 35
+
+
+ else
+
+
+
+
+
+
+
+
+
+ 36
+
+
+ output.insert(chg.old_position, "#{escape_html[chg.new_element]}")
+
+
+ 0
+
+
+
+
+
+
+ 37
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 38
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 39
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 40
+
+
+
+
+
+
+
+
+
+
+
+
+ 41
+
+
+ if newchange.action == '+'
+
+
+ 0
+
+
+
+
+
+
+ 42
+
+
+ output.insert(newstart, "<ins>")
+
+
+ 0
+
+
+
+
+
+
+ 43
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 44
+
+
+
+
+
+
+
+
+
+
+
+
+ 45
+
+
+ if hunk[0].action == '-'
+
+
+ 0
+
+
+
+
+
+
+ 46
+
+
+ output.insert((newstart == oldstart || newchange.action != '+') ? newstart+1 : newstart, "</del>")
+
+
+ 0
+
+
+
+
+
+
+ 47
+
+
+ output.insert(oldstart, "<del>")
+
+
+ 0
+
+
+
+
+
+
+ 48
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 49
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 50
+
+
+
+
+
+
+
+
+
+
+
+
+ 51
+
+
+ output.join.gsub(/\r?\n/, "[nl]")
+
+
+ 0
+
+
+
+
+
+
+ 52
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 53
+
+
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ./lib/danbooru_image_resizer/danbooru_image_resizer.rb
+ 33.33 % covered
+
+
+
+ #
+
+ Hits
+
+
+
+
+
+
+
+ 1
+
+
+ require 'danbooru_image_resizer/danbooru_image_resizer.so'
+
+
+ 1
+
+
+
+
+
+
+ 2
+
+
+
+
+
+
+
+
+
+
+
+
+ 3
+
+
+ module Danbooru
+
+
+ 1
+
+
+
+
+
+
+ 4
+
+
+ def resize(file_ext, read_path, write_path, output_size, output_quality)
+
+
+ 1
+
+
+
+
+
+
+ 5
+
+
+ Danbooru.resize_image(file_ext, read_path, write_path, output_size[:width], output_size[:height], output_quality)
+
+
+ 0
+
+
+
+
+
+
+ 6
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 7
+
+
+
+
+
+
+
+
+
+
+
+
+ 8
+
+
+ def reduce_to(size, max_size)
+
+
+ 1
+
+
+
+
+
+
+ 9
+
+
+ size.dup.tap do |new_size|
+
+
+ 0
+
+
+
+
+
+
+ 10
+
+
+ if new_size[:width] > max_size[:width]
+
+
+ 0
+
+
+
+
+
+
+ 11
+
+
+ scale = max_size[:width].to_f / new_size[:width].to_f
+
+
+ 0
+
+
+
+
+
+
+ 12
+
+
+ new_size[:width] = new_size[:width] * scale
+
+
+ 0
+
+
+
+
+
+
+ 13
+
+
+ new_size[:height] = new_size[:height] * scale
+
+
+ 0
+
+
+
+
+
+
+ 14
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 15
+
+
+
+
+
+
+
+
+
+
+
+
+ 16
+
+
+ if max_size[:height] && (new_size[:height] > max_size[:height])
+
+
+ 0
+
+
+
+
+
+
+ 17
+
+
+ scale = max_size[:height].to_f / new_size[:height].to_f
+
+
+ 0
+
+
+
+
+
+
+ 18
+
+
+ new_size[:width] = new_size[:width] * scale
+
+
+ 0
+
+
+
+
+
+
+ 19
+
+
+ new_size[:height] = new_size[:height] * scale
+
+
+ 0
+
+
+
+
+
+
+ 20
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 21
+
+
+
+
+
+
+
+
+
+
+
+
+ 22
+
+
+ new_size[:width] = new_size[:width].to_i
+
+
+ 0
+
+
+
+
+
+
+ 23
+
+
+ new_size[:height] = new_size[:height].to_i
+
+
+ 0
+
+
+
+
+
+
+ 24
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 25
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 26
+
+
+
+
+
+
+
+
+
+
+
+
+ 27
+
+
+ module_function :resize
+
+
+ 1
+
+
+
+
+
+
+ 28
+
+
+ module_function :reduce_to
+
+
+ 1
+
+
+
+
+
+
+ 29
+
+
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ./vendor/plugins/jrails/lib/jrails.rb
+ 100.0 % covered
+
+
+
+ #
+
+ Hits
+
+
+
+
+
+
+
+ 1
+
+
+ $: << File.expand_path("..", __FILE__)
+
+
+ 1
+
+
+
+
+
+
+ 2
+
+
+
+
+
+
+
+
+
+
+
+
+ 3
+
+
+ require 'jrails/jrails'
+
+
+ 1
+
+
+
+
+
+
+ 4
+
+
+ require 'jrails/asset_tag_ext'
+
+
+ 1
+
+
+
+
+
+
+ 5
+
+
+ require 'jrails/jquery_selector_assertions' if Rails.env == 'test'
+
+
+ 1
+
+
+
+
+
+
+
+
+
+
+
+
+ ./vendor/plugins/jrails/lib/jrails/asset_tag_ext.rb
+ 52.94 % covered
+
+
+
+ #
+
+ Hits
+
+
+
+
+
+
+
+ 1
+
+
+ # The following options can be changed by creating an initializer in config/initializers/jrails.rb
+
+
+
+
+
+
+
+
+
+ 2
+
+
+
+
+
+
+
+
+
+
+
+
+ 3
+
+
+ # jRails does NOT use jQuery.noConflict() by default
+
+
+
+
+
+
+
+
+
+ 4
+
+
+ # to use jQuery.noConflict() , use:
+
+
+
+
+
+
+
+
+
+ 5
+
+
+ # ActionView::Helpers::PrototypeHelper::JQUERY_VAR = 'jQuery'
+
+
+
+
+
+
+
+
+
+ 6
+
+
+
+
+
+
+
+
+
+
+
+
+ 7
+
+
+
+
+
+
+
+
+
+
+
+
+ 8
+
+
+ JRails.load_config
+
+
+ 1
+
+
+
+
+
+
+ 9
+
+
+
+
+
+
+
+
+
+
+
+
+ 10
+
+
+ if JRails.google?
+
+
+ 1
+
+
+
+
+
+
+ 11
+
+
+ ActionView::Helpers::AssetTagHelper.register_javascript_expansion :jrails => ["jrails#{".min" if JRails.compressed?}"]
+
+
+ 0
+
+
+
+
+
+
+ 12
+
+
+ else
+
+
+
+
+
+
+
+
+
+ 13
+
+
+ ActionView::Helpers::AssetTagHelper.register_javascript_expansion :jrails => ["jquery#{".min" if JRails.compressed?}","jquery-ui#{".min" if JRails.compressed?}","jquery-ui-i18n#{".min" if JRails.compressed?}","jrails#{".min" if JRails.compressed?}"]
+
+
+ 1
+
+
+
+
+
+
+ 14
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 15
+
+
+
+
+
+
+
+
+
+
+
+
+ 16
+
+
+
+
+
+
+
+
+
+
+
+
+ 17
+
+
+ ActionView::Helpers::AssetTagHelper.module_eval do
+
+
+ 1
+
+
+
+
+
+
+ 18
+
+
+ def yield_authenticity_javascript
+
+
+ 1
+
+
+
+
+
+
+ 19
+
+
+ <<JAVASCRIPT
+
+
+
+
+
+
+
+
+
+ 20
+
+
+ <script type='text/javascript'>
+
+
+
+
+
+
+
+
+
+ 21
+
+
+ //<![CDATA[
+
+
+
+
+
+
+
+
+
+ 22
+
+
+ window._auth_token = '#{form_authenticity_token}';
+
+
+ 0
+
+
+
+
+
+
+ 23
+
+
+ $(document).ajaxSend(function(event, xhr, s) {
+
+
+
+
+
+
+
+
+
+ 24
+
+
+ if (typeof(window._auth_token) == "undefined") return;
+
+
+
+
+
+
+
+
+
+ 25
+
+
+ if (s.data && s.data.match(new RegExp("\\bauthenticity_token="))) return;
+
+
+
+
+
+
+
+
+
+ 26
+
+
+ if (s.data)
+
+
+
+
+
+
+
+
+
+ 27
+
+
+ s.data += "&";
+
+
+
+
+
+
+
+
+
+ 28
+
+
+ else {
+
+
+
+
+
+
+
+
+
+ 29
+
+
+ s.data = "";
+
+
+
+
+
+
+
+
+
+ 30
+
+
+ xhr.setRequestHeader("Content-Type", s.contentType);
+
+
+
+
+
+
+
+
+
+ 31
+
+
+ }
+
+
+
+
+
+
+
+
+
+ 32
+
+
+ s.data += "authenticity_token=" + encodeURIComponent(window._auth_token);
+
+
+
+
+
+
+
+
+
+ 33
+
+
+ });
+
+
+
+
+
+
+
+
+
+ 34
+
+
+ //]]>
+
+
+
+
+
+
+
+
+
+ 35
+
+
+ </script>
+
+
+
+
+
+
+
+
+
+ 36
+
+
+ JAVASCRIPT
+
+
+
+
+
+
+
+
+
+ 37
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 38
+
+
+
+
+
+
+
+
+
+
+
+
+ 39
+
+
+ def javascript_include_tag_with_jquery(*source)
+
+
+ 1
+
+
+
+
+
+
+ 40
+
+
+ if source.first == :jrails
+
+
+ 5
+
+
+
+
+
+
+ 41
+
+
+ javascripts = []
+
+
+ 0
+
+
+
+
+
+
+ 42
+
+
+ if JRails.google?
+
+
+ 0
+
+
+
+
+
+
+ 43
+
+
+ javascripts \
+
+
+
+
+
+
+
+
+
+ 44
+
+
+ << javascript_include_tag_without_jquery(JRails.jquery_path) \
+
+
+
+
+
+
+
+
+
+ 45
+
+
+ << javascript_include_tag_without_jquery(JRails.jqueryui_path) \
+
+
+
+
+
+
+
+
+
+ 46
+
+
+ << javascript_include_tag_without_jquery(JRails.jqueryui_i18n_path) \
+
+
+
+
+
+
+
+
+
+ 47
+
+
+ end
+
+
+ 0
+
+
+
+
+
+
+ 48
+
+
+ javascripts << javascript_include_tag_without_jquery(*source)
+
+
+ 0
+
+
+
+
+
+
+ 49
+
+
+ javascripts << yield_authenticity_javascript if protect_against_forgery?
+
+
+ 0
+
+
+
+
+
+
+ 50
+
+
+ javascripts.join("\n")
+
+
+ 0
+
+
+
+
+
+
+ 51
+
+
+ else
+
+
+
+
+
+
+
+
+
+ 52
+
+
+ javascript_include_tag_without_jquery(*source)
+
+
+ 5
+
+
+
+
+
+
+ 53
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 54
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 55
+
+
+ alias_method_chain :javascript_include_tag, :jquery
+
+
+ 1
+
+
+
+
+
+
+ 56
+
+
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ./vendor/plugins/jrails/lib/jrails/jquery_selector_assertions.rb
+ 89.47 % covered
+
+
+
+ #
+
+ Hits
+
+
+
+
+
+
+
+ 1
+
+
+ #
+
+
+
+
+
+
+
+
+
+ 2
+
+
+ # jQuery Selector Assertions (modifications to the prototype/scriptaculous assertions)
+
+
+
+
+
+
+
+
+
+ 3
+
+
+ #
+
+
+
+
+
+
+
+
+
+ 4
+
+
+ # From http://pastie.org/303776
+
+
+
+
+
+
+
+
+
+ 5
+
+
+ #
+
+
+
+
+
+
+
+
+
+ 6
+
+
+ # 1. Make sure to use '#' prefix when referring to element IDs in assert_select_rjs(),
+
+
+
+
+
+
+
+
+
+ 7
+
+
+ # like this:
+
+
+
+
+
+
+
+
+
+ 8
+
+
+ # assert_select_rjs :replace_html, '#someid'
+
+
+
+
+
+
+
+
+
+ 9
+
+
+ # instead of prototype convention:
+
+
+
+
+
+
+
+
+
+ 10
+
+
+ # assert_select_rjs :replace_html, 'someid'
+
+
+
+
+
+
+
+
+
+ 11
+
+
+ #
+
+
+
+
+
+
+
+
+
+ 12
+
+
+ # We monkey-patch some RJS-matching constants for assert_select_rjs to work
+
+
+
+
+
+
+
+
+
+ 13
+
+
+ # with jQuery-based code as opposed to Prototype's:
+
+
+
+
+
+
+
+
+
+ 14
+
+
+ #
+
+
+
+
+
+
+
+
+
+ 15
+
+
+ #
+
+
+
+
+
+
+
+
+
+ 16
+
+
+ module JRails
+
+
+ 1
+
+
+
+
+
+
+ 17
+
+
+ module SelectorAssertions
+
+
+ 1
+
+
+
+
+
+
+ 18
+
+
+ def self.included(base)
+
+
+ 1
+
+
+
+
+
+
+ 19
+
+
+ self.constants.each do |cnst|
+
+
+ 1
+
+
+
+
+
+
+ 20
+
+
+ if base.const_defined? cnst
+
+
+ 4
+
+
+
+
+
+
+ 21
+
+
+ base.send(:remove_const,cnst)
+
+
+ 4
+
+
+
+
+
+
+ 22
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 23
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 24
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 25
+
+
+
+
+
+
+
+
+
+
+
+
+ 26
+
+
+ silence_warnings do
+
+
+ 1
+
+
+
+
+
+
+ 27
+
+
+ RJS_PATTERN_HTML = "\"((\\\\\"|[^\"])*)\""
+
+
+ 1
+
+
+
+
+
+
+ 28
+
+
+ RJS_ANY_ID = "[\"']([^\"])*[\"']"
+
+
+ 1
+
+
+
+
+
+
+ 29
+
+
+
+
+
+
+
+
+
+
+
+
+ 30
+
+
+ RJS_STATEMENTS = {
+
+
+ 1
+
+
+
+
+
+
+ 31
+
+
+ :chained_replace => "\(jQuery|$\)\\(#{RJS_ANY_ID}\\)\\.replaceWith\\(#{RJS_PATTERN_HTML}\\)",
+
+
+
+
+
+
+
+
+
+ 32
+
+
+ :chained_replace_html => "\(jQuery|$\)\\(#{RJS_ANY_ID}\\)\\.updateWith\\(#{RJS_PATTERN_HTML}\\)",
+
+
+
+
+
+
+
+
+
+ 33
+
+
+ :replace_html => "\(jQuery|$\)\\(#{RJS_ANY_ID}\\)\\.html\\(#{RJS_PATTERN_HTML}\\)",
+
+
+
+
+
+
+
+
+
+ 34
+
+
+ :replace => "\(jQuery|$\)\\(#{RJS_ANY_ID}\\)\\.replaceWith\\(#{RJS_PATTERN_HTML}\\)",
+
+
+
+
+
+
+
+
+
+ 35
+
+
+ :insert_top => "\(jQuery|$\)\\(#{RJS_ANY_ID}\\)\\.prepend\\(#{RJS_PATTERN_HTML}\\)",
+
+
+
+
+
+
+
+
+
+ 36
+
+
+ :insert_bottom => "\(jQuery|$\)\\(#{RJS_ANY_ID}\\)\\.append\\(#{RJS_PATTERN_HTML}\\)",
+
+
+
+
+
+
+
+
+
+ 37
+
+
+ :effect => "\(jQuery|$\)\\(#{RJS_ANY_ID}\\)\\.effect\\(",
+
+
+
+
+
+
+
+
+
+ 38
+
+
+ :highlight => "\(jQuery|$\)\\(#{RJS_ANY_ID}\\)\\.effect\\('highlight'"
+
+
+
+
+
+
+
+
+
+ 39
+
+
+ }
+
+
+
+
+
+
+
+
+
+ 40
+
+
+
+
+
+
+
+
+
+
+
+
+ 41
+
+
+ [:remove, :show, :hide, :toggle, :reset ].each do |action|
+
+
+ 1
+
+
+
+
+
+
+ 42
+
+
+ RJS_STATEMENTS[action] = "\(jQuery|$\)\\(#{RJS_ANY_ID}\\)\\.#{action}\\(\\)"
+
+
+ 5
+
+
+
+
+
+
+ 43
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 44
+
+
+
+
+
+
+
+
+
+
+
+
+ 45
+
+
+ RJS_STATEMENTS[:any] = Regexp.new("(#{RJS_STATEMENTS.values.join('|')})")
+
+
+ 1
+
+
+
+
+
+
+ 46
+
+
+ RJS_PATTERN_UNICODE_ESCAPED_CHAR = /\\u([0-9a-zA-Z]{4})/
+
+
+ 1
+
+
+
+
+
+
+ 47
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 48
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 49
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 50
+
+
+
+
+
+
+
+
+
+
+
+
+ 51
+
+
+ if (defined? ActionController::Assertions)
+
+
+ 1
+
+
+
+
+
+
+ 52
+
+
+ module ActionController::Assertions::SelectorAssertions
+
+
+ 0
+
+
+
+
+
+
+ 53
+
+
+ include JRails::SelectorAssertions
+
+
+ 0
+
+
+
+
+
+
+ 54
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 55
+
+
+ else
+
+
+
+
+
+
+
+
+
+ 56
+
+
+ module ActionDispatch::Assertions::SelectorAssertions
+
+
+ 1
+
+
+
+
+
+
+ 57
+
+
+ include JRails::SelectorAssertions
+
+
+ 1
+
+
+
+
+
+
+ 58
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 59
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 60
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ./vendor/plugins/jrails/lib/jrails/jrails.rb
+ 29.22 % covered
+
+
+
+ #
+
+ Hits
+
+
+
+
+
+
+
+ 1
+
+
+ module JRails
+
+
+ 1
+
+
+
+
+
+
+ 2
+
+
+ @@config = {
+
+
+ 1
+
+
+
+
+
+
+ 3
+
+
+ :google => false,
+
+
+
+
+
+
+
+
+
+ 4
+
+
+ :jquery_version => "1.4.2",
+
+
+
+
+
+
+
+
+
+ 5
+
+
+ :jqueryui_version => "1.8.4",
+
+
+
+
+
+
+
+
+
+ 6
+
+
+ :compressed => true
+
+
+
+
+
+
+
+
+
+ 7
+
+
+ }
+
+
+
+
+
+
+
+
+
+ 8
+
+
+
+
+
+
+
+
+
+
+
+
+ 9
+
+
+ def self.load_config
+
+
+ 1
+
+
+
+
+
+
+ 10
+
+
+ config_file = File.join(Rails.root, "config", "jrails.yml")
+
+
+ 1
+
+
+
+
+
+
+ 11
+
+
+ if File.exist? config_file
+
+
+ 1
+
+
+
+
+
+
+ 12
+
+
+ loaded_config = YAML.load_file(config_file)
+
+
+ 1
+
+
+
+
+
+
+ 13
+
+
+ if loaded_config and loaded_config.key? Rails.env
+
+
+ 1
+
+
+
+
+
+
+ 14
+
+
+ @@config.merge!(loaded_config[Rails.env].symbolize_keys)
+
+
+ 1
+
+
+
+
+
+
+ 15
+
+
+ if google?
+
+
+ 1
+
+
+
+
+
+
+ 16
+
+
+ @@jquery_path = "http://ajax.googleapis.com/ajax/libs/jquery/#{@@config[:jquery_version]}/jquery#{".min" if compressed?}.js"
+
+
+ 0
+
+
+
+
+
+
+ 17
+
+
+ @@jqueryui_path = "http://ajax.googleapis.com/ajax/libs/jqueryui/#{@@config[:jqueryui_version]}/jquery-ui#{".min" if compressed?}.js"
+
+
+ 0
+
+
+
+
+
+
+ 18
+
+
+ @@jqueryui_i18n_path = "http://ajax.googleapis.com/ajax/libs/jqueryui/#{@@config[:jqueryui_version]}/i18n/jquery-ui-i18n#{".min" if compressed?}.js"
+
+
+ 0
+
+
+
+
+
+
+ 19
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 20
+
+
+ else
+
+
+
+
+
+
+
+
+
+ 21
+
+
+ raise Exception.new "Failed finding '#{Rails.env}' environment in config. check your 'config/jrails.yml' or delete that file "
+
+
+ 0
+
+
+
+
+
+
+ 22
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 23
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 24
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 25
+
+
+
+
+
+
+
+
+
+
+
+
+ 26
+
+
+ def self.config ; @@config ; end
+
+
+ 1
+
+
+
+
+
+
+ 27
+
+
+ def self.google? ; @@config[:google] ; end
+
+
+ 3
+
+
+
+
+
+
+ 28
+
+
+ def self.compressed? ; @@config[:compressed] ; end
+
+
+ 5
+
+
+
+
+
+
+ 29
+
+
+ def self.jquery_path ; @@jquery_path ; end
+
+
+ 1
+
+
+
+
+
+
+ 30
+
+
+ def self.jqueryui_path ; @@jqueryui_path ; end
+
+
+ 1
+
+
+
+
+
+
+ 31
+
+
+ def self.jqueryui_i18n_path ; @@jqueryui_i18n_path ; end
+
+
+ 1
+
+
+
+
+
+
+ 32
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 33
+
+
+
+
+
+
+
+
+
+
+
+
+ 34
+
+
+
+
+
+
+
+
+
+
+
+
+ 35
+
+
+
+
+
+
+
+
+
+
+
+
+ 36
+
+
+ module ActionView
+
+
+ 1
+
+
+
+
+
+
+ 37
+
+
+ module Helpers
+
+
+ 1
+
+
+
+
+
+
+ 38
+
+
+
+
+
+
+
+
+
+
+
+
+ 39
+
+
+ module JavaScriptHelper
+
+
+ 1
+
+
+
+
+
+
+ 40
+
+
+
+
+
+
+
+
+
+
+
+
+ 41
+
+
+ # This function can be used to render rjs inline
+
+
+
+
+
+
+
+
+
+ 42
+
+
+ #
+
+
+
+
+
+
+
+
+
+ 43
+
+
+ # <%= javascript_function do |page|
+
+
+
+
+
+
+
+
+
+ 44
+
+
+ # page.replace_html :list, :partial => 'list', :object => @list
+
+
+
+
+
+
+
+
+
+ 45
+
+
+ # end %>
+
+
+
+
+
+
+
+
+
+ 46
+
+
+ #
+
+
+
+
+
+
+
+
+
+ 47
+
+
+ def javascript_function(*args, &block)
+
+
+ 1
+
+
+
+
+
+
+ 48
+
+
+ html_options = args.extract_options!
+
+
+ 0
+
+
+
+
+
+
+ 49
+
+
+ function = args[0] || ''
+
+
+ 0
+
+
+
+
+
+
+ 50
+
+
+
+
+
+
+
+
+
+
+
+
+ 51
+
+
+ html_options.symbolize_keys!
+
+
+ 0
+
+
+
+
+
+
+ 52
+
+
+ function = update_page(&block) if block_given?
+
+
+ 0
+
+
+
+
+
+
+ 53
+
+
+ javascript_tag(function)
+
+
+ 0
+
+
+
+
+
+
+ 54
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 55
+
+
+
+
+
+
+
+
+
+
+
+
+ 56
+
+
+ def jquery_id(id)
+
+
+ 1
+
+
+
+
+
+
+ 57
+
+
+ id.to_s.count('#.*,>+~:[/ ') == 0 ? "##{id}" : id
+
+
+ 0
+
+
+
+
+
+
+ 58
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 59
+
+
+
+
+
+
+
+
+
+
+
+
+ 60
+
+
+ def jquery_ids(ids)
+
+
+ 1
+
+
+
+
+
+
+ 61
+
+
+ Array(ids).map{|id| jquery_id(id)}.join(',')
+
+
+ 0
+
+
+
+
+
+
+ 62
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 63
+
+
+
+
+
+
+
+
+
+
+
+
+ 64
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 65
+
+
+
+
+
+
+
+
+
+
+
+
+ 66
+
+
+ module PrototypeHelper
+
+
+ 1
+
+
+
+
+
+
+ 67
+
+
+
+
+
+
+
+
+
+
+
+
+ 68
+
+
+ USE_PROTECTION = const_defined?(:DISABLE_JQUERY_FORGERY_PROTECTION) ? !DISABLE_JQUERY_FORGERY_PROTECTION : true
+
+
+ 1
+
+
+
+
+
+
+ 69
+
+
+
+
+
+
+
+
+
+
+
+
+ 70
+
+
+ unless const_defined? :JQUERY_VAR
+
+
+ 1
+
+
+
+
+
+
+ 71
+
+
+ JQUERY_VAR = 'jQuery'
+
+
+ 1
+
+
+
+
+
+
+ 72
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 73
+
+
+
+
+
+
+
+
+
+
+
+
+ 74
+
+
+ unless const_defined? :JQCALLBACKS
+
+
+ 1
+
+
+
+
+
+
+ 75
+
+
+ JQCALLBACKS = Set.new([ :beforeSend, :complete, :error, :success ] + (100..599).to_a)
+
+
+ 1
+
+
+
+
+
+
+ 76
+
+
+ #instance_eval { remove_const :AJAX_OPTIONS }
+
+
+
+
+
+
+
+
+
+ 77
+
+
+ remove_const(:AJAX_OPTIONS) if const_defined?(:AJAX_OPTIONS)
+
+
+ 1
+
+
+
+
+
+
+ 78
+
+
+ AJAX_OPTIONS = Set.new([ :before, :after, :condition, :url,
+
+
+ 1
+
+
+
+
+
+
+ 79
+
+
+ :asynchronous, :method, :insertion, :position,
+
+
+
+
+
+
+
+
+
+ 80
+
+
+ :form, :with, :update, :script ]).merge(JQCALLBACKS)
+
+
+
+
+
+
+
+
+
+ 81
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 82
+
+
+
+
+
+
+
+
+
+
+
+
+ 83
+
+
+ def periodically_call_remote(options = {})
+
+
+ 1
+
+
+
+
+
+
+ 84
+
+
+ frequency = options[:frequency] || 10 # every ten seconds by default
+
+
+ 0
+
+
+
+
+
+
+ 85
+
+
+ code = "setInterval(function() {#{remote_function(options)}}, #{frequency} * 1000)"
+
+
+ 0
+
+
+
+
+
+
+ 86
+
+
+ javascript_tag(code)
+
+
+ 0
+
+
+
+
+
+
+ 87
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 88
+
+
+
+
+
+
+
+
+
+
+
+
+ 89
+
+
+ def remote_function(options)
+
+
+ 1
+
+
+
+
+
+
+ 90
+
+
+ javascript_options = options_for_ajax(options)
+
+
+ 0
+
+
+
+
+
+
+ 91
+
+
+
+
+
+
+
+
+
+
+
+
+ 92
+
+
+ update = ''
+
+
+ 0
+
+
+
+
+
+
+ 93
+
+
+ if options[:update] && options[:update].is_a?(Hash)
+
+
+ 0
+
+
+
+
+
+
+ 94
+
+
+ update = []
+
+
+ 0
+
+
+
+
+
+
+ 95
+
+
+ update << "success:'#{options[:update][:success]}'" if options[:update][:success]
+
+
+ 0
+
+
+
+
+
+
+ 96
+
+
+ update << "failure:'#{options[:update][:failure]}'" if options[:update][:failure]
+
+
+ 0
+
+
+
+
+
+
+ 97
+
+
+ update = '{' + update.join(',') + '}'
+
+
+ 0
+
+
+
+
+
+
+ 98
+
+
+ elsif options[:update]
+
+
+
+
+
+
+
+
+
+ 99
+
+
+ update << "'#{options[:update]}'"
+
+
+ 0
+
+
+
+
+
+
+ 100
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 101
+
+
+
+
+
+
+
+
+
+
+
+
+ 102
+
+
+ function = "#{JQUERY_VAR}.ajax(#{javascript_options})"
+
+
+ 0
+
+
+
+
+
+
+ 103
+
+
+
+
+
+
+
+
+
+
+
+
+ 104
+
+
+ function = "#{options[:before]}; #{function}" if options[:before]
+
+
+ 0
+
+
+
+
+
+
+ 105
+
+
+ function = "#{function}; #{options[:after]}" if options[:after]
+
+
+ 0
+
+
+
+
+
+
+ 106
+
+
+ function = "if (#{options[:condition]}) { #{function}; }" if options[:condition]
+
+
+ 0
+
+
+
+
+
+
+ 107
+
+
+ function = "if (confirm('#{escape_javascript(options[:confirm])}')) { #{function}; }" if options[:confirm]
+
+
+ 0
+
+
+
+
+
+
+ 108
+
+
+ return function
+
+
+ 0
+
+
+
+
+
+
+ 109
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 110
+
+
+
+
+
+
+
+
+
+
+
+
+ 111
+
+
+ class JavaScriptGenerator
+
+
+ 1
+
+
+
+
+
+
+ 112
+
+
+ module GeneratorMethods
+
+
+ 1
+
+
+
+
+
+
+ 113
+
+
+
+
+
+
+
+
+
+
+
+
+ 114
+
+
+ def insert_html(position, id, *options_for_render)
+
+
+ 1
+
+
+
+
+
+
+ 115
+
+
+ insertion = position.to_s.downcase
+
+
+ 0
+
+
+
+
+
+
+ 116
+
+
+ insertion = 'append' if insertion == 'bottom'
+
+
+ 0
+
+
+
+
+
+
+ 117
+
+
+ insertion = 'prepend' if insertion == 'top'
+
+
+ 0
+
+
+
+
+
+
+ 118
+
+
+ call "#{JQUERY_VAR}(\"#{jquery_id(id)}\").#{insertion}", render(*options_for_render)
+
+
+ 0
+
+
+
+
+
+
+ 119
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 120
+
+
+
+
+
+
+
+
+
+
+
+
+ 121
+
+
+ def replace_html(id, *options_for_render)
+
+
+ 1
+
+
+
+
+
+
+ 122
+
+
+ insert_html(:html, id, *options_for_render)
+
+
+ 0
+
+
+
+
+
+
+ 123
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 124
+
+
+
+
+
+
+
+
+
+
+
+
+ 125
+
+
+ def replace(id, *options_for_render)
+
+
+ 1
+
+
+
+
+
+
+ 126
+
+
+ call "#{JQUERY_VAR}(\"#{jquery_id(id)}\").replaceWith", render(*options_for_render)
+
+
+ 0
+
+
+
+
+
+
+ 127
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 128
+
+
+
+
+
+
+
+
+
+
+
+
+ 129
+
+
+ def remove(*ids)
+
+
+ 1
+
+
+
+
+
+
+ 130
+
+
+ call "#{JQUERY_VAR}(\"#{jquery_ids(ids)}\").remove"
+
+
+ 0
+
+
+
+
+
+
+ 131
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 132
+
+
+
+
+
+
+
+
+
+
+
+
+ 133
+
+
+ def show(*ids)
+
+
+ 1
+
+
+
+
+
+
+ 134
+
+
+ call "#{JQUERY_VAR}(\"#{jquery_ids(ids)}\").show"
+
+
+ 0
+
+
+
+
+
+
+ 135
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 136
+
+
+
+
+
+
+
+
+
+
+
+
+ 137
+
+
+ def hide(*ids)
+
+
+ 1
+
+
+
+
+
+
+ 138
+
+
+ call "#{JQUERY_VAR}(\"#{jquery_ids(ids)}\").hide"
+
+
+ 0
+
+
+
+
+
+
+ 139
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 140
+
+
+
+
+
+
+
+
+
+
+
+
+ 141
+
+
+ def toggle(*ids)
+
+
+ 1
+
+
+
+
+
+
+ 142
+
+
+ call "#{JQUERY_VAR}(\"#{jquery_ids(ids)}\").toggle"
+
+
+ 0
+
+
+
+
+
+
+ 143
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 144
+
+
+
+
+
+
+
+
+
+
+
+
+ 145
+
+
+ def jquery_id(id)
+
+
+ 1
+
+
+
+
+
+
+ 146
+
+
+ id.to_s.count('#.*,>+~:[/ ') == 0 ? "##{id}" : id
+
+
+ 0
+
+
+
+
+
+
+ 147
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 148
+
+
+
+
+
+
+
+
+
+
+
+
+ 149
+
+
+ def jquery_ids(ids)
+
+
+ 1
+
+
+
+
+
+
+ 150
+
+
+ Array(ids).map{|id| jquery_id(id)}.join(',')
+
+
+ 0
+
+
+
+
+
+
+ 151
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 152
+
+
+
+
+
+
+
+
+
+
+
+
+ 153
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 154
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 155
+
+
+
+
+
+
+
+
+
+
+
+
+ 156
+
+
+ protected
+
+
+ 1
+
+
+
+
+
+
+ 157
+
+
+ def options_for_ajax(options)
+
+
+ 1
+
+
+
+
+
+
+ 158
+
+
+ js_options = build_callbacks(options)
+
+
+ 0
+
+
+
+
+
+
+ 159
+
+
+
+
+
+
+
+
+
+
+
+
+ 160
+
+
+ url_options = options[:url]
+
+
+ 0
+
+
+
+
+
+
+ 161
+
+
+ url_options = url_options.merge(:escape => false) if url_options.is_a?(Hash)
+
+
+ 0
+
+
+
+
+
+
+ 162
+
+
+ js_options['url'] = "'#{url_for(url_options)}'"
+
+
+ 0
+
+
+
+
+
+
+ 163
+
+
+ js_options['async'] = false if options[:type] == :synchronous
+
+
+ 0
+
+
+
+
+
+
+ 164
+
+
+ js_options['type'] = options[:method] ? method_option_to_s(options[:method]) : ( options[:form] ? "'post'" : nil )
+
+
+ 0
+
+
+
+
+
+
+ 165
+
+
+ js_options['dataType'] = options[:datatype] ? "'#{options[:datatype]}'" : (options[:update] ? nil : "'script'")
+
+
+ 0
+
+
+
+
+
+
+ 166
+
+
+
+
+
+
+
+
+
+
+
+
+ 167
+
+
+ if options[:form]
+
+
+ 0
+
+
+
+
+
+
+ 168
+
+
+ js_options['data'] = "#{JQUERY_VAR}.param(#{JQUERY_VAR}(this).serializeArray())"
+
+
+ 0
+
+
+
+
+
+
+ 169
+
+
+ elsif options[:submit]
+
+
+
+
+
+
+
+
+
+ 170
+
+
+ js_options['data'] = "#{JQUERY_VAR}(\"##{options[:submit]}:input\").serialize()"
+
+
+ 0
+
+
+
+
+
+
+ 171
+
+
+ elsif options[:with]
+
+
+
+
+
+
+
+
+
+ 172
+
+
+ js_options['data'] = options[:with].gsub("Form.serialize(this.form)","#{JQUERY_VAR}.param(#{JQUERY_VAR}(this.form).serializeArray())")
+
+
+ 0
+
+
+
+
+
+
+ 173
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 174
+
+
+
+
+
+
+
+
+
+
+
+
+ 175
+
+
+ js_options['type'] ||= "'post'"
+
+
+ 0
+
+
+
+
+
+
+ 176
+
+
+ if options[:method]
+
+
+ 0
+
+
+
+
+
+
+ 177
+
+
+ if method_option_to_s(options[:method]) == "'put'" || method_option_to_s(options[:method]) == "'delete'"
+
+
+ 0
+
+
+
+
+
+
+ 178
+
+
+ js_options['type'] = "'post'"
+
+
+ 0
+
+
+
+
+
+
+ 179
+
+
+ if js_options['data']
+
+
+ 0
+
+
+
+
+
+
+ 180
+
+
+ js_options['data'] << " + '&"
+
+
+ 0
+
+
+
+
+
+
+ 181
+
+
+ else
+
+
+
+
+
+
+
+
+
+ 182
+
+
+ js_options['data'] = "'"
+
+
+ 0
+
+
+
+
+
+
+ 183
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 184
+
+
+ js_options['data'] << "_method=#{options[:method]}'"
+
+
+ 0
+
+
+
+
+
+
+ 185
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 186
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 187
+
+
+
+
+
+
+
+
+
+
+
+
+ 188
+
+
+ if USE_PROTECTION && respond_to?('protect_against_forgery?') && protect_against_forgery?
+
+
+ 0
+
+
+
+
+
+
+ 189
+
+
+ if js_options['data']
+
+
+ 0
+
+
+
+
+
+
+ 190
+
+
+ js_options['data'] << " + '&"
+
+
+ 0
+
+
+
+
+
+
+ 191
+
+
+ else
+
+
+
+
+
+
+
+
+
+ 192
+
+
+ js_options['data'] = "'"
+
+
+ 0
+
+
+
+
+
+
+ 193
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 194
+
+
+ js_options['data'] << "#{request_forgery_protection_token}=' + encodeURIComponent('#{escape_javascript form_authenticity_token}')"
+
+
+ 0
+
+
+
+
+
+
+ 195
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 196
+
+
+ js_options['data'] = "''" if js_options['type'] == "'post'" && js_options['data'].nil?
+
+
+ 0
+
+
+
+
+
+
+ 197
+
+
+ options_for_javascript(js_options.reject {|key, value| value.nil?})
+
+
+ 0
+
+
+
+
+
+
+ 198
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 199
+
+
+
+
+
+
+
+
+
+
+
+
+ 200
+
+
+ def build_update_for_success(html_id, insertion=nil)
+
+
+ 1
+
+
+
+
+
+
+ 201
+
+
+ insertion = build_insertion(insertion)
+
+
+ 0
+
+
+
+
+
+
+ 202
+
+
+ "#{JQUERY_VAR}('#{jquery_id(html_id)}').#{insertion}(request);"
+
+
+ 0
+
+
+
+
+
+
+ 203
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 204
+
+
+
+
+
+
+
+
+
+
+
+
+ 205
+
+
+ def build_update_for_error(html_id, insertion=nil)
+
+
+ 1
+
+
+
+
+
+
+ 206
+
+
+ insertion = build_insertion(insertion)
+
+
+ 0
+
+
+
+
+
+
+ 207
+
+
+ "#{JQUERY_VAR}('#{jquery_id(html_id)}').#{insertion}(request.responseText);"
+
+
+ 0
+
+
+
+
+
+
+ 208
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 209
+
+
+
+
+
+
+
+
+
+
+
+
+ 210
+
+
+ def build_insertion(insertion)
+
+
+ 1
+
+
+
+
+
+
+ 211
+
+
+ insertion = insertion ? insertion.to_s.downcase : 'html'
+
+
+ 0
+
+
+
+
+
+
+ 212
+
+
+ insertion = 'append' if insertion == 'bottom'
+
+
+ 0
+
+
+
+
+
+
+ 213
+
+
+ insertion = 'prepend' if insertion == 'top'
+
+
+ 0
+
+
+
+
+
+
+ 214
+
+
+ insertion
+
+
+ 0
+
+
+
+
+
+
+ 215
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 216
+
+
+
+
+
+
+
+
+
+
+
+
+ 217
+
+
+ def build_observer(klass, name, options = {})
+
+
+ 1
+
+
+
+
+
+
+ 218
+
+
+ if options[:with] && (options[:with] !~ /[\{=(.]/)
+
+
+ 0
+
+
+
+
+
+
+ 219
+
+
+ options[:with] = "'#{options[:with]}=' + value"
+
+
+ 0
+
+
+
+
+
+
+ 220
+
+
+ else
+
+
+
+
+
+
+
+
+
+ 221
+
+
+ options[:with] ||= 'value' unless options[:function]
+
+
+ 0
+
+
+
+
+
+
+ 222
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 223
+
+
+
+
+
+
+
+
+
+
+
+
+ 224
+
+
+ callback = options[:function] || remote_function(options)
+
+
+ 0
+
+
+
+
+
+
+ 225
+
+
+ javascript = "#{JQUERY_VAR}('#{jquery_id(name)}').delayedObserver("
+
+
+ 0
+
+
+
+
+
+
+ 226
+
+
+ javascript << "#{options[:frequency] || 0}, "
+
+
+ 0
+
+
+
+
+
+
+ 227
+
+
+ javascript << "function(element, value) {"
+
+
+ 0
+
+
+
+
+
+
+ 228
+
+
+ javascript << "#{callback}}"
+
+
+ 0
+
+
+
+
+
+
+ 229
+
+
+ #javascript << ", '#{options[:on]}'" if options[:on]
+
+
+
+
+
+
+
+
+
+ 230
+
+
+ javascript << ")"
+
+
+ 0
+
+
+
+
+
+
+ 231
+
+
+ javascript_tag(javascript)
+
+
+ 0
+
+
+
+
+
+
+ 232
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 233
+
+
+
+
+
+
+
+
+
+
+
+
+ 234
+
+
+ def build_callbacks(options)
+
+
+ 1
+
+
+
+
+
+
+ 235
+
+
+ callbacks = {}
+
+
+ 0
+
+
+
+
+
+
+ 236
+
+
+ options[:beforeSend] = '';
+
+
+ 0
+
+
+
+
+
+
+ 237
+
+
+ [:uninitialized,:loading].each do |key|
+
+
+ 0
+
+
+
+
+
+
+ 238
+
+
+ options[:beforeSend] << (options[key].last == ';' ? options.delete(key) : options.delete(key) << ';') if options[key]
+
+
+ 0
+
+
+
+
+
+
+ 239
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 240
+
+
+ options.delete(:beforeSend) if options[:beforeSend].blank?
+
+
+ 0
+
+
+
+
+
+
+ 241
+
+
+ options[:complete] = options.delete(:loaded) if options[:loaded]
+
+
+ 0
+
+
+
+
+
+
+ 242
+
+
+ options[:error] = options.delete(:failure) if options[:failure]
+
+
+ 0
+
+
+
+
+
+
+ 243
+
+
+ if options[:update]
+
+
+ 0
+
+
+
+
+
+
+ 244
+
+
+ if options[:update].is_a?(Hash)
+
+
+ 0
+
+
+
+
+
+
+ 245
+
+
+ options[:update][:error] = options[:update].delete(:failure) if options[:update][:failure]
+
+
+ 0
+
+
+
+
+
+
+ 246
+
+
+ if options[:update][:success]
+
+
+ 0
+
+
+
+
+
+
+ 247
+
+
+ options[:success] = build_update_for_success(options[:update][:success], options[:position]) << (options[:success] ? options[:success] : '')
+
+
+ 0
+
+
+
+
+
+
+ 248
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 249
+
+
+ if options[:update][:error]
+
+
+ 0
+
+
+
+
+
+
+ 250
+
+
+ options[:error] = build_update_for_error(options[:update][:error], options[:position]) << (options[:error] ? options[:error] : '')
+
+
+ 0
+
+
+
+
+
+
+ 251
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 252
+
+
+ else
+
+
+
+
+
+
+
+
+
+ 253
+
+
+ options[:success] = build_update_for_success(options[:update], options[:position]) << (options[:success] ? options[:success] : '')
+
+
+ 0
+
+
+
+
+
+
+ 254
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 255
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 256
+
+
+ options.each do |callback, code|
+
+
+ 0
+
+
+
+
+
+
+ 257
+
+
+ if JQCALLBACKS.include?(callback)
+
+
+ 0
+
+
+
+
+
+
+ 258
+
+
+ callbacks[callback] = "function(request){#{code}}"
+
+
+ 0
+
+
+
+
+
+
+ 259
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 260
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 261
+
+
+ callbacks
+
+
+ 0
+
+
+
+
+
+
+ 262
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 263
+
+
+
+
+
+
+
+
+
+
+
+
+ 264
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 265
+
+
+
+
+
+
+
+
+
+
+
+
+ 266
+
+
+ class JavaScriptElementProxy < JavaScriptProxy #:nodoc:
+
+
+ 1
+
+
+
+
+
+
+ 267
+
+
+
+
+
+
+
+
+
+
+
+
+ 268
+
+
+ unless const_defined? :JQUERY_VAR
+
+
+ 1
+
+
+
+
+
+
+ 269
+
+
+ JQUERY_VAR = PrototypeHelper::JQUERY_VAR
+
+
+ 1
+
+
+
+
+
+
+ 270
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 271
+
+
+
+
+
+
+
+
+
+
+
+
+ 272
+
+
+ def initialize(generator, id)
+
+
+ 1
+
+
+
+
+
+
+ 273
+
+
+ id = id.to_s.count('#.*,>+~:[/ ') == 0 ? "##{id}" : id
+
+
+ 0
+
+
+
+
+
+
+ 274
+
+
+ @id = id
+
+
+ 0
+
+
+
+
+
+
+ 275
+
+
+ super(generator, "#{JQUERY_VAR}(\"#{id}\")")
+
+
+ 0
+
+
+
+
+
+
+ 276
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 277
+
+
+
+
+
+
+
+
+
+
+
+
+ 278
+
+
+ def replace_html(*options_for_render)
+
+
+ 1
+
+
+
+
+
+
+ 279
+
+
+ call 'html', @generator.send(:render, *options_for_render)
+
+
+ 0
+
+
+
+
+
+
+ 280
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 281
+
+
+
+
+
+
+
+
+
+
+
+
+ 282
+
+
+ def replace(*options_for_render)
+
+
+ 1
+
+
+
+
+
+
+ 283
+
+
+ call 'replaceWith', @generator.send(:render, *options_for_render)
+
+
+ 0
+
+
+
+
+
+
+ 284
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 285
+
+
+
+
+
+
+
+
+
+
+
+
+ 286
+
+
+ def reload(options_for_replace={})
+
+
+ 1
+
+
+
+
+
+
+ 287
+
+
+ replace(options_for_replace.merge({ :partial => @id.to_s.sub(/^#/,'') }))
+
+
+ 0
+
+
+
+
+
+
+ 288
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 289
+
+
+
+
+
+
+
+
+
+
+
+
+ 290
+
+
+ def value()
+
+
+ 1
+
+
+
+
+
+
+ 291
+
+
+ call 'val()'
+
+
+ 0
+
+
+
+
+
+
+ 292
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 293
+
+
+
+
+
+
+
+
+
+
+
+
+ 294
+
+
+ def value=(value)
+
+
+ 1
+
+
+
+
+
+
+ 295
+
+
+ call 'val', value
+
+
+ 0
+
+
+
+
+
+
+ 296
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 297
+
+
+
+
+
+
+
+
+
+
+
+
+ 298
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 299
+
+
+
+
+
+
+
+
+
+
+
+
+ 300
+
+
+ class JavaScriptElementCollectionProxy < JavaScriptCollectionProxy #:nodoc:\
+
+
+ 1
+
+
+
+
+
+
+ 301
+
+
+
+
+
+
+
+
+
+
+
+
+ 302
+
+
+ unless const_defined? :JQUERY_VAR
+
+
+ 1
+
+
+
+
+
+
+ 303
+
+
+ JQUERY_VAR = PrototypeHelper::JQUERY_VAR
+
+
+ 1
+
+
+
+
+
+
+ 304
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 305
+
+
+
+
+
+
+
+
+
+
+
+
+ 306
+
+
+ def initialize(generator, pattern)
+
+
+ 1
+
+
+
+
+
+
+ 307
+
+
+ super(generator, "#{JQUERY_VAR}(#{pattern.to_json})")
+
+
+ 0
+
+
+
+
+
+
+ 308
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 309
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 310
+
+
+
+
+
+
+
+
+
+
+
+
+ 311
+
+
+ module ScriptaculousHelper
+
+
+ 1
+
+
+
+
+
+
+ 312
+
+
+
+
+
+
+
+
+
+
+
+
+ 313
+
+
+ unless const_defined? :JQUERY_VAR
+
+
+ 1
+
+
+
+
+
+
+ 314
+
+
+ JQUERY_VAR = PrototypeHelper::JQUERY_VAR
+
+
+ 1
+
+
+
+
+
+
+ 315
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 316
+
+
+
+
+
+
+
+
+
+
+
+
+ 317
+
+
+ unless const_defined? :SCRIPTACULOUS_EFFECTS
+
+
+ 1
+
+
+
+
+
+
+ 318
+
+
+ SCRIPTACULOUS_EFFECTS = {
+
+
+ 1
+
+
+
+
+
+
+ 319
+
+
+ :appear => {:method => 'fadeIn'},
+
+
+
+
+
+
+
+
+
+ 320
+
+
+ :blind_down => {:method => 'blind', :mode => 'show', :options => {:direction => 'vertical'}},
+
+
+
+
+
+
+
+
+
+ 321
+
+
+ :blind_up => {:method => 'blind', :mode => 'hide', :options => {:direction => 'vertical'}},
+
+
+
+
+
+
+
+
+
+ 322
+
+
+ :blind_right => {:method => 'blind', :mode => 'show', :options => {:direction => 'horizontal'}},
+
+
+
+
+
+
+
+
+
+ 323
+
+
+ :blind_left => {:method => 'blind', :mode => 'hide', :options => {:direction => 'horizontal'}},
+
+
+
+
+
+
+
+
+
+ 324
+
+
+ :bounce_in => {:method => 'bounce', :mode => 'show', :options => {:direction => 'up'}},
+
+
+
+
+
+
+
+
+
+ 325
+
+
+ :bounce_out => {:method => 'bounce', :mode => 'hide', :options => {:direction => 'up'}},
+
+
+
+
+
+
+
+
+
+ 326
+
+
+ :drop_in => {:method => 'drop', :mode => 'show', :options => {:direction => 'up'}},
+
+
+
+
+
+
+
+
+
+ 327
+
+
+ :drop_out => {:method => 'drop', :mode => 'hide', :options => {:direction => 'down'}},
+
+
+
+
+
+
+
+
+
+ 328
+
+
+ :fade => {:method => 'fadeOut'},
+
+
+
+
+
+
+
+
+
+ 329
+
+
+ :fold_in => {:method => 'fold', :mode => 'hide'},
+
+
+
+
+
+
+
+
+
+ 330
+
+
+ :fold_out => {:method => 'fold', :mode => 'show'},
+
+
+
+
+
+
+
+
+
+ 331
+
+
+ :grow => {:method => 'scale', :mode => 'show'},
+
+
+
+
+
+
+
+
+
+ 332
+
+
+ :shrink => {:method => 'scale', :mode => 'hide'},
+
+
+
+
+
+
+
+
+
+ 333
+
+
+ :slide_down => {:method => 'slide', :mode => 'show', :options => {:direction => 'up'}},
+
+
+
+
+
+
+
+
+
+ 334
+
+
+ :slide_up => {:method => 'slide', :mode => 'hide', :options => {:direction => 'up'}},
+
+
+
+
+
+
+
+
+
+ 335
+
+
+ :slide_right => {:method => 'slide', :mode => 'show', :options => {:direction => 'left'}},
+
+
+
+
+
+
+
+
+
+ 336
+
+
+ :slide_left => {:method => 'slide', :mode => 'hide', :options => {:direction => 'left'}},
+
+
+
+
+
+
+
+
+
+ 337
+
+
+ :squish => {:method => 'scale', :mode => 'hide', :options => {:origin => "['top','left']"}},
+
+
+
+
+
+
+
+
+
+ 338
+
+
+ :switch_on => {:method => 'clip', :mode => 'show', :options => {:direction => 'vertical'}},
+
+
+
+
+
+
+
+
+
+ 339
+
+
+ :switch_off => {:method => 'clip', :mode => 'hide', :options => {:direction => 'vertical'}},
+
+
+
+
+
+
+
+
+
+ 340
+
+
+ :toggle_appear => {:method => 'fadeToggle'},
+
+
+
+
+
+
+
+
+
+ 341
+
+
+ :toggle_slide => {:method => 'slide', :mode => 'toggle', :options => {:direction => 'up'}},
+
+
+
+
+
+
+
+
+
+ 342
+
+
+ :toggle_blind => {:method => 'blind', :mode => 'toggle', :options => {:direction => 'vertical'}},
+
+
+
+
+
+
+
+
+
+ 343
+
+
+ }
+
+
+
+
+
+
+
+
+
+ 344
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 345
+
+
+
+
+
+
+
+
+
+
+
+
+ 346
+
+
+ def visual_effect(name, element_id = false, js_options = {})
+
+
+ 1
+
+
+
+
+
+
+ 347
+
+
+ element = element_id ? element_id : "this"
+
+
+ 0
+
+
+
+
+
+
+ 348
+
+
+
+
+
+
+
+
+
+
+
+
+ 349
+
+
+ if SCRIPTACULOUS_EFFECTS.has_key? name.to_sym
+
+
+ 0
+
+
+
+
+
+
+ 350
+
+
+ effect = SCRIPTACULOUS_EFFECTS[name.to_sym]
+
+
+ 0
+
+
+
+
+
+
+ 351
+
+
+ name = effect[:method]
+
+
+ 0
+
+
+
+
+
+
+ 352
+
+
+ mode = effect[:mode]
+
+
+ 0
+
+
+
+
+
+
+ 353
+
+
+ js_options = js_options.merge(effect[:options]) if effect[:options]
+
+
+ 0
+
+
+
+
+
+
+ 354
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 355
+
+
+
+
+
+
+
+
+
+
+
+
+ 356
+
+
+ [:color, :direction, :startcolor, :endcolor].each do |option|
+
+
+ 0
+
+
+
+
+
+
+ 357
+
+
+ js_options[option] = "'#{js_options[option]}'" if js_options[option]
+
+
+ 0
+
+
+
+
+
+
+ 358
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 359
+
+
+
+
+
+
+
+
+
+
+
+
+ 360
+
+
+ if js_options.has_key? :duration
+
+
+ 0
+
+
+
+
+
+
+ 361
+
+
+ speed = js_options.delete :duration
+
+
+ 0
+
+
+
+
+
+
+ 362
+
+
+ speed = (speed * 1000).to_i unless speed.nil?
+
+
+ 0
+
+
+
+
+
+
+ 363
+
+
+ else
+
+
+
+
+
+
+
+
+
+ 364
+
+
+ speed = js_options.delete :speed
+
+
+ 0
+
+
+
+
+
+
+ 365
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 366
+
+
+
+
+
+
+
+
+
+
+
+
+ 367
+
+
+ if ['fadeIn','fadeOut','fadeToggle'].include?(name)
+
+
+ 0
+
+
+
+
+
+
+ 368
+
+
+ # 090905 - Jake - changed ' to \" so it passes assert_select_rjs with an id
+
+
+
+
+
+
+
+
+
+ 369
+
+
+ javascript = "#{JQUERY_VAR}(\"#{jquery_id(element_id)}\").#{name}("
+
+
+ 0
+
+
+
+
+
+
+ 370
+
+
+ javascript << "#{speed}" unless speed.nil?
+
+
+ 0
+
+
+
+
+
+
+ 371
+
+
+ javascript << ");"
+
+
+ 0
+
+
+
+
+
+
+ 372
+
+
+ else
+
+
+
+
+
+
+
+
+
+ 373
+
+
+ # 090905 - Jake - changed ' to \" so it passes "assert_select_rjs :effect, ID"
+
+
+
+
+
+
+
+
+
+ 374
+
+
+ javascript = "#{JQUERY_VAR}(\"#{jquery_id(element_id)}\").#{mode || 'effect'}('#{name}'"
+
+
+ 0
+
+
+
+
+
+
+ 375
+
+
+ javascript << ",#{options_for_javascript(js_options)}" unless speed.nil? && js_options.empty?
+
+
+ 0
+
+
+
+
+
+
+ 376
+
+
+ javascript << ",#{speed}" unless speed.nil?
+
+
+ 0
+
+
+
+
+
+
+ 377
+
+
+ javascript << ");"
+
+
+ 0
+
+
+
+
+
+
+ 378
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 379
+
+
+
+
+
+
+
+
+
+
+
+
+ 380
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 381
+
+
+
+
+
+
+
+
+
+
+
+
+ 382
+
+
+ def sortable_element_js(element_id, options = {}) #:nodoc:
+
+
+ 1
+
+
+
+
+
+
+ 383
+
+
+ #convert similar attributes
+
+
+
+
+
+
+
+
+
+ 384
+
+
+ options[:handle] = ".#{options[:handle]}" if options[:handle]
+
+
+ 0
+
+
+
+
+
+
+ 385
+
+
+ if options[:tag] || options[:only]
+
+
+ 0
+
+
+
+
+
+
+ 386
+
+
+ options[:items] = "> "
+
+
+ 0
+
+
+
+
+
+
+ 387
+
+
+ options[:items] << options.delete(:tag) if options[:tag]
+
+
+ 0
+
+
+
+
+
+
+ 388
+
+
+ options[:items] << ".#{options.delete(:only)}" if options[:only]
+
+
+ 0
+
+
+
+
+
+
+ 389
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 390
+
+
+ options[:connectWith] = options.delete(:containment).map {|x| "##{x}"} if options[:containment]
+
+
+ 0
+
+
+
+
+
+
+ 391
+
+
+ options[:containment] = options.delete(:container) if options[:container]
+
+
+ 0
+
+
+
+
+
+
+ 392
+
+
+ options[:dropOnEmpty] = false unless options[:dropOnEmpty]
+
+
+ 0
+
+
+
+
+
+
+ 393
+
+
+ options[:helper] = "'clone'" if options[:ghosting] == true
+
+
+ 0
+
+
+
+
+
+
+ 394
+
+
+ options[:axis] = case options.delete(:constraint)
+
+
+ 0
+
+
+
+
+
+
+ 395
+
+
+ when "vertical", :vertical
+
+
+
+
+
+
+
+
+
+ 396
+
+
+ "y"
+
+
+ 0
+
+
+
+
+
+
+ 397
+
+
+ when "horizontal", :horizontal
+
+
+
+
+
+
+
+
+
+ 398
+
+
+ "x"
+
+
+ 0
+
+
+
+
+
+
+ 399
+
+
+ when false
+
+
+
+
+
+
+
+
+
+ 400
+
+
+ nil
+
+
+ 0
+
+
+
+
+
+
+ 401
+
+
+ when nil
+
+
+
+
+
+
+
+
+
+ 402
+
+
+ "y"
+
+
+ 0
+
+
+
+
+
+
+ 403
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 404
+
+
+ options.delete(:axis) if options[:axis].nil?
+
+
+ 0
+
+
+
+
+
+
+ 405
+
+
+ options.delete(:overlap)
+
+
+ 0
+
+
+
+
+
+
+ 406
+
+
+ options.delete(:ghosting)
+
+
+ 0
+
+
+
+
+
+
+ 407
+
+
+
+
+
+
+
+
+
+
+
+
+ 408
+
+
+ if options[:onUpdate] || options[:url]
+
+
+ 0
+
+
+
+
+
+
+ 409
+
+
+ if options[:format]
+
+
+ 0
+
+
+
+
+
+
+ 410
+
+
+ options[:with] ||= "#{JQUERY_VAR}(this).sortable('serialize',{key:'#{element_id}[]', expression:#{options[:format]}})"
+
+
+ 0
+
+
+
+
+
+
+ 411
+
+
+ options.delete(:format)
+
+
+ 0
+
+
+
+
+
+
+ 412
+
+
+ else
+
+
+
+
+
+
+
+
+
+ 413
+
+
+ options[:with] ||= "#{JQUERY_VAR}(this).sortable('serialize',{key:'#{element_id}[]'})"
+
+
+ 0
+
+
+
+
+
+
+ 414
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 415
+
+
+
+
+
+
+
+
+
+
+
+
+ 416
+
+
+ options[:onUpdate] ||= "function(){" + remote_function(options) + "}"
+
+
+ 0
+
+
+
+
+
+
+ 417
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 418
+
+
+
+
+
+
+
+
+
+
+
+
+ 419
+
+
+ options.delete_if { |key, value| PrototypeHelper::AJAX_OPTIONS.include?(key) }
+
+
+ 0
+
+
+
+
+
+
+ 420
+
+
+ options[:update] = options.delete(:onUpdate) if options[:onUpdate]
+
+
+ 0
+
+
+
+
+
+
+ 421
+
+
+
+
+
+
+
+
+
+
+
+
+ 422
+
+
+ [:axis, :cancel, :containment, :cursor, :handle, :tolerance, :items, :placeholder].each do |option|
+
+
+ 0
+
+
+
+
+
+
+ 423
+
+
+ options[option] = "'#{options[option]}'" if options[option]
+
+
+ 0
+
+
+
+
+
+
+ 424
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 425
+
+
+
+
+
+
+
+
+
+
+
+
+ 426
+
+
+ options[:connectWith] = array_or_string_for_javascript(options[:connectWith]) if options[:connectWith]
+
+
+ 0
+
+
+
+
+
+
+ 427
+
+
+
+
+
+
+
+
+
+
+
+
+ 428
+
+
+ %(#{JQUERY_VAR}('#{jquery_id(element_id)}').sortable(#{options_for_javascript(options)});)
+
+
+ 0
+
+
+
+
+
+
+ 429
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 430
+
+
+
+
+
+
+
+
+
+
+
+
+ 431
+
+
+ def draggable_element_js(element_id, options = {})
+
+
+ 1
+
+
+
+
+
+
+ 432
+
+
+ %(#{JQUERY_VAR}("#{jquery_id(element_id)}").draggable(#{options_for_javascript(options)});)
+
+
+ 0
+
+
+
+
+
+
+ 433
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 434
+
+
+
+
+
+
+
+
+
+
+
+
+ 435
+
+
+ def drop_receiving_element_js(element_id, options = {})
+
+
+ 1
+
+
+
+
+
+
+ 436
+
+
+ #convert similar options
+
+
+
+
+
+
+
+
+
+ 437
+
+
+ options[:hoverClass] = options.delete(:hoverclass) if options[:hoverclass]
+
+
+ 0
+
+
+
+
+
+
+ 438
+
+
+ options[:drop] = options.delete(:onDrop) if options[:onDrop]
+
+
+ 0
+
+
+
+
+
+
+ 439
+
+
+
+
+
+
+
+
+
+
+
+
+ 440
+
+
+ if options[:drop] || options[:url]
+
+
+ 0
+
+
+
+
+
+
+ 441
+
+
+ options[:with] ||= "'id=' + encodeURIComponent(#{JQUERY_VAR}(ui.draggable).attr('id'))"
+
+
+ 0
+
+
+
+
+
+
+ 442
+
+
+ options[:drop] ||= "function(ev, ui){" + remote_function(options) + "}"
+
+
+ 0
+
+
+
+
+
+
+ 443
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 444
+
+
+
+
+
+
+
+
+
+
+
+
+ 445
+
+
+ options.delete_if { |key, value| PrototypeHelper::AJAX_OPTIONS.include?(key) }
+
+
+ 0
+
+
+
+
+
+
+ 446
+
+
+
+
+
+
+
+
+
+
+
+
+ 447
+
+
+ options[:accept] = array_or_string_for_javascript(options[:accept]) if options[:accept]
+
+
+ 0
+
+
+
+
+
+
+ 448
+
+
+ [:activeClass, :hoverClass, :tolerance].each do |option|
+
+
+ 0
+
+
+
+
+
+
+ 449
+
+
+ options[option] = "'#{options[option]}'" if options[option]
+
+
+ 0
+
+
+
+
+
+
+ 450
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 451
+
+
+
+
+
+
+
+
+
+
+
+
+ 452
+
+
+ %(#{JQUERY_VAR}('#{jquery_id(element_id)}').droppable(#{options_for_javascript(options)});)
+
+
+ 0
+
+
+
+
+
+
+ 453
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 454
+
+
+
+
+
+
+
+
+
+
+
+
+ 455
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 456
+
+
+
+
+
+
+
+
+
+
+
+
+ 457
+
+
+ end
+
+
+
+
+
+
+
+
+
+ 458
+
+
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+