Revision 1297:0a574315af3e .svn/pristine/6c
| .svn/pristine/6c/6c63de300d0e80bc0b6e3de12c96ec81bd4c86b4.svn-base | ||
|---|---|---|
| 1 |
# Redmine - project management software |
|
| 2 |
# Copyright (C) 2006-2012 Jean-Philippe Lang |
|
| 3 |
# |
|
| 4 |
# This program is free software; you can redistribute it and/or |
|
| 5 |
# modify it under the terms of the GNU General Public License |
|
| 6 |
# as published by the Free Software Foundation; either version 2 |
|
| 7 |
# of the License, or (at your option) any later version. |
|
| 8 |
# |
|
| 9 |
# This program is distributed in the hope that it will be useful, |
|
| 10 |
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
| 11 |
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
| 12 |
# GNU General Public License for more details. |
|
| 13 |
# |
|
| 14 |
# You should have received a copy of the GNU General Public License |
|
| 15 |
# along with this program; if not, write to the Free Software |
|
| 16 |
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
|
| 17 |
|
|
| 18 |
module Redmine |
|
| 19 |
module Ciphering |
|
| 20 |
def self.included(base) |
|
| 21 |
base.extend ClassMethods |
|
| 22 |
end |
|
| 23 |
|
|
| 24 |
class << self |
|
| 25 |
def encrypt_text(text) |
|
| 26 |
if cipher_key.blank? || text.blank? |
|
| 27 |
text |
|
| 28 |
else |
|
| 29 |
c = OpenSSL::Cipher::Cipher.new("aes-256-cbc")
|
|
| 30 |
iv = c.random_iv |
|
| 31 |
c.encrypt |
|
| 32 |
c.key = cipher_key |
|
| 33 |
c.iv = iv |
|
| 34 |
e = c.update(text.to_s) |
|
| 35 |
e << c.final |
|
| 36 |
"aes-256-cbc:" + [e, iv].map {|v| Base64.encode64(v).strip}.join('--')
|
|
| 37 |
end |
|
| 38 |
end |
|
| 39 |
|
|
| 40 |
def decrypt_text(text) |
|
| 41 |
if text && match = text.match(/\Aaes-256-cbc:(.+)\Z/) |
|
| 42 |
if cipher_key.blank? |
|
| 43 |
logger.error "Attempt to decrypt a ciphered text with no cipher key configured in config/configuration.yml" if logger |
|
| 44 |
return text |
|
| 45 |
end |
|
| 46 |
text = match[1] |
|
| 47 |
c = OpenSSL::Cipher::Cipher.new("aes-256-cbc")
|
|
| 48 |
e, iv = text.split("--").map {|s| Base64.decode64(s)}
|
|
| 49 |
c.decrypt |
|
| 50 |
c.key = cipher_key |
|
| 51 |
c.iv = iv |
|
| 52 |
d = c.update(e) |
|
| 53 |
d << c.final |
|
| 54 |
else |
|
| 55 |
text |
|
| 56 |
end |
|
| 57 |
end |
|
| 58 |
|
|
| 59 |
def cipher_key |
|
| 60 |
key = Redmine::Configuration['database_cipher_key'].to_s |
|
| 61 |
key.blank? ? nil : Digest::SHA256.hexdigest(key) |
|
| 62 |
end |
|
| 63 |
|
|
| 64 |
def logger |
|
| 65 |
Rails.logger |
|
| 66 |
end |
|
| 67 |
end |
|
| 68 |
|
|
| 69 |
module ClassMethods |
|
| 70 |
def encrypt_all(attribute) |
|
| 71 |
transaction do |
|
| 72 |
all.each do |object| |
|
| 73 |
clear = object.send(attribute) |
|
| 74 |
object.send "#{attribute}=", clear
|
|
| 75 |
raise(ActiveRecord::Rollback) unless object.save(:validation => false) |
|
| 76 |
end |
|
| 77 |
end ? true : false |
|
| 78 |
end |
|
| 79 |
|
|
| 80 |
def decrypt_all(attribute) |
|
| 81 |
transaction do |
|
| 82 |
all.each do |object| |
|
| 83 |
clear = object.send(attribute) |
|
| 84 |
object.send :write_attribute, attribute, clear |
|
| 85 |
raise(ActiveRecord::Rollback) unless object.save(:validation => false) |
|
| 86 |
end |
|
| 87 |
end |
|
| 88 |
end ? true : false |
|
| 89 |
end |
|
| 90 |
|
|
| 91 |
private |
|
| 92 |
|
|
| 93 |
# Returns the value of the given ciphered attribute |
|
| 94 |
def read_ciphered_attribute(attribute) |
|
| 95 |
Redmine::Ciphering.decrypt_text(read_attribute(attribute)) |
|
| 96 |
end |
|
| 97 |
|
|
| 98 |
# Sets the value of the given ciphered attribute |
|
| 99 |
def write_ciphered_attribute(attribute, value) |
|
| 100 |
write_attribute(attribute, Redmine::Ciphering.encrypt_text(value)) |
|
| 101 |
end |
|
| 102 |
end |
|
| 103 |
end |
|
| .svn/pristine/6c/6c693aad7bd181db73cd90834dd1050e5cf2a77a.svn-base | ||
|---|---|---|
| 1 |
--- |
|
| 2 |
custom_fields_001: |
|
| 3 |
name: Database |
|
| 4 |
min_length: 0 |
|
| 5 |
regexp: "" |
|
| 6 |
is_for_all: true |
|
| 7 |
is_filter: true |
|
| 8 |
type: IssueCustomField |
|
| 9 |
max_length: 0 |
|
| 10 |
possible_values: |
|
| 11 |
- MySQL |
|
| 12 |
- PostgreSQL |
|
| 13 |
- Oracle |
|
| 14 |
id: 1 |
|
| 15 |
is_required: false |
|
| 16 |
field_format: list |
|
| 17 |
default_value: "" |
|
| 18 |
editable: true |
|
| 19 |
position: 2 |
|
| 20 |
custom_fields_002: |
|
| 21 |
name: Searchable field |
|
| 22 |
min_length: 1 |
|
| 23 |
regexp: "" |
|
| 24 |
is_for_all: true |
|
| 25 |
is_filter: true |
|
| 26 |
type: IssueCustomField |
|
| 27 |
max_length: 100 |
|
| 28 |
possible_values: "" |
|
| 29 |
id: 2 |
|
| 30 |
is_required: false |
|
| 31 |
field_format: string |
|
| 32 |
searchable: true |
|
| 33 |
default_value: "Default string" |
|
| 34 |
editable: true |
|
| 35 |
position: 1 |
|
| 36 |
custom_fields_003: |
|
| 37 |
name: Development status |
|
| 38 |
min_length: 0 |
|
| 39 |
regexp: "" |
|
| 40 |
is_for_all: false |
|
| 41 |
is_filter: true |
|
| 42 |
type: ProjectCustomField |
|
| 43 |
max_length: 0 |
|
| 44 |
possible_values: |
|
| 45 |
- Stable |
|
| 46 |
- Beta |
|
| 47 |
- Alpha |
|
| 48 |
- Planning |
|
| 49 |
id: 3 |
|
| 50 |
is_required: false |
|
| 51 |
field_format: list |
|
| 52 |
default_value: "" |
|
| 53 |
editable: true |
|
| 54 |
position: 1 |
|
| 55 |
custom_fields_004: |
|
| 56 |
name: Phone number |
|
| 57 |
min_length: 0 |
|
| 58 |
regexp: "" |
|
| 59 |
is_for_all: false |
|
| 60 |
type: UserCustomField |
|
| 61 |
max_length: 0 |
|
| 62 |
possible_values: "" |
|
| 63 |
id: 4 |
|
| 64 |
is_required: false |
|
| 65 |
field_format: string |
|
| 66 |
default_value: "" |
|
| 67 |
editable: true |
|
| 68 |
position: 1 |
|
| 69 |
custom_fields_005: |
|
| 70 |
name: Money |
|
| 71 |
min_length: 0 |
|
| 72 |
regexp: "" |
|
| 73 |
is_for_all: false |
|
| 74 |
type: UserCustomField |
|
| 75 |
max_length: 0 |
|
| 76 |
possible_values: "" |
|
| 77 |
id: 5 |
|
| 78 |
is_required: false |
|
| 79 |
field_format: float |
|
| 80 |
default_value: "" |
|
| 81 |
editable: true |
|
| 82 |
position: 2 |
|
| 83 |
custom_fields_006: |
|
| 84 |
name: Float field |
|
| 85 |
min_length: 0 |
|
| 86 |
regexp: "" |
|
| 87 |
is_for_all: true |
|
| 88 |
type: IssueCustomField |
|
| 89 |
max_length: 0 |
|
| 90 |
possible_values: "" |
|
| 91 |
id: 6 |
|
| 92 |
is_required: false |
|
| 93 |
field_format: float |
|
| 94 |
default_value: "" |
|
| 95 |
editable: true |
|
| 96 |
position: 3 |
|
| 97 |
custom_fields_007: |
|
| 98 |
name: Billable |
|
| 99 |
min_length: 0 |
|
| 100 |
regexp: "" |
|
| 101 |
is_for_all: false |
|
| 102 |
is_filter: true |
|
| 103 |
type: TimeEntryActivityCustomField |
|
| 104 |
max_length: 0 |
|
| 105 |
possible_values: "" |
|
| 106 |
id: 7 |
|
| 107 |
is_required: false |
|
| 108 |
field_format: bool |
|
| 109 |
default_value: "" |
|
| 110 |
editable: true |
|
| 111 |
position: 1 |
|
| 112 |
custom_fields_008: |
|
| 113 |
name: Custom date |
|
| 114 |
min_length: 0 |
|
| 115 |
regexp: "" |
|
| 116 |
is_for_all: true |
|
| 117 |
is_filter: false |
|
| 118 |
type: IssueCustomField |
|
| 119 |
max_length: 0 |
|
| 120 |
possible_values: "" |
|
| 121 |
id: 8 |
|
| 122 |
is_required: false |
|
| 123 |
field_format: date |
|
| 124 |
default_value: "" |
|
| 125 |
editable: true |
|
| 126 |
position: 4 |
|
| 127 |
custom_fields_009: |
|
| 128 |
name: Project 1 cf |
|
| 129 |
min_length: 0 |
|
| 130 |
regexp: "" |
|
| 131 |
is_for_all: false |
|
| 132 |
is_filter: true |
|
| 133 |
type: IssueCustomField |
|
| 134 |
max_length: 0 |
|
| 135 |
possible_values: "" |
|
| 136 |
id: 9 |
|
| 137 |
is_required: false |
|
| 138 |
field_format: date |
|
| 139 |
default_value: "" |
|
| 140 |
editable: true |
|
| 141 |
position: 5 |
|
| 142 |
custom_fields_010: |
|
| 143 |
name: Overtime |
|
| 144 |
min_length: 0 |
|
| 145 |
regexp: "" |
|
| 146 |
is_for_all: false |
|
| 147 |
is_filter: false |
|
| 148 |
type: TimeEntryCustomField |
|
| 149 |
max_length: 0 |
|
| 150 |
possible_values: "" |
|
| 151 |
id: 10 |
|
| 152 |
is_required: false |
|
| 153 |
field_format: bool |
|
| 154 |
default_value: 0 |
|
| 155 |
editable: true |
|
| 156 |
position: 1 |
|
| 157 |
custom_fields_011: |
|
| 158 |
id: 11 |
|
| 159 |
name: Binary |
|
| 160 |
type: CustomField |
|
| 161 |
possible_values: |
|
| 162 |
- !binary | |
|
| 163 |
SGXDqWzDp2prc2Tigqw2NTTDuQ== |
|
| 164 |
- Other value |
|
| 165 |
field_format: list |
|
| .svn/pristine/6c/6c96a40bb02084f0ca89601fc6cb8ef86565a45a.svn-base | ||
|---|---|---|
| 1 |
<p><%= l(:mail_body_register) %><br /> |
|
| 2 |
<%= link_to h(@url), @url %></p> |
|
| .svn/pristine/6c/6cc533b0e56df4187bfb76b52dd325e1a95364a0.svn-base | ||
|---|---|---|
| 1 |
function jsToolBar(e){if(!document.createElement){return}if(!e){return}if(typeof document["selection"]=="undefined"&&typeof e["setSelectionRange"]=="undefined"){return}this.textarea=e;this.editor=document.createElement("div");this.editor.className="jstEditor";this.textarea.parentNode.insertBefore(this.editor,this.textarea);this.editor.appendChild(this.textarea);this.toolbar=document.createElement("div");this.toolbar.className="jstElements";this.editor.parentNode.insertBefore(this.toolbar,this.editor);if(this.editor.addEventListener&&navigator.appVersion.match(/\bMSIE\b/)){this.handle=document.createElement("div");this.handle.className="jstHandle";var t=this.resizeDragStart;var n=this;this.handle.addEventListener("mousedown",function(e){t.call(n,e)},false);window.addEventListener("unload",function(){var e=n.handle.parentNode.removeChild(n.handle);delete n.handle},false);this.editor.parentNode.insertBefore(this.handle,this.editor.nextSibling)}this.context=null;this.toolNodes={}}function jsButton(e,t,n,r){if(typeof jsToolBar.strings=="undefined"){this.title=e||null}else{this.title=jsToolBar.strings[e]||e||null}this.fn=t||function(){};this.scope=n||null;this.className=r||null}function jsSpace(e){this.id=e||null;this.width=null}function jsCombo(e,t,n,r,i){this.title=e||null;this.options=t||null;this.scope=n||null;this.fn=r||function(){};this.className=i||null}jsButton.prototype.draw=function(){if(!this.scope)return null;var e=document.createElement("button");e.setAttribute("type","button");e.tabIndex=200;if(this.className)e.className=this.className;e.title=this.title;var t=document.createElement("span");t.appendChild(document.createTextNode(this.title));e.appendChild(t);if(this.icon!=undefined){e.style.backgroundImage="url("+this.icon+")"}if(typeof this.fn=="function"){var n=this;e.onclick=function(){try{n.fn.apply(n.scope,arguments)}catch(e){}return false}}return e};jsSpace.prototype.draw=function(){var e=document.createElement("span");if(this.id)e.id=this.id;e.appendChild(document.createTextNode(String.fromCharCode(160)));e.className="jstSpacer";if(this.width)e.style.marginRight=this.width+"px";return e};jsCombo.prototype.draw=function(){if(!this.scope||!this.options)return null;var e=document.createElement("select");if(this.className)e.className=className;e.title=this.title;for(var t in this.options){var n=document.createElement("option");n.value=t;n.appendChild(document.createTextNode(this.options[t]));e.appendChild(n)}var r=this;e.onchange=function(){try{r.fn.call(r.scope,this.value)}catch(e){alert(e)}return false};return e};jsToolBar.prototype={base_url:"",mode:"wiki",elements:{},help_link:"",getMode:function(){return this.mode},setMode:function(e){this.mode=e||"wiki"},switchMode:function(e){e=e||"wiki";this.draw(e)},setHelpLink:function(e){this.help_link=e},button:function(e){var t=this.elements[e];if(typeof t.fn[this.mode]!="function")return null;var n=new jsButton(t.title,t.fn[this.mode],this,"jstb_"+e);if(t.icon!=undefined)n.icon=t.icon;return n},space:function(e){var t=new jsSpace(e);if(this.elements[e].width!==undefined)t.width=this.elements[e].width;return t},combo:function(e){var t=this.elements[e];var n=t[this.mode].list.length;if(typeof t[this.mode].fn!="function"||n==0){return null}else{var r={};for(var i=0;i<n;i++){var s=t[this.mode].list[i];r[s]=t.options[s]}return new jsCombo(t.title,r,this,t[this.mode].fn)}},draw:function(e){this.setMode(e);while(this.toolbar.hasChildNodes()){this.toolbar.removeChild(this.toolbar.firstChild)}this.toolNodes={};var t=document.createElement("div");t.className="help";t.innerHTML=this.help_link;"<a href=\"/help/wiki_syntax.html\" onclick=\"window.open('/help/wiki_syntax.html', '', 'resizable=yes, location=no, width=300, height=640, menubar=no, status=no, scrollbars=yes'); return false;\">Aide</a>";this.toolbar.appendChild(t);var n,r,i;for(var s in this.elements){n=this.elements[s];var o=n.type==undefined||n.type==""||n.disabled!=undefined&&n.disabled||n.context!=undefined&&n.context!=null&&n.context!=this.context;if(!o&&typeof this[n.type]=="function"){r=this[n.type](s);if(r)i=r.draw();if(i){this.toolNodes[s]=i;this.toolbar.appendChild(i)}}}},singleTag:function(e,t){e=e||null;t=t||e;if(!e||!t){return}this.encloseSelection(e,t)},encloseLineSelection:function(e,t,n){this.textarea.focus();e=e||"";t=t||"";var r,i,s,o,u,a;if(typeof document["selection"]!="undefined"){s=document.selection.createRange().text}else if(typeof this.textarea["setSelectionRange"]!="undefined"){r=this.textarea.selectionStart;i=this.textarea.selectionEnd;o=this.textarea.scrollTop;r=this.textarea.value.substring(0,r).replace(/[^\r\n]*$/g,"").length;i=this.textarea.value.length-this.textarea.value.substring(i,this.textarea.value.length).replace(/^[^\r\n]*/,"").length;s=this.textarea.value.substring(r,i)}if(s.match(/ $/)){s=s.substring(0,s.length-1);t=t+" "}if(typeof n=="function"){a=s?n.call(this,s):n("")}else{a=s?s:""}u=e+a+t;if(typeof document["selection"]!="undefined"){document.selection.createRange().text=u;var f=this.textarea.createTextRange();f.collapse(false);f.move("character",-t.length);f.select()}else if(typeof this.textarea["setSelectionRange"]!="undefined"){this.textarea.value=this.textarea.value.substring(0,r)+u+this.textarea.value.substring(i);if(s){this.textarea.setSelectionRange(r+u.length,r+u.length)}else{this.textarea.setSelectionRange(r+e.length,r+e.length)}this.textarea.scrollTop=o}},encloseSelection:function(e,t,n){this.textarea.focus();e=e||"";t=t||"";var r,i,s,o,u,a;if(typeof document["selection"]!="undefined"){s=document.selection.createRange().text}else if(typeof this.textarea["setSelectionRange"]!="undefined"){r=this.textarea.selectionStart;i=this.textarea.selectionEnd;o=this.textarea.scrollTop;s=this.textarea.value.substring(r,i)}if(s.match(/ $/)){s=s.substring(0,s.length-1);t=t+" "}if(typeof n=="function"){a=s?n.call(this,s):n("")}else{a=s?s:""}u=e+a+t;if(typeof document["selection"]!="undefined"){document.selection.createRange().text=u;var f=this.textarea.createTextRange();f.collapse(false);f.move("character",-t.length);f.select()}else if(typeof this.textarea["setSelectionRange"]!="undefined"){this.textarea.value=this.textarea.value.substring(0,r)+u+this.textarea.value.substring(i);if(s){this.textarea.setSelectionRange(r+u.length,r+u.length)}else{this.textarea.setSelectionRange(r+e.length,r+e.length)}this.textarea.scrollTop=o}},stripBaseURL:function(e){if(this.base_url!=""){var t=e.indexOf(this.base_url);if(t==0){e=e.substr(this.base_url.length)}}return e}};jsToolBar.prototype.resizeSetStartH=function(){this.dragStartH=this.textarea.offsetHeight+0};jsToolBar.prototype.resizeDragStart=function(e){var t=this;this.dragStartY=e.clientY;this.resizeSetStartH();document.addEventListener("mousemove",this.dragMoveHdlr=function(e){t.resizeDragMove(e)},false);document.addEventListener("mouseup",this.dragStopHdlr=function(e){t.resizeDragStop(e)},false)};jsToolBar.prototype.resizeDragMove=function(e){this.textarea.style.height=this.dragStartH+e.clientY-this.dragStartY+"px"};jsToolBar.prototype.resizeDragStop=function(e){document.removeEventListener("mousemove",this.dragMoveHdlr,false);document.removeEventListener("mouseup",this.dragStopHdlr,false)};jsToolBar.prototype.elements.strong={type:"button",title:"Strong",fn:{wiki:function(){this.singleTag("*")}}};jsToolBar.prototype.elements.em={type:"button",title:"Italic",fn:{wiki:function(){this.singleTag("_")}}};jsToolBar.prototype.elements.ins={type:"button",title:"Underline",fn:{wiki:function(){this.singleTag("+")}}};jsToolBar.prototype.elements.del={type:"button",title:"Deleted",fn:{wiki:function(){this.singleTag("-")}}};jsToolBar.prototype.elements.code={type:"button",title:"Code",fn:{wiki:function(){this.singleTag("@")}}};jsToolBar.prototype.elements.space1={type:"space"};jsToolBar.prototype.elements.h1={type:"button",title:"Heading 1",fn:{wiki:function(){this.encloseLineSelection("h1. ","",function(e){e=e.replace(/^h\d+\.\s+/,"");return e})}}};jsToolBar.prototype.elements.h2={type:"button",title:"Heading 2",fn:{wiki:function(){this.encloseLineSelection("h2. ","",function(e){e=e.replace(/^h\d+\.\s+/,"");return e})}}};jsToolBar.prototype.elements.h3={type:"button",title:"Heading 3",fn:{wiki:function(){this.encloseLineSelection("h3. ","",function(e){e=e.replace(/^h\d+\.\s+/,"");return e})}}};jsToolBar.prototype.elements.space2={type:"space"};jsToolBar.prototype.elements.ul={type:"button",title:"Unordered list",fn:{wiki:function(){this.encloseLineSelection("","",function(e){e=e.replace(/\r/g,"");return e.replace(/(\n|^)[#-]?\s*/g,"$1* ")})}}};jsToolBar.prototype.elements.ol={type:"button",title:"Ordered list",fn:{wiki:function(){this.encloseLineSelection("","",function(e){e=e.replace(/\r/g,"");return e.replace(/(\n|^)[*-]?\s*/g,"$1# ")})}}};jsToolBar.prototype.elements.space3={type:"space"};jsToolBar.prototype.elements.bq={type:"button",title:"Quote",fn:{wiki:function(){this.encloseLineSelection("","",function(e){e=e.replace(/\r/g,"");return e.replace(/(\n|^) *([^\n]*)/g,"$1> $2")})}}};jsToolBar.prototype.elements.unbq={type:"button",title:"Unquote",fn:{wiki:function(){this.encloseLineSelection("","",function(e){e=e.replace(/\r/g,"");return e.replace(/(\n|^) *[>]? *([^\n]*)/g,"$1$2")})}}};jsToolBar.prototype.elements.pre={type:"button",title:"Preformatted text",fn:{wiki:function(){this.encloseLineSelection("<pre>\n","\n</pre>")}}};jsToolBar.prototype.elements.space4={type:"space"};jsToolBar.prototype.elements.link={type:"button",title:"Wiki link",fn:{wiki:function(){this.encloseSelection("[[","]]")}}};jsToolBar.prototype.elements.img={type:"button",title:"Image",fn:{wiki:function(){this.encloseSelection("!","!")}}}
|
|
| .svn/pristine/6c/6cd75d05f4deac0559250c87c2ffccdd03b546c2.svn-base | ||
|---|---|---|
| 1 |
# Redmine - project management software |
|
| 2 |
# Copyright (C) 2006-2012 Jean-Philippe Lang |
|
| 3 |
# |
|
| 4 |
# This program is free software; you can redistribute it and/or |
|
| 5 |
# modify it under the terms of the GNU General Public License |
|
| 6 |
# as published by the Free Software Foundation; either version 2 |
|
| 7 |
# of the License, or (at your option) any later version. |
|
| 8 |
# |
|
| 9 |
# This program is distributed in the hope that it will be useful, |
|
| 10 |
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
| 11 |
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
| 12 |
# GNU General Public License for more details. |
|
| 13 |
# |
|
| 14 |
# You should have received a copy of the GNU General Public License |
|
| 15 |
# along with this program; if not, write to the Free Software |
|
| 16 |
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
|
| 17 |
|
|
| 18 |
require File.expand_path('../../test_helper', __FILE__)
|
|
| 19 |
|
|
| 20 |
class EnumerationsControllerTest < ActionController::TestCase |
|
| 21 |
fixtures :enumerations, :issues, :users |
|
| 22 |
|
|
| 23 |
def setup |
|
| 24 |
@request.session[:user_id] = 1 # admin |
|
| 25 |
end |
|
| 26 |
|
|
| 27 |
def test_index |
|
| 28 |
get :index |
|
| 29 |
assert_response :success |
|
| 30 |
assert_template 'index' |
|
| 31 |
end |
|
| 32 |
|
|
| 33 |
def test_index_should_require_admin |
|
| 34 |
@request.session[:user_id] = nil |
|
| 35 |
get :index |
|
| 36 |
assert_response 302 |
|
| 37 |
end |
|
| 38 |
|
|
| 39 |
def test_new |
|
| 40 |
get :new, :type => 'IssuePriority' |
|
| 41 |
assert_response :success |
|
| 42 |
assert_template 'new' |
|
| 43 |
assert_kind_of IssuePriority, assigns(:enumeration) |
|
| 44 |
assert_tag 'input', :attributes => {:name => 'enumeration[type]', :value => 'IssuePriority'}
|
|
| 45 |
assert_tag 'input', :attributes => {:name => 'enumeration[name]'}
|
|
| 46 |
end |
|
| 47 |
|
|
| 48 |
def test_new_with_invalid_type_should_respond_with_404 |
|
| 49 |
get :new, :type => 'UnknownType' |
|
| 50 |
assert_response 404 |
|
| 51 |
end |
|
| 52 |
|
|
| 53 |
def test_create |
|
| 54 |
assert_difference 'IssuePriority.count' do |
|
| 55 |
post :create, :enumeration => {:type => 'IssuePriority', :name => 'Lowest'}
|
|
| 56 |
end |
|
| 57 |
assert_redirected_to '/enumerations' |
|
| 58 |
e = IssuePriority.find_by_name('Lowest')
|
|
| 59 |
assert_not_nil e |
|
| 60 |
end |
|
| 61 |
|
|
| 62 |
def test_create_with_failure |
|
| 63 |
assert_no_difference 'IssuePriority.count' do |
|
| 64 |
post :create, :enumeration => {:type => 'IssuePriority', :name => ''}
|
|
| 65 |
end |
|
| 66 |
assert_response :success |
|
| 67 |
assert_template 'new' |
|
| 68 |
end |
|
| 69 |
|
|
| 70 |
def test_edit |
|
| 71 |
get :edit, :id => 6 |
|
| 72 |
assert_response :success |
|
| 73 |
assert_template 'edit' |
|
| 74 |
assert_tag 'input', :attributes => {:name => 'enumeration[name]', :value => 'High'}
|
|
| 75 |
end |
|
| 76 |
|
|
| 77 |
def test_edit_invalid_should_respond_with_404 |
|
| 78 |
get :edit, :id => 999 |
|
| 79 |
assert_response 404 |
|
| 80 |
end |
|
| 81 |
|
|
| 82 |
def test_update |
|
| 83 |
assert_no_difference 'IssuePriority.count' do |
|
| 84 |
put :update, :id => 6, :enumeration => {:type => 'IssuePriority', :name => 'New name'}
|
|
| 85 |
end |
|
| 86 |
assert_redirected_to '/enumerations' |
|
| 87 |
e = IssuePriority.find(6) |
|
| 88 |
assert_equal 'New name', e.name |
|
| 89 |
end |
|
| 90 |
|
|
| 91 |
def test_update_with_failure |
|
| 92 |
assert_no_difference 'IssuePriority.count' do |
|
| 93 |
put :update, :id => 6, :enumeration => {:type => 'IssuePriority', :name => ''}
|
|
| 94 |
end |
|
| 95 |
assert_response :success |
|
| 96 |
assert_template 'edit' |
|
| 97 |
end |
|
| 98 |
|
|
| 99 |
def test_destroy_enumeration_not_in_use |
|
| 100 |
assert_difference 'IssuePriority.count', -1 do |
|
| 101 |
delete :destroy, :id => 7 |
|
| 102 |
end |
|
| 103 |
assert_redirected_to :controller => 'enumerations', :action => 'index' |
|
| 104 |
assert_nil Enumeration.find_by_id(7) |
|
| 105 |
end |
|
| 106 |
|
|
| 107 |
def test_destroy_enumeration_in_use |
|
| 108 |
assert_no_difference 'IssuePriority.count' do |
|
| 109 |
delete :destroy, :id => 4 |
|
| 110 |
end |
|
| 111 |
assert_response :success |
|
| 112 |
assert_template 'destroy' |
|
| 113 |
assert_not_nil Enumeration.find_by_id(4) |
|
| 114 |
assert_select 'select[name=reassign_to_id]' do |
|
| 115 |
assert_select 'option[value=6]', :text => 'High' |
|
| 116 |
end |
|
| 117 |
end |
|
| 118 |
|
|
| 119 |
def test_destroy_enumeration_in_use_with_reassignment |
|
| 120 |
issue = Issue.find(:first, :conditions => {:priority_id => 4})
|
|
| 121 |
assert_difference 'IssuePriority.count', -1 do |
|
| 122 |
delete :destroy, :id => 4, :reassign_to_id => 6 |
|
| 123 |
end |
|
| 124 |
assert_redirected_to :controller => 'enumerations', :action => 'index' |
|
| 125 |
assert_nil Enumeration.find_by_id(4) |
|
| 126 |
# check that the issue was reassign |
|
| 127 |
assert_equal 6, issue.reload.priority_id |
|
| 128 |
end |
|
| 129 |
end |
|
| .svn/pristine/6c/6cea03c76318e826b03e4d334daa05b149e4780d.svn-base | ||
|---|---|---|
| 1 |
# ActsAsWatchable |
|
| 2 |
module Redmine |
|
| 3 |
module Acts |
|
| 4 |
module Watchable |
|
| 5 |
def self.included(base) |
|
| 6 |
base.extend ClassMethods |
|
| 7 |
end |
|
| 8 |
|
|
| 9 |
module ClassMethods |
|
| 10 |
def acts_as_watchable(options = {})
|
|
| 11 |
return if self.included_modules.include?(Redmine::Acts::Watchable::InstanceMethods) |
|
| 12 |
class_eval do |
|
| 13 |
has_many :watchers, :as => :watchable, :dependent => :delete_all |
|
| 14 |
has_many :watcher_users, :through => :watchers, :source => :user, :validate => false |
|
| 15 |
|
|
| 16 |
scope :watched_by, lambda { |user_id|
|
|
| 17 |
{ :include => :watchers,
|
|
| 18 |
:conditions => ["#{Watcher.table_name}.user_id = ?", user_id] }
|
|
| 19 |
} |
|
| 20 |
attr_protected :watcher_ids, :watcher_user_ids |
|
| 21 |
end |
|
| 22 |
send :include, Redmine::Acts::Watchable::InstanceMethods |
|
| 23 |
alias_method_chain :watcher_user_ids=, :uniq_ids |
|
| 24 |
end |
|
| 25 |
end |
|
| 26 |
|
|
| 27 |
module InstanceMethods |
|
| 28 |
def self.included(base) |
|
| 29 |
base.extend ClassMethods |
|
| 30 |
end |
|
| 31 |
|
|
| 32 |
# Returns an array of users that are proposed as watchers |
|
| 33 |
def addable_watcher_users |
|
| 34 |
users = self.project.users.sort - self.watcher_users |
|
| 35 |
if respond_to?(:visible?) |
|
| 36 |
users.reject! {|user| !visible?(user)}
|
|
| 37 |
end |
|
| 38 |
users |
|
| 39 |
end |
|
| 40 |
|
|
| 41 |
# Adds user as a watcher |
|
| 42 |
def add_watcher(user) |
|
| 43 |
self.watchers << Watcher.new(:user => user) |
|
| 44 |
end |
|
| 45 |
|
|
| 46 |
# Removes user from the watchers list |
|
| 47 |
def remove_watcher(user) |
|
| 48 |
return nil unless user && user.is_a?(User) |
|
| 49 |
Watcher.delete_all "watchable_type = '#{self.class}' AND watchable_id = #{self.id} AND user_id = #{user.id}"
|
|
| 50 |
end |
|
| 51 |
|
|
| 52 |
# Adds/removes watcher |
|
| 53 |
def set_watcher(user, watching=true) |
|
| 54 |
watching ? add_watcher(user) : remove_watcher(user) |
|
| 55 |
end |
|
| 56 |
|
|
| 57 |
# Overrides watcher_user_ids= to make user_ids uniq |
|
| 58 |
def watcher_user_ids_with_uniq_ids=(user_ids) |
|
| 59 |
if user_ids.is_a?(Array) |
|
| 60 |
user_ids = user_ids.uniq |
|
| 61 |
end |
|
| 62 |
send :watcher_user_ids_without_uniq_ids=, user_ids |
|
| 63 |
end |
|
| 64 |
|
|
| 65 |
# Returns true if object is watched by +user+ |
|
| 66 |
def watched_by?(user) |
|
| 67 |
!!(user && self.watcher_user_ids.detect {|uid| uid == user.id })
|
|
| 68 |
end |
|
| 69 |
|
|
| 70 |
def notified_watchers |
|
| 71 |
notified = watcher_users.active |
|
| 72 |
notified.reject! {|user| user.mail.blank? || user.mail_notification == 'none'}
|
|
| 73 |
if respond_to?(:visible?) |
|
| 74 |
notified.reject! {|user| !visible?(user)}
|
|
| 75 |
end |
|
| 76 |
notified |
|
| 77 |
end |
|
| 78 |
|
|
| 79 |
# Returns an array of watchers' email addresses |
|
| 80 |
def watcher_recipients |
|
| 81 |
notified_watchers.collect(&:mail) |
|
| 82 |
end |
|
| 83 |
|
|
| 84 |
module ClassMethods; end |
|
| 85 |
end |
|
| 86 |
end |
|
| 87 |
end |
|
| 88 |
end |
|
Also available in: Unified diff