Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Original plugin, version 0.1.0

  • Loading branch information...
commit 657d054685431cf9568d590bd60addb2d9e34bed 0 parents
@martin-denizet authored
24 LICENSE
@@ -0,0 +1,24 @@
+Copyright (c) 2010 Konstantin Zaitsev, Sergei Vasiliev, Alexandr Poplavsky, Axmor Software, Jens Alfke
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ * Neither the name of the Axmor Software nor the
+ names of its contributors may be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
10 README.rdoc
@@ -0,0 +1,10 @@
+= redmine_attach_screenshot
+
+This plugin allows attaching several screenshots from clipboard directly to a Redmine issue.
+Requires RMagick (http://rmagick.rubyforge.org/) to show screenshot thumbnails when adding/editing an issue.
+Compatibility: Redmine 1.1.0
+
+Credits:
+Authors: Konstantin Zaitcev (kos@axmor.com), Sergei Vasilyev (vsv@axmor.com), Alexandr Poplavsky (poplavsky@axmor.com),
+Inspired by Atlassian JIRA (http://www.atlassian.com/software/jira)
+Work sponsored by Axmor Software (http://www.axmor.com)
38 app/controllers/attach_screenshot_controller.rb
@@ -0,0 +1,38 @@
+#require 'RMagick'
+
+class AttachScreenshotController < ApplicationController
+ unloadable
+ skip_before_filter :require_login
+ skip_before_filter :verify_authenticity_token
+ accept_key_auth :index
+
+ def index
+ path = "#{RAILS_ROOT}/tmp/"
+ if request.post?
+ date = DateTime.now.strftime("%H%M%S")
+ @fname = make_tmpname(date)
+ file = File.new(path + make_tmpname(date), "wb");
+ file.write(params[:attachments].read);
+ file.close();
+ if (Object.const_defined?(:Magick))
+ img = Magick::Image::read(file.path()).first
+ thumb = img.resize_to_fit(150, 150)
+ @fname = make_tmpname(date, "thumb.png")
+ thumb.write path + @fname
+ end
+ render :inline => "<%= @fname %>"
+ else
+ @fname = params[:id];
+ send_file(path + @fname,
+ :disposition => 'inline',
+ :type => 'image/png',
+ :filename => "screenshot.png");
+ end
+ end
+
+ private
+
+ def make_tmpname(date, name = "screenshot.png")
+ sprintf('%d_%d%s', User.current.id, date, name)
+ end
+end
2  app/helpers/attach_screenshot_helper.rb
@@ -0,0 +1,2 @@
+module AttachScreenshotHelper
+end
90 app/views/attachments/_form.rhtml
@@ -0,0 +1,90 @@
+<% content_for :header_tags do %>
+ <%= stylesheet_link_tag 'attach_screenshot', :plugin => 'redmine_attach_screenshot' %>
+ <%= javascript_include_tag 'attach_screenshot', :plugin => 'redmine_attach_screenshot' %>
+<% end %>
+<span id="attachments_fields">
+<%= file_field_tag 'attachments[1][file]', :size => 30, :id => nil -%><label class="inline"><span id="attachment_description_label_content"><%= l(:label_optional_description) %></span><%= text_field_tag 'attachments[1][description]', '', :size => 60, :id => nil %>
+</label>
+</span>
+<br />
+<small><%= link_to l(:label_add_another_file), '#', :onclick => 'addFileField(); return false;' %>
+(<%= l(:label_max_size) %>: <%= number_to_human_size(Setting.attachment_max_size.to_i.kilobytes) %>)
+</small>
+<br />
+<br />
+<% if @issue %>
+<% if @issue.new_record? %>
+ <label>
+<% end %>
+<%= l(:label_screenshots) %>
+<% if @issue.new_record? %>
+ </label>
+<% else %>
+ <br />
+<% end %>
+<span id="attach_applet" style="display: none; position: fixed; top: 50px; left: 10px; border: solid 1px #BBB;"></span>
+<span id="screenshots_fields">
+<%= submit_tag l(:button_add), :onclick => 'showAttachScreen(); return false;'%>
+</span>
+<small><%= l(:label_max_size) %>: <%= number_to_human_size(Setting.attachment_max_size.to_i.kilobytes) %>
+</small>
+<br />
+<span id="screenshots"></span>
+<br />
+
+<script type="text/javascript">
+ function showAttachScreen() {
+ document.getElementById('attach_applet').style.display = 'block';
+ document.getElementById('attach_applet').innerHTML = '<applet codebase="<%= url_for(:only_path => false, :controller => 'welcome')%>plugin_assets/redmine_attach_screenshot/javascripts/" code="com.axmor.redmine.uploader.Uploader.class" archive="uploader_applet.jar" height="600" width="700" MAYSCRIPT>'+
+ '<param name="label.image" value="<%= l(:label_image) %>">' +
+ '<param name="label.button.paste" value="<%= l(:label_button_paste) %>">' +
+ '<param name="label.button.attach" value="<%= l(:button_attach) %>">' +
+ '<param name="label.button.cancel" value="<%= l(:button_cancel) %>">' +
+ '<param name="error.close.msg" value="<%= l(:error_close_msg) %>">' +
+ '<param name="error.close.title" value="<%= l(:error_close_title) %>">' +
+ '<param name="attach.url" value="<%= url_for(:only_path => false, :controller => 'welcome')%>attach_screenshot">' +
+ '<param name="error.attach.msg" value="<%= l(:error_attach_msg) %>">' +
+ '<param name="error.attach.title" value="<%= l(:error_attach_title) %>">' +
+ '<param name="rss.key" value="<%= User.current.rss_key %>">' +
+ 'Applet</applet>';
+ }
+ function addAttachScreen(fileId) {
+ var s = document.createElement("span");
+ s.id = fileId;
+ s.className = "screen_thumb";
+
+ var s1 = document.createElement("span");
+ s1.className = "st1";
+ var s2 = document.createElement("span");
+ s2.className = "st2";
+
+ var im = document.createElement("img");
+ im.src = "<%= url_for(:only_path => false, :controller => 'welcome')%>attach_screenshot?id=" + fileId;
+
+ var b = document.createElement("input");
+ b.type = "image";
+ b.src = "<%= url_for(:only_path => false, :controller => 'welcome')%>images/delete.png"
+ b.setAttribute("onClick", "deleteAttachScreen('" + fileId + "'); return false;");
+
+ var i = document.createElement("input");
+ i.type = "image";
+ i.src = "<%= url_for(:only_path => false, :controller => 'welcome')%>images/lightning.png";
+ i.setAttribute("onClick", "addLinkToAttachScreen('" + fileId + "'); return false;");
+
+ var d = document.createElement("input");
+ d.name = "screenshots[" + fileId + "][description]";
+ d.type = "text";
+ d.size = 15;
+
+ s1.appendChild(im);
+ s.appendChild(s1);
+ s2.appendChild(d);
+ s2.appendChild(b);
+ s2.appendChild(i);
+ s.appendChild(s2);
+
+ p = document.getElementById("screenshots");
+ p.appendChild(s);
+ }
+</script>
+<% end %>
15 assets/javascripts/attach_screenshot.js
@@ -0,0 +1,15 @@
+//var screenshotFieldCount = 1;
+
+function hideAttachScreen() {
+ document.getElementById('attach_applet').style.display = 'none';
+ document.getElementById('attach_applet').innerHTML = '';
+}
+function deleteAttachScreen(fileId) {
+ p.removeChild(document.getElementById(fileId));
+}
+function addLinkToAttachScreen(fileId) {
+ if (wikiToolbar){
+ fileId = fileId.replace("thumb", "screenshot")
+ wikiToolbar.encloseSelection("!"+ fileId +"!","");
+ }
+}
BIN  assets/javascripts/uploader_applet.jar
Binary file not shown
30 assets/stylesheets/attach_screenshot.css
@@ -0,0 +1,30 @@
+#screenshots_fields input[type=text] {margin-left: 8px; }
+img.scr_attach_icon {
+ text-align: center;
+ vertical-align: middle;
+ border: 1px solid grey;
+}
+span.screen_thumb {
+ display: block;
+ position: relative;
+ float: left;
+ text-align: center;
+ vertical-align: bottom;
+ margin: 3px;
+}
+span.screen_thumb .st1 {
+ display: table-cell;
+ position: relative;
+ width: 160px;
+ height: 160px;
+ text-align: center;
+ vertical-align: middle;
+}
+span.screen_thumb .st1 im {
+ vertical-align: middle;
+}
+span.screen_thumb .st2 {
+ width: 160px;
+ display: block;
+ text-align: center;
+}
10 config/locales/en.yml
@@ -0,0 +1,10 @@
+en:
+ label_screenshots: Screenshots
+ label_add_another_screenshot: Add another screenshot
+ label_button_paste: Paste image from clipboard
+ label_image: Screenshot
+ button_attach: Attach
+ error_close_msg: Can not close applet, {0}
+ error_close_title: Error
+ error_attach_msg: Error, {0}
+ error_attach_title: Attaching error
10 config/locales/ru.yml
@@ -0,0 +1,10 @@
+ru:
+ label_screenshots: Скриншоты
+ label_add_another_screenshot: Добавить еще один скриншот
+ label_button_paste: Вставить скриншот из буфера обмена
+ label_image: Скриншот
+ button_attach: Добавить
+ error_close_msg: Невозможно закрыть аплет, {0}
+ error_close_title: Ошибка
+ error_attach_msg: Ошибка, {0}
+ error_attach_title: Ошибка при загрузке
17 init.rb
@@ -0,0 +1,17 @@
+require 'redmine'
+require 'dispatcher'
+require 'application_patch'
+require 'cleanup_tmp'
+
+require_dependency 'attachment_hook'
+
+Redmine::Plugin.register :redmine_attach_screenshot do
+ name 'Redmine Attach Screenshot plugin'
+ author 'Konstantin Zaitsev, Sergei Vasiliev, Alexandr Poplavsky, Jens Alfke'
+ description 'Attach screenshots from clipboard directly to a Redmine issue'
+ version '0.1.0'
+ Dispatcher.to_prepare do
+ ApplicationController.send(:include, AttachScreenshotPlugin::ApplicationControllerPatch)
+ AccountController.send(:include, AttachScreenshotPlugin::CleanupTmp)
+ end
+end
24 lib/application_patch.rb
@@ -0,0 +1,24 @@
+require 'account_controller'
+require 'ftools'
+
+module AttachScreenshotPlugin
+ module ApplicationControllerPatch
+ def self.included(base) # :nodoc:
+ base.send(:include, InstanceMethods)
+ base.class_eval do
+ unloadable
+ alias_method_chain :find_current_user, :screenshot
+ end
+ end
+
+ module InstanceMethods
+ def find_current_user_with_screenshot
+ if params[:controller] == "attach_screenshot" && request.post? && params[:key].present?
+ User.find_by_rss_key(params[:key])
+ else
+ find_current_user_without_screenshot
+ end
+ end
+ end
+ end
+end
76 lib/attachment_hook.rb
@@ -0,0 +1,76 @@
+require 'redmine'
+
+module AttachmentHook
+ class Hooks < Redmine::Hook::ViewListener
+
+ def attach_screenshots (context ={})
+ issue = context[:issue]
+ journal = context[:journal]
+ params = context[:params]
+
+ unsaved = []
+ screenshots = params[:screenshots]
+ if screenshots && screenshots.is_a?(Hash)
+ screenshots.each_pair do |key, screenshot|
+ key = key.gsub("thumb", "screenshot")
+ path = "#{RAILS_ROOT}/tmp/" + key
+ file = File.open(path, "rb")
+
+ def file.init(name)
+ @screenshot_name = name
+ end
+
+ def file.content_type
+ "image/png"
+ end
+
+ def file.size
+ File.size(path())
+ end
+
+ def file.original_filename
+ @screenshot_name
+ end
+
+ file.init(key)
+
+ next unless file && file.size > 0
+ a = Attachment.create(:container => issue,
+ :file => file,
+ :description => screenshot['description'].to_s.strip,
+ :author => User.current)
+
+ file.close()
+ File.delete(path)
+ key = key.gsub("screenshot", "thumb")
+ path = "#{RAILS_ROOT}/tmp/" + key
+ begin
+ File.delete(path)
+ rescue
+ end
+ if a.new_record?
+ unsaved << a
+ else
+ if journal
+ journal.details << JournalDetail.new(:property => 'attachment',
+ :prop_key => a.id,
+ :value => a.filename)
+ end
+ end
+ end
+ if unsaved.any?
+ flash[:warning] = l(:warning_attachments_not_saved, unsaved.size)
+ end
+ end
+ end
+
+ def controller_issues_edit_before_save (context ={})
+ attach_screenshots(context)
+ end
+
+ def controller_issues_new_after_save (context ={})
+ attach_screenshots(context)
+ end
+
+ end
+end
37 lib/cleanup_tmp.rb
@@ -0,0 +1,37 @@
+require 'account_controller'
+require 'ftools'
+require 'find'
+
+module AttachScreenshotPlugin
+ module CleanupTmp
+ def self.included(base) # :nodoc:
+ base.send(:include, InstanceMethods)
+
+ base.class_eval do
+ alias_method_chain :logout, :cleanup
+ end
+ end
+
+ module InstanceMethods
+ class ApplicationControllerPatchRoutes < Redmine::Hook::Listener
+ def controller_account_success_authentication_after(params)
+ InstanceMethods.cleanup
+ end
+ end
+
+ def self.cleanup
+ ss = sprintf('%d_', User.current.id)
+ Find.find("#{RAILS_ROOT}/tmp/") do |f|
+ if (f[ss]!=nil)
+ File.delete(f)
+ end
+ end
+ end
+
+ def logout_with_cleanup
+ InstanceMethods.cleanup
+ logout_without_cleanup
+ end
+ end
+ end
+end
Please sign in to comment.
Something went wrong with that request. Please try again.